首页 > 其他分享 >从FFmpeg输出日志中分析问题原因——记一次输出流顺序异常

从FFmpeg输出日志中分析问题原因——记一次输出流顺序异常

时间:2022-10-19 12:02:54浏览次数:63  
标签:输出 FFmpeg Stream map 音频 视频流 mp4 amix 日志


输出流的顺序怎么无法改变

一个视频文件,常规地,会将视频流放在第一个位置,其次将音频流放到第二个位置。对于一些特殊的视频,想要改变其顺序,也是非常方便的,直接使用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)

上文已经描述过原始文件的流顺序,那么将这段滤镜图可视化,应当是这样:



source.mp4


#0:0 视频流


#0:1 音频流


voice.mp3


#1:0 音频流


amix:input0


amix:input1


amix

输出 #0:0?

没办法 被挤到#0:1


在上述滤镜图中,仅仅针对音频流进行了处理。在经过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,Stream,map,音频,视频流,mp4,amix,日志
From: https://blog.51cto.com/u_3932467/5769533

相关文章

  • FFmpeg中使用loop输入流与shortest参数后,音视频流时长被改变
    问题来自于制作视频水印需求给一段视频加上一张静态图片制作的logo,在网上已经有很多例子了,只要把它放置在视频的固定位置即可,这个功能非常容易实现:ffmpeg-ivideo.mp4-il......
  • Linux rsyslog 系统日志服务-日志格式说明
    rsyslog系统日志服务  rsyslog是CentOS6以后版本的系统管理服务。它提供了高性能,出色的安全性和模块化设计。rsyslog的相关概念:  facility:设施,表示对日志进行分......
  • MySQL的日志文件
    本文将重点介绍MySQL的日志文件类型,并讲解其作用,并结合一定实操演示,相信跟着做下来你会对MySQL有更深的理解。文件的概念在开始讲MySQL日志文件之前,首先我们要明确一下文......
  • Spring日志打印配置
    日志打印配置示例:<?xmlversion="1.0"encoding="UTF-8"?><!--Copyright2010-2011ThemyBatisTeamLicensedundertheApacheLicense,Version2.0(the"Lice......
  • Python教程Day03-Python输出、输入、转换数据类型、运算符
    一、输出作用:程序输出内容给用户print('helloPython')age=18print(age)#需求:输出“今年我的年龄是18岁”1、格式化输出格式化输出即按照一定的格式输出内容1.1格......
  • winfrom 中配置log4日志
    一、下载log4net组件直接引入log4net.dll文件到引用,或者使用NuGet,搜索log4net下载到项目中  二、创建配置一个log4net.config文件(将此文件属性设置为:始终复制),文件内......
  • 04.大型数据库应用技术课堂测试05-日志数据分析-错误总结
    错误总结:1.ExpressionnotinGROUPBYkey'id'解决:在groupby子句中,select查询的列,要么需要是groupby中的列,要么得是用聚合函数(比如sum、count等)加工过的列。不......
  • 记录清理Oracle归档日志
    一、登录数据库1.切换到Oracle用户su命令–切换用户身份su命令来自于英文单词“switchuser”的缩写,其功能是用于切换用户身份。管理员切换至任意用户身份而无需密......
  • CVPR21最佳检测:不再是方方正正的目标检测输出(附源码)
    计算机视觉研究院专栏作者:Edison_G有些目标往往具有任意方向的分布。因此,检测器需要更多的参数来编码方向信息,这往往是高度冗余和低效的...论文:​​https://openaccess.thec......
  • 已整理-Linux重定向输出
      重定向输出:>  #只收集前面命令的正确输出2> #只收集前面命令的错误输出&> #收集前面命令的正确与......