当前位置: 首页 > news >正文

FFmpeg 基本数据结构 AVFrame分析

1、AVFrame 结构分析

FFmpeg 中的 AVFrame 是一个核心数据结构,用于表示未压缩的(原始)音频或视频数据。它是处理解码后的数据(输入到编码器、滤镜或渲染器之前)和编码前的数据的基石。理解 AVFrame 对于使用 FFmpeg 进行音视频处理(如转码、滤镜应用、分析、渲染)至关重要。
具体代码分析如下所示:

typedef struct AVFrame {uint8_t *data[AV_NUM_DATA_POINTERS]; // 指向图像数据的指针数组int linesize[AV_NUM_DATA_POINTERS]; // 图像数据每行字节数数组uint8_t **extended_data; // 指向扩展数据指针的指针int width, height; // 图像宽度和高度int nb_samples; // 音频采样数int format; // 像素格式enum AVPictureType pict_type; // 图像类型AVRational sample_aspect_ratio; // 采样比例int64_t pts; // 显示时间戳int64_t pkt_dts; // 包解码时间戳AVRational time_base; // 时间基准int quality; // 质量void *opaque; // 透明数据int repeat_pict; // 重复图像int sample_rate; // 采样率AVBufferRef *buf[AV_NUM_DATA_POINTERS]; // 指向缓冲区的指针数组AVBufferRef **extended_buf; // 指向扩展缓冲区指针的指针int nb_extended_buf; // 扩展缓冲区数量AVFrameSideData **side_data; // 指向侧数据指针的指针int nb_side_data; // 侧数据数量int flags; // 标志enum AVColorRange color_range; // 颜色范围enum AVColorPrimaries color_primaries; // 颜色原点enum AVColorTransferCharacteristic color_trc; // 颜色传输特性enum AVColorSpace colorspace; // 颜色空间enum AVChromaLocation chroma_location; // 色度位置int64_t best_effort_timestamp; // 最佳努力时间戳AVDictionary *metadata; // 元数据int decode_error_flags; // 解码错误标志int pkt_size; // 包大小AVBufferRef *hw_frames_ctx; // 硬件帧上下文AVBufferRef *opaque_ref; // 不透明引用size_t crop_top; // 上裁剪尺寸size_t crop_bottom; // 下裁剪尺寸size_t crop_left; // 左裁剪尺寸size_t crop_right; // 右裁剪尺寸AVBufferRef *private_ref; // 私有引用AVChannelLayout ch_layout; // 通道布局int64_t duration; // 持续时间
} AVFrame;

各个成员的含义如下:

  • data: 一个指向图像数据的指针数组,用于存储图像的每个通道的数据。
  • linesize: 一个整数数组,用于存储图像数据每行字节数。
  • extended_data: 一个指向扩展数据指针的指针,用于存储图像数据的扩展指针。
  • width, height: 两个整数,分别表示图像的宽度和高度。
  • nb_samples: 一个整数,表示音频采样的样本数。
  • format: 一个整数,表示像素格式。
  • pict_type: 一个枚举类型,表示图像类型。
  • sample_aspect_ratio: 一个AVRational结构体,表示采样比例。
  • pts, pkt_dts: 两个整数,分别表示显示时间戳和解码时间戳。
  • time_base: 一个AVRational结构体,表示时间基准。
  • quality: 一个整数,表示质量。
  • opaque: 一个指向透明数据的指针。
  • repeat_pict: 一个整数,表示重复图像。
  • sample_rate: 一个整数,表示采样率。
  • buf: 一个指向缓冲区的指针数组,用于存储图像数据的缓冲区。
  • extended_buf: 一个指向扩展缓冲区指针的指针,用于存储图像数据的扩展缓冲区。
  • nb_extended_buf: 一个整数,表示扩展缓冲区数量。
  • side_data: 一个指向侧数据指针的指针,用于存储图像数据的侧数据。
  • nb_side_data: 一个整数,表示侧数据数量。
  • flags: 一个整数,表示标志。
  • color_range: 一个枚举类型,表示颜色范围。
    -color_primaries: 一个枚举类型。

2、AVFrame 内部基础信息

