天天看點

XVID基本參數解析

            XVID,X264等是MPEG4、H264标準的開源編碼器,其中X264隻有編碼部分,解碼部分需要FFMPEG完成;XVID有編解碼部分,其中解碼亦可以利用FFMPEG中的MPEG4完成解碼。視訊壓縮算法的計算複雜度,都是比較高的。其中具有最大計算複雜度有三部分:宏塊搜素運動補償部分、碼率控制部分、濾波算法部分;這三部分占據了算法複雜度的絕大部分資源。

XVID參數解釋:

參數的設定集中在FFMPEG中的libxvidff.C中的 ff_xvid_encode_init()函數裡面,主要是對編碼上下文進行初始化指派操作,此函數中的宏定義在XVID.H之中:

ff_xvid_encode_init(AVCodecContext *avctx)  {

    int xerr, i;

    int xvid_flags = avctx->flags;

    xvid_context_t *x = avctx->priv_data;

    uint16_t *intra, *inter;

    int fd;

    xvid_plugin_single_t single;

    xvid_ff_pass1_t rc2pass1;

    xvid_plugin_2pass2_t rc2pass2;

    xvid_gbl_init_t xvid_gbl_init;

    xvid_enc_create_t xvid_enc_create;

    xvid_enc_plugin_t plugins[7];

    x->vop_flags = XVID_VOP_HALFPEL; 半像素運動插值

    if( xvid_flags & CODEC_FLAG_4MV )

        x->vop_flags |= XVID_VOP_INTER4V; 每個宏塊配置設定四個運動矢量

    if( xvid_flags & CODEC_FLAG_TRELLIS_QUANT)

        x->vop_flags |= XVID_VOP_TRELLISQUANT;

    if( xvid_flags & CODEC_FLAG_AC_PRED )

        x->vop_flags |= XVID_VOP_HQACPRED;

    x->me_flags = 0;

    switch( avctx->me_method ) { //宏塊搜尋區域,搜尋算法

       case ME_FULL:  

           x->me_flags |=  XVID_ME_EXTSEARCH16

                       |   XVID_ME_EXTSEARCH8;

       case ME_EPZS:  

           x->me_flags |=  XVID_ME_ADVANCEDDIAMOND8

                       |   XVID_ME_HALFPELREFINE8

                       |   XVID_ME_CHROMA_PVOP

                       |   XVID_ME_CHROMA_BVOP;

       case ME_LOG:   

       case ME_PHODS:

       case ME_X1:

           x->me_flags |=  XVID_ME_ADVANCEDDIAMOND16

                       |   XVID_ME_HALFPELREFINE16;

       case ME_ZERO:  

       default:

           break;

    }

    switch( avctx->mb_decision ) { //是否選擇碼率控制方式 avctx->mb_decision=1時,編碼一幀時間迅速增加

       case 2:

           x->vop_flags |= XVID_VOP_MODEDECISION_RD;

           x->me_flags |=  XVID_ME_HALFPELREFINE8_RD

                       |   XVID_ME_QUARTERPELREFINE8_RD

                       |   XVID_ME_EXTSEARCH_RD

                       |   XVID_ME_CHECKPREDICTION_RD;

       case 1:

           if( !(x->vop_flags & XVID_VOP_MODEDECISION_RD) )

               x->vop_flags |= XVID_VOP_FAST_MODEDECISION_RD;

           x->me_flags |=  XVID_ME_HALFPELREFINE16_RD

                       |   XVID_ME_QUARTERPELREFINE16_RD;

       default:

           break;

    }

    x->vol_flags = 0;

    if( xvid_flags & CODEC_FLAG_GMC ) {

        x->vol_flags |= XVID_VOL_GMC;

        x->me_flags |= XVID_ME_GME_REFINE;

    }

    if( xvid_flags & CODEC_FLAG_QPEL ) { //是否允許1/4像素

        x->vol_flags |= XVID_VOL_QUARTERPEL;

        x->me_flags |= XVID_ME_QUARTERPELREFINE16;

        if( x->vop_flags & XVID_VOP_INTER4V )

            x->me_flags |= XVID_ME_QUARTERPELREFINE8;

    }

    memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init));

    xvid_gbl_init.version = XVID_VERSION;

    xvid_gbl_init.debug = 0;

#ifdef ARCH_POWERPC

#if HAVE_ALTIVEC==1

    if( has_altivec() ) {

        xvid_gbl_init.cpu_flags = XVID_CPU_FORCE | XVID_CPU_ALTIVEC;

    } else

#endif

        xvid_gbl_init.cpu_flags = XVID_CPU_FORCE;

#else

    xvid_gbl_init.cpu_flags = 0;

