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

FFmpeg 基本数据结构 AVIOContext分析

1、AVIOContext 输入输出IO抽象接口

AVIOContext 是 FFmpeg 中用于抽象 I/O 操作的核心数据结构。它允许 FFmpeg 从非标准来源(如内存缓冲区、自定义协议、加密流等)读取或写入数据,而不仅仅局限于文件系统。理解 AVIOContext 对于实现自定义输入/输出、内存流处理或与特殊协议交互至关重要。

typedef struct AVIOContext {const AVClass *av_class; // 指向一个表示AVIOContext结构的AVClass结构的指针unsigned char *buffer; // 指向缓冲区的指针int buffer_size; // 缓冲区大小unsigned char *buf_ptr; // 指向缓冲区当前位置的指针unsigned char *buf_end; // 指向缓冲区末尾的指针void *opaque; // 指向任意数据的指针int (*read_packet)(void *opaque, uint8_t *buf, int buf_size); // 读取数据的回调函数int (*write_packet)(void *opaque, const uint8_t *buf, int buf_size); // 写入数据的回调函数int64_t (*seek)(void *opaque, int64_t offset, int whence); // 定位文件指针的回调函数int64_t pos; // 当前文件指针位置int eof_reached; // 是否已到达文件末尾的标志int error; // 错误标志int write_flag; // 写入标志int max_packet_size; // 最大数据包大小int min_packet_size; // 最小数据包大小unsigned long checksum; // 校验和unsigned char *checksum_ptr; // 指向校验和缓冲区的指针unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size); // 更新校验和的回调函数int (*read_pause)(void *opaque, int pause); // 暂停/恢复读取的回调函数int64_t (*read_seek)(void *opaque, int stream_index,int64_t timestamp, int flags); // 查找指定时间戳的帧的回调函数int seekable; // 是否支持 seekint direct; // 是否直接访问文件const char *protocol_whitelist; // 允许的协议白名单const char *protocol_blacklist; // 禁止的协议黑名单int (*write_data_type)(void *opaque, const uint8_t *buf, int buf_size, enum AVIODataMarkerType type, int64_t time); // 写入数据类型的回调函数int ignore_boundary_point; // 是否忽略边界点unsigned char *buf_ptr_max; // 指向缓冲区最大位置的指针int64_t bytes_read; // 已读取的字节数int64_t bytes_written; // 已写入的字节数
} AVIOContext;

各个成员的含义如下:

  • buffer:一个用于存储已经从输入源中读取的数据的缓冲区。通常情况下,avio_read函数从输入源读取数据并将其存储在这个缓冲区中,以便后续处理。
  • buffer_size:缓冲区的大小,表示buffer可以存储的最大数据量。
  • pos:当前位置的偏移量,表示已经从输入源读取的字节数。每次读取数据后,pos字段会被更新,以跟踪当前的读取位置。
  • buf_ptr: 当前读取的buffer位置。
  • buf_end: buffer结束的位置,如果读到的数据比请求的数据少,可能会小于buffer + buffer_size,比如流数据已经被读完的情况。
  • opaque:一个指向用户自定义数据结构的指针,通常用于传递用户定义的数据结构体或URLContext给avio操作函数的回调函数。
  • read_packet:一个函数指针,用于从输入源中读取数据的回调函数。当需要读取数据时,FFmpeg会调用这个函数来填充buffer和更新pos等字段。
  • write_packet:一个函数指针,用于将数据写入输出源的回调函数。当需要写入数据时,FFmpeg会调用这个函数来执行写入操作。
  • seek:一个函数指针,用于执行定位操作,允许将读取/写入位置移动到指定的偏移量。
  • seekable:一个标志位,表示输入源是否支持随机访问,即是否可以通过seek函数进行定位操作。
  • max_packet_size:表示write_packet函数可以一次性写入的最大数据量,这有助于控制数据的分块写入。
  • checksum:用于执行数据完整性检查的字段,通常用于网络传输等场景。

2、AVIOContext 核心概念与作用

