我正在尝试使用 FFmpeg 制作包含以下内容的 HLS 播放列表多种音频版本,但我无法让音频和视频轨道同步。以下是场景:
- 假设我有 2 个视频文件,每个文件有 1 个音轨
- 我使用 FFmpeg 将两个视频平移在一起以形成一个视频,例如:
每个文件提取的音轨(转码为 .mp3)
我想要制作一个 HLS 播放列表,其中备选音轨分别是左音频和右音频:
我遇到的问题是无法使音频与视频正确同步。我尝试了几个 ffmpeg 命令,每个命令的简单程度不同,最好的情况是我在桌面上获得同步流,但在移动设备上(播放由设备的本机播放器处理),只要我切换到另一个视频轨道,视频就会很快与音频失去同步。
我正在使用 ffmpeg 3.1.1。
我尝试过的一个示例命令,从一个相对简单的命令开始,其中我将音轨映射到多路复用segmenter
器,并将视频映射到hls
:
ffmpeg -i dual.mp4 -i audio_left.mp3 -i audio_right.mp3 \
-threads 0 -muxdelay 0 -y \
-map 0 -pix_fmt yuv420p -vsync 1 -async 1 -vcodec libx264 -r 29.97 -g 60 -refs 3 -f hls -hls_time 10 -hls_list_size 0 video/index.m3u8 \
-map 1 -acodec aac -strict experimental -async 1 -ar 44100 -ab 96k -f segment -segment_time 10 -segment_list_size 0 -segment_list_flags -cache -segment_format aac -segment_list audio1/audio1.m3u8 audio1/audio1%d.aac \
-map 2 -acodec aac -strict experimental -async 1 -ar 44100 -ab 96k -f segment -segment_time 10 -segment_list_size 0 -segment_list_flags -cache -segment_format aac -segment_list audio2/audio2.m3u8 audio2/audio2%d.aac
为了更复杂,例如输出原始mpegts
容器,然后将轨道切开:
ffmpeg -i dual_short.mp4 -i audio_left_short.mp3 -i audio_right_short.mp3 \
-threads 0 -muxdelay 0 -y \
-map 0:v -map 1 -map 2 -codec copy -pix_fmt yuv420p -vsync 1 -async 1 -shortest -f mpegts pipe:1 | ffmpeg-3.1.1 -i pipe:0 \
-map 0:0 -vcodec copy -r 29.97 -g 60 -refs 3 -bsf:v h264_mp4toannexb -f hls -hls_time 10 -hls_list_size 0 video/index.m3u8 \
-map 0:1 -f ssegment -segment_time 10 -segment_list_size 0 -segment_format aac -segment_list audio1/audio1.m3u8 audio1/audio1_%d.aac \
-map 0:2 -f ssegment -segment_time 10 -segment_list_size 0 -segment_format aac -segment_list audio2/audio2.m3u8 audio2/audio2_%d.aac
我不是音频/视频专家,所以我很确定我的推理存在根本性缺陷,所以我请求你们的帮助和指导。特别是:
- 我在这里尝试做的事情不可行吗?换句话说给定 N 个音轨,与原始视频同步录制,以制作音频始终口型同步的 HLS 播放列表?
- 视频 FPS 和音频比特率是导致 A/V 同步问题的原因吗?它们之间有关联吗?
- 视频的不同质量水平(例如比特率)对同步有影响吗?
- 我选择的目标音频容器(mp3 与 aac)会影响同步吗?
- 我是否应该使用具有多个输入的单个命令或分别处理每个流?
正如您所见,我很迷茫。我确实在互联网上进行了广泛的搜索,观看了 Apple 在 WWDC 2012 上的“有效 HLS”演讲,但有关如何制作有效的多音频播放列表的信息似乎在互联网上很少见。
谢谢您的指点。
答案1
我自己已经找到了解决方案。
问题在于,segment
复用器需要查看一些参考帧才能正确切分音频,因此单独映射流是行不通的。
可行的方法是生成一个包含所有音频和视频文件的“完整” .ts 片段,然后对其进行适当切片。一个简单但可行的示例:
ffmpeg-3.1.1 -i dual_short.mp4 -i audio_left_short.mp3 -i audio_right_short.mp3 \
-threads 0 -muxdelay 0 -y \
-map 0:v -map 1 -map 2 -pix_fmt yuv420p -movflags +faststart -r 29.97 -g 60 -refs 1 \
-vcodec libx264 -acodec aac -profile:v baseline -level 30 -ar 44100 -ab 64k -f mpegts out.ts
# Perform 3 passes:
# 1. Generate the video.
ffmpeg-3.1.1 -i out.ts -threads 0 -muxdelay 0 -y -map 0:v -vcodec copy -f hls -hls_time 10 -hls_list_size 0 video/index.m3u8
# 2. Generate Audio №1
ffmpeg-3.1.1 -i out.ts -threads 0 -muxdelay 0 -y -map 0:a:0 -codec copy -f segment -segment_time 10 -segment_list_size 0 -segment_list audio1/audio1.m3u8 -segment_format mpegts audio1/audio1_%d.aac
# 3. Generate Audio №2
ffmpeg-3.1.1 -i out.ts -threads 0 -muxdelay 0 -y -map 0:a:1 -codec copy -f segment -segment_time 10 -segment_list_size 0 -segment_list audio2/audio2.m3u8 -segment_format mpegts audio2/audio2_%d.aac