一年前写过一篇文章,讲的是用FFmpeg制作图片视频流,大致的思路是:先将单张图片转成一个3秒的视频文件,再在视频的首尾分别加上淡入、淡出效果;每张图片都这么处理后,再把所有小视频文件连接、合并成一个大视频文件。图示:

python ffmpeg rtsp 推流 Protocol not found ffmpeg推流图片_视频流

这种方法比较初级!今天,咱们玩一个更高级的。想法是,怎么让相邻两张图片之间有一个交叉转场效果?就是这样的效果:

python ffmpeg rtsp 推流 Protocol not found ffmpeg推流图片_ffmpeg_02

我们拿3张图片素材来演示。分四步来制作。

第一步:把图片素材分别转成3秒长度的小视频文件。执行的3条命令如下:

ffmpeg -f image2 -framerate 0.33333 -i D:\MTest\IMG01.jpg  -s 720x480 -r 15 -y D:\MTest\Vid1.mp4

ffmpeg -f image2 -framerate 0.33333 -i D:\MTest\IMG02.jpg  -s 720x480 -r 15 -y D:\MTest\Vid2.mp4

ffmpeg -f image2 -framerate 0.33333 -i D:\MTest\IMG03.jpg  -s 720x480 -r 15 -y D:\MTest\Vid3.mp4

稍微解释一下:单张图片作为输入源,帧率framerate为什么是0.33333?因为我们想把它变成3秒长度的视频,1除以3就得到了0.33333。如果以帧率的概念来理解,就说是每秒输出0.33333张图片,这是没有实际意义的——权当控制输入源时长之用吧。最终生成的MP4视频文件都将画面尺寸统一缩放为720x480,帧率都是15fps。

第二步:计算最终视频文件的时长,并加工包含第一张图片的小视频文件与之等长。为什么要有这一步?难道不是将上述小视频文件依次叠加效果后连接起来就可以了吗?你可以试试……算一下:3个3秒的视频文件连接起来是9秒,扣掉两段相邻视频的重叠部分,最终视频的时长应该是7秒。我们需要把Vid1.mp4扩展成7秒:前3秒是图片素材内容,后4秒用白色填充,看起来是这样的:

python ffmpeg rtsp 推流 Protocol not found ffmpeg推流图片_视频流_03

我们分两步来要完成上面的加工处理。先生成一段4秒的纯白色视频文件:

ffmpeg -t 4 -f lavfi -i color=c=white:s=720x480:r=15 -y D:\MTest\pure_white.mp4

然后将它接在Vid1.mp4后面,生成我们想要的7秒时长的Vid0_1.mp4文件:

ffmpeg -i D:\MTest\Vid1.mp4 -i D:\MTest\pure_white.mp4 -filter_complex "concat=n=2:v=1:a=0" -y D:\MTest\Vid0_1.mp4

第三步:将第一、第二个视频叠加相连。我们需要在第一个视频的最后一秒加上淡出效果,在第二个视频的第一秒加上淡入效果,这两部分是要通过overlay滤镜叠加在一起的。有点复杂,所以用到了复杂滤镜filter_complex。命令行如下:

ffmpeg -i D:\MTest\Vid0_1.mp4 -i D:\MTest\Vid2.mp4 -filter_complex [0:v]fade=t=out:st=2:d=1[v0];[1:v]colorkey=#00FFFFFF:0.01:1,fade=t=in:st=2:d=1[v1];[v0][v1]overlay=x='if(gte(t,2),0,NAN)':y=0 -y D:\MTest\Vid1_2.mp4

python ffmpeg rtsp 推流 Protocol not found ffmpeg推流图片_视频流_04

画一条时间线,再详细解释一下:在第一个视频流上(以[0:v]来引用),从第2秒开始加上fade out效果,持续时间1秒,这个流的输出定义为新的标签[v0]。在第二个视频流上(以[1:v]来引用),从第2秒开始加上fade in效果,持续时间1秒,这个流的输出定义为新的标签[v1]。最后,将[v0]和[v1]两个流做overlay,生成Vid1_2.mp4文件。

有个小疑问:为什么要在第二视频上额外加一个colorkey滤镜?(关于colorkey的用法可以参考以前的一篇文章。)大家不妨把这个滤镜去掉后看看效果。如果没有colorkey,第二个视频会在第2-3秒之间完全覆盖在第一个视频之上,也就是说,第一个视频的最后一秒就透不出来了。还有一个问题,我们怎么控制第二个视频在第2秒这个时间点开始做overlay呢?关键看overlay的起始坐标点(x,y)。这里很高级地用到了表达式:if(gte(t,2),0,NAN)——先来看gte(t,2),意思是当时间点大于或等于2的时候返回1,否则返回0。再来看外面一层的if(x,y,z),意思是如果x的值不为0则返回y,否则返回z。综合来看,就是在[0,2)这个区间,overlay的起始坐标是(NAN,0),这是一个无效值,所以不做叠加;而当t大于或等于2时,第二个视频就会在画面的左上角原点(0,0)开始做叠加了。

第四步:在前一步生成的视频基础上叠加第三个视频。方法与第三步类似,只是注意第三个视频开始overlay的时间点是第4秒。命令行如下:

ffmpeg -i D:\MTest\Vid1_2.mp4 -i D:\MTest\Vid3.mp4 -filter_complex [0:v]fade=t=out:st=4:d=1[v0];[1:v]colorkey=#00FFFFFF:0.01:1,fade=t=in:st=0:d=1[v1];[v0][v1]overlay=x='if(gte(t,4),0,NAN)':y=0 -y D:\MTest\Vid1_2_3.mp4

大功告成,来看看效果吧:


python ffmpeg rtsp 推流 Protocol not found ffmpeg推流图片_视频流_05

以前的初级方法-9s

python ffmpeg rtsp 推流 Protocol not found ffmpeg推流图片_帧率_06

今天的高级方法-7s