1、I/O 抽象层:

  • 传统文件操作使用 FILE* 或系统调用 (open, read, write, seek)。
  • AVIOContext 提供了一层回调函数 (Callbacks) 接口,将这些底层 I/O 操作抽象化。
  • FFmpeg 核心库(如 libavformat)通过 AVIOContext 读写数据,无需关心数据实际来源或目的地。

2、关键应用场景:

  • 内存流 (Memory Streams): 从内存缓冲区 (uint8_t*) 读取数据或将数据写入内存缓冲区。
  • 自定义协议: 实现网络协议、加密协议、压缩协议等 (如 myproto://…)。
  • 无文件操作: 处理来自数据库、管道、GUI 控件或其他应用程序内部来源的数据。
  • 代理和过滤: 在数据流经 FFmpeg 时进行实时处理(如日志记录、修改)。
  • 直播协议: 实现或扩展对 RTMP、HLS、DASH 等协议的支持(底层通常已使用 AVIOContext)。

3、AVIOContext 内部重要接口

AVIOContext 定义 (libavformat/avio.h) 包含众多成员,以下是最关键的:

3.1 read_packet 函数

  - int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
- 作用: 从自定义数据源读取数据。
- 参数:- opaque: 用户指定的指针(初始化 AVIOContext 时传入)。- buf: FFmpeg 提供的缓冲区,用于存放读取到的数据。- buf_size: 缓冲区 buf 的大小(请求读取的最大字节数)。
- 返回值: 实际读取到的字节数。如果发生错误或到达 EOF,返回 AVERROR(EIO) 或 AVERROR_EOF。不能返回 0 除非 buf_size 为 0。

3.1 write_packet 函数

int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
- 作用: 将数据写入自定义目的地。
- 参数:- opaque: 用户指定的指针。- buf: 包含待写入数据的缓冲区。- buf_size: 缓冲区 buf 中有效数据的字节数。
- 返回值: 实际写入的字节数。如果发生错误,返回 AVERROR(EIO)。

3.1 seek 函数

  int64_t (*seek)(void *opaque, int64_t offset, int whence);
- 作用: 在自定义数据源/目的地中移动读写位置。
- 参数:- opaque: 用户指定的指针。- offset: 偏移量(字节)。- whence: 定位模式 (类似 fseek/lseek):- SEEK_SET (0): 从文件头开始偏移 offset 字节。- SEEK_CUR (1): 从当前位置偏移 offset 字节。- SEEK_END (2): 从文件尾开始偏移 offset 字节(offset 通常为负)。- AVSEEK_SIZE (65536): 特殊值! 不进行实际 seek,而是查询文件总大小。如果支持查询,返回文件大小;否则返回 AVERROR(ENOSYS)。
- 返回值: 新的绝对位置(从文件头算起)。发生错误时返回负的错误码 (如 AVERROR(EIO))。

4、AVIOContext 缓冲机制 (Buffering)

  • unsigned char *buffer; (buf 在旧版本)
    • 指向内部缓冲区的指针。FFmpeg 使用此缓冲区暂存数据,减少对底层 read_packet/write_packet 回调的调用频率。
  • int buffer_size;
    • 内部缓冲区 buffer 的总大小(字节)。
  • unsigned char *buf_ptr;
    • 指向缓冲区 buffer 中当前有效数据开始位置的指针。
  • unsigned char *buf_end;
    • 指向缓冲区 buffer 中当前有效数据结束位置的下一个字节的指针。
  • 读模式: buf_ptr 到 buf_end 之间的数据是待读取的。当 buf_ptr >= buf_end 时,FFmpeg 会调用 read_packet 来填充缓冲区。
  • 写模式: buf_ptr 指向下一个可写入位置,buf_end 指向缓冲区末尾。当缓冲区满时,FFmpeg 会调用 write_packet 刷出数据。
  • int write_flag;
    • 标志位:1 表示 AVIOContext 用于写入 (Output),0 表示用于读取 (Input)。这决定了缓冲区如何管理和回调如何调用。

5、AVIOContext 用户私有数据

  • void *opaque;
    • 最重要的用户相关成员! 这是一个用户自定义的指针。
    • 在创建 AVIOContext (通常通过 avio_alloc_context) 时传入。
    • 这个指针会被原封不动地传递给所有回调函数 (read_packet, write_packet, seek) 的第一个参数。
    • 用途: 让回调函数知道它们操作的是哪个具体的数据源/目的地。通常指向一个包含实际数据状态的结构体(如内存缓冲区的指针和大小、网络连接句柄、文件描述符、自定义对象等)。

6、AVIOContext 其他重要成员

  • int64_t pos;
    • 当前在逻辑数据流中的绝对位置(字节偏移量,从0开始)。FFmpeg 负责维护它,反映经过缓冲后的真实读写位置。
  • int eof_reached;
    • 标志位:是否已到达输入流的末尾 (End-of-File)。
  • int error;
    • 记录最近一次 I/O 操作发生的错误码(负值)。0 表示无错误。
  • int (*read_pause)(void *opaque, int pause); / int64_t (*read_seek)(void *opaque, int stream_idx, int64_t timestamp, int flags);
    • 主要用于直播或实时流的暂停和按时间戳定位(如 RTSP)。非必需。
  • int seekable;
    • 标志位:指示底层数据源/目的地是否支持 seek 操作。AVIO_SEEKABLE_NORMAL 表示支持常规 seek。影响 FFmpeg 的行为(如是否允许随机访问)。
  • const char *protocol_whitelist; / const char *protocol_blacklist;
    • 协议白名单/黑名单,用于安全限制。

7、AVIOContext 关键 API 函数

7.1 AVIOContext 创建函数

 - AVIOContext *avio_alloc_context( unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t (*seek)(void *opaque, int64_t offset, int whence) );
  • buffer: 用户提供的缓冲区指针。可以为 NULL,此时 FFmpeg 会自动分配和管理一个大小为 buffer_size 的缓冲区。如果非 NULL,则使用用户提供的缓冲区。
  • buffer_size: 缓冲区大小。
  • write_flag: 0 表示读模式,1 表示写模式。
  • opaque: 用户私有数据指针,传递给回调。
  • read_packet, write_packet, seek: 对应的回调函数指针。根据模式 (write_flag) 和需求,不需要的回调可以设为 NULL(例如,只读流不需要 write_packet,不可 seek 的流不需要 seek)。
  • 返回值: 初始化好的 AVIOContext 指针,失败时返回 NULL。

7.2 AVIOContext 释放函数

void avio_context_free(AVIOContext **s);
  • 释放 AVIOContext 及其内部缓冲区(如果是由 FFmpeg 自动分配的)。如果缓冲区是用户提供的 (avio_alloc_context 的 buffer 参数非 NULL),用户需要自行管理该缓冲区的生命周期。
  • 参数是指向指针的指针 (AVIOContext **s),调用后 *s 会被设为 NULL。

3、AVIOContext 和 AVFormatContext关联关系

AVFormatContext *avformat_alloc_context(void); (先创建)

 void avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options); (不用于自定义 AVIO!)

