FFmpeg 基本数据结构 URLProtocol分析
1、URLProtocol 结构体定义
URLProtocol 是 FFmpeg 中用于自定义 I/O 协议的核心结构体,允许开发者实现非标准协议(如私有网络传输、加密流、内存流等)的读写支持。它通过定义一组回调函数抽象底层 I/O 操作,是 FFmpeg I/O 层的基础组件。
基本结构定义分析如下:
typedef struct URLProtocol {const char *name; // 协议名称int (*url_open)( URLContext *h, const char *url, int flags); // 打开URLint (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options); // 打开URL(带有选项)int (*url_accept)(URLContext *s, URLContext **c); // 接受URL连接int (*url_handshake)(URLContext *c); // 执行URL握手int (*url_read)( URLContext *h, unsigned char *buf, int size); // 读取数据int (*url_write)(URLContext *h, const unsigned char *buf, int size); // 写入数据int64_t (*url_seek)( URLContext *h, int64_t pos, int whence); // 定位文件指针int (*url_close)(URLContext *h); // 关闭URLint (*url_read_pause)(void *urlcontext, int pause); // 暂停/恢复读取int64_t (*url_read_seek)(void *urlcontext, int stream_index, int64_t timestamp, int flags); // 查找指定时间戳的帧int (*url_get_file_handle)(URLContext *h); // 获取文件句柄int (*url_get_multi_file_handle)(URLContext *h, int **handles, int *numhandles); // 获取多个文件句柄int (*url_get_short_seek)(URLContext *h); // 检查是否支持短 seekint (*url_shutdown)(URLContext *h, int flags); // 关闭URL(异步)const AVClass *priv_data_class; // 私有数据类int priv_data_size; // 私有数据大小int flags; // 协议标志int (*url_check)(URLContext *h, int mask); // 检查URL是否支持特定操作int (*url_open_dir)(URLContext *h); // 打开目录int (*url_read_dir)(URLContext *h, AVIODirEntry **next); // 读取目录内容int (*url_close_dir)(URLContext *h); // 关闭目录int (*url_delete)(URLContext *h); // 删除文件int (*url_move)(URLContext *h_src, URLContext *h_dst); // 移动文件const char *default_whitelist; // 默认协议白名单
} URLProtocol;
各个成员的含义如下:
- name: 一个字符指针,用于表示URLProtocol的名称。
- url_open: 一个函数指针,用于表示打开URL的函数。
- url_open2: 一个函数指针,用于表示打开URL(带有选项)的函数。
- url_accept: 一个函数指针,用于表示接受URL连接的函数。
- url_handshake: 一个函数指针,用于表示执行URL握手的函数。
- url_read: 一个函数指针,用于表示读取数据的函数。
- url_write: 一个函数指针,用于表示写入数据的函数。
- url_seek: 一个函数指针,用于表示定位文件指针的函数。
- url_close: 一个函数指针,用于表示关闭URL的函数。
- url_read_pause: 一个函数指针,用于表示暂停/恢复读取的函数。
- url_read_seek: 一个函数指针,用于表示查找指定时间戳的帧的函数。
- url_get_file_handle: 一个函数指针,用于表示获取文件句柄的函数。
- url_get_multi_file_handle: 一个函数指针,用于表示获取多个文件句柄的函数。
- url_get_short_seek: 一个函数指针,用于表示检查是否支持短 seek 的函数。
- url_shutdown: 一个函数指针,用于表示关闭URL(异步)的函数。
- priv_data_class: 一个指向AVClass结构的指针,用于表示URLProtocol的私有数据类。
- priv_data_size: 一个整数,用于表示URLProtocol的私有数据大小。
- flags: 一个整数,用于表示URLProtocol的属性标志。
- url_check: 一个函数指针,用于表示检查URL是否支持特定操作
2、URLProtocol 核心作用与定位
- 协议抽象层
- URLProtocol 定义了协议操作的接口(如 url_open, url_read, url_write),FFmpeg 通过它访问各种协议(file://, http://, rtmp:// 等)。
- 开发者可扩展此结构体,实现自定义协议(如 myproto://),集成到 FFmpeg 的 I/O 体系中。
- 与 AVIOContext 的关系
- AVIOContext 是上层 I/O 抽象,依赖 URLProtocol 处理底层协议操作。
- avio_open2() 内部会根据协议名查找对应的 URLProtocol 实现。
3、URLProtocol 核心回调函数
URLProtocol 其内部核心函数指针如下:
typedef struct URLProtocol {const char *name; // 协议名称(如 "http")int (*url_open)(URLContext *h, const char *url, int flags);int (*url_read)(URLContext *h, unsigned char *buf, int size);int (*url_write)(URLContext *h, const unsigned char *buf, int size);int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);int (*url_close)(URLContext *h);// ... 其他可选回调(如超时设置、分块传输等)
} URLProtocol;
- url_open:初始化协议连接,解析 URL 参数,建立网络/文件句柄等。flags 指定模式(读/写/读写),如 AVIO_FLAG_READ67。
- url_read/url_write:数据读写接口,返回实际传输字节数。需处理错误(返回 AVERROR(EIO))和 EOF(返回 AVERROR_EOF)。
- url_seek: 支持随机访问时需实现。whence 参数同标准 lseek(SEEK_SET, SEEK_CUR 等)6。
- url_close:释放资源(如关闭 socket、释放缓冲区
4、URLProtocol 定义示例
// 定义URLProtocol
URLProtocol ff_file_protocol = {.name = "file",.url_open = file_open,.url_read = file_read,.url_write = file_write,.url_seek = file_seek,.url_close = file_close,.priv_data_size = sizeof(FileContext),
};
URLProtocol 是 FFmpeg I/O 子系统的基石,它通过统一的接口:
- 抽象了各种数据源,使得上层代码无需关心数据来自文件、网络还是内存。
- 提供了极大的灵活性,允许开发者通过自定义协议接入任何数据源。
- 封装了协议的复杂性,将协议特定的逻辑(如 HTTP 握手、RTMP 信令)隐藏在各自的实现中。
