0%

ffmpeg_use

ffmpeg简介

用来支持音视频转封装,转码,过滤,音视频相关参数调整的一个库,以及附带工具。
ffmpeg工具可以用于容器转换,转码,对音视频做基本的码流,帧率,分辨率,裁剪等基本动作,以及过滤等复杂操作的功能;

ffmpeg 命令行

命令行参数规则:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
usage: 
./ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...
描述:
提供转换,过滤器;取任意数量的输入“文件”(可以是常规文件、管道、网络流、抓取设备等),由-i选项指定,并写入任意数量的输出“文件”,这些文件由普通输出url指定。在命令行中发现的任何不能被解释为选项的内容都被认为是输出url。
参数理解:进一步解释:
./ffmpeg 为具体执行工具,
1)
[global_options]为全局的选项,即不区分输入输出

2)
infile iptions 为输入文件选项,对应着后面的-i input_url,这里的文件不仅仅支持本地,设备(对录制视频而言,表示设备: 如win下,-i 0,linux :-i /dev/video0),
还支持网络等,所以这里的input_url是广义的;
{[input_file_options] -i input_url} 为一组合参数,或者说一个输入源,以及对应这个输入源的options.
... 表示可以有多个输入源组合参数。

3)
{[output_file_options] output_url} 为一组合参数对应输出选项和目的地。
... 表示可以有多个输出目的地。

例子:ffmpeg -i input.avi -b:v 64k -bufsize 64k output.avi
//输入文件intput.avi 输出选项: -b:v 64k : -b bitrate video bitrate (please use -b:v) z指定比特率 -bufsize 64k
//bufsize:https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate
  • 原则上,每个输入或输出url可以包含任意数量的不同类型的流(视频/音频/字幕/附件/数据)。允许的流的数量和/或类型可能受到容器格式的限制。
    选择哪个流的输入将进入哪个流的输出是自动完成的,或者使用-map选项

  • 要在选项中引用输入文件,必须使用它们的索引(基于0)。例如,第一个输入文件是0,第二个是1,等等。类似地,文件中的流通过索引来引用。
    例如:2:3指的是第三个输入文件中的第四个流。也请参阅流说明符一章。作为一般规则,选项将应用于下一个指定的文件。
    因此,顺序很重要,您可以在命令行上多次使用相同的选项。然后将每次出现的情况应用到下一个输入或输出文件。
    该规则的例外是全局选项(例如,verbose level),它应该首先指定。

  • 不要混合输入和输出文件-首先指定所有输入文件,然后指定所有输出文件。也不要混合属于不同文件的选项。所有选项只应用于下一个输入或输出文件,并在文件之间重置。

    1
    2
    3
    4
    5
    6
    7
    eg:To set the video bitrate of the output file to 64 kbit/s
    ffmpeg -i input.avi -b:v 64k -bufsize 64k output.avi
    To force the frame rate of the output file to 24 fps:
    ffmpeg -i input.avi -r 24 output.avi
    强制输入文件(仅对原始格式有效)的帧率为1 fps,输出文件的帧率为24 fps:
    ffmpeg -r 1 -i input.m2v -r 24 output.avi
    原始输入文件可能需要format选项。

    ffmpeg工具和库相关概念:

  1. libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能,包含demuxers和muxer库;
  2. libavcodec:用于各种类型声音/图像编解码;
  3. libavutil:包含一些公共的工具函数;
  4. libswscale:用于视频场景比例缩放、色彩映射转换;
  5. libpostproc:用于后期效果处理;
  6. ffmpeg:是一个命令行工具,用来对视频文件转换格式,也支持对电视卡实时编码;
  7. ffsever:是一个HTTP多媒体实时广播流服务器,支持时光平移;
  8. ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示;
  • 容器(Container)
    容器就是一种文件格式,比如flv,mkv等。包含下面5种流以及文件头信息。
  • 流(Stream)
    是一种视频数据信息的传输方式,5种流:音频,视频,字幕,附件,数据。
  • 帧(Frame)
    帧代表一幅静止的图像,分为I帧,P帧,B帧。
  • 编解码器(Codec)
    是对视频进行压缩或者解压缩,CODEC =COde (编码) +DECode(解码)
  • 复用/解复用(mux/demux)
    把不同的流按照某种容器的规则放入容器,这种行为叫做复用(mux),所以通常是把视频和音频进行复用封装;
    把不同的流从某种容器中解析出来,这种行为叫做解复用(demux)

ffmpeg处理流程:

整体:

