我正在构建一个涉及服务各种视频内容的网络应用。对网络友好的音频和视频编解码器的处理没有任何问题,但我在设计传输不兼容HTML5视频播放器(如mkv容器或H265)的视频文件时遇到了问题。
到目前为止,我所做的是在服务器上使用ffmpeg对视频文件进行转码,并制作HLS主文件和VOD播放列表,在前端使用hls.js。但问题是,ffmpeg会把播放列表当作一个直播的播放列表,直到整个文件的转码完成后,才会把播放列表改成VOD。所以,用户在转码结束之前不能寻求,如果用户决定中途寻求视频文件,我的服务器已经不必要地对整个文件进行了转码。我使用了以下ffmpeg命令行参数
ffmpeg -i sample.mkv \
-c:v libx264 \
-crf 18 \
-preset ultrafast \
-maxrate 4000k \
-bufsize 8000k \
-vf "scale=1280:-1,format=yuv420p" \
-c:a copy -start_number 0 \
-hls_time 10 \
-hls_list_size 0 \
-f hls \
file.m3u8
现在,为了改进这个系统,我尝试通过我的应用程序而不是ffmpeg生成VOD播放列表,因为格式是不言而喻的。网络应用会使用视频属性,如持续时间、分辨率和比特率(服务器已知)事先生成HLS主播放列表和VOD播放列表,并将主播放列表提供给客户端。然后客户端开始请求各个视频片段,这时服务器将单独对每个片段进行转码和生成,并提供给他们。寻求将是可能的,因为客户端已经有完整的VOD播放列表,它可以请求用户寻求的特定片段。在我看来,这样做的好处是,如果用户决定向前寻求并在中途播放视频,我的服务器将不必对整个文件进行转码。
现在,我试着手动创建片段(每段10秒),从我的 sample.mkv
使用以下命令
ffmpeg -ss 90 \
-t 10 \
-i sample.mkv \
-g 52 \
-strict experimental \
-movflags +frag_keyframe+separate_moof+omit_tfhd_offset+empty_moov \
-c:v libx264 \
-crf 18 \
-preset ultrafast \
-maxrate 4000k \
-bufsize 8000k \
-vf "scale=1280:-1,format=yuv420p" \
-c:a copy \
fileSequence0.mp4
等其他环节,而VOD播放列表为
#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
fileSequence0.mp4
#EXTINF:10.0,
fileSequence1.mp4
...
... and so on
...
#EXT-X-ENDLIST
它能很好地播放第一段,但不能播放后续的片段。
现在我的问题是:
为什么后续的片段不能播放?我到底做错了什么?
我的技术是否可行?由于只有在关键帧之后才能进行分段,所以预设分段的持续时间会不会有问题,以及ffmpeg是否能解决这个问题?
我在视频处理和生成方面的知识充其量也只是个小白。如果能给我一些建议,我将非常感激。
这是可能的,但非常困难。我甚至认为用ffmpeg可能不可能。传输流有时间戳和连续性计数器,这些值应该在段的边界上被保留。-copyts标志可能会有一点帮助。在这种情况下,B帧是极难处理的,因为它们最终会在段外留下时间戳。音频也很难处理。当编码器初始化时,音频有初始化样本,这意味着你可能会有额外的样本,每段通过音频弹出。
TLDR,是可能的,但你需要了解的容器和底层编解码器的结构,并与他们的工作。