AVFrame 中包含基本信息,其描述Audio 和Video 信息,表示帧是不是关键帧等flag。在解码和编码过程中,其重要作用。

  • format: 整数,表示帧数据的格式。
    • 对于视频:这对应于 AVPixelFormat 枚举(例如 AV_PIX_FMT_YUV420P, AV_PIX_FMT_RGB24, AV_PIX_FMT_NV12)。它定义了像素如何排列、存储(平面还是打包)、颜色空间、位深等。
    • 对于音频:这对应于 AVSampleFormat 枚举(例如 AV_SAMPLE_FMT_FLTP - 32位浮点平面, AV_SAMPLE_FMT_S16P - 16位有符号整数平面)。它定义了样本的位深和存储方式(打包或平面)。
  • width, height: 整数,表示视频帧的宽度和高度(以像素为单位)。仅对视频帧有意义。
  • sample_rate: 整数,表示音频数据的采样率(每秒样本数,如 44100, 48000)。仅对音频帧有意义。
  • channels: 整数,表示音频通道的数量(如 1-单声道, 2-立体声)。注意:更推荐使用 channel_layout。
  • channel_layout: uint64_t,表示音频通道的布局(如 AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_5POINT1)。这是一个位掩码,精确指定了每个通道的位置(左、右、中置、LFE等)。比 channels 提供更精确的信息。
  • nb_samples: 整数,表示此音频帧中包含的每个通道的样本数。仅对音频帧有意义。对于视频,通常一帧就是一幅完整的图像(但 H.264 的场编码等是特例)。
  • key_frame: 整数,标志位(1 或 0),指示该视频帧是否是关键帧(I帧)。关键帧可以独立解码,不依赖于其他帧。
  • pict_type: enum AVPictureType,表示视频帧的类型(I帧, P帧, B帧等)。例如 AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B。

3、AVFrame 内部数据存储

  • data: 指向指针数组的指针 (uint8_t **data)。这是存储实际媒体数据(像素或样本)的缓冲区数组。
    • 视频 (Planar Formats - 最常见如YUV420P):
      • data[0] - 指向 Y (亮度) 分量平面。
      • data[1] - 指向 U (Cb) 分量平面。
      • data[2] - 指向 V (Cr) 分量平面。
      • (对于其他平面格式,如RGB24 planar,或 NV12,分量索引和数量会不同)
    • 视频 (Packed Formats - 较少见如RGB24 packed):
      • data[0] - 指向单个缓冲区,其中 R, G, B 值按像素交错存储(如 R0, G0, B0, R1, G1, B1, …)。
    • 音频 (Planar Formats - 最常见):
      • data[0] - 指向通道 0 的样本数据。
      • data[1] - 指向通道 1 的样本数据。
      • … data[channels-1] - 指向最后一个通道的样本数据。每个通道的数据是连续的。
    • 音频 (Packed Formats):
      • data[0] - 指向单个缓冲区,其中所有通道的样本按样本点交错存储(如 S0_C0, S0_C1, S1_C0, S1_C1, …)。
  • linesize: 整数数组 (int linesize[AV_NUM_DATA_POINTERS])。也称为 stride 或 pitch。
    • 对于视频:linesize[i] 表示 data[i] 指向的分量平面中一行数据的字节数。这个值通常大于或等于基于 width 和像素格式计算出的最小字节数。原因包括:
      • 内存对齐要求(如16字节对齐)。
      • 缓冲区由硬件或特定库分配。
      • 图像是另一个更大图像的一部分(子区域)。
    • 对于音频:linesize[i] 表示 data[i] 指向的单个通道的音频数据缓冲区的总字节数(即 通道i的大小 = nb_samples * 每个样本的字节数)。在平面音频中,这通常是 nb_samples * av_get_bytes_per_sample(sample_fmt)。对于打包音频,linesize[0] 包含所有通道交错数据的总大小。

