[xiph-commits] r15866 - in branches/theora-thusnelda: include/theora lib/enc

tterribe at svn.xiph.org tterribe at svn.xiph.org
Fri Mar 27 16:58:08 PDT 2009


Author: tterribe
Date: 2009-03-27 16:58:08 -0700 (Fri, 27 Mar 2009)
New Revision: 15866

Modified:
   branches/theora-thusnelda/include/theora/theora.h
   branches/theora-thusnelda/include/theora/theoraenc.h
   branches/theora-thusnelda/lib/enc/codec_internal.h
   branches/theora-thusnelda/lib/enc/encoder_toplevel.c
Log:
Add encoder API to duplicate frames.


Modified: branches/theora-thusnelda/include/theora/theora.h
===================================================================
--- branches/theora-thusnelda/include/theora/theora.h	2009-03-27 23:12:53 UTC (rev 15865)
+++ branches/theora-thusnelda/include/theora/theora.h	2009-03-27 23:58:08 UTC (rev 15866)
@@ -423,6 +423,32 @@
  * \retval TH_IMPL   Not supported by this implementation in the current
  *                    encoding mode.*/
 #define TH_ENCCTL_SET_SPLEVEL (14)
+/**Sets the number of duplicates of the next frame to produce.
+ * Although libtheora can encode duplicate frames very cheaply, it costs some
+ *  amount of CPU to detect them, and a run of duplicates cannot span a
+ *  keyframe boundary.
+ * 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.
+ * 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.
+ * \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
+ *                    maximum keyframe interval.
+ *                   In the latter case, NO duplicate frames will be produced.
+ *                   You must ensure that the maximum keyframe interval is set
+ *                    larger than the maximum number of duplicates you will
+ *                    ever wish to insert prior to encoding.
+ * \retval TH_IMPL   Not supported by this implementation in the current
+ *                    encoding mode.*/
+#define TH_ENCCTL_SET_DUP_COUNT (18)
 /*@}*/
 
 #define OC_FAULT       -1       /**< General failure */

Modified: branches/theora-thusnelda/include/theora/theoraenc.h
===================================================================
--- branches/theora-thusnelda/include/theora/theoraenc.h	2009-03-27 23:12:53 UTC (rev 15865)
+++ branches/theora-thusnelda/include/theora/theoraenc.h	2009-03-27 23:58:08 UTC (rev 15866)
@@ -139,6 +139,32 @@
  * \retval TH_IMPL   Not supported by this implementation in the current
  *                    encoding mode.*/
 #define TH_ENCCTL_SET_SPLEVEL (14)
+/**Sets the number of duplicates of the next frame to produce.
+ * Although libtheora can encode duplicate frames very cheaply, it costs some
+ *  amount of CPU to detect them, and a run of duplicates cannot span a
+ *  keyframe boundary.
+ * 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.
+ * 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.
+ * \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
+ *                    maximum keyframe interval.
+ *                   In the latter case, NO duplicate frames will be produced.
+ *                   You must ensure that the maximum keyframe interval is set
+ *                    larger than the maximum number of duplicates you will
+ *                    ever wish to insert prior to encoding.
+ * \retval TH_IMPL   Not supported by this implementation in the current
+ *                    encoding mode.*/
+#define TH_ENCCTL_SET_DUP_COUNT (18)
 /*@}*/
 
 

Modified: branches/theora-thusnelda/lib/enc/codec_internal.h
===================================================================
--- branches/theora-thusnelda/lib/enc/codec_internal.h	2009-03-27 23:12:53 UTC (rev 15865)
+++ branches/theora-thusnelda/lib/enc/codec_internal.h	2009-03-27 23:58:08 UTC (rev 15866)
@@ -212,6 +212,10 @@
 
   /* ogg bitpacker for use in packet coding, other API state */
   oggpack_buffer   *oggbuffer;
+  /*The number of duplicates to produce for the next frame.*/
+  int               dup_count;
+  /*The number of duplicates remaining to be emitted for the current frame.*/
+  int               nqueued_dups;
 
   unsigned char   *frame;
   unsigned char   *recon;

Modified: branches/theora-thusnelda/lib/enc/encoder_toplevel.c
===================================================================
--- branches/theora-thusnelda/lib/enc/encoder_toplevel.c	2009-03-27 23:12:53 UTC (rev 15865)
+++ branches/theora-thusnelda/lib/enc/encoder_toplevel.c	2009-03-27 23:58:08 UTC (rev 15866)
@@ -26,6 +26,7 @@
 #include "dsp.h"
 #include "codec_internal.h"
 #include "mathops.h"
+#include "../dec/ocintrin.h"
 
 
 
@@ -129,7 +130,7 @@
   }
   /*Update the buffer fullness level.*/
   if(!_trial){
-    cpi->rc.fullness+=cpi->rc.bits_per_frame-_bits;
+    cpi->rc.fullness+=cpi->rc.bits_per_frame*(1+cpi->dup_count)-_bits;
     /*If we're too quick filling the buffer, that rate is lost forever.*/
     if(cpi->rc.fullness>cpi->rc.max)cpi->rc.fullness=cpi->rc.max;
   }
