6 FFmpeg从入门到精通-FFmpeg滤镜使用

1 FFmpeg从入门到精通-FFmpeg简介
2 FFmpeg从入门到精通-FFmpeg工具使用基础
3 FFmpeg从入门到精通-FFmpeg转封装
4 FFmpeg从入门到精通-FFmpeg转码
5 FFmpeg从入门到精通-FFmpeg流媒体
6 FFmpeg从入门到精通-FFmpeg滤镜使用
7 FFmpeg从入门到精通-FFmpeg中Linux设备操作
8 FFmpeg从入门到精通-FFmpeg接口libavformat的使用
9 FFmpeg从入门到精通-FFmpeg接口libavcodec的使用
10 FFmpeg从入门到精通-FFmpeg接口libavfilter的使用

6.FFmpeg滤镜使用

  6.1 FFmpeg滤镜Filter描述格式

    在使用FFmpeg的滤镜处理音视频特效之前,首先需要了解一下Filter的基本格式。

  6.1.1 FFmpeg滤镜Filter的参数排列方式

    为了便于理解Filter使用的方法,下面先用最简单的方式来描述Filter使用时的参数排列方式:

输入流或标记名]滤镜参数[临时标记名];[输入流或标记名]滤镜参数[临时标记名]

    文字描述的排列方式很明确,接下来列举一个简单的例子:输入两个文件,一个视频input.mp4,一个图片logo.png,将logo进行缩放,然后放在视频的左上角:

ffmpeg -i input.mp4 -i logo.png -filter_complex "[1:v]scale=176:144[logo];[0:v][logo]overlay=x=0:y=0" output.mp4

    从上述命令可以看出,将logo.png的图像流缩放为176×144的分辨率,然后定义一个临时标记名logo,最后将缩放后的图像[logo]铺在输入的视频input.mp4的视频流[0:v]的左上角。

  6.1.2 FFmpeg滤镜Filter时间内置变量

    在使用Filter时,经常会用到根据时间轴进行操作的需求,下面先来了解一下这些相关的变量,见表。
在这里插入图片描述

  6.2 FFmpeg为视频加水印

    FFmpeg可以为视频添加水印,水印可以是文字,也可以是图片,主要用来标记视频所属标记等。下面就来看一下FFmpeg加水印的多种方式。

  6.2.1 文字水印

    在视频中增加文字水印需要准备的条件比较多,需要有文字字库处理的相关文件,在编译FFmpeg时需要支持FreeType、FontConfig、iconv,系统中需要有相关的字库,在FFmpeg中增加纯字母水印可以使用drawtext滤镜进行支持,下面就来看一下drawtext的滤镜参数,具体见表。
在这里插入图片描述
    drawtext滤镜使用举例
    使用drawtext可以根据前面介绍过的参数进行加水印设置,例如将文字的水印加在视频的左上角,命令行如下:

ffmpeg -i input.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='hello world':x=20:y=20" output.mp4

    执行完这条命令行之后,即可在output.mp4视频的左上角增加“hello world”文字水印,为了使文字展示得更清楚一些,将文字大小设置为100像素,如图所示。
在这里插入图片描述
    如图所示,视频的左上角加入了“hello world”文字水印。
    图的文字水印为纯黑色,会展现得比较突兀,为了使水印更加柔和,可以通过drawtext滤镜的fontcolor参数调节颜色,例如将字体的颜色设置为绿色:

ffmpeg -i input.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='hello world':fontcolor=green" output.mp4

    执行完命令行之后,文字水印即为绿色,如图所示。
在这里插入图片描述
    如果想调整文字水印显示的位置,调整x与y参数的数值即可。文字水印还可以增加一个框,然后给框加上背景颜色:

ffmpeg -i input.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='hello world':fontcolor=green:box=1:boxcolor=yellow" output.mp4

    执行完命令行之后,视频左上角显示文字水印,水印背景色为黄色,效果如图所示
在这里插入图片描述
    至此,文字水印的基础功能已经添加完成。
    有些时候文字水印希望以本地时间作为水印内容,可以在drawtext滤镜中配合一些特殊用法来完成,例如:

ffmpeg -re -i input.mp4 -vf "drawtext=fontsize=60:fontfile=FreeSerif.ttf:text='%{localtime\:%Y\-%m\-%d %H-%M-%S}':fontcolor=green:box=1:boxcolor=yellow" output.mp4

    在text中显示本地当前时间,格式为年月日时分秒的方式,具体情况如图所示。
在这里插入图片描述
    在个别场景中,需要定时显示水印,定时不显示水印,这种方式同样可以配合drawtext滤镜进行处理,使用drawtext与enable配合即可,例如每3秒钟显示一次文字水印:

ffmpeg -re -i input.mp4 -vf "drawtext=fontsize=60:fontfile=FreeSerif.ttf:text='test':fontcolor=green:box=1:boxcolor=yellow:enable=lt(mod(t\,3)\,1)" output.mp4

    执行完命令行之后,即可达到每三秒钟闪一下文字水印的效果,由于其是一个动态展示的视频,所以在这里就不抓图展示了。
    当然,大多数时候文字水印会有中文字符,此时系统需要包含中文字库与中文编码支持,这样才能够将中文水印加入到视频中并正常显示。

