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的量化可以有三種方式:常量化,使用者自己設定量化矩陣,調用預設的量化矩陣