ffmpeg源码简析(四)avcodec_find_encoder(),avcodec_open2(),avcodec_close()

avcodec_find_encoder()和avcodec_find_decoder()

avcodec_find_encoder()用于查找FFmpeg的编码器,avcodec_find_decoder()用于查找FFmpeg的解码器。 
avcodec_find_encoder()的声明位于libavcodec\avcodec.h

avcodec_find_encoder()的源代码位于libavcodec\utils.c

    AVCodec *avcodec_find_encoder(enum AVCodecID id)  
    {  
        return find_encdec(id, 1);  
    }  
  • 1
  • 2
  • 3
  • 4

find_encdec() 
find_encdec()的源代码位于libavcodec\utils.c,如下所示。

static AVCodec *first_avcodec;  

static AVCodec *find_encdec(enum AVCodecID id, int encoder)  
{  
    AVCodec *p, *experimental = NULL;  
    p = first_avcodec;  
    id= remap_deprecated_codec_id(id);  
    while (p) {  
        if ((encoder ? av_codec_is_encoder(p) : av_codec_is_decoder(p)) &&  
            p->id == id) {  
            if (p->capabilities & CODEC_CAP_EXPERIMENTAL && !experimental) {  
                experimental = p;  
            } else  
                return p;  
        }  
        p = p->next;  
    }  
    return experimental;  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

find_encdec()中有一个循环,该循环会遍历AVCodec结构的链表,逐一比较输入的ID和每一个编码器的ID,直到找到ID取值相等的编码器。 
在这里有几点需要注意: 
(1)first_avcodec是一个全局变量,存储AVCodec链表的第一个元素。 
(2)remap_deprecated_codec_id()用于将一些过时的编码器ID映射到新的编码器ID。 
(3)函数的第二个参数encoder用于确定查找编码器还是解码器。当该值为1的时候,用于查找编码器,此时会调用av_codec_is_encoder()判断AVCodec是否为编码器;当该值为0的时候,用于查找解码器,此时会调用av_codec_is_decoder()判断AVCodec是否为解码器。

av_codec_is_encoder() 
av_codec_is_encoder()是一个判断AVCodec是否为编码器的函数。如果是编码器,返回非0值,否则返回0。

    int av_codec_is_encoder(const AVCodec *codec)  
    {  
        return codec && (codec->encode_sub || codec->encode2);  
    }  
  • 1
  • 2
  • 3
  • 4

从源代码可以看出,av_codec_is_encoder()判断了一下AVCodec是否包含了encode2()或者encode_sub()接口函数。

avcodec_open2()

该函数用于初始化一个视音频编解码器的AVCodecContext。avcodec_open2()的声明位于libavcodec\avcodec.h

int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); 
  • 1

avctx:需要初始化的AVCodecContext。 
codec:输入的AVCodec 
options:一些选项。例如使用libx264编码的时候,“preset”,“tune”等都可以通过该参数设置。

avcodec_open2() 
avcodec_open2()的定义位于libavcodec\utils.c

avcodec_open2()的源代码量是非常长的,但是它的调用关系非常简单——它只调用了一个关键的函数,即AVCodec的init(),后文将会对这个函数进行分析。 
我们可以简单梳理一下avcodec_open2()所做的工作,如下所列:

(1)为各种结构体分配内存(通过各种av_malloc()实现)。
(2)将输入的AVDictionary形式的选项设置到AVCodecContext。
(3)其他一些零零碎碎的检查,比如说检查编解码器是否处于“实验”阶段。
(4)如果是编码器,检查输入参数是否符合编码器的要求
(5)调用AVCodec的init()初始化具体的解码器。

AVCodec->init() 
avcodec_open2()中最关键的一步就是调用AVCodec的init()方法初始化具体的编码器。AVCodec的init()是一个函数指针,指向具体编解码器中的初始化函数。

avcodec_close()

该函数用于关闭编码器。avcodec_close()函数的声明位于libavcodec\avcodec.h

int avcodec_close(AVCodecContext *avctx); 
  • 1

avcodec_close()的定义位于libavcodec\utils.c,如下所示。

    av_cold int avcodec_close(AVCodecContext *avctx)  
    {  
        if (!avctx)  
            return 0;  

        if (avcodec_is_open(avctx)) {  
            FramePool *pool = avctx->internal->pool;  
            int i;  
            if (CONFIG_FRAME_THREAD_ENCODER &&  
                avctx->internal->frame_thread_encoder && avctx->thread_count > 1) {  
                ff_frame_thread_encoder_free(avctx);  
            }  
            if (HAVE_THREADS && avctx->internal->thread_ctx)  
                ff_thread_free(avctx);  
            //关闭编解码器  
            if (avctx->codec && avctx->codec->close)  
                avctx->codec->close(avctx);  
            avctx->coded_frame = NULL;  
            avctx->internal->byte_buffer_size = 0;  
            av_freep(&avctx->internal->byte_buffer);  
            av_frame_free(&avctx->internal->to_free);  
            for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++)  
                av_buffer_pool_uninit(&pool->pools[i]);  
            av_freep(&avctx->internal->pool);  

            if (avctx->hwaccel && avctx->hwaccel->uninit)  
                avctx->hwaccel->uninit(avctx);  
            av_freep(&avctx->internal->hwaccel_priv_data);  

            av_freep(&avctx->internal);  
        }  

        if (avctx->priv_data && avctx->codec && avctx->codec->priv_class)  
            av_opt_free(avctx->priv_data);  
        av_opt_free(avctx);  
        av_freep(&avctx->priv_data);  
        if (av_codec_is_encoder(avctx->codec))  
            av_freep(&avctx->extradata);  
        avctx->codec = NULL;  
        avctx->active_thread_type = 0;  

        return 0;  
    }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

从avcodec_close()的定义可以看出,该函数释放AVCodecContext中有关的变量,并且调用了AVCodec的close()关闭了解码器。

AVCodec->close() 
AVCodec的close()是一个函数指针,指向了特定编码器的关闭函数。在这里我们以libx264为例,看一下它对应的AVCodec的结构体的定义,如下所示。

AVCodec ff_libx264_encoder = {  
    .name             = "libx264",  
    .long_name        = NULL_IF_CONFIG_SMALL("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),  
    .type             = AVMEDIA_TYPE_VIDEO,  
    .id               = AV_CODEC_ID_H264,  
    .priv_data_size   = sizeof(X264Context),  
    .init             = X264_init,  
    .encode2          = X264_frame,  
    .close            = X264_close,  
    .capabilities     = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,  
    .priv_class       = &x264_class,  
    .defaults         = x264_defaults,  
    .init_static_data = X264_init_static,  
}; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

从ff_libx264_encoder的定义可以看出:close()函数对应的是X264_close()函数。继续看一下X264_close()函数的定义,如下所示。

    static av_cold int X264_close(AVCodecContext *avctx)  
    {  
        X264Context *x4 = avctx->priv_data;  

        av_freep(&avctx->extradata);  
        av_freep(&x4->sei);  
        //关闭编码器  
        if (x4->enc)  
            x264_encoder_close(x4->enc);  

        av_frame_free(&avctx->coded_frame);  

        return 0;  
    }  


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

从X264_close()的定义可以看出,该函数调用了libx264的x264_encoder_close()关闭了libx264编码器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值