文档章节

ffmpeg源码分析——av_register_all

zhangyujsj
 zhangyujsj
发布于 2016/01/10 23:25
字数 780
阅读 151
收藏 1

1 av_register_all()函数骨架

void av_register_all(void)
{
    static int initialized;
    if (initialized)
        return;   // 如果没有初始化过就直接返回
    initialized = 1;
    avcodec_register_all();
    // 注册复用和解复用器,这里其他格式注册的过程是一样的,省略
    REGISTER_MUXDEMUX(MP3,              mp3);
    // 注册协议,这里其他协议注册的过程是一样的,省略
    REGISTER_PROTOCOL(RTP,              rtp);
}

原理:在ffmepg中主要通过链表来保存注册的所有的复用和解复用器,使用全局静态变量来保存这些链表的头指针,所以通过向链表中插入指定的节点来完成注册。

av_register_all()函数就是用这种方式完成了endoder和decoder,parser,muxer和demuxer以及protocol的注册。

2 代码细节分析

2.1 avcodec_register_all()函数骨架

void avcodec_register_all(void)
{
    static int initialized;

    if (initialized)
        return; // 如果已经注册过了,直接返回
    initialized = 1;

    /* hardware accelerators */
    REGISTER_HWACCEL(H263_VAAPI,        h263_vaapi);
    /*注册编解码器*/
    REGISTER_DECODER(H264,              h264);
    REGISTER_DECODER(LIBSTAGEFRIGHT_H264, libstagefright_h264); 
    /*注册解析器*/
    REGISTER_PARSER(H264,               h264);
}

2.1.1 REGISTER_DECODER宏定义

