ffmpeg的内部Video Buffer管理和传送机制

 

本文主要介绍ffmpeg解码器内部管理Video Buffer的原理和过程,ffmpegVideobuffer为内部管理,其流程大致为:注册处理函数->帧级释放->帧级申请->清空。

1 注册get_buffer()release_buffer()

FFAPI_InitCodec()

avcodec_alloc_context()

avcodec_alloc_context2()

avcodec_get_context_default2(AVCodecContext *s,...){

......

s->get_buffer = avcodec_default_get_buffer;

s->release_buffer = avcodec_default_release_buffer;

......

}

2帧级的内存申请和释放调用

1帧级内存申请和释放的函数调用

2.1 FFAPI函数调用libavcodec相应的codec(WMV3对应的CodecVC1)函数进行解码,过程中调用内部buffer处理函数。其中buffer管理被统一封装到Mpegvideo接口中(包括的codecH.261, H.263, H.264, mpeg12, rv10,rv34, svq1VC1)

FFAPI_Decode()

       avcodec_decode_video2()

              avctx->codec->decode()//初始化过程中注册codecwmv3的解码函数是

              vc1_decode_frame(){

       decode_vc1_header;

       MPV_frame_start();                                     //2.2.2

       vc1_decode_blocks();

       MPV_frame_end();                                     //2.2.3

}

2.2 MPV_frame_start()//通过调用get_buffer()申请当前帧的video buffer

MPV_frame_start()

       //首先调用release_buffer()释放非参考帧的video buffer

       for(i=0; i<MAX_PICTURE_COUNT; i++)

if(s->picture[i].data[0] && !s->picture[i].reference)

free_frame_buffer(s, &s->picture[i]); //调用s->avctx->get_buffer(),回调avcodec_default_release_buffer()

 

       ff_alloc_picture()

              alloc_frame_buffer()

                     s->avctx->get_buffer()      //回调avcodec_default_get_buffer()

2.3MPV_frame_end()                                          //完成视频加边等操作

 

3帧级的内存申请和释放处理方法

3.1内部buffer数据结构

   typedef struct InternalBuffer{

       int last_pic_num;              

       uint8_t *base[4];             

       uint8_t *data[4];             

       int linesize[4];           

       int width, height;            

       enum PixelFormat pix_fmt;   

   }InternalBuffer;

   typedef struct AVCodecContext {

          ……

   int internal_buffer_count; //记录当前内部buffer的个数,get_bufferrelease_buffer时均需要对其进行维护。

   void *internal_buffer;//初始化为数组InternalBuffer [INTERNAL_BUFFER_SIZE]

   ……

   } AVCodecContext;

Codec通过维护internal_buffer_countinternal_buffer实现高效的内存管理。

3.2参考帧管理相关数据结构

   typedef  struct Picture{

       uint8_t *data[4];

       int linesize[4];

       uint8_t *base[4];

       int reference;

       ……

   } Picture;

   typedef  struct MpegEncContext{

       ……

       Picture* picture;   //初始化为数组Picture[INTERNAL_BUFFER_SIZE]

       Picture* last_picture_ptr;      //指向前一帧

       Picture* next_picture_ptr;;    //双向预测时,指向后一帧

       Picture* current_picture_ptr;//指向当前帧

   ……

   } MpegEncContext; 

3.3申请和释放原理

2 内存申请和释放原理

(1)初始化时将internal_buffer全部清零

(2)释放buffer时,将释放的buffer与最后一个有效buffer交换,而不是用av_free()释放内存。

avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic){

s->internal_buffer_count--;

    last = &((InternalBuffer*)s->internal_buffer)[s->internal_buffer_count];

    //last buffer和要释放的buffer交换,使last buffer变成无效buffer,在下次get_buffer时能被申请到。

FFSWAP(InternalBuffer, *buf, *last);

    for(i=0; i<4; i++){

        pic->data[i]=NULL;

    }

}

(3)申请buffer时,检查internal_buffer[internal_buffer_count]的基址是否非空,若非空则直接使用internal_buffer[internal_buffer_count];若空,使用av_malloc()函数进行申请。

这样处理的好处是避免了频繁的调用malloc()free(),从而提升了效率。

avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic){

       ……

       buf= &((InternalBuffer*)s->internal_buffer)[s->internal_buffer_count];

       get_size_info(size[]);

       buf->base[0, 1, 2] = av_malloc(size[0, 1, 2]);

       buf->data[0, 1, 2] = buf->base[0, 1, 2] + padding_offset[0, 1, 2];

       ……

}

(4)决定输出帧是在每帧解码后,根据当前帧的类型和参考信息决定输出帧。

if (s->pict_type == FF_B_TYPE || s->low_delay) {

*pict= *(AVFrame*)s->current_picture_ptr;

} else if (s->last_picture_ptr != NULL) {

*pict= *(AVFrame*)s->last_picture_ptr;

}

3.4举例——假设解码IPBPB的非H.264码流。

(1)初始化后的状态如所示,IBCctx->internal_buffer_countCurPtrs->current_picture_ptrLastPtrs->last_picture_ptrNextPtrs->next_picture_ptr

gpAVPicture指针为输出图像的指针。

3 初始化状态

(2)解码第一个I帧,过程中不会不调用release_buffer()get_buffer()得到picture[0] ,此时不输出任何图像。

4解码第一个I帧后的状态

(3)解码第一个P帧,过程中不调用release_buffer()get_buffer()得到picture[1] ,输出picture[0]

5解码第一个P帧后的状态

(4)解码第一个B帧,过程中不调用release_buffer()get_buffer()得到picture[2] ,输出picture[2]

6解码第一个B帧后的状态

(5)解码第二个P帧,调用release_buffer(&picture[2]),再调用get_buffer(),得到picture[2] 输出picture[1]

7解码第二个P帧的状态

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值