ffmpeg4.2.2 av_register_all()的分析

【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) 

ffmpeg4.2.2 av_register_all()的分析

1. av_register_all()介绍

   av_register_all()是所有基于ffmpeg的应用程序中第一个被调用的函数, 只有调用了该函数,才能正常使用ffmpeg的各项功能, 如复用/解复用器,编码/解码器, 以及各种协议等等.

时过境迁, 现在的av_register_all()是ffmpeg的过时函数(deprecated). 当我们使用的时候, 编译器会提示如下的警告: (尽管这个函数已经过时了, 但是我们依旧可以正常使用, 只是多了一个警告)

warning: 'void av_register_all()' is deprecated [-Wdeprecated-declarations]
     av_register_all();
     ^

如何解决呢? 我们接着来看.

2. av_register_all()的函数声明

/**
 * 初始化libavformat和注册所有的复用/解复用器和协议. 
 * 如果你没有调用这个函数, 那么你可以指定选择你想要支持
 * 格式. 具体看如下的两个函数
 *
 * @see av_register_input_format()
 * @see av_register_output_format()
 */
attribute_deprecated
void av_register_all(void);

attribute_deprecated
void av_register_input_format(AVInputFormat *format);
attribute_deprecated
void av_register_output_format(AVOutputFormat *format);

   在版本稍早的ffmpeg中, 其实av_register_input_format()和av_register_output_format()才是真正执行注册的函数(av_register_all()里面也是调用了这两个函数), 只不过av_register_all()函数把所有能注册的都注册上去了, 而av_register_input_format()和av_register_output_format()函数可以让我们选择性地把程序用到的才注册上去.
   但是如上所示, av_register_input_format()和av_register_output_format()这两个函数也过时了!!! 那么, ffmpeg取代的手段是什么呢? 我们接着来看.

3. av_register_all()的源码分析

目录: ffmpeg-4.2.2\libavformat\allformats.c
void av_register_all(void)
{
    ff_thread_once(&av_format_next_init, av_format_init_next);
}

void av_register_input_format(AVInputFormat *format)
{
    ff_thread_once(&av_format_next_init, av_format_init_next);
}

void av_register_output_format(AVOutputFormat *format)
{
    ff_thread_once(&av_format_next_init, av_format_init_next);
}

由上可见, 新版本的ffmpeg的三个函数是等效的! 也就是说, ffmpeg的维护者觉得开头使用av_register_all()注册所有需要的复用/解复用器是可行的(或者说是妥协? 还是av_register_all()函数的内部实现被改了?).

#if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS	// 支持线程的平台
	#define AVOnce pthread_once_t
	#define AV_ONCE_INIT PTHREAD_ONCE_INIT
	#define ff_thread_once(control, routine) pthread_once(control, routine)
	....
#else
	#define AVOnce char
	#define AV_ONCE_INIT 0
	static inline int ff_thread_once(char *control, void (*routine)(void))
	{
	    if (!*control) {
	        routine();
	        *control = 1;
	    }
	    return 0;
	}
#endif

static AVOnce av_format_next_init = AV_ONCE_INIT;
ff_thread_once(&av_format_next_init, av_format_init_next)

上面的宏HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS 指的是那些支持线程的平台跑av_register_all()的流程, 我看了一下, 相当复杂; 相对于不支持线程的分支来说, 我们就可以很容易看明白.(两者想要达成的目的是一样的) 也就是保证av_register_all()里面的注册流程只会被跑一遍! 也就是av_format_init_next()只会被调用一次!

av_format_init_next()所做的事情如下:

static void av_format_init_next(void)
{
    AVOutputFormat *prevout = NULL, *out;
    AVInputFormat *previn = NULL, *in;

    ff_mutex_lock(&avpriv_register_devices_mutex);

    for (int i = 0; (out = (AVOutputFormat*)muxer_list[i]); i++) {
        if (prevout)
            prevout->next = out;
        prevout = out;
    }

    if (outdev_list) {
        for (int i = 0; (out = (AVOutputFormat*)outdev_list[i]); i++) {
            if (prevout)
                prevout->next = out;
            prevout = out;
        }
    }

    for (int i = 0; (in = (AVInputFormat*)demuxer_list[i]); i++) {
        if (previn)
            previn->next = in;
        previn = in;
    }

    if (indev_list) {
        for (int i = 0; (in = (AVInputFormat*)indev_list[i]); i++) {
            if (previn)
                previn->next = in;
            previn = in;
        }
    }

    ff_mutex_unlock(&avpriv_register_devices_mutex);
}

上面的代码只是遍历了几个数组(muxer_list[], outdev_list[], demuxer_list[], indev_list[]), 并没有实际的操作! 也就是说, 我现在完全不调用av_register_all()也是可以成功运行ffmpeg应用的.

4. av_register_all()的分析结果

   在新版本的ffmpeg4.2.2中, av_register_all()函数中已经不做实际的工作, 留在这里是做兼容性考虑!

发布了68 篇原创文章 · 获赞 22 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/MACMACip/article/details/105312299