ffmpeg -re -i input.mp4 -vf "drawtext=fontsize=50:fontfile=/Library/Fonts/Songti.ttc:text='文字水印测试':fontcolor=green:box=1:boxcolor=yellow" output.mp4

    执行完命令行之后即可将中文水印加入到视频当中,并且中文字符的字体为行文楷体。

  6.2.2 图片水印

    FFmpeg除了可以向视频添加文字水印之外,还可以向视频添加图片水印、视频跑马灯等,本节将重点介绍如何为视频添加图片水印;为视频添加图片水印可以使用movie滤镜,下面就来熟悉一下movie滤镜的参数,如表所示。
在这里插入图片描述
    下面举例说明,在FFmpeg中加入图片水印有两种方式,一种是通过movie指定水印文件路径,另外一种方式是通过filter读取输入文件的流并指定为水印,这里重点介绍如何读取movie图片文件作为水印,举例如下:

ffmpeg -i input.mp4 -vf "movie=logo.png[wm]; [in][wm]overlay=30:10[out]" output.mp4

    执行完命令行之后logo.png水印将会打入到input.mp4视频中,显示在x坐标30、y坐标10的位置,如图所示。
在这里插入图片描述
    从图中可以看到,将透明水印加入到视频中的效果更好一些。当只有纯色背景的logo图片时,可以考虑使用movie与colorkey滤镜配合做成半透明效果,例如:

ffmpeg -i input.mp4 -vf "movie=logo.png,colorkey=black:1.0:1.0 [wm]; [in] [wm]overlay=30:10 [out]" output.mp4

    执行完命令行之后,将会根据colorkey设置的颜色值、相似度、混合度与原片混合为半透明水印。

  6.3 FFmpeg生成画中画

    在使用FFmpeg处理流媒体文件时,有时需要使用画中画的效果。在FFmpeg中,可以通过overlay将多个视频流、多个多媒体采集设备、多个视频文件合并到一个界面中,生成画中画的效果。在前面的滤镜使用中,以至于以后的滤镜使用中,与视频操作相关的处理,大多数都会与overlay滤镜配合使用,尤其是用在图层处理与合并场景中,下面就来了解一下overlay的参数,具体见表。
在这里插入图片描述
    从参数列表中可以看到,主要参数并不多,但实际上在overlay滤镜使用中,还有很多组合的参数可以使用,可以使用一些内部变量,例如overlay图层的宽、高、坐标等;下面再列举几个画中画的例子:

ffmpeg -re -i input.mp4 -vf "movie=sub.mp4,scale=480x320[test]; [in][test] overlay [out]" -vcodec libx264 output.flv

    执行完命令行之后会将sub.mp4视频文件缩放成宽480、高320的视频,然后显示在视频input.mp4的x坐标为0、y坐标为0的位置,下面看一下命令行执行后生成的output.flv的效果,如图所示。
在这里插入图片描述
    图即为显示画中画的最基本方式,如果希望子视频显示在指定位置,例如显示在画面的右下角,则需要用到overlay中x坐标与y坐标的内部变量

ffmpeg -re -i input.mp4 -vf "movie=sub.mp4,scale=480x320[test]; [in][test] overlay=x=main_w-480:y=main_h-320 [out]" -vcodec libx264 output.flv

    根据命令行可以分析出,除了显示在overlay画面中,子视频将会定位在主画面的最右边减去子视频的宽度,最下边减去子视频的高度的位置,生成的视频播放效果如图所示。
在这里插入图片描述
    以上两种视频画中画的处理均为静态位置处理,使用overlay还可以配合正则表达式进行跑马灯式画中画处理,动态改变子画面的x坐标与y坐标即可

ffmpeg -re -i input.mp4 -vf "movie=sub.mp4,scale=480x320[test]; [in][test] overlay=x='if(gte(t,2), -w+(t-2)*20, NAN)':y=0 [out]" -vcodec libx264 output.flv

    命令行执行之后,子视频将会从主视频的左侧开始渐入视频从左向右游动,视频画中画的基本处理至此已介绍完毕,重点为overlay滤镜的使用。

  6.4 FFmpeg视频多宫格处理

    视频除了画中画显示,还有一种场景为以多宫格的方式呈现出来,除了可以输入视频文件,还可以输入视频流、采集设备等。从前文中可以看出进行视频图像处理时,overlay滤镜为关键画布,可以通过FFmpeg建立一个画布,也可以使用默认的画布。如果想以多宫格的方式展现,则可以自己建立一个足够大的画布,下面就来看一下多宫格展示的例子:

ffmpeg -re -i input1.mp4 -re -i input2.mp4 -re -i input3.mp4 -re -i input4.mp4 -filter_complex "nullsrc=size=640x480 [base]; [0:v] setpts=PTS-STARTPTS, scale=320x240 [upperleft]; [1:v] setpts=PTS-STARTPTS, scale=320x240 [upperright]; [2:v] setpts=PTS-STARTPTS, scale=320x240 [lowerleft]; [3:v] setpts=PTS-STARTPTS, scale=320x240 [lowerright]; [base][upperleft] overlay=shortest=1 [tmp1]; [tmp1][upperright] overlay=shortest=1:x=320 [tmp2]; [tmp2][lowerleft] overlay=shortest=1:y=240 [tmp3]; [tmp3][lowerright] overlay=shortest=1:x=320:y=240" -c:v libx264 output.flv

    执行完命令行之后,即可通过nullsrc创建一个overlay画布画布的大小为宽640像素、高480像素,使用[0:v][1:v][2:v][3:v]将输入的4个视频流去除分别进行缩放处理,处理为宽320、高240的视频,然后基于nullsrc生成的画布进行视频平铺,平铺的整体情况如图所示。