将input文件—>进行解复用(demuxer),得到视频和音频文件包,此时的文件是经过压缩了的(Encoded Packet)–>接着进行将已经编码的视频、音频包进行分别解码得到音视频帧(注意这里是帧级别的)–>接着对帧级别做filter过滤器处理–>接着再做重新编码–>重新进行复用;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 _______              ______________
| | | |
| input | demuxer | encoded data | decoder
| file | ---------> | packets | -----+
|_______| |______________| |
v
_________
| |
| decoded |
| frames |
|_________|
________ ______________ |
| | | | |
| output | <-------- | encoded data | <----+
| file | muxer | packets | encoder
|________| |______________|

Ffmpeg调用libavformat库(包含解复用器)来读取输入文件并从中获取包含编码数据的包。当有多个输入文件时,ffmpeg试图通过跟踪任何活动输入流的最低时间戳来保持它们的同步。
编码后的数据包随后被传递给解码器(除非为流选择了streamcopy,请参阅进一步的描述)。解码器产生未压缩的帧(原始视频/PCM音频/…),可以通过过滤进一步处理(见下一节)。
过滤后,帧被传递给编码器,编码器对帧进行编码并输出经过编码的包。最后,它们被传递给muxer, muxer将编码后的包写入输出文件。

过滤:

在编码之前,ffmpeg可以使用libavfilter库中的过滤器处理原始音频和视频帧。几个链式过滤器形成一个过滤器图。Ffmpeg区分了两种类型的过滤器图:简单的和复杂的。

  1. 简单过滤:简单过滤器是那些只有一个输入和输出,两者都是相同类型的过滤器。在上面的图表中,它们可以通过简单地在解码和编码之间插入一个额外的步骤来表示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     _________                        ______________
    | | | |
    | decoded | | encoded data |
    | frames |\ _ | packets |
    |_________| \ /||______________|
    \ __________ /
    simple _\|| | / encoder
    filtergraph | filtered |/
    | frames |
    |__________|

    简单的过滤器配置为每个流的-filter选项(分别为视频和音频使用-vf和-af别名)。一个简单的视频滤图可以像这样:

    1
    2
    3
    4
     _______        _____________        _______        ________
    | | | | | | | |
    | input | ---> | deinterlace | ---> | scale | ---> | output |
    |_______| |_____________| |_______| |________|

    注意,有些过滤器只改变框架的属性而不改变框架的内容。例如,上面例子中的fps过滤器改变帧数,但不涉及帧内容。另一个例子是setpts过滤器,它只设置时间戳,否则不更改传递帧。

  2. 复杂过滤:

复杂的过滤器图不能简单地描述为应用于一个流的线性处理链。例如,当图形有多个输入和/或输出时,或者当输出流类型与输入流不同时,就会出现这种情况。它们可以用下图表示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 _________
| |
| input 0 |\ __________
|_________| \ | |
\ _________ /| output 0 |
\ | | / |__________|
_________ \| complex | /
| | | |/
| input 1 |---->| filter |\
|_________| | | \ __________
/| graph | \ | |
/ | | \| output 1 |
_________ / |_________| |__________|
| | /
| input 2 |/
|_________|

使用-filter_complex选项配置复杂筛选器。注意,这个选项是全局的,因为复杂的过滤器图本质上不能明确地与单个流或文件关联。-lavfi选项等价于-filter_complex
复杂过滤器图的一个简单示例是叠加过滤器,它有两个视频输入和一个视频输出,包含一个视频叠加在另一个视频之上。它的音频对应物是混音滤波器。

  1. 流的拷贝;
    流拷贝是通过向-codec选项提供copy参数来选择的一种模式。它使ffmpeg省略指定流的解码和编码步骤,因此它只做解复用和muxing。它对于更改容器格式或修改容器级元数据非常有用。在这种情况下,上面的图表将简化为:

    1
    2
    3
    4
    5
     _______              ______________            ________
    | | | | | |
    | input | demuxer | encoded data | muxer | output |
    | file | ---------> | packets | -------> | file |
    |_______| |______________| |________|

    由于没有解码或编码,它非常快,而且没有质量损失。然而,由于许多因素,它可能在某些情况下不起作用。应用过滤器显然也是不可能的,因为过滤器处理的是未压缩的数据。

  2. 多流情况下,流的选择

  3. 各种选项的使用

    1
    2
    3
    4
    5
    6
    -vcodec codec (output) 
    Set the video codec. This is an alias for -codec:v. -vcodec rawvideo设置
    -vcodec rawvideo means that the video data within the container is not compressed. However, there are many ways uncompressed video could be stored, so it is necessary to specify the -pix_fmt option. In your case, -pix_fmt rgb32 says that each pixel in your raw video data uses 32 bits (1 byte each for red, green, and blue, and the remaining byte ignored).
    ffmpeg -pix_fmgs 可以列出所有格式;
    Normally a video file contains a video stream (whose format is specified using -vcodec), embedded in a media container (e.g. mp4, mkv, wav, etc.). The -f option is used to specify the container format. -f rawvideo is basically a dummy setting that tells ffmpeg that your video is not in any container.
    ...
  4. 例子:

    1
    2
    3
    4
    5
    6
    7
    8
    几个例子:
    1)ffmpeg -i destEarth.ogv -c:v libx264 -c:a aac destEarth_transcoded.mp4
    输入选项为空,输入文件为destEarth.ogv, 输入-i destEarth.ogv;输出选项: -c:v libx264 将视频转码为h264编码,-c为codec缩写,:v指定其中的视频流;-c:a 为指定音频流的编码,这里转为aac ,输出文件为 destEarth_transcoded.mp4
    2)ffmpeg -i destEarth.m4v -ss 00:01:00 -to 00:04:35 -c:v copy -an destEarth_Mars_video.mp4
    -ss 00:01:00 = 设置起始时间点;-to 00:04:45 = sets end point to 4 minutes and 45 seconds from start of file
    -c:v copy = 直接拷贝视频流,不转码 -an = 忽略音频流,不写入输出文件中
    3)设置帧率:ffmpeg –i input.mp4 –r fps output.mp4 如设置为25:ffmpeg –i input.mp4 –r 25 output.mp4
    4)设置视频码率:ffmpeg -i input.avi -b:v 1500k output.mp4 b为bitrate的意思

