从FFmpeg输出日志中分析问题原因——记一次输出流顺序异常
Posted Jack_Chai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从FFmpeg输出日志中分析问题原因——记一次输出流顺序异常相关的知识,希望对你有一定的参考价值。
本文出处:http://blog.csdn.net/chaijunkun/article/details/117572832,转载请注明。由于本人不定期会整理相关博文,会对相应内容作出完善。因此强烈建议在原始出处查看此文。
输出流的顺序怎么无法改变
一个视频文件,常规地,会将视频流放在第一个位置,其次将音频流放到第二个位置。对于一些特殊的视频,想要改变其顺序,也是非常方便的,直接使用FFmpeg提供的-map参数来重新映射即可:
ffmpeg -i source.mp4 -c copy -map v -map a out.mp4
由于不涉及重新编解码,因此命令执行速度非常快。
而我接下来遇到的问题,无论是否使用-map来重新映射流顺序,都无法将其改变。
原始文件
原始文件有两个,如下表所示:
文件名 | 文件类型 | 视频流信息 | 音频流信息 |
---|---|---|---|
source.mp4 | 视频 | index: 0, codec_name: h264, codec_type: video | index: 1, codec_name: aac, codec_type: audio |
voice.mp3 | 音频 | N/A | index: 0, codec_name: pcm_s16le, codec_type: audio |
可以看到,视频文件同时具有视频流和音频流,且按前述顺序布局;音频文件比较简单,只有一个音频流。
加工,重现问题
期望实现的功能是将音频混音到原始视频的音频轨道中,保持原有的视频流,以备后续处理。为了降低问题复杂度,我对命令进行了精简:
ffmpeg -i source.mp4 -i voice.mp3 -filter_complex "[0:a][1:a]amix=duration=first" \\
-c:v copy out.mp4
过程很简单,由于在filter_complex中只处理了音频流,因此后面对视频流直接进行了copy处理,这样能减少计算量并加快输出速度。执行命令,文件能正常输出,也能播放,但查看流的顺序,我们发现了问题:
ffprobe -show_streams -of json out.mp4
流信息:
...
"index": 0,
"codec_name": "aac",
...
"index": 1,
"codec_name": "h264",
...
相比于原始视频,流的顺序发生了变化。由于还需要进行拼接处理,流的顺序如果不正确,会影响到后续流程,这个问题必须解决。
老办法,先尝试使用-map进行强制映射:
ffmpeg -i source.mp4 -i voice.mp3 -filter_complex "[0:a][1:a]amix=duration=first" \\
-map v -map a -c:v copy out.mp4
问题依旧,并没有随着该参数的加入而改变结果。
输出日志,或许这里有你想要的
正在苦思冥想问题原因的时候,目光瞄准到了输出日志,希望在这里能够找到蛛丝马迹。由于使用了滤镜,因此注意到了这段对于滤镜图的解析信息:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'source.mp4':
...
Input #1, wav, from 'voice.mp3':
...
Stream mapping:
Stream #0:1 (aac) -> amix:input0
Stream #1:0 (pcm_s16le) -> amix:input1
amix -> Stream #0:0 (aac)
Stream #0:0 -> #0:1 (copy)
上文已经描述过原始文件的流顺序,那么将这段滤镜图可视化,应当是这样:
在上述滤镜图中,仅仅针对音频流进行了处理。在经过amix滤镜处理后,输出的流就占用了index=0的流位置。而后,原有的视频流还未使用,由于0已经被占用,因此该流向后顺延,就变成了index=1。至此,也就不难理解为什么两个流的位置发生了颠倒。
如何解决
既然已经知道了原因,那么想办法不让音频流抢先占用index=0即可。这里提供两种解决办法。
占位法
既然视频流的位置被抢占,那就先处理视频流,可以使用直通滤镜,不做任何加工:
ffmpeg -i source.mp4 -i voice.mp3 -filter_complex "[0:v]null;[0:a][1:a]amix=duration=first" out.mp4
这样视频流就抢占了index=0的位置。然而,由于滤镜中使用了视频流,因此输出时就不能再使用-c:v copy来进行视频流拷贝了,相当于引入了重新编解码,效率非常低。
更名法
既然滤镜输出的音频流没有被主动声明一个流名称,导致了使用默认策略,如果强制给他起个名字,或许可以:
ffmpeg -i source.mp4 -i voice.mp3 -filter_complex "[0:a][1:a]amix=duration=first[mixed]" \\
-map v -map "[mixed]" -c:v copy out.mp4
从结果来看,是可以的:
Stream mapping:
Stream #0:1 (aac) -> amix:input0
Stream #1:0 (pcm_s16le) -> amix:input1
Stream #0:0 -> #0:0 (copy)
amix -> Stream #0:1 (aac)
强烈推荐这种方法。由于没有引入针对视频流的滤镜操作,可以直接使用流复制,极大减少了计算量。通过对音频流更名后重新映射,避免了流的抢占。
总结
FFmpeg作为优秀的音视频编解码工具,不仅提供了非常强大的功能,而且还具有非常详尽的日志输出体系。笔者之前遇到的很多问题都是通过日志来反向查找源代码,了解算法原理后,从而有针对性地进行解决。
以上是关于从FFmpeg输出日志中分析问题原因——记一次输出流顺序异常的主要内容,如果未能解决你的问题,请参考以下文章
从FFmpeg输出日志中分析问题原因——记一次输出流顺序异常
从FFmpeg输出日志中分析问题原因——记一次输出流顺序异常