视频入门系列-FFmpeg篇(FFmpeg结构体分析)

通过之前的学习,我们知道了如何通过调用FFmpeg代码来进行解码和编码,正所谓知其然还要知其所以然,这篇文章分析下FFmpeg编解码过程中主要的结构体,通过对这些结构体的分析,可以更好的理解FFmpeg的编解码过程。

1.FFmpeg结构体分析
通过之前对于FFmpeg进行解码、编码的代码学习,我们总结FFmpeg结构体主要分为三个层次:协议层(AVIOContext)、封装层(AVInputFormat)、解码层(AVStream)。具体如下

图片

2.FFmpeg编解码关键结构体
按照FFmpeg编解码时代码的调用过程,笔者总结有八个关键结构体。本文按照编解码调用顺序介绍如下:

2.1AVFormatContext:描述媒体文件或媒体流的构成和基本信息,贯穿ffmpeg使用整个流程

AVInputFormat *iformat、AVOutputFormat *oformat:输入或者输出流的格式(只能存在一个)
AVIOContext *pb:管理输入输出数据        
unsigned int nb_streams:音视频流的个数
AVStream **streams:音视频流        
char *url:文件名
int64_t duration:时长
int bit_rate:比特率(单位bite/s)
AVDictionary *metadata:元数据(查看元数据:ffprobe filename)

2.2.AVInputFormat:文件的封装格式

char* name:封装格式的名字
char* long_name:封装格式的长名字
char* extensions:文件扩展名

2.3AVIOContext->URLContext->URLProtocol

    ◆ 2.3.1 AVIOContext:文件(协议)操作的顶层对象

unsigned char *buffer:缓冲开始位置
int buffer_size:缓冲区大小(默认32768)
unsigned char *buf_ptr:当前指针读取到的位置
unsigned char *buf_end:缓存结束的位置
void *opaque:URLContext结构体
(*read_packet)(...):读取音视频数据的函数指针
(*write_packet)(...):写入音视频数据的函数指针
(*read_pause)(...):网络流媒体协议的暂停或恢复播放函数指针

◆ 2.3.2 URLContext:每种协议,有一个协议操作对象和一个关联的协议对象

char* name:协议名称
const struct URLProtocol *prot:协议操作对象(ff_file_protocol、ff_librtmp_protocol...)
void *priv_data:协议对象(FileContext、LibRTMPContext)

◆ 2.3.3 URLProtocol:协议操作对象

2.4 AVStream:存储音频流或视频流的结构体

int index:音频流或视频流的索引
AVRational time_base:计算pts或dts是使用的时间戳基本单位(显示时间:pt = av_q2d(video_stream->time_base) * frame->pts)
int64_t duration:该视频/音频流长度
AVRational avg_frame_rate:平均帧率(对于视频来说,frame_rate=avg_frame_rate.num / avg_frame_rate.den)
AVCodecParameters *codecpar:解码器参数

2.5.AVCodecParameter 和 AVCodecContext
   ◆新的 ffmpeg 中 AVStream.codecpar(struct AVCodecParameter) 代替 AVStream.codec(struct AVCodecContext):AVCodecParameter 是由 AVCodecContext 分离出来的,AVCodecParameter中没有函数
  ◆AVCodecContext 结构体仍然是编解码时不可或缺的结构体:avcodec_send_packet 和 avcodec_receive_frame 使用 AVCodecContext
  ◆ AVCodecContext 和 AVCodec 的获取方法 

//=============== new version code ===============
char filePath[] = "test.mp4";
AVFormatContext  *pFormatCtx;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
pFormatCtx = avformat_alloc_context();

av_register_all();
avformat_network_init();
avformat_open_input(&pFormatCtx, filePath, NULL, NULL);
avformat_find_stream_info(pFormatCtx, NULL);
for (int i = 0; i < pFormatCtx->nb_streams; i++)
{
    AVStream *pStream = pFormatCtx->streams[i];
    pCodec = avcodec_find_decoder(pStream->codecpar->codec_id);
    pCodecCtx = avcodec_alloc_context3(pCodec);
    avcodec_parameters_to_context(pCodecCtx, pStream->codecpar);
}
//============ old version code ============
char filePath[] = "test.mp4";
AVFormatContext  *pFormatCtx;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
pFormatCtx = avformat_alloc_context();

