[xiph-commits] r16334 - in branches/theora-thusnelda: examples include/theora lib/dec lib/enc

tterribe at svn.xiph.org tterribe at svn.xiph.org
Sat Jul 25 12:27:31 PDT 2009


Author: tterribe
Date: 2009-07-25 12:27:31 -0700 (Sat, 25 Jul 2009)
New Revision: 16334

Modified:
   branches/theora-thusnelda/examples/encoder_example.c
   branches/theora-thusnelda/include/theora/codec.h
   branches/theora-thusnelda/include/theora/theoraenc.h
   branches/theora-thusnelda/lib/dec/decode.c
   branches/theora-thusnelda/lib/enc/encint.h
   branches/theora-thusnelda/lib/enc/encode.c
   branches/theora-thusnelda/lib/enc/rate.c
Log:
Rate control enhancements.
Enable hard frame dropping, and replace the exponential moving averages in the
 rate control with a 2nd order Bessel filter.
The Bessel filter is both reactive and critically damped, and provides a much
 smoother quality level, while still maintaining accurate bit usage.
Also adds encoder ctl's to enable or disable frame dropping, overflow/underflow
 accounting, and to set the buffer size.


Modified: branches/theora-thusnelda/examples/encoder_example.c
===================================================================
--- branches/theora-thusnelda/examples/encoder_example.c	2009-07-24 10:44:55 UTC (rev 16333)
+++ branches/theora-thusnelda/examples/encoder_example.c	2009-07-25 19:27:31 UTC (rev 16334)
@@ -61,7 +61,7 @@
 }
 #endif
 
-const char *optstring = "b:e:o:a:A:v:V:s:S:f:F:ck:";
+const char *optstring = "b:e:o:a:A:v:V:s:S:f:F:ck:\1";
 struct option options [] = {
   {"begin-time",required_argument,NULL,'b'},
   {"end-time",required_argument,NULL,'e'},
@@ -75,6 +75,7 @@
   {"framerate-numerator",required_argument,NULL,'f'},
   {"framerate-denominator",required_argument,NULL,'F'},
   {"vp3-compatible",no_argument,NULL,'c'},
+  {"soft-target",no_argument,NULL,'\1'},
   {"keyframe-freq",required_argument,NULL,'k'},
   {NULL,0,NULL,0}
 };
@@ -123,7 +124,7 @@
 y4m_convert_func y4m_convert=NULL;
 
 int video_r=-1;
-int video_q=48;
+int video_q=-1;
 ogg_uint32_t keyframe_frequency=64;
 
 long begin_sec=-1;
@@ -143,6 +144,12 @@
           "                                  as -a gives higher quality for a given\n"
           "                                  bitrate.\n\n"
           "  -V --video-rate-target <n>      bitrate target for Theora video\n\n"
+          "     --soft-target                Use a large reservoir and treat the rate\n"
+          "                                  as a soft target; rate control is less\n"
+          "                                  strict but resulting quality is usually\n"
+          "                                  higher/smoother overall. Soft target also\n"
+          "                                  allows an optional -v setting to specify\n"
+          "                                  a minimum allowed quality.\n\n"
           "  -a --audio-quality <n>          Vorbis quality selector from -1 to 10\n"
           "                                  (-1 yields smallest files but lowest\n"
           "                                  fidelity; 10 yields highest fidelity\n"
@@ -1137,6 +1144,7 @@
   int videoflag=0;
   int akbps=0;
   int vkbps=0;
+  int soft_target=0;
 
   ogg_int64_t audio_bytesout=0;
   ogg_int64_t video_bytesout=0;
@@ -1178,7 +1186,6 @@
         fprintf(stderr,"Illegal video quality (choose 0 through 10)\n");
         exit(1);
       }
-      video_r=0;
       break;
 
     case 'A':
@@ -1196,9 +1203,12 @@
         fprintf(stderr,"Illegal video bitrate (choose > 0 please)\n");
         exit(1);
       }
-      video_q=0;
      break;
 
+    case '\1':
+      soft_target=1;
+      break;
+
     case 's':
       video_par_n=(int)rint(atof(optarg));
       break;
@@ -1283,6 +1293,20 @@
     }
   }
 