ffmpeg map和stream的概念

  • 流的概念:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    ffprobe输出信息:
    λ ffprobe.exe ..\destEarth.ogv
    ffprobe version N-93955-g415886588f Copyright (c) 2007-2019 the FFmpeg developers
    built with gcc 8.3.1 (GCC) 20190414
    configuration: --disable-static --enable-shared --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt
    libavutil 56. 28.100 / 56. 28.100
    libavcodec 58. 52.102 / 58. 52.102
    libavformat 58. 27.103 / 58. 27.103
    libavdevice 58. 7.100 / 58. 7.100
    libavfilter 7. 55.100 / 7. 55.100
    libswscale 5. 4.101 / 5. 4.101
    libswresample 3. 4.100 / 3. 4.100
    libpostproc 55. 4.100 / 55. 4.100
    Input #0, ogg, from '..\destEarth.ogv': --->这里指明容器格式是ogg
    Duration: 00:13:39.62, start: 0.000000, bitrate: 595 kb/s -->码率
    Stream #0:0: Video: theora, yuv420p, 400x300 [SAR 1:1 DAR 4:3], 29.97 fps, 29.97 tbr, 29.97 tbn, 29.97 tbc-->这里指明了第一条流为视频流,以theora为编码,yuv420解码出来或者叫采集方式,400x300分辨率,fps等数据;
    Metadata:
    TITLE : Destination Earth
    DATE : 1956
    LOCATION : http://archive.org/details/4050_Destination_Earth_01_47_33_28
    encoder : Lavf54.49.102
    Stream #0:1: Audio: vorbis, 44100 Hz, stereo, fltp, 128 kb/s--->这里指明第二条流:音频流,以vorbis编码,44100hz,立体声,128kb/s
    Metadata:
    TITLE : Destination Earth
    DATE : 1956
    LOCATION : http://archive.org/details/4050_Destination_Earth_01_47_33_28
    encoder : Lavf54.49.102

再看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ffprobe version N-93955-g415886588f Copyright (c) 2007-2019 the FFmpeg developers
built with gcc 8.3.1 (GCC) 20190414
configuration: --disable-static --enable-shared --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt
libavutil 56. 28.100 / 56. 28.100
libavcodec 58. 52.102 / 58. 52.102
libavformat 58. 27.103 / 58. 27.103
libavdevice 58. 7.100 / 58. 7.100
libavfilter 7. 55.100 / 7. 55.100
libswscale 5. 4.101 / 5. 4.101
libswresample 3. 4.100 / 3. 4.100
libpostproc 55. 4.100 / 55. 4.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '..\destEarth.m4v':
Metadata:
major_brand : mp42
minor_version : 1
compatible_brands: mp42mp41
creation_time : 2013-08-03T13:58:40.000000Z
Duration: 00:13:39.62, start: 0.000000, bitrate: 3162 kb/s
Stream #0:0(eng): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(tv, smpte170m/smpte170m/bt709), 640x480, 2999 kb/s, 29.97 fps, 29.97 tbr, 2997 tbn, 5994 tbc (default)
Metadata:
creation_time : 2013-08-03T13:58:40.000000Z
handler_name : Apple Video Media Handler
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 159 kb/s (default)
Metadata:
creation_time : 2013-08-03T13:58:40.000000Z
handler_name : Apple Sound Media Handler

所以一个容器可能有多个流:音频,视频,字幕,附件,数据

  • map的使用:https://trac.ffmpeg.org/wiki/Map 这里把map的使用以例子说明白了,暂时不解释;
    就是针对输入的每条流做处理(编码或者其他方式),然后再写入到输出文件中 ;

