veza/veza-backend-api/internal/services/hls_playlist_generator.go
2025-12-03 20:29:37 +01:00

174 lines
5.9 KiB
Go

package services
import (
"fmt"
"sort"
"strings"
)
// HLSPlaylistGenerator génère des playlists HLS au format standard
// T0341: Create HLS Master Playlist Generator
type HLSPlaylistGenerator struct{}
// NewHLSPlaylistGenerator crée un nouveau générateur de playlist HLS
func NewHLSPlaylistGenerator() *HLSPlaylistGenerator {
return &HLSPlaylistGenerator{}
}
// GenerateMasterPlaylist génère un master playlist HLS avec les variantes de qualité
// bitrates: liste des bitrates en kbps (ex: [128, 192, 320])
// baseURL: URL de base pour les playlists de qualité (ex: "track_123" ou "http://example.com/track_123")
// Retourne le contenu du master playlist au format HLS standard
func (g *HLSPlaylistGenerator) GenerateMasterPlaylist(bitrates []int, baseURL string) string {
var builder strings.Builder
// En-tête HLS standard
builder.WriteString("#EXTM3U\n")
builder.WriteString("#EXT-X-VERSION:3\n")
// Trier les bitrates par ordre croissant pour un meilleur streaming adaptatif
sortedBitrates := make([]int, len(bitrates))
copy(sortedBitrates, bitrates)
sort.Ints(sortedBitrates)
// Générer une entrée pour chaque qualité
for _, bitrate := range sortedBitrates {
// Calculer la bandwidth en bits par seconde (bitrate est en kbps)
bandwidth := bitrate * 1000
// Format HLS standard: #EXT-X-STREAM-INF:BANDWIDTH={bandwidth}
// Pour l'audio, on peut aussi ajouter CODECS si nécessaire
builder.WriteString(fmt.Sprintf("#EXT-X-STREAM-INF:BANDWIDTH=%d\n", bandwidth))
// URL relative vers le playlist de qualité
// Format: {baseURL}/{bitrate}k/playlist.m3u8
builder.WriteString(fmt.Sprintf("%s/%dk/playlist.m3u8\n", baseURL, bitrate))
}
return builder.String()
}
// GenerateMasterPlaylistWithCodecs génère un master playlist HLS avec codecs spécifiés
// bitrates: liste des bitrates en kbps
// baseURL: URL de base pour les playlists de qualité
// codec: codec audio (ex: "mp4a.40.2" pour AAC-LC)
// Retourne le contenu du master playlist avec codecs
func (g *HLSPlaylistGenerator) GenerateMasterPlaylistWithCodecs(bitrates []int, baseURL string, codec string) string {
var builder strings.Builder
// En-tête HLS standard
builder.WriteString("#EXTM3U\n")
builder.WriteString("#EXT-X-VERSION:3\n")
// Trier les bitrates par ordre croissant
sortedBitrates := make([]int, len(bitrates))
copy(sortedBitrates, bitrates)
sort.Ints(sortedBitrates)
// Générer une entrée pour chaque qualité avec codec
for _, bitrate := range sortedBitrates {
bandwidth := bitrate * 1000
// Format HLS avec codec: #EXT-X-STREAM-INF:BANDWIDTH={bandwidth},CODECS="{codec}"
builder.WriteString(fmt.Sprintf("#EXT-X-STREAM-INF:BANDWIDTH=%d,CODECS=\"%s\"\n", bandwidth, codec))
// URL relative vers le playlist de qualité
builder.WriteString(fmt.Sprintf("%s/%dk/playlist.m3u8\n", baseURL, bitrate))
}
return builder.String()
}
// GenerateQualityPlaylist génère une quality playlist HLS pour une qualité spécifique
// T0342: Create HLS Quality Playlist Generator
// segments: liste des noms de fichiers de segments (ex: ["segment_000.ts", "segment_001.ts"])
// segmentDuration: durée de chaque segment en secondes (ex: 10.0)
// Retourne le contenu de la quality playlist au format HLS standard
func (g *HLSPlaylistGenerator) GenerateQualityPlaylist(segments []string, segmentDuration float64) string {
var builder strings.Builder
// En-tête HLS standard
builder.WriteString("#EXTM3U\n")
builder.WriteString("#EXT-X-VERSION:3\n")
// TARGETDURATION: durée maximale d'un segment (arrondie à l'entier supérieur)
// Format: #EXT-X-TARGETDURATION:{duration}
targetDuration := int(segmentDuration)
if segmentDuration > float64(targetDuration) {
targetDuration++
}
builder.WriteString(fmt.Sprintf("#EXT-X-TARGETDURATION:%d\n", targetDuration))
// MEDIA-SEQUENCE: numéro de séquence du premier segment (0 pour VOD)
builder.WriteString("#EXT-X-MEDIA-SEQUENCE:0\n")
// PLAYLIST-TYPE: VOD (Video On Demand) pour les playlists complètes
builder.WriteString("#EXT-X-PLAYLIST-TYPE:VOD\n")
builder.WriteString("\n")
// Ajouter chaque segment avec sa durée
for _, segment := range segments {
// Format: #EXTINF:{duration},
// La durée est en secondes avec 2 décimales
builder.WriteString(fmt.Sprintf("#EXTINF:%.2f,\n", segmentDuration))
// Nom du fichier segment
builder.WriteString(segment + "\n")
}
// Marqueur de fin pour les playlists VOD
builder.WriteString("#EXT-X-ENDLIST\n")
return builder.String()
}
// GenerateQualityPlaylistWithVariableDurations génère une quality playlist avec durées variables par segment
// segments: liste des segments avec leurs durées respectives
// Retourne le contenu de la quality playlist au format HLS standard
func (g *HLSPlaylistGenerator) GenerateQualityPlaylistWithVariableDurations(segments []SegmentInfo) string {
if len(segments) == 0 {
return "#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-ENDLIST\n"
}
var builder strings.Builder
// En-tête HLS standard
builder.WriteString("#EXTM3U\n")
builder.WriteString("#EXT-X-VERSION:3\n")
// Calculer la durée maximale pour TARGETDURATION
maxDuration := 0.0
for _, seg := range segments {
if seg.Duration > maxDuration {
maxDuration = seg.Duration
}
}
targetDuration := int(maxDuration)
if maxDuration > float64(targetDuration) {
targetDuration++
}
builder.WriteString(fmt.Sprintf("#EXT-X-TARGETDURATION:%d\n", targetDuration))
// MEDIA-SEQUENCE: numéro de séquence du premier segment
builder.WriteString("#EXT-X-MEDIA-SEQUENCE:0\n")
// PLAYLIST-TYPE: VOD
builder.WriteString("#EXT-X-PLAYLIST-TYPE:VOD\n")
builder.WriteString("\n")
// Ajouter chaque segment avec sa durée spécifique
for _, seg := range segments {
builder.WriteString(fmt.Sprintf("#EXTINF:%.2f,\n", seg.Duration))
builder.WriteString(seg.Filename + "\n")
}
// Marqueur de fin
builder.WriteString("#EXT-X-ENDLIST\n")
return builder.String()
}
// SegmentInfo représente un segment avec sa durée
type SegmentInfo struct {
Filename string
Duration float64
}