AVFormatContext 再分析二
说明 :将 avfromatContext 的变量依次打印分析,根据ffmpeg 给的说明,猜测,结合网上的文章字节写测试代码分析二。
37 AVInputFormat *iformat;
/**
* The input container format.
*
* Demuxing only, set by avformat_open_input().
*/
ff_const59 struct AVInputFormat *iformat;
AVInputFormat 再分析-CSDN博客
38 AVFormatInternal *internal; 对开发者隐藏,但是对于阅读ffmpeg源码有用。
/**
* An opaque field for libavformat internal usage.
* Must not be accessed in any way by callers.
*/
AVFormatInternal *internal;
*libavformat内部使用的不透明字段。
*使用不得以任何方式访问。
AVFormatContext 中的 AVFormatInternal *internal
字段是 FFmpeg 内部用于存储与解封装/封装过程相关的私有状态数据的结构体7。以下是其核心特性的总结:
1. 设计目的
- 内部数据隔离:
internal
封装了AVFormatContext
运行时的临时状态和中间数据,避免用户直接操作导致的结构不稳定或版本兼容性问题7。 - 模块化扩展:通过独立结构体管理内部状态,方便 FFmpeg 在不同版本中扩展或修改内部实现逻辑,而无需修改
AVFormatContext
的公开接口7。
2. 关键特性
-
不透明性:
AVFormatInternal
的具体定义未在公共头文件(如avformat.h
)中公开,开发者无法直接访问其内部字段7。- 所有操作需通过 FFmpeg 提供的 API 完成(如
avformat_open_input()
、av_read_frame()
等)78。
-
生命周期管理:
internal
的内存分配与释放由 FFmpeg 内部自动完成,用户无需手动干预(例如在调用avformat_close_input()
时会自动清理)7。- 初始化时,
internal
通常通过avformat_alloc_context()
函数间接创建7。
3. 关联功能
- 流探测缓冲:缓存输入数据的部分内容,用于格式探测(如
avformat_find_stream_info()
中的流参数分析)8。 - 中间状态存储:
- 封装/解封装过程中的临时数据包队列3。
- 时间戳校正、流交错(interleaving)等算法所需的上下文信息38。
4. 开发者注意事项
- 禁止直接访问:由于 FFmpeg 不保证
AVFormatInternal
的跨版本二进制兼容性,直接操作其字段可能导致程序崩溃或未定义行为7。 - 调试限制:若需调试内部状态,通常需结合 FFmpeg 源码中的日志输出或使用调试器跟踪相关函数调用7。
与类似字段的对比
字段 | 作用域 | 可见性 | 管理方式 |
---|---|---|---|
priv_data | 格式私有数据 | 半公开(需API) | 由 AVInputFormat/AVOutputFormat 管理14 |
internal | 全局运行时 | 完全内部 | FFmpeg 内部自动管理7 |
此设计模式体现了 FFmpeg 对“接口稳定”和“实现灵活”的平衡,确保用户仅通过规范 API 即可安全使用核心功能78。
39.AVIOInterruptCB interrupt_callback
/**
* Custom interrupt callbacks for the I/O layer.
*
* demuxing: set by the user before avformat_open_input().
* muxing: set by the user before avformat_write_header()
* (mainly useful for AVFMT_NOFILE formats). The callback
* should also be passed to avio_open2() if it's used to
* open the file.
*/
AVIOInterruptCB interrupt_callback;
/**
* Callback for checking whether to abort blocking functions.
* AVERROR_EXIT is returned in this case by the interrupted
* function. During blocking operations, callback is called with
* opaque as parameter. If the callback returns 1, the
* blocking operation will be aborted.
*
* No members can be added to this struct without a major bump, if
* new elements have been added after this struct in AVFormatContext
* or AVIOContext.
*/
typedef struct AVIOInterruptCB {
int (*callback)(void*);
void *opaque;
} AVIOInterruptCB;
AVFormatContext 中的 interrupt_callback
字段用于实现自定义 I/O 中断控制机制,主要解决网络流处理时的阻塞问题。以下是其核心功能与使用方法的总结:
1. 功能与作用
- 阻塞中断:在
avformat_open_input()
或av_read_frame()
等操作中,若因网络延迟、设备断开或无数据导致长时间阻塞,可通过回调函数强制终止等待12。 - 超时控制:允许开发者设置最大等待时间,避免程序无响应(如 RTSP 流超时断开)48。
- 跨协议兼容:适用于 RTSP、RTMP 等网络协议,弥补某些协议(如 RTMP)不支持超时参数的缺陷16。
2. 结构体定义
interrupt_callback
是 AVFormatContext
的成员,类型为 AVIOInterruptCB
,包含两个关键字段:
-
callback
:函数指针,指向用户定义的中断检测函数。 -
opaque
:用户自定义的上下文指针(如对象实例、计时器等),传递给回调函数。
typedef struct AVIOInterruptCB {int (*callback)(void*); // 中断检测函数void *opaque; // 用户上下文数据
} AVIOInterruptCB;
3. 回调函数实现
回调函数需返回 1
(中断) 或 0
(继续等待)。典型实现逻辑:
- 通过
opaque
获取上下文数据(如超时起始时间)。 - 计算当前时间与起始时间的差值。
- 若超过预设阈值(如 5 秒),返回
1
终止操作。
// 示例:超时检测回调
int interrupt_cb(void *ctx) {int64_t start_time = *(int64_t*)ctx; // 通过 opaque 传递起始时间int64_t current_time = av_gettime(); // 获取当前时间(微秒)return (current_time - start_time > 5000000) ? 1 : 0; // 超过5秒则中断
}
4. 设置步骤
- 分配上下文:创建
AVFormatContext
实例。 - 绑定回调:设置
interrupt_callback
的callback
和opaque
。 - 启动计时:在关键操作前记录起始时间(如
av_gettime()
)。 - 打开输入流:调用
avformat_open_input()
,阻塞操作将触发回调检测。
AVFormatContext *fmt_ctx = avformat_alloc_context();
int64_t timeout_start = av_gettime(); // 记录起始时间// 设置回调函数及上下文
fmt_ctx->interrupt_callback.callback = interrupt_cb;
fmt_ctx->interrupt_callback.opaque = &timeout_start;// 打开输入流(如 RTSP)
if (avformat_open_input(&fmt_ctx, "rtsp://example.com", NULL, NULL) < 0) {// 错误处理
}
5. 注意事项
- 协议差异:对于 RTSP,可同时设置
stimeout
参数(单位:微秒)增强超时控制68:cCopy Code
AVDictionary *options = NULL; av_dict_set(&options, "stimeout", "2000000", 0); // 2秒超时 avformat_open_input(&fmt_ctx, url, NULL, &options);
- 线程安全:回调函数需确保线程安全,避免竞态条件8。
- 资源释放:无需手动释放
interrupt_callback
,其生命周期与AVFormatContext
绑定5。
6. 典型问题与调试
- 回调未触发:检查是否在
avformat_open_input()
前正确设置回调8。 - 误中断:调整超时阈值,或在回调中增加状态判断(如网络重连尝试次数)6。
40 回调函数 io_open
谨慎
/**
* A callback for opening new IO streams.
*
* Whenever a muxer or a demuxer needs to open an IO stream (typically from
* avformat_open_input() for demuxers, but for certain formats can happen at
* other times as well), it will call this callback to obtain an IO context.
*
* @param s the format context
* @param pb on success, the newly opened IO context should be returned here
* @param url the url to open
* @param flags a combination of AVIO_FLAG_*
* @param options a dictionary of additional options, with the same
* semantics as in avio_open2()
* @return 0 on success, a negative AVERROR code on failure
*
* @note Certain muxers and demuxers do nesting, i.e. they open one or more
* additional internal format contexts. Thus the AVFormatContext pointer
* passed to this callback may be different from the one facing the caller.
* It will, however, have the same 'opaque' field.
*/
int (*io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url,
int flags, AVDictionary **options);
目前看的信息是:avformatContext 的 io_open 回调函数 在默认情况下叫 io_open_default,在解复用的 avformat_open_input 方法中一定会调用。
io_open_default
是 FFmpeg 中用于初始化输入/输出上下文 (AVIOContext
) 的关键函数,主要在解封装流程中处理协议检测与连接。以下是其核心机制与作用解析:
一、功能定位
-
协议初始化入口
在avformat_open_input()
调用流程中,io_open_default
作为默认的 I/O 上下文初始化函数,负责根据输入 URL 的协议类型(如 HTTP、HLS、文件)创建对应的AVIOContext
,并绑定底层协议实现1。 -
协议白名单校验
通过调用ffio_open_whitelist
,该函数会校验协议是否在允许范围内,防止加载未授权的协议实现(如自定义或非标准协议),确保安全性1。 -
多层封装调用链
其执行链路为:
avformat_open_input
→init_input
→io_open_default
→ffio_open_whitelist
→ffurl_open_whitelist
→ffurl_connect
→ 具体协议实现(如http_open
)1。
最终通过系统调用(如socket
)建立网络连接或打开本地文件12。
二、实现机制
-
协议适配层
io_open_default
通过协议前缀(如http://
、file://
)匹配对应的URLProtocol
实现(如ff_http_protocol
),并初始化协议上下文 (URLContext
),最终关联到AVIOContext
的opaque
字段15。 -
缓冲与回调设置
自动配置读写缓冲区大小,并设置默认的read_packet
、write_packet
等回调函数,确保数据通过协议层高效传输至解封装模块17。 -
错误处理
若协议检测失败(如 URL 无效或协议未注册),函数返回错误码并终止后续流程,触发avformat_open_input
的异常处理逻辑1。
三、应用场景
- 标准协议处理:自动处理 HTTP、RTMP、HLS 等协议连接的初始化,无需手动创建
AVIOContext
15。 - 安全限制场景:通过白名单机制限制可访问的协议类型,适用于需严格管控输入源的场景(如嵌入式设备)1。
四、扩展性
- 自定义协议支持:若需支持私有协议,需绕过
io_open_default
,通过avio_alloc_context
手动创建AVIOContext
并注册自定义协议实现37。
41 回调函数io_close
/**
* A callback for closing the streams opened with AVFormatContext.io_open().
*/
void (*io_close)(struct AVFormatContext *s, AVIOContext *pb);
42 int io_repositioned;
/**
* IO repositioned flag.
* This is set by avformat when the underlaying IO context read pointer
* is repositioned, for example when doing byte based seeking.
* Demuxers can use the flag to detect such changes.
*/
int io_repositioned;
io_repositioned
是 FFmpeg 中 AVFormatContext
结构体的一个标志字段,用于指示底层 I/O 上下文的读指针是否发生了位置重置。其核心作用与应用场景如下:
一、功能定义
-
标志位作用
io_repositioned
由 FFmpeg 的解封装模块(avformat
)自动设置,主要用于标识底层 I/O 上下文(如AVIOContext
)的读指针是否被显式重定位。例如,在基于字节的随机访问(byte-based seeking)时,该标志会被触发。 -
触发条件
当调用av_seek_frame()
或类似函数导致底层 I/O 缓冲区的读指针位置发生变化时,io_repositioned
会被设置为非零值,表示发生了位置重置。
二、应用场景
-
解封装逻辑适配
解复用器(Demuxer)可通过检查io_repositioned
标志判断是否需要重新同步内部状态(如重新解析流头信息或调整时间戳计算逻辑),以应对底层 I/O 位置突变带来的数据不一致问题。 -
性能优化
在处理网络流或大文件时,通过检测io_repositioned
标志,可避免无效的缓存数据读取,确保后续操作基于最新的 I/O 位置执行1。
三、实现关联
- 与
AVIOContext
的交互
io_repositioned
直接关联AVIOContext
的seek
操作,若用户代码通过avio_seek()
手动调整读指针位置,也会触发该标志的更新
打印值是0
avformatContext->io_repositioned;cout << "avformatContext->io_repositioned = " << avformatContext->io_repositioned << endl;
43 const uint8_t *key; 作用未知
const uint8_t *key;
int keylen;
44 int keylen;作用未知
const uint8_t *key;
int keylen;
45 int max_chunk_duration;
/**
* Max chunk time in microseconds.
* Note, not all formats support this and unpredictable things may happen if it is used when not supported.
* - encoding: Set by user
* - decoding: unused
*/
int max_chunk_duration;
用于设置流媒体传输中的最大块持续时间。在FFmpeg的RTMP协议中,这个参数定义了每个RTMP消息的最大持续时间。如果超过这个时间,FFmpeg会自动将数据分成多个块进行传输,以确保流媒体的稳定性和效率。
max_chunk_duration的作用和重要性
- 稳定性:通过限制每个数据块的大小,max_chunk_duration有助于确保流媒体的稳定性。如果数据块过大,可能会导致网络延迟或丢包,影响观看体验。
- 效率:合理设置max_chunk_duration可以提高传输效率,减少缓冲时间,提升用户体验。
- 兼容性:不同的设备和网络环境对数据块的大小有不同的要求,合理设置max_chunk_duration可以增强兼容性。
如何设置max_chunk_duration
在FFmpeg的命令行中,可以通过-max_chunk_duration
选项来设置
46
47
48
49