在这里插入图片描述
    根据命令中定义的upperleft、upperright、lowerleft、lowerright进行不同位置的平铺,平铺的整体步骤如图所示。
在这里插入图片描述
    执行完命令行之后的最终展现形式如图所示。
在这里插入图片描述

  6.5 FFmpeg音频流滤镜操作

    FFmpeg除了可以操作视频之外,还可以对音频进行操作,例如拆分声道合并多声道为单声道调整声道布局调整音频采样率等,而进行音频的拆分与合并,在FFmpeg中可以使用滤镜进行操作,可以通过amix、amerge、pan、channelsplit、volume、volumedetect等滤镜进行常用的音频操作,下面就来了解一下相关的操作。

  6.5.1 双声道合并单声道

    在进行音频转换时常常会遇到音频声道发生改变的情况,例如将双声道合并为单声道,通过ffmpeg –layouts参数可以查看音频的声道布局支持情况,例如将双声道合并为单声道操作,则是将stereo转变为mono模式,如图所示。
在这里插入图片描述

ffmpeg -i input.aac -ac 1 output.aac

    执行完命令行之后,input.aac的音频原为双声道,现被转为单声道,下面来看一下执行后的对比信息:

Input #0, aac, from 'input.aac':
  Duration: 00:00:34.25, bitrate: 5 kb/s
  Stream #0:0: Audio: aac (LC), 48000 Hz, stereo, fltp, 5 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (aac (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, adts, to 'output.aac':
  Metadata:
    encoder         : Lavf59.34.102
  Stream #0:0: Audio: aac (LC), 48000 Hz, mono, fltp, 69 kb/s
    Metadata:
      encoder         : Lavc59.54.100 aac
size=      18kB time=00:00:35.00 bitrate=   4.2kbits/s speed= 477x

    从图中可以看到,input.aac的音频是stereo布局方式,即FL与FR两个声道,通过ac将双声道转为单声道mono布局,输出为output.aac。原本双声道的音频,左耳右耳都可以听到声音,调整后依然可以左右耳都听到声音,只是布局发生了改变,为中央布局;接下来可以将双声道拆分成左耳与右耳两个音频,每个耳朵只能听到一个声道的声音。

  6.5.2 双声道提取

    使用FFmpeg可以提取多声道的音频并输出至新音频文件或者多个音频流,以便于后续的编辑等,下面看一下提取多声道音频的方式,如图所示。
在这里插入图片描述
    从提取方式中可以看到,将音频为stereo的布局提取为两个mono流,左声道一个流,右声道一个流,命令格式如下。可以使用FFmpeg的map_channel参数实现:

ffmpeg -i input.aac -map_channel 0.0.0 left.aac -map_channel 0.0.1 right.aac

    这里也可以使用pan滤镜实现:

ffmpeg -i input.aac -filter_complex "[0:0]pan=1c|c0=c0[left];[0:0]pan=1c|c0=c1[right]" -map "[left]" left.aac -map "[right]" right.aac

    命令行执行后,会将布局格式为stereo的input.aac转换为两个mono布局的left.aac与right.aac:

Input #0, aac, from 'input.aac':
  Duration: 00:00:34.25, bitrate: 5 kb/s
  Stream #0:0: Audio: aac (LC), 48000 Hz, stereo, fltp, 5 kb/s
Stream mapping:
  Stream #0:0 (aac) -> pan:default
  Stream #0:0 (aac) -> pan:default
  pan:default -> Stream #0:0 (aac)
  pan:default -> Stream #1:0 (aac)
Output #0, adts, to 'left.aac':
  Metadata:
    encoder         : Lavf59.34.102
  Stream #0:0: Audio: aac (LC), 48000 Hz, mono, fltp, 69 kb/s
    Metadata:
      encoder         : Lavc59.54.100 aac
Output #1, adts, to 'right.aac':
  Metadata:
    encoder         : Lavf59.34.102
  Stream #1:0: Audio: aac (LC), 48000 Hz, mono, fltp, 69 kb/s
    Metadata:
      encoder         : Lavc59.54.100 aac
size=      18kB time=00:00:35.00 bitrate=   4.2kbits/s speed= 276x

    从上述输出中可以看到,input.aac为stereo,而left.aac与right.aac为mono

  6.5.3 双声道转双音频流

    FFmpeg不但可以将双声道音频提取出来生成两个音频文件,还可以将双声道音频提取出来转为一个音频文件两个音频流,每个音频流为一个声道,转换方式如图所示。
在这里插入图片描述

ffmpeg -i input.aac -filter_complex channelsplit=channel_layout=stereo output.mka

    命令行通过channelsplit滤镜将stereo布局方式的音频切分开,分成两个音频流,下面来看一下切分前后的音频效果:

Input #0, aac, from 'input.aac':
  Duration: 00:00:34.25, bitrate: 5 kb/s
  Stream #0:0: Audio: aac (LC), 48000 Hz, stereo, fltp, 5 kb/s