int avio_open(AVIOContext **s, const char *url, int flags); (用于标准文件/协议 URL)
正确方法 (自定义 AVIO):

AVFormatContext *fmt_ctx = avformat_alloc_context();
AVIOContext *avio_ctx = ...; // 用 avio_alloc_context 创建的自定义 AVIOContext
fmt_ctx->pb = avio_ctx; // 关键!将自定义 AVIOContext 赋值给 AVFormatContext 的 pb 成员
int ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL); // filename 必须为 NULL!
  • 将自定义的 AVIOContext* 赋值给 AVFormatContext->pb (pb 即 “protocol buffer”)。
  • 调用 avformat_open_input 时,第一个参数 (&fmt_ctx) 是已经设置了 pb 的 AVFormatContext,第二个参数 (filename) 必须设为 NULL。这样 FFmpeg 就知道使用 fmt_ctx->pb 作为输入源。
  • 输出 (Muxing) 类似:
AVFormatContext *fmt_ctx = NULL;
avformat_alloc_output_context2(&fmt_ctx, NULL, "format", NULL); // 注意 filename=NULL
AVIOContext *avio_ctx = ...; // 创建用于输出的自定义 AVIOContext (write_flag=1)
fmt_ctx->pb = avio_ctx;
// ... 设置流、写头、写包等

