av_register_all,avcodec_register_all的源码分析

内存分配与释放

内存管理在libavutil下mem.h。

av_malloc()就是简单的封装了系统函数malloc(),并做了一些错误检查工作。

void *av_malloc(size_t size)

{

    void *ptr = NULL;

    /* let's disallow possibly ambiguous cases */

    if (size > (max_alloc_size - 32))

        return NULL;

    ptr = malloc(size);

    if(!ptr && !size) {

        size = 1;

        ptr= av_malloc(1);

    }

    return ptr;

}


av_realloc()
简单封装了系统的realloc()函数。

void *av_realloc(void *ptr, size_t size)

{

    /* let's disallow possibly ambiguous cases */

    if (size > (max_alloc_size - 32))

        return NULL;

    return realloc(ptr, size + !size);

}

av_mallocz()可以理解为av_malloc()+zeromemory。从源代码可以看出av_mallocz()中调用了av_malloc()之后,又调用memset()将分配的内存设置为0

 

void *av_mallocz(size_t size)

{

    void *ptr = av_malloc(size);

    if (ptr)

        memset(ptr, 0, size);

    return ptr;

}

av_calloc()则是简单封装了av_mallocz()
从代码中可以看出,它调用av_mallocz()分配了nmemb*size个字节的内存。

void *av_calloc(size_t nmemb, size_t size)

{

    if (size <= 0 || nmemb >= INT_MAX / size)

        return NULL;

    return av_mallocz(nmemb * size);

}

释放内存

av_free()简单的封装了free()

void av_free(void *ptr)

{

    free(ptr);

}

av_freep()简单封装了av_free()。并且在释放内存之后将目标指针设置为NULL

void av_freep(void *arg)

{

    void **ptr = (void **)arg;

    av_free(*ptr);

    *ptr = NULL;

}

 

av_register_all

av_register_all的源代码(libavformat下allformats.c)如下:

……

#define REGISTER_DEMUXER(X, x)                                          \

    {                                                                   \

        extern AVInputFormat ff_##x##_demuxer;                          \

        if (CONFIG_##X##_DEMUXER)                                       \

            av_register_input_format(&ff_##x##_demuxer);                \

    }

void av_register_all(void)

{

    static int initialized;

    if (initialized)

        return;

    initialized = 1;

    avcodec_register_all();

    /* (de)muxers */

    REGISTER_MUXER   (A64,              a64);

    REGISTER_DEMUXER (AAC,              aac);

              ……

}

我们以REGISTER_DEMUXER  (AAC, aac)为例,则它等效于

extern AVInputFormat ff_aac_demuxer;

if(CONFIG_AAC_DEMUXER) av_register_input_format(&ff_aac_demuxer);

从上面这段代码我们可以看出,真正注册的函数是av_register_input_format(&ff_aac_demuxer),那我就看看这个和函数的作用,查看一下av_register_input_format()的代码:

void av_register_input_format(AVInputFormat *format)

{

    AVInputFormat **p;

    p = &first_iformat;

    while (*p != NULL) p = &(*p)->next;

    *p = format;

    format->next = NULL;

}

这段代码是比较容易理解的,首先先提一点,first_iformat是个什么东东呢?其实它是Input Format链表的头部地址,是一个全局静态变量,定义如下:

/** head of registered input format linked list */

static AVInputFormat *first_iformat = NULL;

由此我们可以分析出av_register_input_format()的含义,一句话概括就是:遍历链表并把当前的Input Format加到链表的尾部。
至此REGISTER_DEMUXER  (X, x)分析完毕。

avcodec_register_all

avcodec_register_all的源代码(libavcodec下的allcodecs.c)如下:

#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);                        \

}

……

void avcodec_register_all (void)

{

    static int initialized;

    if (initialized)

        return;

    initialized = 1;

          ……

    REGISTER_DECODER(H264,              h264);         

……

}

在这里,我发现其实编码器和解码器用的注册函数都是一样的:avcodec_register()

以REGISTER_DECODER (H264, h264)为例,就是等效于

extern AVCodec ff_h264_decoder;

if(CONFIG_H264_DECODER)  avcodec_register(&ff_h264_decoder);
下面看一下avcodec_register()的源代码:

//注册所有的AVCodec

void avcodec_register(AVCodec *codec)

{

    AVCodec **p;

    //初始化

    avcodec_init();

    //从第一个开始

    p = &first_avcodec;

    while (*p != NULL) p = &(*p)->next;

    *p = codec;

    codec->next = NULL;

    if (codec->init_static_data)

        codec->init_static_data(codec);

}
这段代码是比较容易理解的。首先先提一点,first_avcdec是就是AVCodec链表的头部地址,是一个全局静态变量,定义如下:

/* encoder management */

static AVCodec *first_avcodec = NULL;

由此我们可以分析出avcodec_register()的含义,一句话概括就是:遍历链表并把当前的AVCodec加到链表的尾部。

同理,ParserBSF(bitstream filters,比特流滤镜)HWACCEL(hardware accelerators,硬件加速器)的注册方式都是类似的。不再详述。

AVFormatContext-AVIOContext-AVStream-AVFrame-AVPacket

AVFormatContext:统领全局的基本结构体。主要用于处理封装格式(FLV/MKV/RMVB等)。

AVIOContext:输入输出对应的结构体,用于输入输出(读写文件,RTMP协议等)。

AVStreamAVCodecContext:视音频流对应的结构体,用于视音频编解码。

AVFrame:存储非压缩的数据(视频对应RGB/YUV像素数据,音频对应PCM采样数据)

AVPacket:存储压缩数据(视频对应H.264等码流数据,音频对应AAC/MP3等码流数据)

他们之间的关系如下图所示:

结构体

初始化

销毁

AVFormatContext

avformat_alloc_context()

声明libavformat\avformat.hh

定义libavformat\options.c

avformat_free_context()

AVIOContext

avio_alloc_context()

声明libavformat\avio.h

定义libavformat\aviobuf.c

 

AVStream

avformat_new_stream()

声明libavformat\avformat.h

定义libavformat\utils.c

 

AVCodecContext

avcodec_alloc_context3()

声明libavcodec\avcodec.h

定义libavcodec\options.c

 

AVFrame

av_frame_alloc();

声明libavutil\frame.h

定义libavutil\frame.c

av_frame_free()

AVPacket

av_init_packet();

声明libavcodec\avcodec.h

定义libavcodec\avpacket.c

av_new_packet()

声明libavcodec\avcodec.h

定义libavcodec\avpacket.c

av_free_packet()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值