利用FFmpeg制作视频序列

来源:互联网 发布:移动数据终端 市场 编辑:程序博客网 时间:2024/05/17 05:10

前言

本文介绍了利用FFmpeg进行视频测试序列制作的方法。所谓测试序列就是将若干个不同场景的视频片段,按照不同的分辨率、码率、编码方法等进行处理,然后拼接成一条长视频,供测试者打分。一般包括以下几个步骤:视频截取、采样/编码/转码、黑帧/灰帧制作、视频拼接、视音频融合等。

    • 前言
    • 一视频截取
    • 二采样和编码
    • 三黑帧灰帧的制作
    • 四视频拼接
      • 1 先音视频片段融合再拼接
      • 2 先视音频片段分别拼接得到长视频和长音频再将二者融合
    • 后记

一、视频截取

截取视频之前,一般要先获取原始高清视频,可以到Youtube、Gopro等网站下载,商用的话请注意版权问题,或者可以自己录制视频。然后浏览获取到的视频,确定要截取的片段后,可利用FFmpeg截取。比如要截取名为input.mp4的视频1分20秒至1分40秒的片段,命令如下:

ffmpeg -i %input_path%\input.mp4 -ss 000120 -t 00:00:20 %output_path%\output.mp4

上述命令中,-i为输入的文件,-ss 即为起始时间,-t为截取长度,这两个时间可以用 hh:mm:ss 的格式,也可以直接用秒,如 00:01:20 可写成 80。另外,时间还可以精确到毫秒级,比如可以截取20.358秒的长度,虽然实际截出来不会那么精确。

二、采样和编码

截取出来的视频片段,若想重新编码到其他分辨率、码率的话,一般要先转为YUV格式(此后会丢失音频,因为yuv不存储音频),因为YUV格式是把每一帧的图像用亮度和色度分开表示的格式,所以压缩时容易去掉色度的数据;之后将原始yuv采样到目标分辨率,接着对yuv进行x264编码得到.264文件,最后将.264文件封装成MP4等格式。各步骤命令大致如下:
MP4转YUV:

ffmpeg -i %input_path%\input.mp4 %output_path%\output.yuv

对YUV采样(假设原始分辨率为3840x1920,目标分辨率为1920x960):

ffmpeg -s 3840x1920 -i %input_path%\input_3840x1920.yuv -s 1920x960 %output_path%\output_1920x960.yuv

其中-s依次为原始分辨率和目标分辨率。
对采样后的YUV进行x264编码(应先下载x264源码编译得到x264.exe):

x264.exe -I %MAX_GOP_SIZE% -i %MIN_GOP_SIZE% --ref 1 --qpstep 2 --profile baseline --bitrate %bitrate% --vbv-maxrate %bitrate% --vbv-bufsize %output_path%\output.264 %input_path%\input.yuv --input-res %input_resolution%

.264文件封装为MP4:

ffmpeg -i %input_path%\input.264 %output_path%\output.mp4

至此,可将各视频素材编码到目标分辨率和码率。编码器可替换成其他,x264是我本次项目用的。

三、黑帧/灰帧的制作

制作视频测试序列时,测试片段之间应该留有10秒左右时间间隙给测试者打分,此时一般使用黑帧或者灰帧过渡,目前行业内逐渐使用灰帧代替黑帧。黑帧的话,可以截取电影片段,或者自己录制,方法比较多。灰帧不好找,所以一般使用代码产生若干帧YUV,然后根据所需长度、分辨率、帧率等编码得到灰帧视频。无论黑帧/灰帧,无论何种方法,建议务必保证它们的质量足够好,不然可能无法拼接,或者能拼接但在解码播放时出问题。我一开始拿的两个短黑帧视频拼出一个10秒长的,拿去拼接时经常出问题,浪费了不少精力。
从YUV编码得到一个灰帧视频后,可以利用这个视频来转换得到其他分辨率的,没必要对原YUV采样几次,毕竟灰帧的质量要求没有测试片段高。ts格式视频转分辨率命令如下,其他格式亦可依样画葫芦:

ffmpeg -i %input_path%\gray_3840x1920.ts -s 1920x960 -vcodec copy %output_path%\gray_1920x960.ts

其中,-s是目标分辨率,-vcodec copy 意为使用原视频的编码方式,一般不更改编码方式的话,都最好附上这个参数,能够避免不少意外。去掉-vcodec copy 也能转分辨率,输出的文件也能正常播放,但拿去拼接的时候会出错。

