使用ffmpeg命令行实现一入多出转码

13 篇文章 0 订阅
3 篇文章 0 订阅

1 前言

我们在实际工作中有时会遇到一入多出的转码需求,比如在给播放器提供多种网络环境的播放源选择(如流畅、清晰、高清和超清等)时就会需要这种操作。

当然,我们可以有很多种方法来实现这个需求。

在这篇文章中,我们讲一下如何使用一条ffmpeg命令来实现同一个输入源转码输出多路不同视频的功能。

2 转码输出

不使用滤镜

ffmpeg支持使用相同的输入创建多个不同的输出,一般我们可以使用下面这种方式来实现:

ffmpeg -i input	-acodec … -vcodec … output1 -acodec … -vcodec … output2 -acodec … -vcodec … output3

比如说将一个相同的视频转码为HD, VGA和QVGA三种分辨率,可以这么来用:

ffmpeg -i input -s 1280x720 -acodec … -vcodec … output1 -s 640x480  -acodec … -vcodec … output2 -s 320x240  -acodec … -vcodec … output3

所有输出使用同一个滤镜

如果你想在转码时使用滤镜,并且所有的输出都用同一个滤镜,那么就增加一个"-filter_complex"参数使用"split"滤镜。进行多分辨率转码并添加"yadif"滤镜的操作如下所示:

# `split=3`的意思是分成三个流
ffmpeg -i input -filter_complex '[0:v]yadif,split=3[out1][out2][out3]' -map '[out1]' -s 1280x720 -acodec … -vcodec … output1 \
-map '[out2]' -s 640x480  -acodec … -vcodec … output2 -map '[out3]' -s 320x240  -acodec … -vcodec … output3

每路输出使用独立的滤镜

如果你想在转码时每一路都使用一个独立的滤镜,我们可以使用"split"来直接指定输入。

分别添加"boxblur", "negate", "yadif"三个滤镜到三个相应的输出的写法如下所示:

ffmpeg -i input -filter_complex '[0:v]split=3[in1][in2][in3];[in1]boxblur[out1];[in2]negate[out2];[in3]yadif[out3]' -map '[out1]' -acodec … -vcodec … output1 \
-map '[out2]' -acodec … -vcodec … output2 -map '[out3]' -acodec … -vcodec … output3

3 复制输出

这里说的复制输出不是我们常用的比如“-vcodec copy -acodec copy”之类的操作,而是指的将重新编码后的音视频做不同的封装,也就是说用了相同的编码后的音视频数据做不同的封装。

T型虚拟封装器(Tee pseudo-muxer)

T型虚拟封装器是ffmpeg在2013年2月3日添加的新功能,这个功能支持用一行命令将音视频流复制到不同的输出文件中。

下面的例子输出了一路MKV文件流和一路UDP网络流,两个不同的流使用“|”隔开。“[f=mpegts]”这个操作可应用于某一路的单独输出,跟正常使用时的“-f mpegts”是相同的。多个选项可以使用“:”隔开。

ffmpeg -i input.file -c:v libx264 -c:a mp2 -f tee -map 0:v -map 0:a "output.mkv|[f=mpegts]udp://10.0.1.255:1234/"

如果你想选择指定的流,可以使用"select"选项。下一个例子就是将一个视频流切分并缩放为两路不同尺寸的输出,并且两路输出只需对音频编码一次,否则的话得需要对音频编码多次。最后面输出选项中"onfail"的值"ignore"意思是当这一路输出出错失败的话,不会对其他几路输出造成影响。"onfail"的默认值为"abort"。

ffmpeg -i input -filter_complex "[0:v]split=2[s0][s1]; [s0]scale=1280:-2[v0]; 
[s1]scale=640:-2[v1]" -map "[v0]" -map "[v1]" -map 0:a -c:v libx264 -c:a aac -f tee
 "[select=\'v:0,a\']local0.mkv| [select=\'v:0,a\':f=flv]rtmp://server0/app/instance/playpath| [select=\'v:1,a\']local1.mkv| 
[select=\'v:1,a\':f=flv:onfail=ignore]rtmp://server1/app/instance/playpath"

管道进程

在一些低版本的ffmpeg中,还可以这样做:使用两个ffmpeg进程,第一个进程用来编码stream(s),第二个进程将其分发为多个不同的输出。

ffmpeg -i input1 -i input2 -acodec … -vcodec … -f mpegts - | ffmpeg -f mpegts -i - -c copy output1 -c copy output2 -c copy output3

如果使用的旧版ffmpeg不支持"-c copy",那么可以使用"-vcodec copy -acodec copy"来代替。

ffmpeg -f v4l2 -i /dev/video0 -vcodec libx264 -f mpegts - | ffmpeg -f mpegts -i - -c copy -f mpegts udp://1.2.3.4:5678 -c copy -f mpegts local.ts

并行编码

在同一个ffmpeg进程中进行多次编码输出会大大降低编码效率。有一些编码器(如libx264)在编码时会使用“多线程后台”,所以有效的允许了并行编码,但是音频编码可能会是串行的,从而成为了瓶颈。似乎是如果你有任何串行编码,ffmpeg会将其视为“真正的串行”,因此你的ffmpeg可能不会使用所有可用的cpu核心。有一种办法是使用多个ffmpeg实例并行运行,通过管道从一个ffmpeg到另一个ffmpeg进行“第二编码”。或者你可以避开编码器限制(例如:使用一个更快的方式【例如:原始格式(raw format)】或者只是做一个原始流复制),希望能对提升效率有所帮助。

4 备注

因ffmpeg版本在不停更新,新版本中参数会存在调整的可能,若您在实际操作中发现有不可用的命令,可通过评论或私信提出,我会尽快修正。

参考:Creating multiple outputs – FFmpeg

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值