4、AVFrame 内部元数据与时间信息

  • pts: 显示时间戳。表示何时应该向用户显示/呈现此帧。时间基由流 (AVStream->time_base) 或编解码器上下文 (AVCodecContext->time_base) 定义。AV_NOPTS_VALUE 表示未定义。至关重要 用于音视频同步。
  • dts: 解码时间戳。表示何时应该将此帧送入解码器进行解码。主要用于视频编码/解码的比特流排序(特别是存在 B 帧时)。通常 dts <= pts。对于未压缩数据或没有 B 帧的情况,dts 可能未设置或等于 pts。
  • duration: 帧的持续时间。表示此帧在显示时应持续多久(使用与 pts 相同的时间基)。
  • quality: 整数,编码器内部使用的质量指示(值越大质量越好,值越小质量越差)。对解码输出意义不大。
  • opaque: 指向用户私有数据的指针。FFmpeg 本身不使用,供应用程序在帧生命周期内关联自定义数据。
  • crop_top, crop_bottom, crop_left, crop_right: 裁剪信息(较少直接使用)。指示在显示或处理前应从帧的边缘裁剪多少像素。
  • metadata: 字典 (AVDictionary *)。可以存储与帧相关的任意键值对元数据(例如来自编码器设置、滤镜标记)。

5、AVFrame 内部内存管理与引用计数

  • buf: 指向 AVBufferRef 指针数组的指针 (AVBufferRef **buf)。这是现代 FFmpeg 中管理 data 缓冲区内存的推荐方式。它实现了引用计数。
    • 每个 data[i] 缓冲区通常由一个对应的 buf[i] 管理(对于平面格式)。对于打包格式,可能只有一个 buf[0] 管理整个 data[0]。
    • AVBufferRef 封装了实际的数据缓冲区 (AVBuffer) 和引用计数。
    • 引用计数原理:
      • 当创建一个新的 AVFrame(如通过 av_frame_alloc())或显式引用一个现有帧(av_frame_ref())时,引用计数会增加。
      • 当你不再需要一个 AVFrame 时,调用 av_frame_unref()。这会减少引用计数。
      • 当引用计数变为 0 时,FFmpeg 会自动释放 data 缓冲区以及 AVFrame 结构体本身(如果它是通过 av_frame_alloc() 分配的)。
    • 为什么重要? 避免了手动内存管理错误(内存泄漏、野指针、重复释放)。允许多个部分(解码器、滤镜、你的代码)安全地共享同一帧数据,而无需深度拷贝。始终优先使用基于 buf/ref 的 API (av_frame_ref(), av_frame_move_ref()) 来复制帧,而不是直接拷贝结构体或 data 指针。
  • extended_data: 指向指针数组的指针 (uint8_t **extended_data)。通常等于 data。在音频帧的通道数超过 AV_NUM_DATA_POINTERS (通常为8) 时,extended_data 会指向一个单独分配的、包含所有通道指针的数组,而 data 可能只包含前几个通道或为 NULL。最佳实践:处理音频时总是使用 extended_data 来访问样本数据,以确保兼容高通道数。

视频数据(以 YUV420P 为例):这是一种 Planar(平面)格式,Y、U、V 分量分别存储在 data[0]、data[1]、data[2] 三个独立的平面中。

  • data[0] 存储所有 Y(亮度)分量数据,大小为 width * height。
  • data[1] 存储所有 U(色度)分量数据,大小为 (width/2) * (height/2)。
  • data[2] 存储所有 V(色度)分量数据,大小为 (width/2) * (height/2)。
  • linesize[0] 是 Y 平面一行的字节数,由于对齐可能 >= width。
  • linesize[1] 是 U 平面一行的字节数,可能 >= width/2。
  • linesize[2] 是 V 平面一行的字节数,可能 >= width/2。

音频数据(以 Planar Float 为例):每个声道的数据存储在独立的平面。例如,立体声(双声道):

  • data[0] 指向左声道所有采样点数据。
  • data[1] 指向右声道所有采样点数据。
  • linesize[0] 和 linesize[1] 分别表示每个声道数据缓冲区的大小。