四、视频拼接

用来拼接到同一序列的视频片段们,分辨率最好是一样的,帧率不必一样,码率随意。ffmpeg拼接视频之前,需要把视频转为.ts格式。拼接有两条思路:一是先将个视频片段与其对应的音频融合再拼接,二是将视频片段和音频片段分别拼接,再将得到的长视频序列和长音频序列融合。

4.1 先音视频片段融合再拼接

先从截取得到的有声MP4视频片段中提取音频:

ffmpeg -i input.mp4 -vn -acodec copy output.aac

其中,-vn意为屏蔽视频信息,只获取音频;-acodec copy意为复制原音频的编码方式。(ps,若要提取视频,命令为:ffmpeg -i input.mp4 -an -vcodec copy output.mp4 )
接着将音视频片段融合产生可用来拼接的.ts文件:

ffmpeg -i input_v.mp4 -i input_a.aac -vcodec copy -acodec copy output.ts

最后,将前面得到的有声ts视频和灰帧ts视频 gray.ts 拼接成一条长视频:

ffmpeg -i "concat:%path1%\video1.ts|%gray_path%\gray.ts|%path2%\video2.ts|%gray_path%\gray.ts|... ...|%pathN%\videoN.ts|%gray_path%\gray.ts" -vcodec copy -acodec copy -bsf:a aac_adtstoasc %output_path%\output.mp4

其中,-vcodec copy 意为复制原视频编码方式, -acodec copy 意为复制原音频编码方式,-bsf:a aac_adtstoasc 是一个bitstream filter,不加的话,会提示无法音视频融合。
至此,一个有声的视频测试序列就完成了!

4.2 先视音频片段分别拼接得到长视频和长音频,再将二者融合

视频片段拼接:

ffmpeg -i "concat:%path1%\video1.ts|%gray_path%\gray.ts|%path2%\video2.ts|%gray_path%\gray.ts|... ...|%pathN%\videoN.ts|%gray_path%\gray.ts" -vcodec copy %output_path%\output.mp4

在进行音频片段拼接之前,需要先获取静音音频,时长等于灰帧时长。一般可以用软件产生,比如用cool edit pro,产生静音pcm,然后把pcm转为aac。FFmpeg也能完成音频拼接,命令格式和视频拼接相似,但是在我的实验过程中,ffmpeg拼接出来的长音频会比各音频片段相加的总和还长,总长度为15分钟整的音频片段们,拼接后长度为15分8秒!和视频融合后,音视频严重不同步。所以我后来使用的是另一个软件:音频编辑专家。效果良好,而且能自动统一各片段的音量,很不错的功能。
之后长视频和长音频融合,可以使用ffmpeg实现:

ffmpeg -i %input_path%\input_video.mp4 -i %input_path%\input_audio.aac output.mp4

也可以使用MP4box实现,软件 YAMB 中有交互界面可以方便高效地实现。这个软件的其他功能也相当实用。
在上述两种拼接方法中,第一种方法的优点是音视频同步非常好,而且只需拼接一次,比较省事。第二种方法的好处是思路简单,成功率高。我是在尝试第一种方法失败,而且折腾数日无果后,才退而求其次采用第二种方法。不过现在想来应该是我当时使用的黑帧视频质量太差,或者是黑帧转分辨率编码时没加上-vcodec copy之类的参数。我实验室的师姐向来都用的第一种方法,一直没什么问题。

后记

我是在研二师兄师姐们忙于找工作,无暇兼顾项目工作之时,接手了这个任务。此时的我本科刚毕业,对批处理只有朦胧印象,对视频编码也知之甚少,对FFmpeg则是一无所知。一周左右的时间里,我匆忙学习了批处理,照着前人的实现方法写批处理文件调用ffmpeg去实现。遇到许多问题,有些原始MP4文件头无法被FFmpeg识别,截取不了;有个别YUV文件无法使用ffmpeg进行下采样;转码后视频长度变化;来自于同一片段的音视频长度不相等;拼接后音视频不同步,等。尝遍了各种失败的方法,个中艰苦,非三言两语所能道明。不过现在想来,觉得几天前的自己太傻,这么简单的任务应该两天能做完。这大概也是一种进步吧,快乐。细心很重要,批处理简单实用,FFmpeg极其强大。

0 0
原创粉丝点击