+  if(soft_target){
+    if(video_r<=0){
+      fprintf(stderr,"Soft rate target (--soft-tagret) requested without a bitrate (-V).\n");
+      exit(1);
+    }
+    if(video_q==-1)
+      video_q=0;
+  }else{
+    if(video_r>0)
+      video_q=0;
+    if(video_q==-1)
+      video_q=48;
+  }
+
   while(optind<argc){
     /* assume that anything following the options must be a filename */
     id_file(argv[optind]);
@@ -1358,6 +1382,22 @@
     }
   }
 
+  if(soft_target){
+    /* reverse the rate control flags to favor a 'long time' strategy */
+    int arg = TH_RATECTL_CAP_UNDERFLOW;
+    ret=th_encode_ctl(td,TH_ENCCTL_SET_RATE_FLAGS,&arg,sizeof(arg));
+    if(ret<0)
+      fprintf(stderr,"Could not set encoder flags for --soft-target\n");
+
+    if((keyframe_frequency*7>>1) > 5*video_fps_n/video_fps_d)
+      arg=keyframe_frequency*7>>1;
+    else
+      arg=30*video_fps_n/video_fps_d;
+    ret=th_encode_ctl(td,TH_ENCCTL_SET_RATE_BUFFER,&arg,sizeof(arg));
+    if(ret<0)
+      fprintf(stderr,"Could not set rate control buffer for --soft-target\n");
+  }
+
   /* initialize Vorbis too, assuming we have audio to compress. */
   if(audio){
     vorbis_info_init(&vi);

Modified: branches/theora-thusnelda/include/theora/codec.h
===================================================================
--- branches/theora-thusnelda/include/theora/codec.h	2009-07-24 10:44:55 UTC (rev 16333)
+++ branches/theora-thusnelda/include/theora/codec.h	2009-07-25 19:27:31 UTC (rev 16334)
@@ -259,9 +259,6 @@
   /**The target bit-rate in bits per second.
      If initializing an encoder with this struct, set this field to a non-zero
       value to activate CBR encoding by default.*/
-  /*TODO: Current encoder does not support CBR mode, or anything like it.
-    We also don't really know what nominal rate each quality level
-     corresponds to yet.*/
   int           target_bitrate;
   /**The target quality level.
      Valid values range from 0 to 63, inclusive, with higher values giving

Modified: branches/theora-thusnelda/include/theora/theoraenc.h
===================================================================
--- branches/theora-thusnelda/include/theora/theoraenc.h	2009-07-24 10:44:55 UTC (rev 16333)
+++ branches/theora-thusnelda/include/theora/theoraenc.h	2009-07-25 19:27:31 UTC (rev 16334)
@@ -85,8 +85,8 @@
 #define TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE (4)
 /**Disables any encoder features that would prevent lossless transcoding back
  *  to VP3.
- * This primarily means disabling block-level QI values and not using 4MV mode
- *  when any of the luma blocks in a macro block are not coded.
+ * This primarily means disabling block-adaptive quantization and always coding
+ *  all four luma blocks in a macro block when 4MV is used.
  * It also includes using the VP3 quantization tables and Huffman codes; if you
  *  set them explicitly after calling this function, the resulting stream will
  *  not be VP3-compatible.
@@ -117,9 +117,9 @@
  *  may actually improve, but in this case bitrate will also likely increase.
  * In any case, overall rate/distortion performance will probably decrease.
  * The maximum value, and the meaning of each value, may change depending on
- *  the current encoding mode (VBR vs. CQI, etc.).
+ *  the current encoding mode (VBR vs. constant quality, etc.).
  *
- * \param[out] _buf int: The maximum encoding speed level.
+ * \param[out] _buf <tt>int</tt>: The maximum encoding speed level.
  * \retval TH_EFAULT \a _enc_ctx or \a _buf is <tt>NULL</tt>.
  * \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>.
  * \retval TH_IMPL   Not supported by this implementation in the current
@@ -128,8 +128,8 @@
 /**Sets the speed level.
  * By default, the slowest speed (0) is used.
  *
- * \param[in] _buf int: The new encoding speed level.
- *                      0 is slowest, larger values use less CPU.
+ * \param[in] _buf <tt>int</tt>: The new encoding speed level.
+ *                 0 is slowest, larger values use less CPU.
  * \retval TH_EFAULT \a _enc_ctx or \a _buf is <tt>NULL</tt>.
  * \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>, or the
  *                    encoding speed level is out of bounds.
@@ -146,14 +146,14 @@
  * This control code tells the encoder to produce the specified number of extra
  *  duplicates of the next frame.
  * This allows the encoder to make smarter keyframe placement decisions and
- *  rate control decisions, as well as reduces CPU usage, when compared to just
- *  submitting the same frame for encoding multiple times.
+ *  rate control decisions, and reduces CPU usage as well, when compared to
+ *  just submitting the same frame for encoding multiple times.
  * This setting only applies to the next frame submitted for encoding.
  * You MUST call th_encode_packetout() repeatedly until it returns 0, or the
  *  extra duplicate frames will be lost.
  *
- * \param[in] _buf int: The number of duplicates to produce.
- *                      Unless this is positive, no duplicates will be produced.
+ * \param[in] _buf <tt>int</tt>: The number of duplicates to produce.
+ *                 If this is negative or zero, no duplicates will be produced.
  * \retval TH_EFAULT \a _enc_ctx or \a _buf is <tt>NULL</tt>.
  * \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>, or the
  *                    number of duplicates is greater than or equal to the
@@ -165,10 +165,81 @@
  * \retval TH_IMPL   Not supported by this implementation in the current
  *                    encoding mode.*/
 #define TH_ENCCTL_SET_DUP_COUNT (18)
+/**Modifies the default bitrate management behavior.
+ * Use to allow or disallow frame dropping, and to enable or disable capping
+ *  bit reservoir overflows and underflows.
+ * See \ref encctlcodes "the list of available flags".
+ * The flags are set by default to
+ *  <tt>#TH_RATECTL_DROP_FRAMES|#TH_RATECTL_CAP_OVERFLOW</tt>.
+ *
+ * \param[in] _buf <tt>int</tt>: Any combination of
+ *                  \ref ratectlflags "the available flags":
+ *                 - #TH_RATECTL_DROP_FRAMES: Enable frame dropping.
+ *                 - #TH_RATECTL_CAP_OVERFLOW: Don't bank excess bits for later
+ *                    use.
+ *                 - #TH_RATECTL_CAP_UNDERFLOW: Don't try to make up shortfalls
+ *                    later.
+ * \retval TH_EFAULT \a _enc_ctx or \a _buf is <tt>NULL</tt>.
+ * \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt> or rate control
+ *                    is not enabled.
+ * \retval TH_IMPL   Not supported by this implementation in the current
+ *                    encoding mode.*/
+#define TH_ENCCTL_SET_RATE_FLAGS (20)
+/**Sets the size of the bitrate management bit reservoir as a function
+ *  of number of frames.
+ * The reservoir size affects how quickly bitrate management reacts to
+ *  instantaneous changes in the video complexity.
+ * Larger reservoirs react more slowly, and provide better overall quality, but
+ *  require more buffering by a client, adding more latency to live streams.
+ * By default, libtheora sets the reservoir to the maximum distance between
+ *  keyframes, subject to a minimum and maximum limit.
+ * This call may be used to increase or decrease the reservoir, increasing or
+ *  decreasing the allowed temporary variance in bitrate.
+ * An implementation may impose some limits on the size of a reservoir it can
+ *  handle, in which case the actual reservoir size may not be exactly what was
+ *  requested.
+ * The actual value set will be returned.
+ *
+ * \param[in] _buf  <tt>int</tt>: Requested size of the reservoir measured in
+ *                   frames.
+ * \param[out] _buf <tt>int</tt>: The actual size of the reservoir set.
+ * \retval TH_EFAULT \a _enc_ctx or \a _buf is <tt>NULL</tt>.
+ * \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>, or rate control
+ *                    is not enabled.  The buffer has an implementation
+ *                    defined minimum and maximum size and the value in _buf
+ *                    will be adjusted to match the actual value set.
+ * \retval TH_IMPL   Not supported by this implementation in the current
+ *                    encoding mode.*/
+#define TH_ENCCTL_SET_RATE_BUFFER (22)
 /*@}*/
 
 
+/**\name TH_ENCCTL_SET_RATE_FLAGS flags
+ * \anchor ratectlflags
+ * These are the flags available for use with #TH_ENCCTL_SET_RATE_FLAGS.*/
+/*@{*/
+/**Drop frames to keep within bitrate buffer constraints.
+ * This can have a severe impact on quality, but is the only way to ensure that
+ *  bitrate targets are met at low rates during sudden bursts of activity.*/
+#define TH_RATECTL_DROP_FRAMES   (0x1)
+/**Ignore bitrate buffer overflows.
+ * If the encoder uses so few bits that the reservoir of available bits
+ *  overflows, ignore the excess.
+ * The encoder will not try to use these extra bits in future frames.
+ * At high rates this may cause the result to be undersized, but allows a
+ *  client to play the stream using a finite buffer; it should normally be
+ *  enabled.*/
+#define TH_RATECTL_CAP_OVERFLOW  (0x2)
+/**Ignore bitrate buffer underflows.
+ * If the encoder uses so many bits that the reservoir of available bits
+ *  underflows, ignore the deficit.
+ * The encoder will not try to make up these extra bits in future frames.
+ * At low rates this may cause the result to be oversized; it should normally
+ *  be disabled.*/
+#define TH_RATECTL_CAP_UNDERFLOW (0x4)
+/*@}*/
 
+
 /**The quantization parameters used by VP3.*/
 extern const th_quant_info TH_VP31_QUANT_INFO;
 

Modified: branches/theora-thusnelda/lib/dec/decode.c
===================================================================
--- branches/theora-thusnelda/lib/dec/decode.c	2009-07-24 10:44:55 UTC (rev 16333)
+++ branches/theora-thusnelda/lib/dec/decode.c	2009-07-25 19:27:31 UTC (rev 16334)
@@ -1555,7 +1555,10 @@
       else{
         int ebflag;
         token=dct_tokens[ti[zzi]++];
-        ebflag=OC_DCT_TOKEN_EXTRA_BITS[token]!=0;
+        /*This is equivalent to
+            ebflag=OC_DCT_TOKEN_EXTRA_BITS[token]!=0;
+           but should be simpler on platforms that can use 16-bit immediates.*/
+        ebflag=-0x1E08>>token&1;
         eb=extra_bits[ebi[zzi]]&-ebflag;
         ebi[zzi]+=ebflag;
         if(token<OC_NDCT_EOB_TOKEN_MAX){

Modified: branches/theora-thusnelda/lib/enc/encint.h
===================================================================
--- branches/theora-thusnelda/lib/enc/encint.h	2009-07-24 10:44:55 UTC (rev 16333)
+++ branches/theora-thusnelda/lib/enc/encint.h	2009-07-25 19:27:31 UTC (rev 16334)
@@ -34,6 +34,7 @@
 typedef struct oc_enc_opt_vtable      oc_enc_opt_vtable;
 typedef struct oc_mb_enc_info         oc_mb_enc_info;
 typedef struct oc_mode_scheme_chooser oc_mode_scheme_chooser;
+typedef struct oc_iir_filter          oc_iir_filter;
 typedef struct oc_rc_state            oc_rc_state;
 typedef struct th_enc_ctx             oc_enc_ctx;
 typedef struct oc_token_checkpoint    oc_token_checkpoint;
@@ -160,40 +161,60 @@
 
 
 
+/*A 2nd order low-pass Bessel follower.
+  We use this for rate control because it has fast reaction time, but is
+   critically damped.*/
+struct oc_iir_filter{
+  ogg_int32_t c[2];
+  ogg_int64_t g;
+  ogg_int32_t x[2];
+  ogg_int32_t y[2];
+};
+
 /*Rate control state information.*/
 struct oc_rc_state{
   /*The target average bits per frame.*/
-  ogg_int64_t  bits_per_frame;
+  ogg_int64_t     bits_per_frame;
   /*The current buffer fullness (bits available to be used).*/
-  ogg_int64_t  fullness;
+  ogg_int64_t     fullness;
   /*The target buffer fullness.
     This is where we'd like to be by the last keyframe the appears in the next
      buf_delay frames.*/
-  ogg_int64_t  target;
+  ogg_int64_t     target;
   /*The maximum buffer fullness (total size of the buffer).*/
-  ogg_int64_t  max;
+  ogg_int64_t     max;
   /*The log of the number of pixels in a frame in Q57 format.*/
-  ogg_int64_t  log_npixels;
+  ogg_int64_t     log_npixels;
   /*The exponent used in the rate model in Q8 format.*/
-  unsigned     exp[2];
+  unsigned        exp[2];
   /*The number of frames to distribute the buffer usage over.*/
-  int          buf_delay;
+  int             buf_delay;
   /*The total drop count from the previous frame.
     This includes duplicates explicitly requested via the
      TH_ENCCTL_SET_DUP_COUNT API as well as frames we chose to drop ourselves.*/
-  ogg_uint32_t prev_drop_count;
+  ogg_uint32_t    prev_drop_count;
   /*The log of an estimated scale factor used to obtain the real framerate, for
      VFR sources or, e.g., 12 fps content doubled to 24 fps, etc.*/
-  ogg_int64_t  log_drop_scale;
+  ogg_int64_t     log_drop_scale;
   /*The log of estimated scale factor for the rate model in Q57 format.*/
-  ogg_int64_t  log_scale[2];
+  ogg_int64_t     log_scale[2];
   /*The log of the target quantizer level in Q57 format.*/
-  ogg_int64_t  log_qtarget;
+  ogg_int64_t     log_qtarget;
+  /*Will we drop frames to meet bitrate target?*/
+  unsigned char   drop_frames;
+  /*Do we respect the maximum buffer fullness?*/
+  unsigned char   cap_overflow;
+  /*Can the reservoir go negative?*/
+  unsigned char   cap_underflow;
+  /*Second-order lowpass filters to track scale and VFR.*/
+  oc_iir_filter   scalefilter[2];
+  oc_iir_filter   vfrfilter;
 };
 
 
 void oc_enc_calc_lambda(oc_enc_ctx *_enc,int _frame_type);
 void oc_rc_state_init(oc_rc_state *_rc,const oc_enc_ctx *_enc);
+void oc_rc_state_reinit(oc_rc_state *_rc,const oc_enc_ctx *_enc);
 int oc_enc_update_rc_state(oc_enc_ctx *_enc,
  long _bits,int _qti,int _qi,int _trial,int _droppable);
 int oc_enc_select_qi(oc_enc_ctx *_enc,int _qti,int _clamp);

Modified: branches/theora-thusnelda/lib/enc/encode.c
===================================================================
--- branches/theora-thusnelda/lib/enc/encode.c	2009-07-24 10:44:55 UTC (rev 16333)
+++ branches/theora-thusnelda/lib/enc/encode.c	2009-07-25 19:27:31 UTC (rev 16334)
@@ -1315,6 +1315,28 @@
       _enc->dup_count=OC_MAXI(dup_count,0);
       return 0;
     }break;
+    case TH_ENCCTL_SET_RATE_FLAGS:{
+      int set;
+      if(_enc==NULL||_buf==NULL)return TH_EFAULT;
+      if(_buf_sz!=sizeof(set))return TH_EINVAL;
+      if(_enc->state.info.target_bitrate<=0)return TH_EINVAL;
+      set=*(int *)_buf;
+      _enc->rc.drop_frames=set&TH_RATECTL_DROP_FRAMES;
+      _enc->rc.cap_overflow=set&TH_RATECTL_CAP_OVERFLOW;
+      _enc->rc.cap_underflow=set&TH_RATECTL_CAP_UNDERFLOW;
+      return 0;
+    }break;
+    case TH_ENCCTL_SET_RATE_BUFFER:{
+      int set;
+      if(_enc==NULL||_buf==NULL)return TH_EFAULT;
+      if(_buf_sz!=sizeof(set))return TH_EINVAL;
+      if(_enc->state.info.target_bitrate<=0)return TH_EINVAL;
+      set=*(int *)_buf;
+      _enc->rc.buf_delay=set;
+      oc_rc_state_reset(&_enc->rc,_enc);
+      *(int *)_buf=_enc->rc.buf_delay;
+      return 0;
+    }break;
     default:return TH_EIMPL;
   }
 }