#define REGISTER_DECODER(X, x)                                          \
    {                                                                   \
        extern AVCodec ff_##x##_decoder;                                \
        if (CONFIG_##X##_DECODER)                                       \
            avcodec_register(&ff_##x##_decoder);                        \
    }
相当于就是:
extern AVCodec ff_h264_decoder;
if(CONFIG_H264_DECODER)
    avcodec_register(&ff_h264_decoder);
2.1.1.1 avcodec_register()函数

刚开始分析不要陷入代码细节中,无法自拔!一句话,把当前的AVCodec加到链表的尾部。

void avcodec_register(AVCodec *codec)
{
    AVCodec **p;
    avcodec_init();
    p = last_avcodec;
    codec->next = NULL;

    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);
}

2.1.2 REGISTER_PARSER宏定义

#define REGISTER_PARSER(X, x)                                           \
    {                                                                   \
        extern AVCodecParser ff_##x##_parser;                           \
        if (CONFIG_##X##_PARSER)                                        \
            av_register_codec_parser(&ff_##x##_parser);                 \
    }
extern AVCodecParser ff_h264_parser;
if(CONFIG_H264_PARSER)
     av_register_codec_parser(&ff_h264_parser);


2.2 REGISTER_MUXDEMUX宏定义

#define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x)

这个宏定义显然是用了两个宏定义。

2.2.1  REGISTER_MUXER和REGISTER_DEMUXER

#define REGISTER_MUXER(X, x)                                            \
    {                                                                   \
        extern AVOutputFormat ff_##x##_muxer;                           \
        if (CONFIG_##X##_MUXER)                                         \
            av_register_output_format(&ff_##x##_muxer);                 \
    }
#define REGISTER_DEMUXER(X, x)                                          \
    {                                                                   \
        extern AVInputFormat ff_##x##_demuxer;                          \
        if (CONFIG_##X##_DEMUXER)                                       \
            av_register_input_format(&ff_##x##_demuxer);                \
    }
这段代码宏定义展开之后是:
extern AVOutputFormat ff_mp3_muxer;
if(CONFIG_MP3_MUXER)
    av_register_output_format(&ff_mp3_muxer);
extern AVInputFormat ff_mp3_demuxer;                          
if (CONFIG_MP3_DEMUXER)                                       
    av_register_input_format(&ff_mp3_demuxer);

    

2.2.1.1 av_register_output_format()函数和av_register_input_format()函数

输入格式和输出格式都是用的链表来管理的,而这两个链表的头尾指针则用静态全局变量(文件内)来保存,如下:

/** head of registered input format linked list */
static AVInputFormat *first_iformat = NULL;
/** head of registered output format linked list */
static AVOutputFormat *first_oformat = NULL;

static AVInputFormat **last_iformat = &first_iformat;
static AVOutputFormat **last_oformat = &first_oformat;

遍历链表把当前的AVInputFormat和AVOutputFormat加到链表的尾部。

void av_register_input_format(AVInputFormat *format)
{
    AVInputFormat **p = last_iformat;

    format->next = NULL;
    while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
        p = &(*p)->next;
    last_iformat = &format->next;
}
void av_register_output_format(AVOutputFormat *format)
{
    AVOutputFormat **p = last_oformat;

    format->next = NULL;
    while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
        p = &(*p)->next;
    last_oformat = &format->next;
}


2.3 REGISTER_PROTOCOL宏定义

#define REGISTER_PROTOCOL(X, x)                                         \
    {                                                                   \
        extern URLProtocol ff_##x##_protocol;                           \
        if (CONFIG_##X##_PROTOCOL)                                      \
            ffurl_register_protocol(&ff_##x##_protocol);                \
    }
这段代码就相当于:
extern URLProtocol ff_rtp_protocol;                           \
        if (CONFIG_RTP_PROTOCOL)                                      \
            ffurl_register_protocol(&ff_rtp_protocol);

2.3.1 ffurl_register_protocol()函数

同样的协议也是用的链表来保存的,由全局静态变量first_protocol指针。

static URLProtocol *first_protocol = NULL;

这样ffurl_register_protocol()函数就是把参数中的这个指针给插入到链表中去(完成注册)。

int ffurl_register_protocol(URLProtocol *protocol)
{
    URLProtocol **p;
    p = &first_protocol;
    while (*p)
        p = &(*p)->next;
    *p             = protocol;
    protocol->next = NULL;
    return 0;
}

3 代码中的链表深入分析

参考资料:

1 http://blog.csdn.net/leixiaohua1020/article/details/12677129

2 http://blog.csdn.net/leixiaohua1020/article/details/12677265

© 著作权归作者所有

上一篇: getopt如何用
下一篇: Live555基础
zhangyujsj
粉丝 24
博文 358
码字总数 224241
作品 0
广州
私信 提问
FFmpeg 是如何实现多态的?

前言 众所周知,FFmpeg 在解码的时候,无论输入文件是 MP4 文件还是 FLV 文件,或者其它文件格式,都能正确解封装、解码,而代码不需要针对不同的格式做出任何改变,这是面向对象中很常见的多...

shzwork
03/11
0
0
FFmpeg命令行工具学习(四):FFmpeg API 介绍与通用 API 分析

一、FFmpeg 相关术语 1. 容器/文件(Container/File):即特定格式的多媒体文件,比如MP4,flv,mov等。 2. 媒体流(Stream):表示在时间轴上的一段连续的数据,比如一段声音数据、一段视频...

灰色飘零
2018/07/17
0
0
android端采用FFmpeg进行音频混合与拼接剪切

接触FFmpeg有一段时间了,它是音视频开发的开源库,几乎其他所有播放器、直播平台都基于FFmpeg进行二次开发。本篇文章来总结下采用FFmpeg进行音频处理:音频混合、音频剪切、音频拼接与音频转...

mp624183768
2018/05/13
0
0
最简单的基于FFmpeg的AVUtil例子 (AVLog, AVOption等)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/leixiaohua1020/article/details/46890739 本文的示例程序记录了FFmpeg的libavutil中几种工具函数的使用方法:...

雷霄骅
2015/07/18
0
0
最简单的基于FFmpeg的AVDevice例子(屏幕录制)

原文地址:http://blog.csdn.net/leixiaohua1020/article/details/39706721 雷神的博客,致敬雷神。 抓屏方法 上篇文章记录了libavdevice的使用方法,本文不再重复。在Windows系统使用libav...

zwg流泪
2017/11/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

读书replay《maven实战》.1.20190526

前情提要 maven这个工具用了好久了,但是一直都用的迷迷糊糊的,没有对它进行过系统性的学习,只是知道一些常用的功能怎么实现,所以20190516这一天我从JD购买了徐晓斌老师所著的《maven实战...

wanxiangming
25分钟前
0
0
真实项目案例实战——【状态设计模式】使用场景

什么是状态模式 状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。 状态模式应用场景 1.一个对象的行为取决于它的状态,并且它必须在运行时刻根...

须臾之余
31分钟前
0
0
Java 实现把字符串转换成整数【底层实现】

https://blog.csdn.net/zl18310999566/article/details/80263396

qimh
35分钟前
0
0
IDEA的debugger

1、win下节省内存空间 3、条件断点

一只小青蛙
45分钟前
3
0
炸!亿级数据DB秒级平滑扩容

一步一步,娓娓道来。 一般来说,并发量大,吞吐量大的互联网分层架构是怎么样的? 数据库上层都有一个微服务,服务层记录“业务库”与“数据库实例配置”的映射关系,通过数据库连接池向数据...

编程SHA
51分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部