ffmpeg 过滤器 filter,filterchain,filtergraph

几个概念:
  • filter,filterchain,fitergraph的关系:
  • filter是单个过滤器
  • filterchain是: filter1,filter2,…组成
  • filtergraph是: filterchain1,filterchain2,filterchain3这样组成的;
过滤器简介:

FFmpeg filter提供了很多音视频特效处理的功能,比如视频缩放、截取、翻转、叠加等。
其中定义了很多的filter,例如以下常用的一些filter。

1
2
3
4
5
scale:视频/图像的缩放
overlay:视频/图像的叠加
crop:视频/图像的裁剪
trim:截取视频的片段
rotate:以任意角度旋转视频

通过ffmpeg -filters 可以获得支持的filter列表;
ffmpeg -h filter=filter_name

过滤器使用:
1
2
-af filter_graph set audio filters
-vf filter_graph set video filters

例子:

1
2
3
4
ffmpeg -i input -vf scale=w=iw/2:h=ih/2 output
这里进行视频过滤: vf
scale是其中一种过滤器:ffmpeg -h filter= scale 可以看参数,主要是视频/图像的缩放
=w=iw/2:h=ih/2 这里把宽高裁剪为1半;

ref:
https://trac.ffmpeg.org/wiki/FilteringGuide
https://www.bilibili.com/read/cv4910766 简单整理一下x264参数
x264 FFmpeg Options Guide https://sites.google.com/site/linuxencoding/x264-ffmpeg-mapping

采集使用:

windows下

1
2
3
ffmpeg.exe -f dshow -i audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{E41DED46-6012-4493-8D55-7D9322A433B6}" D:\output.mp3
ffmpeg.exe -f dshow -t 10 -i audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{E41DED46-6012-4493-8D55-7D9322A433B6}" -f s16le -y D:\sound.pcm
ffplay.exe -channels 2 -f s16le -i D:\sound.pcm

ffmpeg相关库的使用简记:

https://github.com/leandromoreira/ffmpeg-libav-tutorial/blob/master/README-cn.md

结构:

  1. AVFormatContext 组件(容器这个词你认为是文件格式就好了) –容器 组件工具
  2. AVStream: 音频流和视频流
    首先我们需要加载媒体文件到 AVFormatContext 组件(容器这个词你认为是文件格式就好了),它并不是真正的加载整个文件,它只是加载了文件头。
    这样我们就可以访问媒体文件流(流只是最基本的音频和视频数据)。每个流对于AVStream都是有用的。
  3. AVPacket 音视频的封装包 ,从代码使用上看,AVPacket解码前传入的数据是不带头的,比如flv中获取,视频会-11-5,音频会-11-2
    一个是 AAC 的音频流,一个是 H264(AVC)视频流。我们可以从每一个流中提取出数据包,这些数据包将被加载到 AVPacket。
    AVPacket :如对flv ,视频: flvtag-11-5-4(presize),音频:flvtag-11-2-4
    反过来,编码是把AVFrame->AVPacket
  4. 编解码工具
    AVCodec将解压这些数据到 AVFrame —AVCodec 编解码器 工具
  5. 解码帧

AVFrame: 解码后的帧

一般流程:

  1. 注册: av_register_all
  2. 分配结构体:比如解封装时:avformat_alloc_context(),解码时:avcodec_alloc_context3(不过解码时要先找对应的解码器:avcodec_find_decoder_by_name)
  3. 初始化结构体等:如解码:avcodec_open2
  4. 创建结构 压缩帧: AVPacket ,解码后帧:AVFrame:
    开始解码:avcodec_decode_video2 注意分配的时候:av_init_packet,av_frame_alloc,av_free_packet,av_frame_free
  5. AVFrame* decFrame 得到这个格式的解码后的帧,再接着传到混画那里:
    混画解码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    main: 注册:av_register_all(); //初始化注册所有要用的编码器解码器等
    收帧解码线程:
    m_flvReader.UnpackFlvFrame ;//拆出flv tag
    m_videoDecoder.setUpDec(config); //找解码器:
    avcodec_find_decoder_by_name //找解码器
    avcodec_alloc_context3 //分配解码结构
    avcodec_open2 //初始化结构体
    m_videoDecoder.doDecVideo 开始解码
    av_init_packet(pkt) //分配AVPacket编码格式结构
    pkt.data =(uint8_t*)data.data(); //塞数据
    分配解码后数据结构: decframe = av_frame_alloc();
    开始解码:avcodec_decode_video2(dec, frame, &got_frame, pkt);
    释放相关结构体:av_free_packet(&pkt);
    混画过程:opencv
    编码:类似解码;
    ffmpeg使用可以参考example文件夹下的例子;