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

但是总体思路是没有问题的:

video scale缩放 fade_in淡入 fade_out淡出 overlay叠放 输出文件

那么问题出在哪里了?其实问题是因为上面提到的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参数后,音视频流时长被改变的主要内容,如果未能解决你的问题,请参考以下文章

FFmpeg:图像滚动,绿色背景?

如何循环输入视频x使用FFMPEG的时间?

ffmpeg推流与播放

如何在ffmpeg中同步多个rtsp输入?

如何通过python实现H.264视频推流与接收

ffmpeg:如何将 wav 作为音频输入来创建视频?