FFMPEG组成组件
- ffmpeg 是一个命令行工具,用来对视频文件转换格式,也支持对电视卡实时编码
- ffserver 是一个 HTTP 多媒体实时广播流服务器,支持时光平移
- ffplay 是一个简单的播放器,基于 SDL 与 FFmpeg 库
- libavcodec 包含了全部 FFmpeg 音频/视频 编解码库
- libavdevice 对输出输入设备的支持; 包含多媒体输入/输出软件框架中抓取和呈现的输入输出设备,包含video4linux,video4linux2,vfw和ALSA的库。
- libavfilter 提供了通用的视频音频滤镜框架
- libavformat 包含 demuxers 和 muxer 库;提供对音频、视频、字幕流的分解和合并;
- libavutil 包含一些工具库
- libpostproc 对于视频做前处理的库
- libswscale 对于图像作缩放的库
- libavresampler 为libswresample库中的音频重采样功能提供更高层次的接口。
- libswresample 对音频重采样、音频格式转换、 Rematrixing;
- libswscale : 视频场景比例缩放、色彩映射转换;
FFMPEG解码流程:
1. 注册所有容器格式和CODEC: av_register_all()
2. 打开文件: av_open_input_file()
3. 从文件中提取流信息: av_find_stream_info()
4. 穷举所有的流,查找其中种类为CODEC_TYPE_VIDEO
5. 查找对应的解码器: avcodec_find_decoder()
6. 打开编解码器: avcodec_open()
7. 为解码帧分配内存: avcodec_alloc_frame()
8. 不停地从码流中提取出帧数据: av_read_frame()
9. 判断帧的类型,对于视频帧调用:avcodec_decode_video()
10.解码完后,释放解码器: avcodec_close()
11.关闭输入文件: avformat_close_input_file()
基本概念:
编解码器、数据帧、媒体流和容器是数字媒体处理系统的四个基本概念。
首先需要统一术语:
- 容器/文件(Conainer/File):即特定格式的多媒体文件。
- 媒体流(Stream):指时间轴上的一段连续数据,如一段声音数据,一段视频数据或一段字幕数据,可以是压缩的,也可以是非压缩的,压缩的数据需要关联特定的编解码器。
- 数据帧/数据包(Frame/Packet):通常,一个媒体流由大量的数据帧组成,对于压缩数据,帧对应着编解码器的最小处理单元。通常,分属于不同媒体流的数据帧交错复用于容器之中,参见交错。
- 编解码器:编解码器以帧为单位实现压缩数据和原始数据之间的相互转换。
在FFMPEG中,使用AVFormatContext、AVStream、AVCodecContext、AVCodec及AVPacket等结构来抽象这些基本要素,
主要数据结构
AVCodecContext
这是一个描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息;
如果是单纯使用libavcodec,这部分信息需要调用者进行初始化;如果是使用整个FFMPEG库,这部分信息在调用 av_open_input_file和av_find_stream_info的过程中根据文件的头信息及媒体流内的头部信息完成初始化。其中几个主要域的释义如下:
- extradata/extradata_size: 这个buffer中存放了解码器可能会用到的额外信息,在av_read_frame中填充。一般来说,首先,某种具体格式的demuxer在读取格式头 信息的时候会填充extradata,其次,如果demuxer没有做这个事情,比如可能在头部压根儿就没有相关的编解码信息,则相应的parser会继 续从已经解复用出来的媒体流中继续寻找。在没有找到任何额外信息的情况下,这个buffer指针为空。
- time_base:
- width/height:视频的宽和高。
- sample_rate/channels:音频的采样率和信道数目。
- sample_fmt: 音频的原始采样格式。
- codec_name/codec_type/codec_id/codec_tag:编解码器的信息。
- index/id:index对应流的索引,这个数字是自动生成的,根据index可以从AVFormatContext::streams表中索引到该流;而id则是流的标识,依赖于具体的容器格式。比如对于MPEG TS格式,id就是pid。
- time_base:流的时间基准,是一个实数,该流中媒体数据的pts和dts都将以这个时间基准为粒度。通常,使用av_rescale/av_rescale_q可以实现不同时间基准的转换。
- start_time:流的起始时间,以流的时间基准为单位,通常是该流中第一个帧的pts。
- duration:流的总时间,以流的时间基准为单位。
- need_parsing:对该流parsing过程的控制域。
- nb_frames:流内的帧数目。
- r_frame_rate/framerate/avg_frame_rate:帧率相关。
- codec:指向该流对应的AVCodecContext结构,调用av_open_input_file时生成。
- parser:指向该流对应的AVCodecParserContext结构,调用av_find_stream_info时生成。
- nb_streams和streams所表示的AVStream结构指针数组包含了所有内嵌媒体流的描述;
- iformat和oformat指向对应的demuxer和muxer指针;
- pb则指向一个控制底层数据读写的ByteIOContext结构。
- start_time和duration是从streams数组的各个AVStream中推断出的多媒体文件的起始时间和长度,以微妙为单位。
- probesize
- mux_rate
- packet_size
- flags
- max_analyze_duration
- key
- max_index_size
- max_picture_buffer
- max_delay
- dts表示解码时间戳,pts表示显示时间戳,它们的单位是所属媒体流的时间基准。
- stream_index给出所属媒体流的索引;
- data为数据缓冲区指针,size为长度;
- duration为数据的时长,也是以所属媒体流的时间基准为单位;
- pos表示该数据在媒体流中的字节偏移量;
- destruct为用于释放数据缓冲区的函数指针;
- flags为标志域,其中,最低为置1表示该数据是一个关键帧。
- av_destruct_packet_nofree或 0;
- av_destruct_packet,
- 时间信息
- 时间信息的获取:
AVCodecParser
用来对不同视频编码标准,分析出一个完整的一帧,如
AVCodecParser ff_h264_parser = {
{ CODEC_ID_H264 },
sizeof(H264Context),
init,
h264_parse,
close,
h264_split,
};
h.264的parser
4)h.264 decoder
AVCodec ff_h264_decoder = {
"h264",
AVMEDIA_TYPE_VIDEO,
CODEC_ID_H264,
sizeof(H264Context),
ff_h264_decode_init,
NULL,
ff_h264_decode_end,
decode_frame,
/*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 | CODEC_CAP_DELAY |
CODEC_CAP_FRAME_THREADS |
CODEC_CAP_SLICE_THREADS,
.flush= flush_dpb,
.long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
.init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
.update_thread_context = ONLY_IF_THREADS_ENABLED(decode_update_thread_context),
.profiles = NULL_IF_CONFIG_SMALL(profiles),
};