av_register_all();
avformat_network_init();
avformat_open_input(&pFormatCtx, filePath, NULL, NULL);
avformat_find_stream_info(pFormatCtx, NULL);
for (int i = 0; i < pFormatCtx->nb_streams; i++)
{
    AVStream *pStream = pFormatCtx->streams[i];
    pCodecCtx = pStream->codec;
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
}

 ◆ 关键参数:可参考 avcodec_parameters_to_context 源码

num AVMediaType codec_type:编解码器的类型(视频,音频...)
enum AVCodecID codec_id:标示特定的编码器
AVCodecContext:struct AVCodec *codec:采用的解码器AVCodec(H.264,MPEG2...)
int bit_rate:平均比特率
uint8_t *extradata; int extradata_size:针对特定编码器包含的附加信息(例如对于H.264解码器来说,存储SPS,PPS等)
AVCodecContext:enum AVPixelFormat pix_fmt:像素格式(视频)
int width, height:宽和高(视频)
AVCodecContext:enum AVSampleFormat sample_fmt:采样格式(音频)
int sample_rate:采样率(音频)
int channels:声道数(音频)
uint64_t channel_layout:声道格式
AVCodecParameters:int format:像素格式(视频)/采样格式(音频)

2.6 AVCodec:编解码器结构体
  ◆ 每一个解码器对应一个AVCodec结构体,比如:AVCodec ff_h264_decoder,AVCodec ff_jpeg2000_decoder
  ◆ 关键成员变量如下:

const char *name:编解码器短名字(形如:"h264")
const char *long_name:编解码器全称(形如:"H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10")
enum AVMediaType type:媒体类型:视频、音频或字母
enum AVCodecID id:标示特定的编码器
const AVRational *supported_framerates:支持的帧率(仅视频)
const enum AVPixelFormat *pix_fmts:支持的像素格式(仅视频)
const int *supported_samplerates:支持的采样率(仅音频)
const enum AVSampleFormat *sample_fmts:支持的采样格式(仅音频)
const uint64_t *channel_layouts:支持的声道数(仅音频)

2.7 AVPacket:存储解码前数据的结构体
    ◆ 关键成员变量

AVBufferRef *buf:管理data指向的数据
uint8_t *data:压缩编码的数据
int size:data的大小
int64_t pts:显示时间戳
int64_t dts:解码时间戳
int stream_index:标识该AVPacket所属的视频/音频流

    ◆ AVPacket内存管理:AVPacket本身并不包含压缩的数据,通过data指针引用数据的缓存空间
    ◆ 多个AVPacket共享同一个数据缓存(AVBufferRef、AVBuffer)
    ◆ AVBuffer拥有独立的数据缓存

av_read_frame(pFormatCtx, packet)  // 读取Packet
av_packet_ref(dst_pkt,packet) // dst_pkt 和 packet 共享同一个数据缓存空间,引用计数+1
av_packet_unref(dst_pkt); //释放 pkt_pkt 引用的数据缓存空间,引用计数-1

   ◆ AVBuffer 关键成员变量

uint8_t *data:压缩编码的数据
size_t size:数据长度
atomic_uint refcount:引用计数,如果引用计数为0,则释放数据缓存空间

2.8AVFrame:存储解码后数据的结构体

uint8_t *data[AV_NUM_DATA_POINTERS]:解码后原始数据(对视频来说是YUV,RGB,对音频来说是PCM)
int linesize[AV_NUM_DATA_POINTERS]:data中“一行”数据的大小。注意:未必等于图像的宽,一般大于图像的宽。
int width, height:视频帧宽和高(1920x1080,1280x720...)
int nb_samples:音频的一个AVFrame中可能包含多个音频帧,在此标记包含了几个
int format:解码后原始数据类型(YUV420,YUV422,RGB24...)
int key_frame:是否是关键帧
enum AVPictureType pict_type:帧类型(I,B,P...)
AVRational sample_aspect_ratio:图像宽高比(16:9,4:3...)
int64_t pts:显示时间戳
int coded_picture_number:编码帧序号
int display_picture_number:显示帧序号

音视频入门系列文章已同步在微信公众号(可扫下方二维码关注):八小时码字员

音视频入门系列,同步录制了学习视频,已上传至bilibili(八小时码字员):音视频入门系列(图像、音频、字幕、视频封装格式,FFmpeg、ffplay源码分析,解码、编码、转码,流媒体协议,服务器部署)_哔哩哔哩_bilibili

音视频学习交流QQ群:693316541

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值