FFmpeg是很优秀的音视频库,很多播放器的内核都是使用ffmpeg来实现的,ijk、暴风影音等......本系列是对FFmpeg4.4源码进行的分析,FFmpeg在源码上不同版本间还是有点差别的,不过流程都很类似。
先介绍FFmpeg大概模块、结构体和基本使用,为之后的分析打个基础,先有个基本框架。
整体流程图
这里引用一张流程图,大概流程为注册-初始化数据-探测文件格式-寻找解码器-打开文件(判断起播条件)-收帧-解码-渲染。
模块
- libavformat 该模块下实现了目前绝大多数媒体封装格式,包括封装和解封装,如MP4、FLV、TS等文件格式;RTMP、RTSP、HLS等网络协议封装格式。
- libavcodec 该模块下实现了目前绝大多数常用的编解码格式,包括编码和解码。如AAC、MP3、、H.264、H.265等
- libavutil 该模块包含一些公共的工具函数的使用库,包括算数运算,字符操作等。
- libswscale 该模块提供了高级别的图像转换API,如按原始视频的比例缩放、色彩映射转换、图像颜色空间或格式转换等功能(比如YUV转RGB)
- libswresample 该模块提供了高级别的音频重采样API,如采样格式转换、音频通道布局转换与布局等功能
- libavfilter 该模块提供了一个通用的音频、视频、字幕等滤镜处理框架。
- libpostproc 该模块用于后期效果处理,如图像的去块效应等。
- libavdevice 用于硬件的音视频采集、加速和显示。
常用的结构体
封装格式
- AVFormatContext 描述了媒体文件的构成及基本信息,是统领全局的基本结构体,贯穿程序始终,很多函数都要用它作为参数;
- AVInputFormat 解复用器对象,每种作为输入的封装格式(例如FLV、MP4、TS等)对应一个该结构体。如ff_flv_demuxer。
- AVOutputFormat 复用器对象,每种作为输出的封装格式(例如FLV, MP4、TS等)对应一个该结构体,如ff_flv_muxer。
- AVStream 用于描述一个视频/音频流的相关数据信息。
编解码
- AVCodecContext 描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息,持有AVCodec。
- AVCodec 编解码器对象,每种编解码格式(例如H.264、AAC等)对应一个该结构体,如aacdec.c。
- AVCodecParameters 编解码参数,每个AVStream中都含有一个AVCodecParameters,用来存放当前流的编解码参数。
IO协议
- AVIOContext 提供输入输出数据,透传给了URLContext。
- URLContext 封装了协议对象及其上下文信息,持有URLProtocol
- URLProtocol 描述了音视频数据传输所使用的协议,用URLProtocol结构体来表达某种传输协议,如ff_librtmp_protocol、ff_https_protocol。
数据封装
- AVPacket 存放解码前、编码后的压缩数据,即封装数据
- AVFrame 存放解码后、编码前、的原始数据,如YUV格式的视频数据或PCM格式的音频数据等;
基本使用
void start(){
//注册复用器、编码器等
av_register_all();
avformat_network_init();
char *url = "fileAbsolutePath";
//打开文件
AVFormatContext *formatContext = avformat_alloc_context();
avformat_open_input(&formatContext, url, NULL, NULL);
avformat_find_stream_info(formatContext, NULL);
// 创建解码器解码线程
for (int i = 0; i < formatContext->nb_streams; ++i) {
AVStream *stream = formatContext->streams[i];
AVCodecParameters *codecParameters = stream->codecpar;
AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id);
AVCodecContext *codecContext = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codecContext, codecParameters);
avcodec_open2(codecContext, codec, 0)
if (codecParameters->codec_type == AVMEDIA_TYPE_AUDIO) {
// 创建音频解码线程
} else if (codecParameters->codec_type == AVMEDIA_TYPE_VIDEO) {
// 创建视频解码线程
}
}
AVPacket pkt;
int packet = 0;
//读取音视频数据
while(isPlaying) {
packet = av_packet_alloc();
av_read_frame(formatContext, &packet);
// 音视频解码线程读取packet解码播放
queue.put(packet);
}
avformat_close_input(&formatContext);
avformat_free_context(formatContext);
}
void decodePacket() {
AVPacket *packet;
while (isPlaying) {
ret = pkt_queue.take(packet);
// 送入解码器
ret = avcodec_send_packet(avCodecContext, packet);
releaseAvPacket(packet);
// 解码获取一帧
AVFrame *frame = av_frame_alloc();
ret = avcodec_receive_frame(avCodecContext, frame);
frame_queue.put(frame);
}
}
★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。
见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