4、AVIOContext 相关读写辅助函数

  • int avio_read(AVIOContext *s, unsigned char *buf, int size); - 从 s 读取数据到 buf。
  • int avio_write(AVIOContext *s, const unsigned char *buf, int size); - 将 buf 中的数据写入 s。
  • int64_t avio_seek(AVIOContext *s, int64_t offset, int whence); - 在 s 中 Seek。
  • int64_t avio_size(AVIOContext *s); - 获取文件大小(如果支持)。
  • int avio_feof(AVIOContext *s); - 检查是否到达 EOF。
  • void avio_flush(AVIOContext *s); - 强制刷出写缓冲区。

5、AVIOContext 相关总结与关键点

  1. 核心是回调 (read_packet, write_packet, seek): 你实现这些函数来定义数据如何存取。
  2. opaque 是关键桥梁: 它连接 AVIOContext 和你的自定义数据状态,传递给所有回调。
  3. 缓冲提高效率: FFmpeg 内置缓冲区减少回调次数。理解 buffer, buf_ptr, buf_end 有助于调试。
  4. 正确关联到 AVFormatContext: 创建 AVFormatContext -> 创建自定义 AVIOContext -> 设置 fmt_ctx->pb = avio_ctx -> avformat_open_input(&fmt_ctx, NULL, …)。
  5. 生命周期管理: 使用 avio_alloc_context 创建,avio_context_free 释放。注意用户提供的缓冲区 (buffer 参数) 需自行管理。
  6. seek 非必需但重要: 支持随机访问能解锁更多功能(如快速定位、格式探测)。务必处理 AVSEEK_SIZE 查询。
  7. 错误处理: 回调函数应返回负的错误码 (AVERROR_xxx) 表示失败。
  8. 替代 avio_open: 当标准协议 (file:, http:, rtmp:) 不满足需求时,自定义 AVIOContext 是解决方案。
http://www.dtcms.com/a/536512.html

相关文章:

  • SAP SD系统开票审批功能分享
  • 有口碑的常州网站优化wordpress发邮件慢
  • 注册中心(discovery)和配置中心(config)
  • Abaqus部件间Cohesive单元建立的共面识别技术
  • 建设网站有哪些步骤金螳螂装饰公司
  • 商城网站建设公司排行在线代理网页浏览
  • 【Linux】多线程同步与互斥机制详解:从互斥锁到条件变量与信号量
  • iOS混淆实战用多工具组合把IPA加固做成可复用的工程能力(iOS混淆 IPA加固 无源码混淆
  • RTPENGINE ISSUE 1818(silent-timeout有关)
  • LeetCode:231. 2 的幂/136. 只出现一次的数字
  • Flutter fedaora42 64位安装 避坑指南
  • Docker自动化部署与配置详解③
  • istio业务返回503问题
  • 建设服装网站的意义国内免费空间可以做什么网站
  • 餐饮商城网站制作多少钱动漫设计一年学费多少
  • Web 前端工具全流程指南 从开发到调试的完整生态体系
  • 清理谷歌浏览器垃圾文件 Chrome “User Data”
  • 科技创新的重要前沿是新网站前期seo怎么做
  • [论文笔记•(多智能体)]LLMs Can Simulate Standardized Patients via Agent Coevolution
  • CAS:2055198-03-1,PC-Biotin-PEG4-NHS carbonate在分子标记与生物分析中的应用潜力
  • 人工智能时代医疗大健康微服务编程:架构与实践(代码部分)
  • 【论文阅读】AAAI 2025 | 面向精确分割式联邦学习的多模型聚合与知识重放
  • 网站建设对工厂意义外贸网站建设智能建站
  • 小企业网站建设公司哪家好深圳做网站服务
  • 《地理信息系统》第四章空间数据结构学习笔记
  • docker网络代理
  • 域名买了之后如何建设网站公司形象墙
  • RabbitMQ延迟队列详解
  • Vue 项目集成声网SDK
  • 云南网站设计多少钱零件加工网上接订单