我正在尝试创建一个媒体服务器,并且只想在播放视频时对其进行转码。但是我需要提前播放列表,以便客户端播放可以加载视频元数据。这可能吗?
我想做这样的事情:
Client -> GET m3u8 (pregenerated in advance)
Client -> GET ts -> Transcode only this single ts file
Client -> GET ts -> Transcode only this single ts file
Client -> GET ts -> Transcode only this single ts file
我不想立即对整个视频进行转码,我希望能够仅对请求的部分进行转码。
这可能吗?如果需要,也可以使用 MPEG-DASH。
当运行时 ffmpeg 运行时,使用请求的段号生成开始秒并将其放在 ffmpeg 命令选项的“-ss”之后,并且您必须指定“-r”选项以匹配最终 ts 段的 hls_time 和 fps时间与您预定义的片段持续时间相匹配。否则您将得到以下错误的 ts 持续时间
root@YOLE-UJIK:~/tran_6# cat generated_by_ffmpeg.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:5
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:5.005000,
stream0_0.ts
#EXTINF:5.005000,
stream0_1.ts
#EXTINF:5.005000,
stream0_2.ts
#EXTINF:5.005000,
stream0_3.ts
#EXTINF:5.005000,
stream0_4.ts
#EXTINF:5.005000,
stream0_5.ts
#EXTINF:4.971633,
stream0_6.ts
#EXTINF:5.005000,
stream0_7.ts
我使用 golang 作为 hls 服务代码语言,我的分段持续时间预定义为 5 秒
我使用视频总持续时间和片段持续时间选项生成 m3u8 部分,下面的代码显示了如何编写保留 m3u8:
func BuildMainPlaylistTranscoding(opt Sw, segmentDuration float64) string {
segmentDurationsSeconds := []float64{}
totalDuration := float64(opt.Duration)
standardPartSegDuration := segmentDuration
for ; totalDuration > 0; totalDuration -= standardPartSegDuration {
if totalDuration > standardPartSegDuration {
segmentDurationsSeconds = append(segmentDurationsSeconds, standardPartSegDuration)
} else {
segmentDurationsSeconds = append(segmentDurationsSeconds, totalDuration)
}
}
buildder := strings.Builder{}
buildder.WriteString(fmt.Sprintf(`#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:%d
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD`, 6))
// apple must end with .ts, otherwise safari will not request ts data
for index := 0; index < len(segmentDurationsSeconds); index++ {
buildder.WriteString(fmt.Sprintf("\n#EXTINF:%.3f,\nstream0_%d.ts", segmentDurationsSeconds[index], index))
}
buildder.WriteString(fmt.Sprintf("\n#EXT-X-ENDLIST"))
return buildder.String()
}
当媒体段http请求到达时,我使用下面的ffmpeg命令来生成ts段并提供服务。
ffmpeg -hide_banner -analyzeduration 200M -init_hw_device vaapi=va:/dev/dri/renderD128 -filter_hw_device va -hwaccel vaapi -hwaccel_output_format vaapi -i "/data/user/admin/Downloads/迪迦奥特曼 EP48 -月球来的逃亡者1080P.mkv" -copyts -autoscale 0 -map_metadata -1 -map_chapters -1 -threads 0 -codec:v:0 h264_vaapi -b:v 1000000 -r 30 -force_key_frames "expr:gte(t,n_forced*5)" -filter_complex "[0:3]scale=s=960x720:flags=fast_bilinear[sub];[0:0]setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709,scale_vaapi=w=960:h=720:format=nv12:extra_hw_frames=24,hwdownload,format=nv12[main];[main][sub]overlay=eof_action=pass:shortest=1:repeatlast=0,hwupload_vaapi" -start_at_zero -codec:a:0 aac -ac 2 -ab 128000 -max_muxing_queue_size 2048 -f hls -start_number 0 -hls_time 5 -hls_segment_type mpegts -hls_list_size 0 -hls_segment_filename "/root/tran_7/stream0_%d.ts" -hls_playlist_type vod "/root/tran_7/generated_by_ffmpeg.m3u8"