[xiph-commits] r16302 - branches/theora-thusnelda/lib/enc

tterribe at svn.xiph.org tterribe at svn.xiph.org
Sat Jul 18 11:36:27 PDT 2009


Author: tterribe
Date: 2009-07-18 11:36:26 -0700 (Sat, 18 Jul 2009)
New Revision: 16302

Modified:
   branches/theora-thusnelda/lib/enc/rate.c
Log:
Add rate check to make sure we don't bust the budget on the next frame.


Modified: branches/theora-thusnelda/lib/enc/rate.c
===================================================================
--- branches/theora-thusnelda/lib/enc/rate.c	2009-07-18 15:06:53 UTC (rev 16301)
+++ branches/theora-thusnelda/lib/enc/rate.c	2009-07-18 18:36:26 UTC (rev 16302)
@@ -19,6 +19,29 @@
 #include "encint.h"
 
 
+/*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,
+ int _qi_min,ogg_int64_t _log_qtarget){
+  ogg_int64_t best_qdiff;
+  int         best_qi;
+  int         qi;
+  best_qi=_qi_min;
+  best_qdiff=_enc->log_qavg[_qti][best_qi]-_log_qtarget;
+  best_qdiff=best_qdiff+OC_SIGNMASK(best_qdiff)^OC_SIGNMASK(best_qdiff);
+  for(qi=_qi_min+1;qi<64;qi++){
+    ogg_int64_t qdiff;
+    qdiff=_enc->log_qavg[_qti][qi]-_log_qtarget;
+    qdiff=qdiff+OC_SIGNMASK(qdiff)^OC_SIGNMASK(qdiff);
+    if(qdiff<best_qdiff||
+     qdiff==best_qdiff&&abs(qi-_qi_old)<abs(best_qi-_qi_old)){
+      best_qi=qi;
+      best_qdiff=qdiff;
+    }
+  }
+  return best_qi;
+}
 
 void oc_enc_calc_lambda(oc_enc_ctx *_enc,int _frame_type){
   ogg_int64_t lq;
@@ -158,8 +181,7 @@
   int          nframes[2];
   int          buf_delay;
   ogg_int64_t  log_qtarget;
-  int          best_qi;
-  ogg_int64_t  best_qdiff;
+  ogg_int64_t  log_scale0;
   int          old_qi;
   int          qi;
   /*Figure out how to re-distribute bits so that we hit our fullness target
@@ -190,18 +212,17 @@
     }
     else nframes[1]=!!nframes[1];
   }
+  log_scale0=_enc->rc.log_scale[_qti]+_enc->rc.log_npixels;
   /*If there aren't enough bits to achieve our desired fullness level, use the
      minimum quality permitted.*/
   if(rate_total<=buf_delay)log_qtarget=OC_QUANT_MAX_LOG;
   else{
     static const unsigned char KEY_RATIO[2]={32,17};
-    ogg_int64_t   log_scale0;
     ogg_int64_t   log_scale1;
     ogg_int64_t   prevr;
     ogg_int64_t   curr;
     ogg_int64_t   realr;
     int           i;
-    log_scale0=_enc->rc.log_scale[_qti]+_enc->rc.log_npixels;
     log_scale1=_enc->rc.log_scale[1-_qti]+_enc->rc.log_npixels;
     curr=(rate_total+(buf_delay>>1))/buf_delay;
     realr=curr*KEY_RATIO[_qti]+16>>5;
@@ -245,23 +266,28 @@
     log_qmax=_enc->log_qavg[_qti][old_qi]+0x00A4D3C25E68DC58LL;
     log_qtarget=OC_CLAMPI(log_qmin,log_qtarget,log_qmax);
   }
-  /*Search for the quantizer that matches the target most closely.
-    We don't assume a linear ordering, but when there are ties we do pick the
-     quantizer closest to the current one.*/
-  best_qi=_enc->state.info.quality;
-  best_qdiff=_enc->log_qavg[_qti][best_qi]-log_qtarget;
-  best_qdiff=best_qdiff+OC_SIGNMASK(best_qdiff)^OC_SIGNMASK(best_qdiff);
-  for(qi=_enc->state.info.quality+1;qi<64;qi++){
-    ogg_int64_t qdiff;
-    qdiff=_enc->log_qavg[_qti][qi]-log_qtarget;
-    qdiff=qdiff+OC_SIGNMASK(qdiff)^OC_SIGNMASK(qdiff);
-    if(qdiff<best_qdiff||
-     qdiff==best_qdiff&&abs(qi-old_qi)<abs(best_qi-old_qi)){
-      best_qi=qi;
-      best_qdiff=qdiff;
+  /*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.*/
+  {
+    ogg_int64_t log_hard_limit;
+    ogg_int64_t log_qexp;
+    int         exp0;
+    /*Allow 50% of the rate for a single frame for prediction error.
+      This may not be enough for keyframes.*/
+    log_hard_limit=oc_blog64(_enc->rc.fullness+(_enc->rc.bits_per_frame>>1));
+    exp0=_enc->rc.exp[_qti];
+    log_qexp=log_qtarget-OC_Q57(2);
+    log_qexp=(log_qtarget-OC_Q57(2)>>6)*exp0;
+    if(log_scale0-log_qexp>log_hard_limit){
+      log_qexp=log_scale0-log_hard_limit;
+      log_qtarget=((log_qexp+(exp0>>1))/exp0<<6)+OC_Q57(2);
     }
   }
+  qi=oc_enc_find_qi_for_target(_enc,_qti,old_qi,
+   _enc->state.info.quality,log_qtarget);
   /*Save the quantizer target for lambda calculations.*/
   _enc->rc.log_qtarget=log_qtarget;
-  return best_qi;
+  return qi;
 }



More information about the commits mailing list