Output #0, matroska, to 'output.mka':
  Stream #0:0: Audio: vorbis (oV[0][0] / 0x566F), 48000 Hz, 1 channels (FL), fltp (default)
    Metadata:
      encoder         : Lavc59.54.100 libvorbis
  Stream #0:1: Audio: vorbis (oV[0][0] / 0x566F), 48000 Hz, 1 channels (FR), fltp
    Metadata:
      encoder         : Lavc59.54.100 libvorbis

  6.5.4 单声道转双声道

    使用FFmpeg可以将单声道转换为双声道,即当只有中央声道或者只有mono布局时,才可以通过FFmpeg转换为stereo布局,转换方式如图所示。
在这里插入图片描述
    根据前面章节提到的stereo布局转出来的mono布局的音频文件left.aac进行生成,命令行如下:

ffmpeg -i left.aac -ac 2 output.m4a

    执行完命令行之后,将会从left.aac中,将布局为mono的音频转换为stereo布局的音频文件output.m4a,下面查看一下输入与输出文件:

Input #0, aac, from 'left.aac':
  Duration: 00:00:34.13, bitrate: 4 kb/s
  Stream #0:0: Audio: aac (LC), 48000 Hz, mono, fltp, 4 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (aac (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, ipod, to 'output.m4a':
  Metadata:
    encoder         : Lavf59.34.102
  Stream #0:0: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s
    Metadata:
      encoder         : Lavc59.54.100 aac
size=      17kB time=00:00:35.02 bitrate=   4.0kbits/s speed= 280x

    从以上的输出信息中可以看到,输入的left.aac中音频为mono布局,而输出的文件output.m4a中的音频布局则为stereo。除了使用ac参数,还可以使用amerge滤镜进行处理,命令行如下:

ffmpeg -i left.aac -filter_complex "[0:a][0:a]amerge=inputs=2[aout]" -map "[aout]" output.m4a

    命令行执行后的效果与使用ac的效果相同。
    当然,这样执行之后的双声道并不是真正的双声道,而是由单声道处理成的多声道,效果不会比原有的多声道效果好

  6.5.5 两个音频源合并双声道

    前面讲过将单mono处理为双声道,如果将输入的单mono转换为stereo双声道为伪双声道,则可以考虑将两个音频源合并为双声道,相对来说这样操作更容易理解一些,下面就来看一下如何将两个音频源输入为双声道,如图所示。
在这里插入图片描述
    输入两个布局为mono的音频源,合并为一个布局为stereo双声道的音频流,输出到output文件,下面用命令行执行来举例说明:

ffmpeg -i left.aac -i right.aac -filter_complex "[0:a][1:a]amerge=inputs=2[aout]" -map "[aout]" output.mka

    命令行执行之后,会将left.aac与right.aac两个音频为mono布局的AAC合并为一个布局为stereo的音频流,输出至output.mka文件,下面就来看一下输入文件与输出文件信息:

Input #0, aac, from 'left.aac':
  Duration: 00:00:34.13, bitrate: 4 kb/s
  Stream #0:0: Audio: aac (LC), 48000 Hz, mono, fltp, 4 kb/s
[aac @ 000002afbe53a640] Estimating duration from bitrate, this may be inaccurate
Input #1, aac, from 'right.aac':
  Duration: 00:00:34.13, bitrate: 4 kb/s
  Stream #1:0: Audio: aac (LC), 48000 Hz, mono, fltp, 4 kb/s
Stream mapping:
  Stream #0:0 (aac) -> amerge
  Stream #1:0 (aac) -> amerge
  amerge:default -> Stream #0:0 (libvorbis)
Press [q] to stop, [?] for help
Output #0, matroska, to 'output.mka':
  Metadata:
    encoder         : Lavf59.34.102
  Stream #0:0: Audio: vorbis (oV[0][0] / 0x566F), 48000 Hz, stereo, fltp
    Metadata:
      encoder         : Lavc59.54.100 libvorbis

    从以上三个Input信息可以看,输入的两路mono转换为stereo了,输出音频为AC3,这个可以通过acodec aac指定为输出AAC编码的音频

  6.5.6 多个音频合并为多声道

    除了双声道音频,FFmpeg还可以支持多声道,通过ffmpeg-layouts即可看到声道布局有很多种,常见的多声道还有一种是5.1方式的多声道,其原理如图6-20所示。
在这里插入图片描述
    图表示将6个mono布局的音频流合并为一个多声道(5.1声道)的音频流。如果希望实现这样的效果,则可以使用如下命令行:

ffmpeg -i front_left.wav -i front_right.wav -i front_center.wav -i lfe.wav -i back_left.wav -i back_right.wav -filter_complex "[0:a][1:a][2:a][3:a][4:a][5:a]amerge=inputs=6[aout]" -map "[aout]" output.wav

    命令行执行之后,将会生成一个5.1布局的音频,下面就来看一下执行后的效果:

Input #0, wav, from 'output.wav':
    Metadata:
        encoder         : Lavf57.71.100
    Duration: 00:00:50.03, bitrate: 4608 kb/s
        Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 48000 Hz, 5.1, s16, 4608 kb/s

    如Input信息所示,多音频输入合并后生成为5.1布局的音频,码率为4608kbit/s。
    使用FFmpeg除了可以生成以上这些布局方式之外,还可以生成很多种,可以通过ffmpeg -layouts方式获得布局方式信息。

  6.6 FFmpeg音频音量探测

    在拿到音频文件播放音频时,有时会需要根据音频的音量绘制出音频的波形,而有时候会希望根据音频的音量来过滤音频文件,将重点介绍音频音量与音频波形相关的滤镜操作。

  6.6.1 音频音量获得

    使用FFmpeg可以获得音频的音量分贝,以及与音频相关的一些信息,可以使用滤镜volumedetect获得,下面举例说明:

