AVClass
1 | AVFormatContext *s; |
1 |
|
1 | int avformat_open_input(AVFormatContext **ps, const char *filename, |
以AVFormatContext来分析,av_format_context_class.option 是一个列表,基本对应着 AVFormatContext 内部成员。option 通过offset宏 来找到对应的成员的偏移位置。
在avformat_open_input方法中,会遍历外部传入的options参数,对AVFormatContext实例进行属性成员赋值。
类似的这种用法 在ffmpeg中很常见,比如 AVIOContext、URLContext、AVCodecContext …
priv_data
1 | typedef struct URLContext { |
以 URLContext 来分析,在 url_alloc_for_protocol 方法中,URLContext.priv_data 赋值的其实就是 对用的 URLProtocol的 priv_data_class实例,以http-protocol来举例,
URLContext.priv_data 就是 httpcontext, 而 httpcontext 也符合上面avclass那一套,通过option对 httpcontext实例的成员变量赋值。
这里有个问题?URLContext 持有对应的 prot,为什么还要 弄一个 priv_data呢? protocol里面有priv_data_class 、priv_data_size,也可以搞一个 priv_data,URLContext用过 prot来访问priv_data就好了。
类似的用法在ffmpeg中 也有很多,比如AVFormatContext,AVFormatContext.priv_data是处理 封装解封装的上下文,mp4格式对应的就是MOVContext. 比如 mp4格式的AVStream,AVStream.priv_data是 MOVStreamContext
1 | typedef struct AVFormatContext { |
internal
在 libavformat/internal.h
文件中, FFFormatContext & FFStream 定义如下:
1 | typedef struct FFFormatContext { |
AVFormatContext & AVStream 都是作为第一个成员存在于FFFormatContext & FFStream 结构体中。
1 | AVFormatContext *avformat_alloc_context(void) |
初始化逻辑都是通过创建 FFFormatContext & FFStream 实例,然后取成员pub
1 | static av_always_inline FFFormatContext *ffformatcontext(AVFormatContext *s) |
av_always_inline 是编译器优化,强制内敛
由于 AVFormatContext & AVStream 作为第一个成员,所以二者可以跟FFFormatContext & FFStream 做强制类型转换
从定义上看, 好像AVFormatContext & AVStream 是应该作为internal,但是实际用法上,FFFormatContext & FFStream才是作为internal 来辅助 AVFormatContext & AVStream存储相关信息
FFIOContext -> AVIOContext , FFCodec -> AVCodec 也是这种形式
ffmepg中也不是 所有的internal 都是这种用法, AVCodecInternal、AVFilterInternal 就是 常规的 作为 AVCodecContext & AVFilterContext 的 internal 成员存在的
个人目前使用的ffmepg 是 5.x的version,早期4.x的时候,avformat & avstream 也是类似 codec & filter 这样常规的用法