Modified: branches/theora-thusnelda/lib/enc/rate.c
===================================================================
--- branches/theora-thusnelda/lib/enc/rate.c	2009-07-24 10:44:55 UTC (rev 16333)
+++ branches/theora-thusnelda/lib/enc/rate.c	2009-07-25 19:27:31 UTC (rev 16334)
@@ -18,11 +18,104 @@
 #include <string.h>
 #include "encint.h"
 
+/*A rough lookup table for tan(x), 0<=x<pi/2.
+  The values are Q12 fixed-point and spaced at 5 degree intervals.
+  These decisions are somewhat arbitrary, but sufficient for the 2nd order
+   Bessel follower below.
+  Values of x larger than 85 degrees are extrapolated from the last inteval,
+   which is way off, but "good enough".*/
+static unsigned short OC_ROUGH_TAN_LOOKUP[18]={
+      0,  358,  722, 1098, 1491, 1910,
+   2365, 2868, 3437, 4096, 4881, 5850,
+   7094, 8784,11254,15286,23230,46817
+};
 
+/*_alpha is Q24 in the range [0,0.5).
+  The return values is 5.12.*/
+static int oc_warp_alpha(int _alpha){
+  int i;
+  int d;
+  int t0;
+  int t1;
+  i=_alpha*36>>24;
+  if(i>=17)i=16;
+  t0=OC_ROUGH_TAN_LOOKUP[i];
+  t1=OC_ROUGH_TAN_LOOKUP[i+1];
+  d=_alpha*36-(i<<24);
+  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){
+  int         alpha;
+  ogg_int64_t one48;
+  ogg_int64_t warp;
+  ogg_int64_t k1;
+  ogg_int64_t k2;
+  ogg_int64_t d;
+  ogg_int64_t a;
+  ogg_int64_t ik2;
+  ogg_int64_t b1;
+  ogg_int64_t b2;
+  /*This borrows some code from an unreleased version of Postfish.*/
+  /*alpha is Q24*/
+  alpha=(1<<24)/_delay;
+  one48=(ogg_int64_t)1<<48;
+  /*warp is 5.12*/
+  warp=oc_warp_alpha(alpha);
+  /*k1 is 6.12*/
+  k1=3*warp;
+  /*k2 is 10.24.*/
+  k2=k1*warp;
+  /*d is 11.24.*/
+  d=((1<<12)+k1<<12)+k2;
+  /*a is 34.24.*/
+  a=(k2<<24)/d;
+  /*ik2 is 25.24.*/
+  ik2=one48/k2;
+  /*b1 is Q48; in practice, the integer part is limited.*/
+  b1=2*a*(ik2-(1<<24));
+  /*b2 is Q48; in practice, the integer part is limited.*/
+  b2=one48-(4*a<<24)-b1;
+  /*All of the filter parameters are Q24.*/
+  _f->c[0]=(ogg_int32_t)(b1+(1<<23)>>24);
+  _f->c[1]=(ogg_int32_t)(b2+(1<<23)>>24);
+  _f->g=(ogg_int32_t)a;
+  _f->y[1]=_f->y[0]=_f->x[1]=_f->x[0]=_value;
+}
+
+static ogg_int64_t oc_iir_filter_update(oc_iir_filter *_f,int _x){
+  ogg_int64_t c0;
+  ogg_int64_t c1;
+  ogg_int64_t g;
+  ogg_int64_t x0;
+  ogg_int64_t x1;
+  ogg_int64_t y0;
+  ogg_int64_t y1;
+  ogg_int64_t ya;
+  c0=_f->c[0];
+  c1=_f->c[1];
+  g=_f->g;
+  x0=_f->x[0];
+  x1=_f->x[1];
+  y0=_f->y[0];
+  y1=_f->y[1];
+  ya=(_x+x0*2+x1)*g+y0*c0+y1*c1+(1<<23)>>24;
+  _f->x[1]=(ogg_int32_t)x0;
+  _f->x[0]=_x;
+  _f->y[1]=(ogg_int32_t)y0;
+  _f->y[0]=(ogg_int32_t)ya;
+  return ya;
+}
+
+
+
 /*Search for the quantizer that matches the target most closely.
   We don't assume a linear ordering, but when there are ties we pick the
    quantizer closest to the old one.*/