ffmpeg -i output.wav -filter_complex volumedetect -c:v copy -f null /dev/null

    命令行执行之后,输出信息如下:

Input #0, wav, from 'output.wav':
  Duration: 00:00:46.18, bitrate: 1411 kb/s
  Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, stereo, s16, 1411 kb/s
[Parsed_volumedetect_0 @ 0x41cf6c0] n_samples: 0
Stream mapping:
  Stream #0:0 (pcm_s16le) -> volumedetect:default
  volumedetect:default -> Stream #0:0 (pcm_s16le)
Press [q] to stop, [?] for help
Output #0, null, to '/dev/null':
  Metadata:
    encoder         : Lavf59.27.100
  Stream #0:0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s
    Metadata:
      encoder         : Lavc59.37.100 pcm_s16le
size=N/A time=00:00:46.18 bitrate=N/A speed=2.53e+03x    
video:0kB audio:7956kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
[Parsed_volumedetect_0 @ 0x4210d40] n_samples: 4073400
[Parsed_volumedetect_0 @ 0x4210d40] mean_volume: -16.2 dB
[Parsed_volumedetect_0 @ 0x4210d40] max_volume: -2.8 dB
[Parsed_volumedetect_0 @ 0x4210d40] histogram_2db: 206
[Parsed_volumedetect_0 @ 0x4210d40] histogram_3db: 3454
[Parsed_volumedetect_0 @ 0x4210d40] histogram_4db: 5650

    从输出信息中可以看到,mean_volume为获得的音频的平均大小,即-16.2dB。

  6.6.2 绘制音频波形

    一些应用场景需要用到音频的波形图,随着声音分贝的增大,波形波动越强烈,使用FFmpeg可以通过showwavespic滤镜来绘制音频的波形图,下面将列举几个例子,首先看一下如何使用FFmpeg绘制简单的波形图:

ffmpeg -i output.wav -filter_complex "showwavespic=s=640x120" -frames:v 1 output.png

    命令行执行之后将会生成一个宽高为640×120大小的output.png图片,图片内容为音频波形,如图所示。
在这里插入图片描述
    图中所绘的为音频波形的全部信息。前边章节中看到的output.wav为5.1布局方式的多声道音频,如果希望看到每个声道的音频的波形图,则可以使用showwavepic与split_channel滤镜配合绘制出不同声道的波形图。

ffmpeg -i output.wav -filter_complex "showwavespic=s=640x240:split_channels=1" -frames:v 1 output.png

    由于现实的波形有些多,所以生成图片的宽高会发生一些改变,可以将高度设置得大一些,这条命令执行完之后会将音频的每一个声道进行拆分,然后绘制出图像,如图所示。
在这里插入图片描述
    六条波形图分别表示5.1布局每一个声道的波形图

  6.7 FFmpeg为视频加字幕

    为视频添加字幕的方式有很多种,大概可以分为将字幕编码进视频流中以及在封装容器中加入字幕流。将字幕编码进入视频流中的方式与为视频增加水印的方式基本相似,而在封装容器中加入字幕流的方式则需要封装容器支持加入字幕流,下面就来看一下如何使用FFmpeg为视频文件增添字幕。

  6.7.1 ASS字幕流写入视频流

    使用FFmpeg可以将字幕流写入视频流,通过ASS滤镜即可,首先需要将视频流进行解码,然后将ASS字幕写入视频流,编码压缩之后再进行容器封装即可完成,字幕文件的内容格式大致如下:

Script Info]
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: *Default,微软雅黑,21,&H00FFFFFF,&H0000FFFF, &H2D804000,&H32000000,-1,0,0,0,100,100,0,0,0,2,1,2,5,5,5,134
Style: logo,微软雅黑,21,&H00FFFFFF,&HF0000000,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,1,2,5,5,5 ,134
[Events]
Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:00.91,0:00:02.56,*Default,NTP,0000,0000,0000,,前情提要\N{
    
    \1c&HFFFFFF&}{
    
    \3a&H82&\4c&H030303&}{
    
    \fnArial Black}{
    
    \fs20}{
    
    \b1}{
    
    \fe0}{
    
    \shad1}{
    
    \3c&H030303&}{
    
    \4c&H030303&}Previously on “the Vampire Diaries”...
Dialogue: 0,0:00:02.59,0:00:05.47,*Default,NTP,0000,0000,0000,,Elena很享受你们兄弟俩对她的爱慕吧\N{
    
    \1c&HFFFFFF&}{
    
    \3a&H82&\4c&H030303&}{
    
    \fnArial Black}{
    
    \fs20}{
    
    \b1}{
    
    \fe0}{
    
    \shad1}{
    
    \3c&H030303&}{
    
    \4c&H030303&}Does Elena enjoy having both of you worship at her altar?
