FFmpeg中使用loop输入流与shortest参数后,音视频流时长被改变
Posted Jack_Chai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FFmpeg中使用loop输入流与shortest参数后,音视频流时长被改变相关的知识,希望对你有一定的参考价值。
本文出处:http://blog.csdn.net/chaijunkun/article/details/115731799,转载请注明。由于本人不定期会整理相关博文,会对相应内容作出完善。因此强烈建议在原始出处查看此文。
问题来自于制作视频水印需求
给一段视频加上一张静态图片制作的logo,在网上已经有很多例子了,只要把它放置在视频的固定位置即可,这个功能非常容易实现:
ffmpeg -i video.mp4 -i logo.jpg -filter_complex "[1:v]scale=w=120:h=120:\\
force_original_aspect_ratio=decrease:force_divisible_by=2[logo];\\
[0:v][logo]overlay=x=32:y=64" \\
new_video.mp4
详细的操作步骤是:
- 将输入的任意尺寸图片都等比例缩放至不大于120x120大小的小图,并且缩放时计算的尺寸保持宽高均为偶数;
- 将上一步缩放好的图片放置在主视频的(32,64)位置上。
输入的logo是一张静态图片,从视频的角度上说,它只有1帧,因此它会一直“卡”在这一帧上,然后经过缩放后交给后续滤镜处理。
淡入淡出水印的实现思路
但正是在制作带淡入淡出的水印时,遇到了标题中所述的问题。
淡入淡出功能,在FFmpeg中有现成的fade滤镜。但是如果直接加入此滤镜,输出结果与想象的结果完全不同——画面没有logo出现。
下面的命令是有问题的:
ffmpeg -i video.mp4 -i logo.jpg -filter_complex "[1:v]scale=w=120:h=120:\\
force_original_aspect_ratio=decrease:force_divisible_by=2,\\
fade=t=in:s=160:n=15:alpha=1,\\
fade=t=out:s=230:n=20:alpha=1[logo];\\
[0:v][logo]overlay=x=32:y=64" \\
new_video.mp4
但是总体思路是没有问题的:
那么问题出在哪里了?其实问题是因为上面提到的logo图片一直“卡”在一帧上,导致fade滤镜无法触发后续的计算,而fade滤镜启用了alpha通道方式淡入,在淡入之前,alpha会被设置为0,因此后续logo一直是透明输入,看不到叠加效果。
改进实现
知道了问题所在,那是不是让FFmpeg把logo图片当做视频流输入,就可以触发淡入淡出滤镜的计算了呢?答案是:正确。
ffmpeg -i video.mp4 -loop 1 -i logo.jpg ... -shortest new_video.mp4
- 在输入logo图片前增加-loop 1参数,开启此输入的循环选项;
这样图片就会变成一个永不停止的静态视频源 - 在输出文件前增加-shortest参数,让生成的视频最短化。
由于logo图片已经变成了永不停止的视频源,如果不加此参数,会一直输出,因此千万不要忘了。
直觉上,这种方案会使得logo图片展示的时间与原始视频的长度一样,那么事实是这样吗?
查看原始视频信息:
ffprobe -show_streams -of json video.mp4
输出部分的结果:
# 原始视频长度
"time_base": "1/12800",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 128512,
"duration": "10.040000",
# 原始音频长度
"time_base": "1/44100",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 442764,
"duration": "10.040000",
查看输出视频信息:
ffprobe -show_streams -of json new_video.mp4
输出部分的结果:
# 加logo后视频长度
"time_base": "1/12800",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 158208,
"duration": "12.360000",
# 加logo后音频长度
"time_base": "1/44100",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 443381,
"duration": "10.053991",
通过对比可以看出,在输入源开启了循环之后,即便后面对应开启了-shortest参数,输出的视频无论视频流还是音频流,长度都有所改变。而且原视频流时长:10.04秒,加入logo后视频流时长:12.36秒,夸张地增加了2秒多。这样的视频如果直接用于子片段拼接(concat),将会引起很大的音视频同步问题。
继续改进实现
通过查阅文档,发现overlay滤镜中提供了一个类似的shortest选项,专门用来处理这种情况。
在overlay滤镜后启用该选项即可
overlay=x=32:y=64:shortest=1
既然在overlay滤镜中已经将logo视频流截断了,那么就可以去掉-shortest输出参数了。
ffmpeg -i video.mp4 -loop 1 -i logo.jpg ...overlay=x=32:y=64:shortest=1... new_video.mp4
此时再查看输出视频信息:
# 加logo后视频长度
"time_base": "1/12800",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 128512,
"duration": "10.040000",
# 加logo后音频长度
"time_base": "1/44100",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 443381,
"duration": "10.053991",
可以看到,输出文件视频流时间长度与原视频一致。音频流时长稍微长一点点,可以在拼接时修正掉,如果是单个文件播放,可忽略不计。
以上代码,在FFmpeg 4.3.1上测试通过。
以上是关于FFmpeg中使用loop输入流与shortest参数后,音视频流时长被改变的主要内容,如果未能解决你的问题,请参考以下文章