<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    ffmpeg的內部Video Buffer管理和傳送機制

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    ffmpeg的內部Video Buffer管理和傳送機制

    本文主要介紹ffmpeg解碼器內部管理Video Buffer的原理和過程,ffmpeg的Videobuffer為內部管理,其流程大致為:注冊處理函數->幀級釋放->幀級申請->清空。

    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幀級的內存申請和釋放調用

     

    0_1302927911vOO3

    圖1幀級內存申請和釋放的函數調用

    2.1 FFAPI函數調用libavcodec相應的codec(WMV3對應的Codec是VC1)函數進行解碼,過程中調用內部buffer處理函數。其中buffer管理被統一封裝到Mpegvideo接口中(包括的codec有H.261, H.263, H.264, mpeg12, rv10,rv34, svq1和VC1)

    FFAPI_Decode()

    avcodec_decode_video2()

    avctx->codec->decode()//初始化過程中注冊codec,wmv3的解碼函數是

    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_buffer和release_buffer時均需要對其進行維護。

    –   void *internal_buffer;//初始化為數組InternalBuffer [INTERNAL_BUFFER_SIZE]

    –   ……

    –   } AVCodecContext;

    Codec通過維護internal_buffer_count和internal_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申請和釋放原理

    0_13029279181Joq

    圖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)初始化后的狀態如所示,IBC為ctx->internal_buffer_count,CurPtr為s->current_picture_ptr,LastPtr為s->last_picture_ptr,NextPtr為s->next_picture_ptr。

    gpAVPicture指針為輸出圖像的指針。

     0_1302927929p9BZ

    圖3 初始化狀態

    (2)解碼第一個I幀,過程中不會不調用release_buffer(),get_buffer()得到picture[0] ,此時不輸出任何圖像。

     0_1302927934rV3c

    圖4解碼第一個I幀后的狀態

    (3)解碼第一個P幀,過程中不調用release_buffer(),get_buffer()得到picture[1] ,輸出picture[0]。

     0_13029279382i4T

    圖5解碼第一個P幀后的狀態

    (4)解碼第一個B幀,過程中不調用release_buffer(),get_buffer()得到picture[2] ,輸出picture[2]。

     0_1302927943C7D9

    圖6解碼第一個B幀后的狀態

    (5)解碼第二個P幀,調用release_buffer(&picture[2]),再調用get_buffer(),得到picture[2], 輸出picture[1]。

     0_1302928016IUon

    圖7解碼第二個P幀的狀態

    ref: http://blog.csdn.net/xietao_live_cn/article/details/6327451

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全