6、AVFrame 相关的重要API 函数

  • av_frame_alloc(): 分配一个新的空 AVFrame。必须使用此函数分配。
  • av_frame_free(AVFrame **frame): 释放 AVFrame 及其所有关联的缓冲区(减少引用计数,必要时释放)。
  • av_frame_unref(AVFrame *frame): 取消对 frame 所引用的所有缓冲区的引用,并将 frame 重置为空状态(不释放 frame 结构本身)。
  • av_frame_ref(AVFrame *dst, const AVFrame *src): 设置 dst 为对 src 中数据的新引用。增加引用计数。dst 需要已分配。
  • av_frame_move_ref(AVFrame *dst, AVFrame *src): 将引用从 src 移动到 dst。src 在调用后被置空。高效且避免引用计数变化。
  • av_frame_get_buffer(AVFrame *frame, int align): 根据 frame 的格式、宽度、高度(视频)或通道数、样本数(音频)为 frame 分配数据缓冲区。设置 data 和 linesize。align 指定缓冲区对齐要求(通常为 0 或 1 让 FFmpeg 决定,或 32 用于 SIMD)。
  • av_frame_make_writable(AVFrame *frame): 确保 frame 是可写的。如果引用计数 > 1(即存在其他引用),它会创建并复制一份数据的副本。在修改 data 内容之前调用此函数非常重要!
  • av_frame_copy(AVFrame *dst, const AVFrame *src): 将 src 的内容(数据和元数据)复制到 dst。dst 需要已分配并有足够大小的缓冲区。比 ref 更重,因为它涉及内存拷贝。
  • av_frame_copy_props(AVFrame *dst, const AVFrame *src): 仅复制 src 的属性(pts, dts, duration, format, width/height, sample_rate 等)到 dst。不复制实际数据。

7、AVFrame 使用总结与重要提示

  1. 核心作用: AVFrame 是原始音视频数据的载体。
  2. data 和 linesize: 访问实际像素/样本的关键。理解格式(format)对于正确解释 data 至关重要。linesize 不等于 width * bytes_per_pixel 是常见情况!
  3. format: 必须始终检查以知晓如何处理 data。
  4. pts/dts/duration: 同步和处理流程的核心。
  5. 引用计数 (buf): 现代 FFmpeg 内存管理的基石。理解 av_frame_ref(), av_frame_unref(), av_frame_move_ref(), av_frame_make_writable() 是避免内存错误的关键。永远不要简单地对 AVFrame 结构体进行 memcpy。
  6. 分配/释放: 总是使用 av_frame_alloc() 和 av_frame_free()(或正确使用引用计数)。
  7. 音频优先使用 extended_data。
  8. 修改前调用 av_frame_make_writable(): 防止意外修改共享缓冲区。
http://www.dtcms.com/a/536845.html

相关文章:

  • Kafka 相关内容总结
  • 霍邱网站设计10000ip网站怎么做
  • C++ 从零实现Json-Rpc 框架
  • 29. Makefile 创建和使用变量
  • Docker 安装和配置 Redis 完整指南
  • 高效对象池设计:提升Unity性能的关键
  • 网站建设需要了解哪些信息常州网站制作公司
  • 如何做正版小说网站工厂电商具体是做什么的
  • 磁盘和注册表清理工具
  • 【windows】证书引起的浏览器请求问题-https红色斜线-解决方法
  • mormot2创建一个httpserver
  • 科技类网站简介怎么做有哪些游戏可以做网站
  • 定制化TTS数据实践:解锁语音大模型的无限潜能
  • 微网站是什么嘉兴高端网站定制
  • 一分钟讲透:c++新特性string_view
  • sns社交网站 建设做网站图片尺寸
  • 营销网站结构网站免费优化平台
  • 免费视频模板网站制作微信网页
  • android实践:loadUrl执行JavaScript异常
  • FFmpeg 基本数据结构 AVCodecParser分析
  • celery知识点总结
  • langchain将用户问题转sql查询探索
  • compareAndSet怎么用
  • Skill Seeker——一站式自动化将文档网站、GitHub 仓库和 PDF 文件转换为可部署 AI 技能的深度解析
  • 浅谈 Agent 开发工具链演进历程
  • 帝国cms小说阅读网站模板果洛电子商务网站建设哪家快
  • 学校网站建设背景科技作品手工
  • SmartPLS下载安装教程(附安装包)SmartPLS 4.1保姆级图文教程
  • ECR扫描管理功能完整实现:提升云原生镜像安全管控效率
  • PySide6 Win10记事本从零到一——第二章 第一个窗口程序