avcodec_register_all()的函数定义位于libavcodec/allcodecs.c。
它是用来注册编解码器的函数,只有调用了该函数,才能使用编解码器、解析器、硬件加速器等。
编码器和解码器调用的是同一个注册函数 avcodec_register();
代码解析:
这段代码使用了链表结构,并为链表设置了两个全局指针,
指向链表头的 first_avcodec,
指向链表尾的 last_avcodec,
调用函数avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec),将新的codec添加到链表的尾部。
如果last_avcodec没有指向链表的尾,则要先遍历链表,将其指向链表的尾部。
这样做的好处是省去了每次添加一个新codec时,必须对链表的从头到尾遍历以找到链表的尾部。
如果使用遍历的方法,则代码要用如下写:
//注册所有的AVCodec
void avcodec_register(AVCodec *codec)
{
AVCodec **p;
/* 初始化 */
avcodec_init();
/* 从第一个开始, 遍历到链表的尾部 */
p = &first_avcodec;
while (*p != NULL)
p = &(*p)->next;
/* 将新的codec添加到链表的尾部 */
*p = codec;
codec->next = NULL;
if (codec->init_static_data)
codec->init_static_data(codec);
}
这段代码和编解码器的用法一样。
代码解析:
解析器的注册方法和编解码器的注册方法不一样,
它是用av_first_parser指向链表的头,
然后再将新的parser添加到原链表的头之前,再将av_first_parser指向这个新链表头。
参考文档:
http://blog.youkuaiyun.com/leixiaohua1020/article/details/12677265
它是用来注册编解码器的函数,只有调用了该函数,才能使用编解码器、解析器、硬件加速器等。
1. 函数主体如下:
- void avcodec_register_all(void)
- {
- static int initialized;
- if (initialized)
- return;
- initialized = 1;
- /* hardware accelerators
*/
- REGISTER_HWACCEL();
- /* video codecs
*/
- REGISTER_ENCODER();
- REGISTER_DECODER();
- /* audio codecs
*/
- REGISTER_ENCODER();
- REGISTER_DECODER();
- /* PCM codecs
*/
- REGISTER_ENCODER();
- REGISTER_DECODER();
- /* subtitles
*/
- /* external libraries
*/
- /* parsers
*/
- REGISTER_PARSER();
- }
2. 注册函数的宏定义如下:
- #define REGISTER_HWACCEL(X, x)
\
- { \
- extern AVHWAccel ff_##x##_hwaccel;
\
- if (CONFIG_##X##_HWACCEL)
\
- av_register_hwaccel(&ff_##x##_hwaccel);
\
- }
- #define REGISTER_ENCODER(X, x)
\
- { \
- extern AVCodec ff_##x##_encoder;
\
- if (CONFIG_##X##_ENCODER)
\
- avcodec_register(&ff_##x##_encoder);
\
- }
- #define REGISTER_DECODER(X, x)
\
- { \
- extern AVCodec ff_##x##_decoder;
\
- if (CONFIG_##X##_DECODER)
\
- avcodec_register(&ff_##x##_decoder);
\
- }
- #define REGISTER_ENCDEC(X, x) REGISTER_ENCODER(X, x);
REGISTER_DECODER(X, x)
- #define REGISTER_PARSER(X, x)
\
- { \
- extern AVCodecParser ff_##x##_parser;
\
- if (CONFIG_##X##_PARSER)
\
- av_register_codec_parser(&ff_##x##_parser);
\
- }
编码器和解码器调用的是同一个注册函数 avcodec_register();
3. 编解码器
- REGISTER_DECODER(H264, h264);
- #define REGISTER_DECODER(X, x)
\
- { \
- extern AVCodec ff_##x##_decoder;
\
- if (CONFIG_##X##_DECODER)
\
- avcodec_register(&ff_##x##_decoder);
\
- }
- 的宏展开后:
- {
- /* extern表明全局唯一
*/
- extern AVCodec ff_h264_decoder;
- if (CONFIG_H264_DECODER)
- avcodec_register(&ff_h264_decoder);
- }
- avcodec_register的函数定义: libavcodec/utils.c
- /* encoder management
*/
- static AVCodec *first_avcodec
= NULL;
- static AVCodec **last_avcodec
= &first_avcodec;
- av_cold void avcodec_register(AVCodec
*codec)
- {
- AVCodec **p;
- avcodec_init();
- p = last_avcodec;
- codec->next
= NULL;
- /* 将新的codec 添加到链接的尾部*/
- while(*p
|| avpriv_atomic_ptr_cas((void
* volatile *)p,
NULL, codec))
- p = &(*p)->next;
- last_avcodec =
&codec->next;
- if (codec->init_static_data)
- codec->init_static_data(codec);
- }
- void *avpriv_atomic_ptr_cas(void
* volatile *ptr, void
*oldval, void
*newval)
- {
- if (*ptr
== oldval)
{
- *ptr = newval;
- return oldval;
- }
- return *ptr;
- }
这段代码使用了链表结构,并为链表设置了两个全局指针,
指向链表头的 first_avcodec,
指向链表尾的 last_avcodec,
调用函数avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec),将新的codec添加到链表的尾部。
如果last_avcodec没有指向链表的尾,则要先遍历链表,将其指向链表的尾部。
这样做的好处是省去了每次添加一个新codec时,必须对链表的从头到尾遍历以找到链表的尾部。
如果使用遍历的方法,则代码要用如下写:
//注册所有的AVCodec
void avcodec_register(AVCodec *codec)
{
AVCodec **p;
/* 初始化 */
avcodec_init();
/* 从第一个开始, 遍历到链表的尾部 */
p = &first_avcodec;
while (*p != NULL)
p = &(*p)->next;
/* 将新的codec添加到链表的尾部 */
*p = codec;
codec->next = NULL;
if (codec->init_static_data)
codec->init_static_data(codec);
}
4. 硬件加速器
- REGISTER_HWACCEL(H264_CUVID, h264_cuvid);
- 的宏展开后为:
- {
- extern AVHWAccel ff_h264_cuvid_hwacel;
- if (CONFIG_H264_CUVID_HWACCEL)
- av_register_hwaccel(&ff_h264_cuvid_hwacel);
- }
- av_register_hwaccel()的定义位于libavcodec/utils.c
- static AVHWAccel *first_hwaccel
= NULL;
- static AVHWAccel **last_hwaccel
= &first_hwaccel;
- void av_register_hwaccel(AVHWAccel
*hwaccel)
- {
- AVHWAccel **p
= last_hwaccel;
- hwaccel->next
= NULL;
- while(*p
|| avpriv_atomic_ptr_cas((void
* volatile *)p,
NULL, hwaccel))
- p = &(*p)->next;
- last_hwaccel =
&hwaccel->next;
- }
5. 解析器
- REGISTER_PARSER(AAC, aac);
- #define REGISTER_PARSER(X, x)
\
- { \
- extern AVCodecParser ff_##x##_parser;
\
- if (CONFIG_##X##_PARSER)
\
- av_register_codec_parser(&ff_##x##_parser);
\
- }
- 宏展开后:
- {
- extern AVCodecParser ff_aac_parser;
- if (CONFIG_AAC_PARSER)
- av_register_codec_parser(&ff_aac_parser);
- }
- av_register_codec_parser的函数定义,libavcodec/parser.c
- static AVCodecParser *av_first_parser
= NULL;
- void av_register_codec_parser(AVCodecParser
*parser)
- {
- do {
- parser->next
= av_first_parser;
- } while
(parser->next
!= avpriv_atomic_ptr_cas((void
* volatile *)&av_first_parser, parser->next,
parser));
- }
- void *avpriv_atomic_ptr_cas(void
* volatile *ptr, void
*oldval, void
*newval)
- {
- if (*ptr
== oldval)
{
- *ptr = newval;
- return oldval;
- }
- return *ptr;
- }
解析器的注册方法和编解码器的注册方法不一样,
它是用av_first_parser指向链表的头,
然后再将新的parser添加到原链表的头之前,再将av_first_parser指向这个新链表头。
参考文档:
http://blog.youkuaiyun.com/leixiaohua1020/article/details/12677265
本文详细解析了FFmpeg中avcodec_register_all()函数的工作原理,包括编解码器、硬件加速器及解析器的注册过程。通过宏定义实现不同组件的注册,采用链表结构高效管理。
3万+

被折叠的 条评论
为什么被折叠?