#endif

    xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);

    memset(&xvid_enc_create, 0, sizeof(xvid_enc_create));

    xvid_enc_create.version = XVID_VERSION;

    xvid_enc_create.width = x->xsize = avctx->width; //圖像寬度

    xvid_enc_create.height = x->ysize = avctx->height; //圖像高度

     xvid_enc_create.profile = XVID_PROFILE_S_L3; //  編碼設定檔次和級别 //壓縮級别,MPEG4-ASP最高壓縮級别

    xvid_enc_create.zones = NULL;

    xvid_enc_create.num_zones = 0;

    xvid_enc_create.num_threads = 0;

    xvid_enc_create.plugins = plugins;

    xvid_enc_create.num_plugins = 0;

    x->twopassbuffer = NULL;

    x->old_twopassbuffer = NULL;

    x->twopassfile = NULL;

    if( xvid_flags & CODEC_FLAG_PASS1 ) {

        }

        x->twopassbuffer[0] = x->old_twopassbuffer[0] = 0;

        plugins[xvid_enc_create.num_plugins].func = xvid_ff_2pass;

        plugins[xvid_enc_create.num_plugins].param = &rc2pass1;

        xvid_enc_create.num_plugins++;

    } else if( xvid_flags & CODEC_FLAG_PASS2 ) {//第二次編碼,需要第一次編碼生成的檔案才可以完成第二次編碼,不适用實時編碼

        memset(&rc2pass2, 0, sizeof(xvid_plugin_2pass2_t));

        rc2pass2.version = XVID_VERSION;

        rc2pass2.bitrate = avctx->bit_rate;

        close(fd);

        rc2pass2.filename = x->twopassfile;

        plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2;

        plugins[xvid_enc_create.num_plugins].param = &rc2pass2;

        xvid_enc_create.num_plugins++;

    } else if( !(xvid_flags & CODEC_FLAG_QSCALE) ) {

        memset(&single, 0, sizeof(xvid_plugin_single_t));

        single.version = XVID_VERSION;

        single.bitrate = avctx->bit_rate;

        plugins[xvid_enc_create.num_plugins].func = xvid_plugin_single;

        plugins[xvid_enc_create.num_plugins].param = &single;

        xvid_enc_create.num_plugins++;

    }

    if( 0.0 != avctx->lumi_masking ) {

        plugins[xvid_enc_create.num_plugins].func = xvid_plugin_lumimasking;

        plugins[xvid_enc_create.num_plugins].param = NULL;

        xvid_enc_create.num_plugins++;

    }

    xvid_correct_framerate(avctx);

    xvid_enc_create.fincr = avctx->time_base.num;

    xvid_enc_create.fbase = avctx->time_base.den;

    if( avctx->gop_size > 0 )

        xvid_enc_create.max_key_interval = avctx->gop_size; //圖像組的長度設定

    else

        xvid_enc_create.max_key_interval = 240;

    if( xvid_flags & CODEC_FLAG_QSCALE ) x->qscale = 1; ///encodes[i]->codec.vcc->flags|=CODEC_FLAG_QSCALE; 選擇常量化/ //品質控制=量化參數,1~31,數值越小品質越高

    else x->qscale = 0;

    xvid_enc_create.min_quant[0] = avctx->qmin;

    xvid_enc_create.min_quant[1] = avctx->qmin;

    xvid_enc_create.min_quant[2] = avctx->qmin;

    xvid_enc_create.max_quant[0] = avctx->qmax;

    xvid_enc_create.max_quant[1] = avctx->qmax;

    xvid_enc_create.max_quant[2] = avctx->qmax;

    x->intra_matrix = x->inter_matrix = NULL;

    if( avctx->mpeg_quant ) //允許MPEG量化 量化矩陣

       x->vol_flags |= XVID_VOL_MPEGQUANT;

    if( (avctx->intra_matrix || avctx->inter_matrix) ) { //可以自己設定量化矩陣avctx->intra_matrix,avctx->inter_matrix

       x->vol_flags |= XVID_VOL_MPEGQUANT;

       if( avctx->intra_matrix ) {

           intra = avctx->intra_matrix;

           x->intra_matrix = av_malloc(sizeof(unsigned char) * 64);

       } else

           intra = NULL;

       if( avctx->inter_matrix ) {

           inter = avctx->inter_matrix;

           x->inter_matrix = av_malloc(sizeof(unsigned char) * 64);

       } else

           inter = NULL;

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

           if( intra )

               x->intra_matrix[i] = (unsigned char)intra[i];

           if( inter )

               x->inter_matrix[i] = (unsigned char)inter[i];

       }

    }

    xvid_enc_create.frame_drop_ratio = 0; //丢幀率;0~100

    xvid_enc_create.global = 0;

    if( xvid_flags & CODEC_FLAG_CLOSED_GOP )

        xvid_enc_create.global |= XVID_GLOBAL_CLOSED_GOP;

    avctx->extradata = NULL;

    avctx->extradata_size = 0;

    if( xvid_flags & CODEC_FLAG_GLOBAL_HEADER ) {

        x->quicktime_format = 1;

        avctx->codec_id = CODEC_ID_MPEG4;

    } else {

        x->quicktime_format = 0;

        if(!avctx->codec_tag)

            avctx->codec_tag = ff_get_fourcc("xvid");

    }

    xvid_enc_create.max_bframes = avctx->max_b_frames;

    xvid_enc_create.bquant_offset = 100 * avctx->b_quant_offset;

    xvid_enc_create.bquant_ratio = 100 * avctx->b_quant_factor;

    if( avctx->max_b_frames > 0  && !x->quicktime_format ) xvid_enc_create.global |= XVID_GLOBAL_PACKED;

    xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL); //建立編碼上下文

    if( xerr ) {

        av_log(avctx, AV_LOG_ERROR, "XviD: Could not create encoder reference\n");

        return -1;

    }

    x->encoder_handle = xvid_enc_create.handle;

    avctx->coded_frame = &x->encoded_picture;

    return 0;

}

int ff_xvid_encode_frame(AVCodecContext *avctx,

                         unsigned char *frame, int buf_size, void *data) { 開始編碼一幀

 xerr = xvid_encore(x->encoder_handle, XVID_ENC_ENCODE,

        &xvid_enc_frame, &xvid_enc_stats); //開始編碼一幀

XVID的量化可以有三種方式:常量化,使用者自己設定量化矩陣,調用預設的量化矩陣

繼續閱讀