174 lines
5.9 KiB
Go
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
|
|
}
|