--- plugin_single.c 2003/10/01 23:23:01 1.1.2.5 +++ plugin_single.c 2010/03/09 10:00:14 1.4 @@ -1,9 +1,9 @@ /***************************************************************************** * - * XviD Standard Plugins + * Xvid Standard Plugins * - single-pass bitrate controller implementation - * - * Copyright(C) 2002 Benjamin Lambert + * Copyright(C) 2002-2004 Benjamin Lambert * 2002-2003 Edouard Gomez * * This program is free software; you can redistribute it and/or modify @@ -20,7 +20,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: plugin_single.c,v 1.1.2.5 2003/10/01 23:23:01 edgomez Exp $ + * $Id: plugin_single.c,v 1.4 2010/03/09 10:00:14 Isibaar Exp $ * ****************************************************************************/ @@ -54,7 +54,7 @@ double avg_framesize; double quant_error[31]; - double fq_error; + double fq_error; } rc_single_t; @@ -64,7 +64,7 @@ { #if defined(DEFAULT_INITIAL_QUANTIZER) - return (DEFAULT_INITIAL_QUANTIZER); + return (DEFAULT_INITIAL_QUANTIZER); #else int i; @@ -120,7 +120,7 @@ rc->sequence_quality = 2.0 / (double) rc->rtn_quant; rc->avg_framesize = rc->target_framesize; - rc->fq_error = 0; + rc->fq_error = 0; /* Bind the RC */ *handle = rc; @@ -147,15 +147,24 @@ rc_single_before(rc_single_t * rc, xvid_plg_data_t * data) { - if (data->quant <= 0) { - if (data->zone && data->zone->mode == XVID_ZONE_QUANT) { - rc->fq_error += (double)data->zone->increment / (double)data->zone->base; - data->quant = (int)rc->fq_error; - rc->fq_error -= data->quant; - }else { - data->quant = rc->rtn_quant; - } - } + if (data->quant <= 0) { + if (data->zone && data->zone->mode == XVID_ZONE_QUANT) { + rc->fq_error += (double)data->zone->increment / (double)data->zone->base; + data->quant = (int)rc->fq_error; + rc->fq_error -= data->quant; + } else { + int q = rc->rtn_quant; + /* limit to min/max range + we don't know frame type of the next frame, so we just use + P-VOP's range... */ + if (q > data->max_quant[XVID_TYPE_PVOP-1]) + q = data->max_quant[XVID_TYPE_PVOP-1]; + else if (q < data->min_quant[XVID_TYPE_PVOP-1]) + q = data->min_quant[XVID_TYPE_PVOP-1]; + + data->quant = q; + } + } return 0; } @@ -177,40 +186,50 @@ rc->time += (double) data->fincr / data->fbase; rc->total_size += data->length; - if(data->type == XVID_TYPE_BVOP) - return (0); - - rc->rtn_quant = data->quant; - /* Compute the deviation from expected total size */ - deviation = (int64_t) - ((double) rc->total_size - (double) rc->bytes_per_sec * rc->time); - - - if (data->quant >= 2) { - - averaging_period = (double) rc->averaging_period; + deviation = + rc->total_size - rc->bytes_per_sec * rc->time; - rc->sequence_quality -= rc->sequence_quality / averaging_period; + averaging_period = (double) rc->averaging_period; - rc->sequence_quality += - 2.0 / (double) data->quant / averaging_period; - - if (rc->sequence_quality < 0.1) - rc->sequence_quality = 0.1; - - if (data->type != XVID_TYPE_IVOP) { - reaction_delay_factor = (double) rc->reaction_delay_factor; - rc->avg_framesize -= rc->avg_framesize / reaction_delay_factor; - rc->avg_framesize += data->length / reaction_delay_factor; - } + /* calculate the sequence quality */ + rc->sequence_quality -= rc->sequence_quality / averaging_period; + rc->sequence_quality += + 2.0 / (double) data->quant / averaging_period; + + /* clamp the sequence quality to 10% to 100% + * to try to avoid using the highest + * and lowest quantizers 'too' much */ + if (rc->sequence_quality < 0.1) + rc->sequence_quality = 0.1; + else if (rc->sequence_quality > 1.0) + rc->sequence_quality = 1.0; + + /* factor this frame's size into the average framesize + * but skip using ivops as they are usually very large + * and as such, usually disrupt quantizer distribution */ + if (data->type != XVID_TYPE_IVOP) { + reaction_delay_factor = (double) rc->reaction_delay_factor; + rc->avg_framesize -= rc->avg_framesize / reaction_delay_factor; + rc->avg_framesize += data->length / reaction_delay_factor; } + /* don't change the quantizer between pvops */ + if (data->type == XVID_TYPE_BVOP) + return (0); + + /* calculate the quality_scale which will be used + * to drag the target quality up or down, depending + * on if avg_framesize is >= target_framesize */ quality_scale = - rc->target_framesize / rc->avg_framesize * rc->target_framesize / - rc->avg_framesize; + rc->target_framesize / rc->avg_framesize * + rc->target_framesize / rc->avg_framesize; + /* use the current sequence_quality as the + * base_quality which will be dragged around + * + * 0.06452 = 6.452% quality (quant:31) */ base_quality = rc->sequence_quality; if (quality_scale >= 1.0) { base_quality = 1.0 - (1.0 - base_quality) / quality_scale; @@ -220,10 +239,20 @@ overflow = -((double) deviation / (double) rc->buffer); + /* clamp overflow to 1 buffer unit to avoid very + * large bursts of bitrate following still scenes */ + if (overflow > rc->target_framesize) + overflow = rc->target_framesize; + else if (overflow < -rc->target_framesize) + overflow = -rc->target_framesize; + + /* apply overflow / buffer to get the target_quality */ target_quality = base_quality + (base_quality - 0.06452) * overflow / rc->target_framesize; + /* clamp the target_quality to quant 1-31 + * 2.0 = 200% quality (quant:1) */ if (target_quality > 2.0) target_quality = 2.0; else if (target_quality < 0.06452) @@ -231,25 +260,35 @@ rtn_quant = (int) (2.0 / target_quality); + /* accumulate quant <-> quality error and apply if >= 1.0 */ if (rtn_quant > 0 && rtn_quant < 31) { rc->quant_error[rtn_quant - 1] += 2.0 / target_quality - rtn_quant; if (rc->quant_error[rtn_quant - 1] >= 1.0) { rc->quant_error[rtn_quant - 1] -= 1.0; rtn_quant++; + rc->rtn_quant++; } } - /* prevent rapid quantization change */ - if (rtn_quant > data->quant + 1) - rtn_quant = data->quant + 1; - else if (rtn_quant < data->quant - 1) - rtn_quant = data->quant - 1; - - /* limit to min/max range */ - if (rtn_quant > data->max_quant[data->type-1]) - rtn_quant = data->max_quant[data->type-1]; - else if (rtn_quant < data->min_quant[data->type-1]) - rtn_quant = data->min_quant[data->type-1]; + /* prevent rapid quantization change */ + if (rtn_quant > rc->rtn_quant + 1) { + if (rtn_quant > rc->rtn_quant + 3) + if (rtn_quant > rc->rtn_quant + 5) + rtn_quant = rc->rtn_quant + 3; + else + rtn_quant = rc->rtn_quant + 2; + else + rtn_quant = rc->rtn_quant + 1; + } + else if (rtn_quant < rc->rtn_quant - 1) { + if (rtn_quant < rc->rtn_quant - 3) + if (rtn_quant < rc->rtn_quant - 5) + rtn_quant = rc->rtn_quant - 3; + else + rtn_quant = rc->rtn_quant - 2; + else + rtn_quant = rc->rtn_quant - 1; + } rc->rtn_quant = rtn_quant; @@ -266,6 +305,7 @@ { switch (opt) { case XVID_PLG_INFO: + case XVID_PLG_FRAME : return 0; case XVID_PLG_CREATE: