1.FFmpeg整体结构
ffplay、ffprobe、ffmpeg是上层的三个应用程序
libavutil:核心工具库,其他模块一般都会依赖这个模块做一些基本的音视频处理。
libavformat:文件格式协议库,封装了protocol层和demuxer、Muxer层,使得格式和协议对于开发者是透明的。
libavcodec:编解码库,封装了codec层,有一些codec具备自己的license,ffmpeg默认并不会自动添加x264、fdkaac等库,但是ffmpeg像一个平台一样,这些可以通过插件的方式集成进来,然后为开发者提供统一的接口。
libswscale:该模块是将图像进行格式转换的模块,比如,可以将YUV的数据转换为RGB的数据,缩放尺寸由1280720变为800480
libswresample:该模块可用于音频重采样,可以对数字音频进行声道数、数据格式、采样率等多种基本信息的转换
libavfilter:音视频滤镜库,该模块提供了包括音频特效和视频特效的处理,在使用FFmpeg的API进行编解码的过程中,直接使用该模块为音视频数据做特效处理是非常方便同时也非常高效的一种方式。
avdevice:输入输出设备库,比如,需要编译出播放声音或者视频的工具ffplay,就需要确保该模块是打开的,同时也需要SDL的预先编译,因为该设备模块播放声音与播放视频使用的都是SDL库。
libpostproc:该模块可用于进行后期处理,当我们使用AVFilter的时候需要打开该模块的开关,因为Filter中会使用到该模块的一些基
础函数。
2.初始化
av_register_all():注册所有组件,4.0已经废弃了。
avdevice_register_all():对设备进行注册。
avformat_network_init():处理话网络库以及网络协议相关的库(比如openssl)
3.封装格式相关
avformat_alloc_context():负责申请一个AVFormatContext结构的内存,并进行简单初始化。
avformat_free_context():释放该结构里的所有东西以及该结构本身。
avformat_close_input():关闭解复用器。关闭后就不再需要使用avformat_free_context 进行释放。
avformat_open_input():打开输入视频文件
avformat_find_stream_info():获取音视频文件信息
av_read_frame(): 读取音视频包
avformat_seek_file():定位文件
av_seek_frame():定位文件
复用器这块调用大体过程:
- avformat_alloc_context(分配解复用器上下文)
- avformat_open_input(根据url打开本地文件或网络流)
- avformat_find_stream_info(读取媒体的部分数据包以获取码流信息)
- av_read_frame:从文件中读取数据包
- avformat_seek_file或av_seek_frame:定位文件
- avformat_close_input:关闭解复用器
4.解码器相关
avcodec_alloc_context3():分配解码器上下文
avcodec_find_decoder():根据ID查找解码器
avcodec_find_decoder_by_name():根据解码器名字
avcodec_open2():打开编解码器
avcodec_send_packet():发送编码数据包
avcodec_receive_frame():接收解码后数据
avcodec_free_context():释放解码器上下文
avcodec_close():关闭解码器
编解码器相关调用流程:
- avcodec_alloc_context3:分配解码器上下文
- avcodec_parameters_to_context:将码流中的编解码器信息拷贝到AVCodecContex
- avcodec_find_decoder或指定解码器avcodec_find_decoder_by_name:根据编解码器信息查找相应的解码器
- avcodec_open2:打开编解码器并关联到AVCodecContex
- avcodec_send_packet:向解码器发送数据包
- avcodec_receive_frame:接收解码后的帧
- avcodec_close avcodec_free_context:关闭解码器和释放上下文
5.组件注册
ffmpeg 3.x 需要主动调用av_register_all,4.x会自动进行注册,但是注册的流程类似。调用av_register_all,会把全局的编码器、解码器等结构体注册到各自全局的对象链表里,以便后边查找调用。
6.常用的结构体介绍
-
AVFormatContext:封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式等相关信息。
- iformat:输入媒体的AVInputFormat,比如指向AVInputFormat ff_flv_demuxer
- nb_streams:输入媒体的AVStream 个数,一般可以通过遍历这个来得到流信息,进而判断流的类型codec_type
- streams:输入媒体的AVStream []数组,通过这个数组拿到流信息
- duration:输入媒体的时长(以微秒为单位),计算方式可以参考**av_dump_format()**函数。
- bit_rate:输入媒体的码率
-
AVInputFormat 对应demuxer ,每一种封装格式对应一个这样的结构体(例如FLV, MKV, MP4, AVI)。
AVInputFormat ff_flv_demuxer = { .name = "flv", .long_name = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"), .priv_data_size = sizeof(FLVContext), .read_probe = flv_probe, .read_header = flv_read_header, .read_packet = flv_read_packet, .read_seek = flv_read_seek, .read_close = flv_read_close, .extensions = "flv", .priv_class = &flv_class, };
- name:封装格式名称
- extensions:封装格式的扩展名
- 一些封装格式处理的接口函数,比如read_packet()
-
AVOutputFormat 对应muxer
AVOutputFormat ff_flv_muxer = { .name = "flv", .long_name = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"), .mime_type = "video/x-flv", .extensions = "flv", }
-
AVStream:每个视频流或者音频流对应一个这样的结构体
- index:标识该视频/音频流
- time_base:该流的时基,PTS*time_base=真正的时间(秒)
- avg_frame_rate:该流的帧率
- duration:该视频/音频流长度
- codecpar:编解码器参数属性
-
AVCodecParameters
- codec_type:媒体类型,比如AVMEDIA_TYPE_VIDEO AVMEDIA_TYPE_AUDIO等
- codec_id:编解码器类型,比如AV_CODEC_ID_H264 AV_CODEC_ID_AAC等。
-
AVCodecContext:编码器上下文保存了视频或者音频编解码相关的信息。
- codec:编解码器的AVCodec,比如指向AVCodec ff_aac_latm_decoder
- width, height:图像的宽高(只针对视频)
- pix_fmt:像素格式(只针对视频)
- sample_rate:采样率(只针对音频)
- channels:声道数(只针对音频)
- sample_fmt:采样格式(只针对音频)
-
AVCodec:每种视频或者音频编解码器对应一个这样的结构体。
- name:编解码器名称
- type:编解码器类型
- id:编解码器ID
- 一些编解码的接口函数,比如int (*decode)()
-
AVPacket:存储一帧这样的压缩数据。
- pts:显示时间戳
- dts:解码时间戳
- data:压缩编码数据
- size:压缩编码数据大小
- pos:数据的偏移地址
- stream_index:所属的AVStream
-
AVFrame:存储一帧解码或者采样数据。
- data:解码后的图像像素数据(音频采样数据)
- linesize:对视频来说是图像中一行像素的大小;对音频来说是整个音频帧的大小
- width, height:图像的宽高(只针对视频)
- key_frame:是否为关键帧(只针对视频)
- pict_type:帧类型(只针对视频)。例如I,P,B
- sample_rate:音频采样率(只针对音频)
- nb_samples:音频每通道采样数(只针对音频)
- pts:显示时间戳
7.AVFormatContext, AVStream和AVCodecContext之间的关系
通过遍历AVFormatContext中的streams,拿到AVStream,每一个AVStream对应一个流,流内部包好解码器相关的参数信息codecpar,通过avcodec_parameters_to_context将解码器相关的参数拷贝到AVCodecContext中去。