Mercurial > libavcodec.hg
changeset 690:a1c69cb685b3 libavcodec
adaptive quantization (lumi/temporal & spatial complexity masking)
author | michaelni |
---|---|
date | Mon, 23 Sep 2002 14:56:11 +0000 |
parents | efcbfbd18864 |
children | 199b324b2693 |
files | avcodec.h h263.c motion_est.c mpegvideo.c mpegvideo.h ratecontrol.c |
diffstat | 6 files changed, 267 insertions(+), 31 deletions(-) [+] |
line wrap: on
line diff
--- a/avcodec.h Mon Sep 23 08:44:24 2002 +0000 +++ b/avcodec.h Mon Sep 23 14:56:11 2002 +0000 @@ -5,8 +5,8 @@ #define LIBAVCODEC_VERSION_INT 0x000406 #define LIBAVCODEC_VERSION "0.4.6" -#define LIBAVCODEC_BUILD 4624 -#define LIBAVCODEC_BUILD_STR "4624" +#define LIBAVCODEC_BUILD 4625 +#define LIBAVCODEC_BUILD_STR "4625" enum CodecID { CODEC_ID_NONE, @@ -123,6 +123,8 @@ #define CODEC_FLAG_DR1 0x8000 /* direct renderig type 1 (store internal frames in external buffers) */ #define CODEC_FLAG_NOT_TRUNCATED 0x00010000 /* input bitstream is not truncated, except before a startcode allows the last part of a frame to be decoded earlier */ +#define CODEC_FLAG_NORMALIZE_AQP 0x00020000 /* normalize adaptive quantization */ + /* codec capabilities */ #define CODEC_CAP_DRAW_HORIZ_BAND 0x0001 /* decoder can use draw_horiz_band callback */ @@ -174,8 +176,8 @@ * some codecs need / can use extra-data like huffman tables * mjpeg: huffman tables * rv10: additional flags - * encoding: set/allocated/freed by user. - * decoding: set/allocated/freed by lavc. (can be NULL) + * encoding: set/allocated/freed by lavc. + * decoding: set/allocated/freed by user. */ void *extradata; int extradata_size; @@ -285,8 +287,13 @@ uint8_t *mbskip_table; /* encoding parameters */ + /** + * quality (between 1 (good) and 31 (bad)) + * encoding: set by user if CODEC_FLAG_QSCALE is set otherwise set by lavc + * decoding: set by lavc + */ int quality; /* quality of the previous encoded frame - (between 1 (good) and 31 (bad)) + this is allso used to set the quality in vbr mode and the per frame quality in CODEC_FLAG_TYPE (second pass mode) */ float qcompress; /* amount of qscale change between easy & hard scenes (0.0-1.0)*/ @@ -632,6 +639,34 @@ * decoding; set by lavc */ long long int pts; + + /** + * luminance masking (0-> disabled) + * encoding: set by user + * decoding: unused + */ + float lumi_masking; + + /** + * temporary complexity masking (0-> disabled) + * encoding: set by user + * decoding: unused + */ + float temporal_cplx_masking; + + /** + * spatial complexity masking (0-> disabled) + * encoding: set by user + * decoding: unused + */ + float spatial_cplx_masking; + + /** + * p block masking (0-> disabled) + * encoding: set by user + * decoding: unused + */ + float p_masking; //FIXME this should be reordered after kabis API is finished ... //TODO kill kabi
--- a/h263.c Mon Sep 23 08:44:24 2002 +0000 +++ b/h263.c Mon Sep 23 14:56:11 2002 +0000 @@ -31,11 +31,17 @@ #include "h263data.h" #include "mpeg4data.h" +//#undef NDEBUG +//#include <assert.h> + //rounded divison & shift #define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b)) +#if 1 #define PRINT_MB_TYPE(a) {} -//#define PRINT_MB_TYPE(a) printf(a) +#else +#define PRINT_MB_TYPE(a) printf(a) +#endif #define INTRA_MCBPC_VLC_BITS 6 #define INTER_MCBPC_VLC_BITS 6 @@ -298,6 +304,54 @@ return score0 > score1 ? 1 : 0; } +void ff_clean_mpeg4_qscales(MpegEncContext *s){ + int i; + /* more braindead iso mpeg mess */ + + for(i=1; i<s->mb_num; i++){ + if(s->qscale_table[i] - s->qscale_table[i-1] >2) + s->qscale_table[i]= s->qscale_table[i-1]+2; + } + for(i=s->mb_num-2; i>=0; i--){ + if(s->qscale_table[i] - s->qscale_table[i+1] >2) + s->qscale_table[i]= s->qscale_table[i+1]+2; + } + + for(i=1; i<s->mb_num; i++){ + if(s->qscale_table[i] != s->qscale_table[i-1] && (s->mb_type[i]&MB_TYPE_INTER4V)){ + s->mb_type[i]&= ~MB_TYPE_INTER4V; + s->mb_type[i]|= MB_TYPE_INTER; + } + } + + if(s->pict_type== B_TYPE){ + int odd=0; + /* ok, come on, this isnt funny anymore, theres more code for handling this mpeg4 mess than + for the actual adaptive quantization */ + + for(i=0; i<s->mb_num; i++){ + odd += s->qscale_table[i]&1; + } + + if(2*odd > s->mb_num) odd=1; + else odd=0; + + for(i=0; i<s->mb_num; i++){ + if((s->qscale_table[i]&1) != odd) + s->qscale_table[i]++; + if(s->qscale_table[i] > 31) + s->qscale_table[i]= 31; + } + + for(i=1; i<s->mb_num; i++){ + if(s->qscale_table[i] != s->qscale_table[i-1] && (s->mb_type[i]&MB_TYPE_DIRECT)){ + s->mb_type[i]&= ~MB_TYPE_DIRECT; + s->mb_type[i]|= MB_TYPE_BIDIR; + } + } + } +} + void mpeg4_encode_mb(MpegEncContext * s, DCTELEM block[6][64], int motion_x, int motion_y) @@ -308,6 +362,7 @@ PutBitContext * const tex_pb = s->data_partitioning && s->pict_type!=B_TYPE ? &s->tex_pb : &s->pb; PutBitContext * const dc_pb = s->data_partitioning && s->pict_type!=I_TYPE ? &s->pb2 : &s->pb; const int interleaved_stats= (s->flags&CODEC_FLAG_PASS1) && !s->data_partitioning ? 1 : 0; + const int dquant_code[5]= {1,0,9,2,3}; // printf("**mb x=%d y=%d\n", s->mb_x, s->mb_y); if (!s->mb_intra) { @@ -328,20 +383,27 @@ s->last_mv[1][0][0]= s->last_mv[1][0][1]= 0; } + + assert(s->dquant>=-2 && s->dquant<=2); + assert((s->dquant&1)==0); + assert(mb_type>=0); /* nothing to do if this MB was skiped in the next P Frame */ - if(s->mbskip_table[s->mb_y * s->mb_width + s->mb_x]){ + if(s->mbskip_table[s->mb_y * s->mb_width + s->mb_x]){ //FIXME avoid DCT & ... s->skip_count++; s->mv[0][0][0]= s->mv[0][0][1]= s->mv[1][0][0]= s->mv[1][0][1]= 0; s->mv_dir= MV_DIR_FORWARD; //doesnt matter + s->qscale -= s->dquant; return; } if ((cbp | motion_x | motion_y | mb_type) ==0) { /* direct MB with MV={0,0} */ + assert(s->dquant==0); + put_bits(&s->pb, 1, 1); /* mb not coded modb1=1 */ if(interleaved_stats){ @@ -356,8 +418,13 @@ put_bits(&s->pb, mb_type+1, 1); // this table is so simple that we dont need it :) if(cbp) put_bits(&s->pb, 6, cbp); - if(cbp && mb_type) - put_bits(&s->pb, 1, 0); /* no q-scale change */ + if(cbp && mb_type){ + if(s->dquant) + put_bits(&s->pb, 2, (s->dquant>>2)+3); + else + put_bits(&s->pb, 1, 0); + }else + s->qscale -= s->dquant; if(interleaved_stats){ bits= get_bit_count(&s->pb); @@ -421,7 +488,7 @@ s->last_bits=bits; } }else{ /* s->pict_type==B_TYPE */ - if ((cbp | motion_x | motion_y) == 0 && s->mv_type==MV_TYPE_16X16) { + if ((cbp | motion_x | motion_y | s->dquant) == 0 && s->mv_type==MV_TYPE_16X16) { /* check if the B frames can skip it too, as we must skip it if we skip here why didnt they just compress the skip-mb bits instead of reusing them ?! */ if(s->max_b_frames>0){ @@ -470,12 +537,16 @@ put_bits(&s->pb, 1, 0); /* mb coded */ if(s->mv_type==MV_TYPE_16X16){ cbpc = cbp & 3; + if(s->dquant) cbpc+= 8; put_bits(&s->pb, inter_MCBPC_bits[cbpc], inter_MCBPC_code[cbpc]); + cbpy = cbp >> 2; cbpy ^= 0xf; put_bits(pb2, cbpy_tab[cbpy][1], cbpy_tab[cbpy][0]); + if(s->dquant) + put_bits(pb2, 2, dquant_code[s->dquant+2]); if(interleaved_stats){ bits= get_bit_count(&s->pb); @@ -580,10 +651,12 @@ cbpc = cbp & 3; if (s->pict_type == I_TYPE) { + if(s->dquant) cbpc+=4; put_bits(&s->pb, intra_MCBPC_bits[cbpc], intra_MCBPC_code[cbpc]); } else { + if(s->dquant) cbpc+=8; put_bits(&s->pb, 1, 0); /* mb coded */ put_bits(&s->pb, inter_MCBPC_bits[cbpc + 4], @@ -592,6 +665,8 @@ put_bits(pb2, 1, s->ac_pred); cbpy = cbp >> 2; put_bits(pb2, cbpy_tab[cbpy][1], cbpy_tab[cbpy][0]); + if(s->dquant) + put_bits(dc_pb, 2, dquant_code[s->dquant+2]); if(interleaved_stats){ bits= get_bit_count(&s->pb); @@ -963,6 +1038,7 @@ } else if (val >= l) { val -= m; } + assert(val>=-l && val<l); if (val >= 0) { sign = 0;
--- a/motion_est.c Mon Sep 23 08:44:24 2002 +0000 +++ b/motion_est.c Mon Sep 23 14:56:11 2002 +0000 @@ -1142,6 +1142,7 @@ //printf("%d %d %d %X %X %X\n", s->mb_width, mb_x, mb_y,(int)s, (int)s->mb_var, (int)s->mc_mb_var); fflush(stdout); s->mb_var [s->mb_width * mb_y + mb_x] = varc; s->mc_mb_var[s->mb_width * mb_y + mb_x] = vard; + s->mb_mean [s->mb_width * mb_y + mb_x] = (sum+7)>>4; s->mb_var_sum += varc; s->mc_mb_var_sum += vard; //printf("E%d %d %d %X %X %X\n", s->mb_width, mb_x, mb_y,(int)s, (int)s->mb_var, (int)s->mc_mb_var); fflush(stdout);
--- a/mpegvideo.c Mon Sep 23 08:44:24 2002 +0000 +++ b/mpegvideo.c Mon Sep 23 14:56:11 2002 +0000 @@ -207,6 +207,7 @@ CHECKED_ALLOCZ(s->mb_var , s->mb_num * sizeof(INT16)) CHECKED_ALLOCZ(s->mc_mb_var, s->mb_num * sizeof(INT16)) + CHECKED_ALLOCZ(s->mb_mean , s->mb_num * sizeof(INT8)) /* Allocate MV tables */ CHECKED_ALLOCZ(s->p_mv_table , mv_table_size * 2 * sizeof(INT16)) @@ -329,6 +330,7 @@ av_freep(&s->mb_type); av_freep(&s->mb_var); av_freep(&s->mc_mb_var); + av_freep(&s->mb_mean); av_freep(&s->p_mv_table); av_freep(&s->b_forw_mv_table); av_freep(&s->b_back_mv_table); @@ -442,6 +444,12 @@ /* Fixed QSCALE */ s->fixed_qscale = (avctx->flags & CODEC_FLAG_QSCALE); + s->adaptive_quant= ( s->avctx->lumi_masking + || s->avctx->temporal_cplx_masking + || s->avctx->spatial_cplx_masking + || s->avctx->p_masking) + && !s->fixed_qscale; + switch(avctx->codec->id) { case CODEC_ID_MPEG1VIDEO: s->out_format = FMT_MPEG1; @@ -893,7 +901,8 @@ if (s->out_format == FMT_MJPEG) mjpeg_picture_trailer(s); - avctx->quality = s->qscale; + if(!s->fixed_qscale) + avctx->quality = s->qscale; if(s->flags&CODEC_FLAG_PASS1) ff_write_pass1_stats(s); @@ -1753,6 +1762,24 @@ } #endif for(i=0; i<6; i++) skip_dct[i]=0; + + if(s->adaptive_quant){ + s->dquant= s->qscale_table[mb_x + mb_y*s->mb_width] - s->qscale; + if(s->codec_id==CODEC_ID_MPEG4){ + if (s->dquant> 2) s->dquant= 2; + else if(s->dquant<-2) s->dquant=-2; + + if(!s->mb_intra){ + assert(s->dquant==0 || s->mv_type!=MV_TYPE_8X8); + + if(s->mv_dir&MV_DIRECT) + s->dquant=0; + } + } + s->qscale+= s->dquant; + s->y_dc_scale= s->y_dc_scale_table[ s->qscale ]; + s->c_dc_scale= s->c_dc_scale_table[ s->qscale ]; + } if (s->mb_intra) { UINT8 *ptr; @@ -2080,6 +2107,8 @@ ff_set_mpeg4_time(s, s->picture_number); s->scene_change_score=0; + + s->qscale= (int)(s->frame_qscale + 0.5); //FIXME qscale / ... stuff for ME ratedistoration /* Estimate motion for every MB */ if(s->pict_type != I_TYPE){ @@ -2125,7 +2154,8 @@ sum= (sum+8)>>4; varc = (pix_norm1(pix, s->linesize) - sum*sum + 500 + 128)>>8; - s->mb_var[s->mb_width * mb_y + mb_x] = varc; + s->mb_var [s->mb_width * mb_y + mb_x] = varc; + s->mb_mean[s->mb_width * mb_y + mb_x] = (sum+7)>>4; s->mb_var_sum += varc; } } @@ -2154,12 +2184,19 @@ ff_fix_long_b_mvs(s, s->b_bidir_back_mv_table, s->b_code, MB_TYPE_BIDIR); } -//printf("f_code %d ///\n", s->f_code); + if (s->fixed_qscale) + s->frame_qscale = s->avctx->quality; + else + s->frame_qscale = ff_rate_estimate_qscale(s); -// printf("%d %d\n", s->avg_mb_var, s->mc_mb_var); - if (!s->fixed_qscale) - s->qscale = ff_rate_estimate_qscale(s); - + if(s->adaptive_quant && s->codec_id==CODEC_ID_MPEG4) + ff_clean_mpeg4_qscales(s); + + if(s->adaptive_quant) + s->qscale= s->qscale_table[0]; + else + s->qscale= (int)(s->frame_qscale + 0.5); + if (s->out_format == FMT_MJPEG) { /* for mjpeg, we do include qscale in the matrix */ s->intra_matrix[0] = ff_mpeg1_default_intra_matrix[0];
--- a/mpegvideo.h Mon Sep 23 08:44:24 2002 +0000 +++ b/mpegvideo.h Mon Sep 23 14:56:11 2002 +0000 @@ -53,7 +53,7 @@ typedef struct RateControlEntry{ int pict_type; - int qscale; + float qscale; int mv_bits; int i_tex_bits; int p_tex_bits; @@ -188,6 +188,9 @@ int input_pict_type; /* pict_type prior to reordering of frames */ int force_type; /* 0= no force, otherwise I_TYPE, P_TYPE, ... */ int qscale; /* QP */ + float frame_qscale; /* qscale from the frame level rc */ + int adaptive_quant; /* use adaptive quantization */ + int dquant; /* qscale difference to prev qscale */ int pict_type; /* I_TYPE, P_TYPE, B_TYPE, ... */ int last_pict_type; int last_non_b_pict_type; /* used for mpeg4 gmc b-frames & ratecontrol */ @@ -241,13 +244,14 @@ int hurry_up; /* when set to 1 during decoding, b frames will be skiped when set to 2 idct/dequant will be skipped too */ - + /* macroblock layer */ int mb_x, mb_y; int mb_incr; int mb_intra; UINT16 *mb_var; /* Table for MB variances */ UINT16 *mc_mb_var; /* Table for motion compensated MB variances */ + UINT8 *mb_mean; /* Table for MB luminance */ UINT8 *mb_type; /* Table for MB type */ #define MB_TYPE_INTRA 0x01 #define MB_TYPE_INTER 0x02 @@ -582,6 +586,7 @@ void ff_mpeg4_init_partitions(MpegEncContext *s); void ff_mpeg4_merge_partitions(MpegEncContext *s); extern inline int ff_mpeg4_pred_dc(MpegEncContext * s, int n, UINT16 **dc_val_ptr, int *dir_ptr); +void ff_clean_mpeg4_qscales(MpegEncContext *s); /* rv10.c */ void rv10_encode_picture_header(MpegEncContext *s, int picture_number); @@ -611,8 +616,7 @@ /* rate control */ int ff_rate_control_init(MpegEncContext *s); -int ff_rate_estimate_qscale(MpegEncContext *s); -int ff_rate_estimate_qscale_pass2(MpegEncContext *s); +float ff_rate_estimate_qscale(MpegEncContext *s); void ff_write_pass1_stats(MpegEncContext *s); void ff_rate_control_uninit(MpegEncContext *s); double ff_eval(char *s, double *const_value, char **const_name,
--- a/ratecontrol.c Mon Sep 23 08:44:24 2002 +0000 +++ b/ratecontrol.c Mon Sep 23 14:56:11 2002 +0000 @@ -38,9 +38,9 @@ static double get_qscale(MpegEncContext *s, RateControlEntry *rce, double rate_factor, int frame_num); void ff_write_pass1_stats(MpegEncContext *s){ - sprintf(s->avctx->stats_out, "in:%d out:%d type:%d q:%d itex:%d ptex:%d mv:%d misc:%d fcode:%d bcode:%d mc-var:%d var:%d icount:%d;\n", + sprintf(s->avctx->stats_out, "in:%d out:%d type:%d q:%f itex:%d ptex:%d mv:%d misc:%d fcode:%d bcode:%d mc-var:%d var:%d icount:%d;\n", s->picture_number, s->input_picture_number - s->max_b_frames, s->pict_type, - s->qscale, s->i_tex_bits, s->p_tex_bits, s->mv_bits, s->misc_bits, + s->frame_qscale, s->i_tex_bits, s->p_tex_bits, s->mv_bits, s->misc_bits, s->f_code, s->b_code, s->mc_mb_var_sum, s->mb_var_sum, s->i_count); } @@ -105,7 +105,7 @@ assert(picture_number < rcc->num_entries); rce= &rcc->entry[picture_number]; - e+=sscanf(p, " in:%*d out:%*d type:%d q:%d itex:%d ptex:%d mv:%d misc:%d fcode:%d bcode:%d mc-var:%d var:%d icount:%d", + e+=sscanf(p, " in:%*d out:%*d type:%d q:%f itex:%d ptex:%d mv:%d misc:%d fcode:%d bcode:%d mc-var:%d var:%d icount:%d", &rce->pict_type, &rce->qscale, &rce->i_tex_bits, &rce->p_tex_bits, &rce->mv_bits, &rce->misc_bits, &rce->f_code, &rce->b_code, &rce->mc_mb_var_sum, &rce->mb_var_sum, &rce->i_count); if(e!=12){ @@ -433,7 +433,7 @@ q= exp(q); } - + return q; } @@ -462,10 +462,89 @@ p->coeff+= new_coeff; } -int ff_rate_estimate_qscale(MpegEncContext *s) +static void adaptive_quantization(MpegEncContext *s, double q){ + int i; + const float lumi_masking= s->avctx->lumi_masking / (128.0*128.0); + const float temp_cplx_masking= s->avctx->temporal_cplx_masking; + const float spatial_cplx_masking = s->avctx->spatial_cplx_masking; + const float p_masking = s->avctx->p_masking; + float bits_sum= 0.0; + float cplx_sum= 0.0; + float cplx_tab[s->mb_num]; + float bits_tab[s->mb_num]; + const int qmin= 2; //s->avctx->mb_qmin; + const int qmax= 31; //s->avctx->mb_qmax; + + for(i=0; i<s->mb_num; i++){ + float temp_cplx= sqrt(s->mc_mb_var[i]); + float spat_cplx= sqrt(s->mb_var[i]); + const int lumi= s->mb_mean[i]; + float bits, cplx, factor; + + if(spat_cplx < q/3) spat_cplx= q/3; //FIXME finetune + if(temp_cplx < q/3) temp_cplx= q/3; //FIXME finetune + + if((s->mb_type[i]&MB_TYPE_INTRA)){//FIXME hq mode + cplx= spat_cplx; + factor= 1.0 + p_masking; + }else{ + cplx= temp_cplx; + factor= pow(temp_cplx, - temp_cplx_masking); + } + factor*=pow(spat_cplx, - spatial_cplx_masking); + factor*= (1.0 - (lumi-128)*(lumi-128)*lumi_masking); + + if(factor<0.00001) factor= 0.00001; + + bits= cplx*factor; + cplx_sum+= cplx; + bits_sum+= bits; + cplx_tab[i]= cplx; + bits_tab[i]= bits; + } + + /* handle qmin/qmax cliping */ + if(s->flags&CODEC_FLAG_NORMALIZE_AQP){ + for(i=0; i<s->mb_num; i++){ + float newq= q*cplx_tab[i]/bits_tab[i]; + newq*= bits_sum/cplx_sum; + + if (newq > qmax){ + bits_sum -= bits_tab[i]; + cplx_sum -= cplx_tab[i]*q/qmax; + } + else if(newq < qmin){ + bits_sum -= bits_tab[i]; + cplx_sum -= cplx_tab[i]*q/qmin; + } + } + } + + for(i=0; i<s->mb_num; i++){ + float newq= q*cplx_tab[i]/bits_tab[i]; + int intq; + + if(s->flags&CODEC_FLAG_NORMALIZE_AQP){ + newq*= bits_sum/cplx_sum; + } + + if(i && ABS(s->qscale_table[i-1] - newq)<0.75) + intq= s->qscale_table[i-1]; + else + intq= (int)(newq + 0.5); + + if (intq > qmax) intq= qmax; + else if(intq < qmin) intq= qmin; +//if(i%s->mb_width==0) printf("\n"); +//printf("%2d%3d ", intq, ff_sqrt(s->mc_mb_var[i])); + s->qscale_table[i]= intq; + } +} + +float ff_rate_estimate_qscale(MpegEncContext *s) { float q; - int qscale, qmin, qmax; + int qmin, qmax; float br_compensation; double diff; double short_term_q; @@ -581,16 +660,20 @@ // printf("%f %d %d %d\n", q, picture_number, (int)wanted_bits, (int)s->total_bits); //printf("%f %f %f\n", q, br_compensation, short_term_q); - qscale= (int)(q + 0.5); - + //printf("q:%d diff:%d comp:%f st_q:%f last_size:%d type:%d\n", qscale, (int)diff, br_compensation, // short_term_q, s->frame_bits, pict_type); //printf("%d %d\n", s->bit_rate, (int)fps); - rcc->last_qscale= qscale; + if(s->adaptive_quant) + adaptive_quantization(s, q); + else + q= (int)(q + 0.5); + + rcc->last_qscale= q; rcc->last_mc_mb_var_sum= s->mc_mb_var_sum; rcc->last_mb_var_sum= s->mb_var_sum; - return qscale; + return q; } //----------------------------------------------