@@ -158,6 +159,15 @@
   nframes[1]=buf_delay-nframes[0];
   rate_total=cpi->rc.fullness-cpi->rc.target
    +buf_delay*cpi->rc.bits_per_frame;
+  /*Downgrade the frame rate to correspond to the current dup count.
+    This will way over-estimate the bits to use for an occasional dup (as
+     opposed to a consistent dup count, as used with VFR input), but the
+     hysteresis on the quantizer below will keep us from going out of control,
+     and we _do_ have more bits to spend after all.*/
+  if(cpi->dup_count>0){
+    nframes[0]=(nframes[0]+cpi->dup_count)/(cpi->dup_count+1);
+    nframes[1]=(nframes[1]+cpi->dup_count)/(cpi->dup_count+1);
+  }
   /*If there aren't enough bits to achieve our desired fullness level, use the
      minimum quality permitted.*/
   if(rate_total<=0)log_qtarget=OC_QUANT_MAX_LOG;
@@ -361,6 +371,9 @@
   /* Set up an encode buffer */
   cpi->oggbuffer = _ogg_malloc(sizeof(oggpack_buffer));
   oggpackB_writeinit(cpi->oggbuffer);
+  cpi->dup_count=0;
+  cpi->nqueued_dups=0;
+  cpi->packetflag=0;
 
   InitFrameInfo(cpi);
 
@@ -434,7 +447,7 @@
 
   /* don't allow generating invalid files that overflow the p-frame
      shift, even if keyframe_auto_p is turned off */
-  if(cpi->LastKeyFrame==-1 || cpi->LastKeyFrame >= (ogg_uint32_t)
+  if(cpi->LastKeyFrame==-1 || cpi->LastKeyFrame+cpi->dup_count>= (ogg_uint32_t)
      cpi->info.keyframe_frequency_force){
 
     CompressKeyFrame(cpi,0);
@@ -474,34 +487,44 @@
   t->granulepos=
     ((cpi->CurrentFrame - cpi->LastKeyFrame)<<cpi->keyframe_granule_shift)+
     cpi->LastKeyFrame - 1;
+  cpi->nqueued_dups=cpi->dup_count;
+  cpi->dup_count=0;
 
   return 0;
 }
 
-int theora_encode_packetout( theora_state *t, int last_p, ogg_packet *op){
-  CP_INSTANCE *cpi=(CP_INSTANCE *)(t->internal_encode);
-  long bytes=oggpackB_bytes(cpi->oggbuffer);
-
-  if(!bytes)return(0);
-  if(!cpi->packetflag)return(0);
-  if(cpi->doneflag>0)return(-1);
-
-  op->packet=oggpackB_get_buffer(cpi->oggbuffer);
-  op->bytes=bytes;
-  op->b_o_s=0;
-  op->e_o_s=last_p;
-
-  op->packetno=cpi->CurrentFrame;
-  op->granulepos=t->granulepos;
-
-  cpi->packetflag=0;
-  if(last_p){
-    cpi->doneflag=1;
+int theora_encode_packetout(theora_state *_t,int _last_p,ogg_packet *_op){
+  CP_INSTANCE *cpi;
+  cpi=(CP_INSTANCE *)_t->internal_encode;
+  if(cpi->doneflag>0)return -1;
+  if(cpi->packetflag){
+    cpi->packetflag=0;
+    _op->packet=oggpackB_get_buffer(cpi->oggbuffer);
+    _op->bytes=oggpackB_bytes(cpi->oggbuffer);
+  }
+  else if(cpi->nqueued_dups>0){
+    cpi->nqueued_dups--;
+    cpi->CurrentFrame++;
+    _t->granulepos=cpi->LastKeyFrame-1
+     +(cpi->CurrentFrame-cpi->LastKeyFrame<<cpi->keyframe_granule_shift);
+    _op->packet=NULL;
+    _op->bytes=0;
+  }
+  else{
+    if(_last_p){
+      cpi->doneflag=1;
 #ifdef COLLECT_METRICS
-    DumpMetrics(cpi);
+      DumpMetrics(cpi);
 #endif
+    }
+    return 0;
   }
-  return 1;
+  _last_p=_last_p&&cpi->nqueued_dups<=0;
+  _op->b_o_s=0;
+  _op->e_o_s=_last_p;
+  _op->packetno=cpi->CurrentFrame;
+  _op->granulepos=_t->granulepos;
+  return 1+cpi->nqueued_dups;
 }
 
 static void _tp_writebuffer(oggpack_buffer *opb, const char *buf, const long len)
@@ -763,6 +786,15 @@
       value = 2;
       memcpy(buf, &value, sizeof(int));
       return 0;
+    case TH_ENCCTL_SET_DUP_COUNT:{
+      int dup_count;
+      if(buf==NULL)return TH_EFAULT;
+      if(buf_sz!=sizeof(int))return TH_EINVAL;
+      dup_count=*(int *)buf;
+      if(dup_count>=cpi->info.keyframe_frequency_force)return TH_EINVAL;
+      cpi->dup_count=OC_MAXI(dup_count,0);
+      return 0;
+    }break;
     default:
       return TH_EIMPL;
   }



More information about the commits mailing list