Dialogue: 0,0:00:05.50,0:00:06.66,*Default,NTP,0000,0000,0000,,我听说过你\N{
    
    \1c&HFFFFFF&}{
    
    \3a&H82&\4c&H030303&}{
    
    \fnArial Black}{
    
    \fs20}{
    
    \b1}{
    
    \fe0}{
    
    \shad1}{
    
    \3c&H030303&}{
    
    \4c&H030303&}I've heard about you...

    打开的文件中的内容为字幕文件的片段,内容格式为ASS字幕格式。下面将字幕写入视频流中:

ffmpeg -i input.mp4 -vf ass=t1.ass -f mp4 output.mp4

    命令行执行之后即可根据input.mp4的信息增加ASS字幕,将字幕写入视频流中生成output.mp4,下面可以看一下输入与输出文件的情况:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.mp4':
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 2497 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 159 kb/s (default)
Output #0, mp4, to 'output.mp4':
  Stream #0:0(und): Video: h264 (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 30 fps, 15360 tbn (default)
  Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default)

    从Input信息中可以看到,输入与输出的封装容器格式基本相同,均为一个视频流和一个音频流,并未包含字幕流,因为字幕已经通过ASS容器将文字写入视频流中。播放效果如图所示。
在这里插入图片描述
    从图所示的播放效果可以看到,字幕流已经写入视频文件中,并且在播放时可以看到字幕。

  6.7.2 ASS字幕流写入封装容器

    下面看一下如何利用·FFmpeg将ASS字幕流写入MKV封装容器中·,并以字幕流的形式存在:

ffmpeg -i input.mp4 -i t1.ass -acodec copy -vcodec copy -scodec copy output.mkv

    命令行执行之后,会将input.mp4中的音频流、视频流、t1.ass中的字幕流在不改变编码的情况下封装入output.mkv文件中,而output.mkv文件将会包含三个流,分别为视频流、音频流以及字幕流;而在input.mp4中或者输入的视频文件中原本同样带有字幕流,并希望使用t1.ass字幕流时,可以通过map功能将对应的字幕流指定封装入output.mkv,例如:

ffmpeg -i input.mp4 -i t1.ass -map 0:0 -map 0:1 -map 1:0 -acodec copy -vcodec copy -scodec copy output.mkv

  6.8 FFmpeg视频抠图合并

    FFmpeg还可以进行视频抠图与背景视频合并的操作——chromakey操作,下面就来介绍chromakey操作。

参数 类型 说明
color 颜色 设置chromakey颜色值 默认为黑色
similarity 浮点 设置chromakey相似值
blend 浮点 设置chromakey融合值
yuv 布尔 yuv替代rgb 默认为false

    参数介绍完毕,接下来再举一个例子实战体验一下。如果当前有两个视频:一个为input.mp4,另一个为绿色背景的视频input_green.mp4。
    背景颜色可以根据ffmpeg-colors查询颜色支持,这个背景颜色为绿色,那么可以设置透明色部分为绿色,下面使用chromakey滤镜将绿色背景中的人物抠出来,然后贴到以input.mp4为背景的视频中:

ffmpeg -i input.mp4 -i input_green.mp4 -filter_complex "[1:v]chromakey=Green:0.1:0.2[ckout];[0:v][ckout]overlay[out]" -map "[out]" output.mp4

    命令行执行之后,会设置chrom-akey的背景色为绿色,设置标签为ckout,然后将ckout铺在以input.mp4的视频为背景的画布上,最后输出output.mp4,输出效果如图所示。
在这里插入图片描述
    从图中可以看到,人物已经被铺在了视频中,两个图层已经合并。chromakey效果已经达到。。
    注意:
    FFmpeg中除了有chromakey滤镜之外,还有一个colorkey参数,chromakey滤镜主要处理YUV数据,所以一般来说做绿幕处理更有优势而colorkey处理纯色均可以,因为colorkey处理主要以RGB数据为主

  6.9 FFmpeg3D视频处理

    使用FFmpeg可以进行相关的处理,介绍一下如何通过stereo3d滤镜方式实现3D效果

  6.9.1 stereo3d处理3D视频

    查询FFmpeg滤镜stereo3d参数。接下来举个例子验证一下,首先获得一个左右眼的视频,然后将其转变为红蓝眼镜观看的视频。

  6.9.2 3D图像转换举例

    3D视频除了用VR眼镜观看之外,还有一种场景是在电影院裸眼用黄蓝眼镜观看,这时候看这样的视频同样是左右效果而不是3D效果,可以通过stereo3d滤镜转换之后使用黄蓝眼镜观看

ffplay -vf "stereo3d=sbsl:aybd" input.mp4

    命令行执行后,会将原片的左右排列效果合并为黄蓝合并排列效果,视频播放起来将会更有立体感;如果使用红蓝眼镜观看视频,可以使用红蓝输出参数:

ffplay -vf "stereo3d=sbsl:arbg" input.mp4

  6.10 FFmpeg定时视频截图

    使用FFmpeg截图有很多种,常见的为使用vframe参数与fps滤镜,下面重点介绍vframe参数与fps滤镜两种方法的使用例子。

  6.10.1 vframe参数截取一张图片

    在获取指定时间位置的视频图像缩略图时,可使用vframe获得,通过FFmpeg参数ss与vframe即可获得,下面来看一下例子:

ffmpeg -i input.flv -ss 00:00:7.435 -vframes 1 out.png

    命令行执行之后,FFmpeg会定位到input.flv的第7秒位置,获得对应的视频帧,然后将图像解码出来编码成RGB24的图像并封装成PNG图像,过程如下:

