FFmpeg:浅谈 AVFrame 结构体

成员变量

struct AVFrame 是一个很基础的类型,顾名思义,主要用来管理解码后的音视频数据:

  • 视频:一个 AVFrame 对象可存储一帧图像。
  • 音频:一个 AVFrame 对象可存储若干个采样点。

个人理解,AVFrame 主要的成员变量按照功能可划分为四部分:

  • 数据部分,这是最核心的部分啦,存储了解码后的音视频数据
    • uint8_t *data[AV_NUM_DATA_POINTERS]:存储音视频数据
    • int linesize[AV_NUM_DATA_POINTERS];:描述数据长度。具体含义取决于数据格式。
    • uint8_t **extended_data;data 的补充字段。当 data 不够用时,可用该字段存储。
    • AVBufferRef *buf[AV_NUM_DATA_POINTERS];:和 data 对应的引用计数器。buf[i]data[i] 一一对应。当 buf 全为 nullptr 时,说明该对应未启用引用计数功能。
    • AVBufferRef **extended_buf;:和 extended_data 对应的引用计数器。
    • int nb_extended_buf;extended_buf 的长度。
  • 辅助部分,用于解析数据部分,这里仅列出了一部分
    • 视频部分:
      • int width, height;:宽高
      • int key_frame;:1 → keyframe, 0 → not
      • enum AVPictureType pict_type;:类型。IPB, SSISP, BI
      • AVRational sample_aspect_ratio;:注释没看懂,度娘说是单个像素的宽高比。
      • int coded_picture_number;:比特流中的编码序列号。
      • int display_picture_number;:播放序列号。
      • int repeat_pict;:延迟参数,extra_delay = repeat_pict / (2*fps),未使用过。
    • 音频部分:
      • int nb_samples;:采样点的数量。
      • int sample_rate;:采样率。
      • uint64_t channel_layout;:声道布局。单声道,立体声,5.1 等等,详见函数 av_bprint_channel_layout
      • channels:声道数量。
    • 共用:
      • int format;:其值为 enum AVPixelFormat(对应视频) 或 enum AVSampleFormat(对应音频)
      • int64_t pts;:渲染时间,单位记录在 time_base 中。按个人经验看,有些解码器未给出该值,还是从对应的 AVStream 中取妥当。
      • int64_t pkt_dts;:该帧的解包时间。
      • AVRational time_base;:时间单位。
      • int quality;:取值范围在 [1,FF_LAMBDA_MAX],越小越好。
  • 用户相关部分:
    • AVBufferRef *opaque_ref; :用户可以放一些自定义数据在这。av_frame_* 等相关函数会维护其生命周期。
    • void *opaque:也是用户自定义的数据,但用户需自己维护生命周期。
  • codec 相关部分,一些 codec 依赖的字段,具体怎么用还不清楚,先记录在这里
    • AVFrameSideData **side_data;:具体怎么用还不清楚。
    • int nb_side_data;side_data 的长度。
    • AVBufferRef *private_ref;
    • AVBufferRef *hw_frames_ctx;
    • AVDictionary *metadata;:用户和 codec 可通过此字段传递各种类型的 KV 数据。

个人感觉,较难理清的是 dataextened_databufextended_buf 之间的关系,这里记录下 av_frame_get_buffer 如何初始化上述四个变量。

根据音视频数据是 packed 或者 planar 格式,使用方法略有差异。

视频的 packed 格式有 AV_PIX_FMT_YUYV422AV_PIX_FMT_UYYVYY411 等。
视频的 planar 格式有 AV_PIX_FMT_YUV420PAV_PIX_FMT_YUV444P 等。
音频的 packed 格式有 AV_SAMPLE_FMT_U8AV_SAMPLE_FMT_FLT 等。
音频的 planar 格式有 AV_SAMPLE_FMT_S32PAV_SAMPLE_FMT_FLTP 等。
简单概括,后缀为 P 的则为 planar 格式,反之为 packed 格式。

当数据为 packed 格式时:

  • extended_buf:未使用,初始化后值为 nullptr
  • buf:仅使用 buf[0],其余均为空。
  • data
    • 当数据为音频时,仅使用 data[0],值为 buf[0]->data
    • 当数据为视频时,根据AVFrame::format 字段决定。
  • extended_data:指向 data

下图是 AVFrame::formatAV_PIX_FMT_YUYV422 时的情形:

当数据为 planar 格式时,设 cplanar 的数量:

  • buf:使用 buf[0..min(7,c-1)]
  • extend_buf:当 c > 8 c\gt 8 c>8 时启用,指向一段新分配的内存,该内存存储了长度为 c − 8 c-8 c8 的指针数组。
  • data:使用 buf[0..min(7,c-1)]
  • extended_data
    • c ≤ 8 c\le 8 c8 时,指向 data
    • c > 8 c\gt 8 c>8 时,新分配一段内存,该内存存储了长度为 c c c 的指针数组。

下图以 c = 10 c = 10 c=10 的音频数据为例:

相关函数

AVFrame *av_frame_alloc(void)

分配一段内存,用于存储一个 AVFrame 对象。

void av_frame_free(AVFrame **frame)

释放相关内存。

int av_frame_ref(AVFrame *dst, const AVFrame *src)

该函数会处理所有字段,该复制的复制,该引用的引用。

void av_frame_unref(AVFrame *frame)

重置 AVFrame。可复用重置后的 AVFrame 对象,避免重复的分配回收内存。

int av_frame_copy_props(AVFrame *dst, const AVFrame *src)

该函数不会处理 AVFrame::bufAVFrame::extended_buf

int av_frame_get_buffer(AVFrame *frame, int align)

该函数会根据初始化 dataextended_databufextended_buf 等字段。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值