-int oc_enc_find_qi_for_target(oc_enc_ctx *_enc,int _qti,int _qi_old,
+static int oc_enc_find_qi_for_target(oc_enc_ctx *_enc,int _qti,int _qi_old,
  int _qi_min,ogg_int64_t _log_qtarget){
   ogg_int64_t best_qdiff;
   int         best_qi;
@@ -91,15 +184,25 @@
      lq-(OC_Q57(6)+5)/10);
     if(qi1!=qi&&qi1!=_enc->state.qis[nqis-1])_enc->state.qis[nqis++]=qi1;
   }
-  /*printf("%i %.3f:",_qti,oc_bexp64(lq+OC_Q57(3))*0.125);
-  for(qi=0;qi<nqis;qi++)printf(" %2i",_enc->state.qis[qi]);
-  printf("\n");*/
   _enc->state.nqis=nqis;
 }
 
+/*Binary exponential of _log_scale with 24-bit fractional precision and
+   saturation.
+  _log_scale: A binary logarithm in Q57 format.
+  Return: The binary exponential in Q24 format, saturated to 2**31-1 if
+   _log_scale was too large.*/
+static ogg_int32_t oc_bexp_q24(ogg_int64_t _log_scale){
+  if(_log_scale<OC_Q57(8)){
+    ogg_int64_t ret;
+    ret=oc_bexp64(_log_scale+OC_Q57(24));
+    return ret<0x7FFFFFFF?(ogg_int32_t)ret:0x7FFFFFFF;
+  }
+  return 0x7FFFFFFF;
+}
 
 
-void oc_rc_state_init(oc_rc_state *_rc,const oc_enc_ctx *_enc){
+void oc_rc_state_reset(oc_rc_state *_rc,const oc_enc_ctx *_enc){
   ogg_int64_t npixels;
   ogg_int64_t ibpp;
   /*TODO: These parameters should be exposed in a th_encode_ctl() API.*/
@@ -112,14 +215,6 @@
     _rc->bits_per_frame=(ogg_int64_t)0x400000000000LL;
   }
   else if(_rc->bits_per_frame<32)_rc->bits_per_frame=32;
-  /*The buffer size is set equal to the keyframe interval, clamped to the range
-     [12,256] frames.
-    The 12 frame minimum gives us some chance to distribute bit estimation
-     errors.
-    The 256 frame maximum means we'll require 8-10 seconds of pre-buffering at
-     24-30 fps, which is not unreasonable.*/
-  _rc->buf_delay=_enc->keyframe_frequency_force>256?
-   256:_enc->keyframe_frequency_force;
   _rc->buf_delay=OC_MAXI(_rc->buf_delay,12);
   _rc->max=_rc->bits_per_frame*_rc->buf_delay;
   /*Start with a buffer fullness of 75%.
@@ -158,19 +253,37 @@
   }
   _rc->prev_drop_count=0;
   _rc->log_drop_scale=OC_Q57(0);
+  /*Set up second order followers, initialized according to corresponding
+     time constants.*/
+  oc_iir_filter_init(&_rc->scalefilter[0],2,oc_bexp_q24(_rc->log_scale[0]));
+  oc_iir_filter_init(&_rc->scalefilter[1],_rc->buf_delay>>1,
+   oc_bexp_q24(_rc->log_scale[1]));
+  oc_iir_filter_init(&_rc->vfrfilter,2,oc_bexp_q24(_rc->log_drop_scale));
 }
 