Input #0, flv, from 'input.flv':
  Stream #0:0: Video: h264 (High), yuv420p(progressive), 1280x720, 2500 kb/s, 30 fps, 30 tbr, 1k tbn
  Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp, 160 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> png (native))
Output #0, image2, to 'out.png':
  Stream #0:0: Video: png, rgb24(pc, gbr/unknown/unknown, progressive), 1280x720, q=2-31, 200 kb/s, 30 fps, 30 tbn
[image2 @ 000001505cd0d240] The specified filename 'out.png' does not contain an image sequence pattern or a pattern is invalid.
[image2 @ 000001505cd0d240] Use a pattern such as %03d for an image sequence or use the -update option (with -frames:v 1 if needed) to write a single image.
frame=    1 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.00 bitrate=N/A dup=1 drop=0 speed=   0x

  6.10.2 fps滤镜定时获得图片

    下面来看一下FFmpeg的fps滤镜是如何在间隔时间获得图片的:

ffmpeg -i input.flv -vf fps=1 out%d.png

    命令行执行之后,将会每隔1秒钟生成一张PNG图片

ffmpeg -i input.flv -vf fps=1/60 img%03d.jpg

    命令行执行之后,将会每隔1分钟生成一张JPEG图片

ffmpeg -i input.flv -vf fps=1/600 thumb%04d.bmp

    命令行执行之后,将会每隔10分钟生成一张BMP图片
    以上三种方式均为按照时间截取图片,那么如果希望按照关键帧截取图片,可以使用select来截取:

ffmpeg -i input.flv -vf "select='eq(pict_type,PICT_TYPE_I)'" -vsync vfr thumb%04d.png

    命令行执行之后,FFmpeg将会判断图像类型是否为I帧,如果是I帧则会生成一张PNG图像

  6.11 FFmpeg生成测试元数据

    FFmpeg不但可以处理音视频文件,还可以生成音视频文件,可以通过lavfi设备虚拟音视频源数据,下面就来简单介绍几个常用的案例。

  6.11.1 FFmpeg生成音频测试流

    在FFmpeg中,可以通过lavfi虚拟音频源的abuffer、aevalsrc、anullsrc、flite、anoisesrc、sine滤镜生成音频流,下面就来举例说明:

ffmpeg -re -f lavfi -i abuffer=sample_rate=44100:sample_fmt=s16p:channel_layout=stereo -acodec aac -y output.aac

    命令行执行之后,FFmpeg会根据lavfi设备输入的abuffer中定义的采样率、格式,以及声道布局,通过AAC编码,然后生成AAC音频文件;下面再列举一个例子:

ffmpeg -re -f lavfi "aevalsrc=sin(420*2*PI*t)|cos(430*2*PI*t):c=FC|BC" -acodec aac output.aac

    命令行执行之后,音频为使用aevalsrc生成的双通道音频,输出为output.aac,下面就来使用前边提到过的波形查看方式查看一下音频波形,效果如图所示。
在这里插入图片描述
    以上举例为abuffer与aevalsrc两种输入举例,还可以以类似的方式使用anullsrc、flite、anoisesrc、sine来虚拟输入的音频设备生成音频流。以便使用FFmpeg测试音频流处理。

  6.11.2 FFmpeg生成视频测试流

    在使用FFmpeg测试流媒体时,如果没有输入文件,则可以通过FFmpeg虚拟设备虚拟出来一个输入视频流,可以通过FFmpeg模拟多种视频源:allrgb、allyuv、color、haldclutsrc、nullsrc、rgbtestsrc、smptebars、smptehdbars、testsrc、testsrc2、yuvtestsrc;下面就对常见的视频源进行举例测试。

ffmpeg -re -f lavfi -i testsrc=duration=5.3:size=qcif:rate=25 -vcodec libx264 -r:v 25 output.mp4

    命令行执行之后,FFmpeg会根据testsrc生成长度为5.3秒、图像大小为QCIF分辨率、帧率为25fps的视频图像数据,并编码成为H.264,然后输出output.mp4视频文件,下面就来看一下生成的MP4文件,如图所示。
在这里插入图片描述

ffmpeg -re -f lavfi -i testsrc2=duration=5.3:size=qcif:rate=25 -vcodec libx264 -r:v 25 output.mp4

    命令行执行之后,会根据testsrc2生成一个视频图像内容,其他参数与testsrc相同。下面就来看一下命令行执行之后生成的output.mp4文件内容,如图所示。
在这里插入图片描述

ffmpeg -re -f lavfi -i color=c=[email protected]:s=qcif:r=25 -vcodec libx264 -r:v 25 output.mp4

    命令行执行之后,会使用color作为视频源,图像内容为纯红色,编码为H.264,编码出来后生成的output.mp4视频内容如图所示。
在这里插入图片描述

ffmpeg -re -f lavfi -i "nullsrc=s=256x256, geq=random(1)*255:128:128" -vcodec libx264 -r:v 25 output.mp4

    命令行执行之后,会使用nullsrc作为视频源,宽高为256×256,数据为随机雪花样。下面看一下命令行执行之后的效果图,如图所示。
