[xiph-commits] r16498 - trunk/theora/lib
tterribe at svn.xiph.org
tterribe at svn.xiph.org
Sat Aug 22 08:50:29 PDT 2009
Author: tterribe
Date: 2009-08-22 08:50:28 -0700 (Sat, 22 Aug 2009)
New Revision: 16498
Modified:
trunk/theora/lib/encint.h
trunk/theora/lib/rate.c
Log:
More rate control tweaks.
1) Use a smaller time constant for the Bessel filters at the start of a
sequence, slowly increasing them to the desired level, to avoid catastrophic
failure in the case that the first frame metrics are completely off (e.g., in
a fade-in from black).
2) Don't add prediction corrections for the virtual padding frames added at the
end of a 2-pass sequence.
Modified: trunk/theora/lib/encint.h
===================================================================
--- trunk/theora/lib/encint.h 2009-08-22 10:03:45 UTC (rev 16497)
+++ trunk/theora/lib/encint.h 2009-08-22 15:50:28 UTC (rev 16498)
@@ -231,6 +231,9 @@
unsigned char cap_underflow;
/*Second-order lowpass filters to track scale and VFR.*/
oc_iir_filter scalefilter[2];
+ int inter_count;
+ int inter_delay;
+ int inter_delay_target;
oc_iir_filter vfrfilter;
/*Two-pass mode state.
0 => 1-pass encoding.
Modified: trunk/theora/lib/rate.c
===================================================================
--- trunk/theora/lib/rate.c 2009-08-22 10:03:45 UTC (rev 16497)
+++ trunk/theora/lib/rate.c 2009-08-22 15:50:28 UTC (rev 16498)
@@ -45,10 +45,14 @@
return (int)(((ogg_int64_t)t0<<32)+(t1-t0<<8)*(ogg_int64_t)d>>32);
}
-/*Initialize a 2nd order low-pass Bessel filter with the corresponding delay
- and initial value.
- _value is Q24.*/
-void oc_iir_filter_init(oc_iir_filter *_f,int _delay,ogg_int32_t _value){
+/*Re-initialize the Bessel filter coefficients with the specified delay.
+ This does not alter the x/y state, but changes the reaction time of the
+ filter.
+ Altering the time constant of a reactive filter without alterning internal
+ state is something that has to be done carefuly, but our design operates at
+ high enough delays and with small enough time constant changes to make it
+ safe.*/
+static void oc_iir_filter_reinit(oc_iir_filter *_f,int _delay){
int alpha;
ogg_int64_t one48;
ogg_int64_t warp;
@@ -85,6 +89,13 @@
_f->c[0]=(ogg_int32_t)(b1+((ogg_int64_t)1<<31)>>32);
_f->c[1]=(ogg_int32_t)(b2+((ogg_int64_t)1<<31)>>32);
_f->g=(ogg_int32_t)(a+128>>8);
+}
+
+/*Initialize a 2nd order low-pass Bessel filter with the corresponding delay
+ and initial value.
+ _value is Q24.*/
+static void oc_iir_filter_init(oc_iir_filter *_f,int _delay,ogg_int32_t _value){
+ oc_iir_filter_reinit(_f,_delay);
_f->y[1]=_f->y[0]=_f->x[1]=_f->x[0]=_value;
}
@@ -288,13 +299,19 @@
_enc->rc.log_drop_scale=OC_Q57(0);
/*Set up second order followers, initialized according to corresponding
time constants.*/
- oc_iir_filter_init(&_enc->rc.scalefilter[0],2,
+ oc_iir_filter_init(&_enc->rc.scalefilter[0],4,
oc_q57_to_q24(_enc->rc.log_scale[0]));
- inter_delay=_enc->rc.twopass?
- OC_MAXI(_enc->keyframe_frequency_force,12):_enc->rc.buf_delay;
- oc_iir_filter_init(&_enc->rc.scalefilter[1],inter_delay>>1,
+ inter_delay=(_enc->rc.twopass?
+ OC_MAXI(_enc->keyframe_frequency_force,12):_enc->rc.buf_delay)>>1;
+ _enc->rc.inter_count=0;
+ /*We clamp the actual inter_delay to a minimum of 10 to work within the range
+ of values where later incrementing the delay works as designed.
+ 10 is not an exact choice, but rather a good working trade-off.*/
+ _enc->rc.inter_delay=10;
+ _enc->rc.inter_delay_target=inter_delay;
+ oc_iir_filter_init(&_enc->rc.scalefilter[1],_enc->rc.inter_delay,
oc_q57_to_q24(_enc->rc.log_scale[1]));
- oc_iir_filter_init(&_enc->rc.vfrfilter,2,
+ oc_iir_filter_init(&_enc->rc.vfrfilter,4,
oc_bexp64_q24(_enc->rc.log_drop_scale));
}
@@ -329,6 +346,7 @@
/*If encoding has not yet begun, reset the buffer state.*/
if(_enc->state.curframe_num<0)oc_enc_rc_reset(_enc);
else{
+ int idt;
/*Otherwise, update the bounds on the buffer, but not the current
fullness.*/
_enc->rc.bits_per_frame=(_enc->state.info.target_bitrate*
@@ -344,8 +362,15 @@
_enc->rc.max=_enc->rc.bits_per_frame*_enc->rc.buf_delay;
_enc->rc.target=(_enc->rc.max+1>>1)+(_enc->rc.bits_per_frame+2>>2)*
OC_MINI(_enc->keyframe_frequency_force,_enc->rc.buf_delay);
- oc_iir_filter_init(&_enc->rc.scalefilter[1],_enc->rc.buf_delay>>1,
- oc_q57_to_q24(_enc->rc.log_scale[1]));
+ /*Update the INTER-frame scale filter delay.
+ We jump to it immediately if we've already seen enough frames; otherwise
+ it is simply set as the new target.*/
+ _enc->rc.inter_delay_target=idt=OC_MAXI(_enc->rc.buf_delay>>1,10);
+ if(idt<OC_MINI(_enc->rc.inter_delay,_enc->rc.inter_count)){
+ oc_iir_filter_init(&_enc->rc.scalefilter[1],idt,
+ _enc->rc.scalefilter[1].y[0]);
+ _enc->rc.inter_delay=idt;
+ }
}
/*If we're in pass-2 mode, make sure the frame metrics array is big enough
to hold frame statistics for the full buffer.*/
@@ -440,6 +465,7 @@
ogg_int64_t rate_bias;
int nframes[2];
int buf_delay;
+ int buf_pad;
ogg_int64_t log_qtarget;
ogg_int64_t log_scale0;
ogg_int64_t log_cur_scale;
@@ -447,11 +473,11 @@
int exp0;
int old_qi;
int qi;
- oc_restore_fpu(&_enc->state);
/*Figure out how to re-distribute bits so that we hit our fullness target
before the last keyframe in our current buffer window (after the current
frame), or the end of the buffer window, whichever comes first.*/
log_cur_scale=(ogg_int64_t)_enc->rc.scalefilter[_qti].y[0]<<33;
+ buf_pad=0;
switch(_enc->rc.twopass){
default:{
ogg_uint32_t next_key_frame;
@@ -480,7 +506,6 @@
case 2:{
ogg_int64_t scale_sum[2];
int qti;
- int buf_pad;
/*Pass 2 mode: we know exactly how much of each frame type there is in
the current buffer window, and have estimates for the scales.*/
nframes[0]=_enc->rc.nframes[0];
@@ -593,7 +618,8 @@
}break;
}
/*If we've been missing our target, add a penalty term.*/
- rate_bias=(_enc->rc.rate_bias/(_enc->state.curframe_num+1000))*buf_delay;
+ rate_bias=(_enc->rc.rate_bias/(_enc->state.curframe_num+1000))*
+ (buf_delay-buf_pad);
/*rate_total is the total bits available over the next buf_delay frames.*/
rate_total=_enc->rc.fullness-_enc->rc.target+rate_bias
+buf_delay*_enc->rc.bits_per_frame;
@@ -780,6 +806,12 @@
_enc->rc.log_scale[_qti]=log_scale;
}
else{
+ /*Lengthen the time constant for the INTER filter as we collect more
+ frame statistics, until we reach our target.*/
+ if(_enc->rc.inter_delay<_enc->rc.inter_delay_target&&
+ _enc->rc.inter_count>=_enc->rc.inter_delay&&_qti==OC_INTER_FRAME){
+ oc_iir_filter_reinit(&_enc->rc.scalefilter[1],++_enc->rc.inter_delay);
+ }
/*Otherwise update the low-pass scale filter for this frame type,
regardless of whether or not we dropped this frame.*/
_enc->rc.log_scale[_qti]=oc_iir_filter_update(
@@ -807,6 +839,8 @@
_enc->rc.prev_drop_count=_enc->dup_count;
}
}
+ /*Increment the INTER frame count, for filter adaptation purposes.*/
+ if(_enc->rc.inter_count<INT_MAX)_enc->rc.inter_count+=_qti;
}
/*Increase the drop count.*/
else _enc->rc.prev_drop_count+=1+_enc->dup_count;
More information about the commits
mailing list