+
+void oc_rc_state_init(oc_rc_state *_rc,const oc_enc_ctx *_enc){
+  /*The buffer size is set equal to the keyframe interval, clamped to the range
+     [12,256] frames.
+    The 12 frame minimum gives us some chance to distribute bit estimation
+     errors.
+    The 256 frame maximum means we'll require 8-10 seconds of pre-buffering at
+     24-30 fps, which is not unreasonable.*/
+  _rc->buf_delay=_enc->keyframe_frequency_force>256?
+   256:_enc->keyframe_frequency_force;
+  /*By default, enforce all buffer constraints.*/
+  _rc->drop_frames=1;
+  _rc->cap_overflow=1;
+  _rc->cap_underflow=0;
+  oc_rc_state_reset(_rc,_enc);
+}
+
 int oc_enc_update_rc_state(oc_enc_ctx *_enc,
  long _bits,int _qti,int _qi,int _trial,int _droppable){
-  /*Note, setting OC_SCALE_SMOOTHING[1] to 0x80 (0.5), which one might expect
-     to be a reasonable value, actually causes a feedback loop with, e.g., 12
-     fps content encoded at 24 fps; use values near 0 or near 1 for now.
-    TODO: Should probably revisit using an exponential moving average in the
-     first place at some point; dup tracking should help as well.*/
-  static const unsigned OC_SCALE_SMOOTHING[2]={0x13,0x00};
   ogg_int64_t buf_delta;
   int         dropped;
   dropped=0;
+  if(!_enc->rc.drop_frames)_droppable=0;
   buf_delta=_enc->rc.bits_per_frame*(1+_enc->dup_count);
   if(_bits<=0){
     /*We didn't code any blocks in this frame.
@@ -193,10 +306,10 @@
     /*Use it to set that factor directly if this was a trial.*/
     if(_trial)_enc->rc.log_scale[_qti]=log_scale;
     else{
-      /*Otherwise update an exponential moving average for log_scale,
+      /*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]=log_scale
-       +(_enc->rc.log_scale[_qti]-log_scale+128>>8)*OC_SCALE_SMOOTHING[_qti];
+      _enc->rc.log_scale[_qti]=oc_blog64(oc_iir_filter_update(
+       _enc->rc.scalefilter+_qti,oc_bexp_q24(log_scale)))-OC_Q57(24);
       /*If this frame busts our budget, it must be dropped.*/
       if(_droppable&&_enc->rc.fullness+buf_delta<_bits){
         _enc->rc.prev_drop_count+=1+_enc->dup_count;
@@ -204,12 +317,19 @@
         dropped=1;
       }
       else{
+        ogg_uint32_t drop_count;
         /*Update a simple exponential moving average to estimate the "real"
            frame rate taking drops and duplicates into account.
           This is only done if the frame is coded, as it needs the final count
            of dropped frames.*/
-        _enc->rc.log_drop_scale=_enc->rc.log_drop_scale
-         +oc_blog64(_enc->rc.prev_drop_count+1)>>1;
+        drop_count=_enc->rc.prev_drop_count+1;
+        if(drop_count>0x7F)drop_count=0x7FFFFFFF;
+        else drop_count<<=24;
+        _enc->rc.log_drop_scale=oc_blog64(oc_iir_filter_update(
+         &_enc->rc.vfrfilter,drop_count))-OC_Q57(24);
+        /*Initialize the drop count for this frame to the user-requested dup
+           count.
+          It will be increased if we drop more frames.*/
         _enc->rc.prev_drop_count=_enc->dup_count;
       }
     }
@@ -217,8 +337,16 @@
   if(!_trial){
     /*And update the buffer fullness level.*/
     _enc->rc.fullness+=buf_delta-_bits;
-    /*If we're too quick filling the buffer, that rate is lost forever.*/
-    if(_enc->rc.fullness>_enc->rc.max)_enc->rc.fullness=_enc->rc.max;
+    /*If we're too quick filling the buffer and overflow is capped,
+      that rate is lost forever.*/
+    if(_enc->rc.cap_overflow&&_enc->rc.fullness>_enc->rc.max){
+      _enc->rc.fullness=_enc->rc.max;
+    }
+    /*If we're too quick draining the buffer and underflow is capped,
+      don't try to make up that rate later.*/
+    if(_enc->rc.cap_underflow&&_enc->rc.fullness<0){
+      _enc->rc.fullness=0;
+    }
   }
   return dropped;
 }
@@ -317,8 +445,8 @@
   /*The above allocation looks only at the total rate we'll accumulate in the
      next buf_delay frames.
     However, we could bust the budget on the very next frame, so check for that
-     here.*/
-  {
+     here, if we're not using a soft target.*/
+  if(!_enc->rc.cap_underflow||_enc->rc.drop_frames){
     ogg_int64_t log_hard_limit;
     ogg_int64_t log_qexp;
     int         exp0;



More information about the commits mailing list