在这里插入图片描述

  6.12 FFmpeg对音视频倍速处理

    在音视频处理中,常见的处理还包括音视频的倍速处理,如2倍速播放、4倍速播放,常见的处理方式包含跳帧播放与不跳帧播放,两种处理方式FFmpeg均可支持,跳帧处理方式的用户体验稍差一些,下面就来了解两个滤镜:atempo与setpts

  6.12.1 atempo音频倍速处理

    在FFmpeg的音频处理滤镜中,atempo是用来处理倍速的滤镜,能够控制音频播放速度的快与慢,这个滤镜只有一个参数:tempo,将这个参数的值设置为浮点型,取值范围从0.5到2,0.5则是原来速度的一半,调整为2则是原来速度的2倍速。下面列举两个测试例子。
    (1)半速处理

ffmpeg -i input.wav -filter_complex "atempo=tempo=0.5" -acodec aac output.aac

    命令行执行之后,FFmpeg将会输出如下执行信息:

Input #0, aac, from 'input_audio.aac':
    Duration: 00:00:50.82, bitrate: 127 kb/s
        Stream #0:0: Audio: aac (LC), 48000 Hz, stereo, fltp, 127 kb/s
Stream mapping:
    Stream #0:0 (aac) -> atempo
    atempo -> Stream #0:0 (aac)
Press [q] to stop, [?] for help
Output #0, adts, to 'output.aac':
    Metadata:
        encoder         : Lavf57.71.100
         Stream #0:0: Audio: aac (LC), 48000 Hz, stereo, fltp, 128 kb/s
        Metadata:
            encoder         : Lavc57.89.100 aac
size=    1600kB time=00:01:39.94 bitrate= 131.1kbits/s speed=31.8

    从命令行执行后的内容中可以看到,该命令行执行总时长消耗为输入的duration的2倍,处理过后的output.aac可以通过播放器播放,效果是源音频速度的一半。
    (2)2倍速处理

ffmpeg -i input.wav -filter_complex "atempo=tempo=2.0" -acodec aac output.aac

    命令行执行之后,FFmpeg将会输出如下执行信息:

Input #0, aac, from 'input_audio.aac':
Input #0, aac, from 'input_audio.aac':
    Duration: 00:00:50.82, bitrate: 127 kb/s
        Stream #0:0: Audio: aac (LC), 48000 Hz, stereo, fltp, 127 kb/s
Stream mapping:
    Stream #0:0 (aac) -> atempo
    atempo -> Stream #0:0 (aac)
Press [q] to stop, [?] for help
Output #0, adts, to 'output.aac':
    Metadata:
        encoder         : Lavf57.71.100
        Stream #0:0: Audio: aac (LC), 48000 Hz, stereo, fltp, 128 kb/s
        Metadata:
            encoder         : Lavc57.89.100 aac
size=     400kB time=00:00:24.98 bitrate= 131.2kbits/s speed=30.4x

    从以上输出的内容中可以看到,该命令执行总时长消耗为输入的duration的二分之一,处理过后的output.aac可以通过播放器播放,效果会比源音频快一倍。

  6.12.2 setpts视频倍速处理

    在FFmpeg的视频处理滤镜中,通过setpts能够控制视频速度的快与慢,这个滤镜只有一个参数:expr,这个参数可用来描述视频的每一帧的时间戳,下面就来看一下setpts的可用的常见值,具体见表。

说明
FRAME_RATE 根据帧率设置帧率值 只用于固定帧率
PTS 输入的pts时间戳
RICTIME 使用RTC的时间作为时间戳
TB 输入的时间戳的实践基

    下面对如何使用PTS值来控制播放速度的应用列举两个例子。
    (1)半速处理

ffmpeg -re -i input.mp4 -filter_complex "setpts=PTS*2" output.mp4

    命令行执行之后FFmpeg将会输出如下信息:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input_video.mp4':
    Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2avc1mp41
        encoder         : Lavf57.66.102
    Duration: 00:00:50.00, start: 0.080000, bitrate: 2486 kb/s
        Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x714 [SAR 1:1 DAR 640:357], 2484 kb/s, 25 fps, 25 tbr, 25k tbn, 50 tbc (default)

    如上述输出内容所示,输出的视频output.mp4的时长刚好是input.mp4的duration的2倍,因为是半速的视频,所以处理时间长度是原视频的2倍,而使用播放器播放output.mp4时将会看到其速度比原视频慢一半的运动效果。
    (2)2倍速处理

ffmpeg -i input.mp4 -filter_complex "setpts=PTS/2" output.mp4

    命令行执行之后FFmpeg将会输出如下信息:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input_video.mp4':
    Metadata:
        major_brand     : isom
 major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2avc1mp41
        encoder         : Lavf57.66.102
    Duration: 00:00:50.00, start: 0.080000, bitrate: 2486 kb/s
        Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x714 [SAR 1:1 DAR 640:357], 2484 kb/s, 25 fps, 25 tbr, 25k tbn, 50 tbc (default)
        Metadata:
            handler_name    : VideoHandler

    如以上输出内容所示,输出的视频output.mp4的时长刚好是input.mp4的duration的一半,因为是2倍速的视频,所以处理时间长度是原视频的一半,使用播放器播放output.mp4时将会看到速度比原视频快一倍的运动效果。

  6.13 小结

    FFmpeg功能强大的主要原因是其包含了滤镜处理avfilterFFmpeg的avfilter能够实现的音频、视频、字幕渲染效果数不胜数

猜你喜欢

转载自blog.csdn.net/migu123/article/details/129314333