[xiph-commits] r14715 - trunk/theora/lib/enc

tterribe at svn.xiph.org tterribe at svn.xiph.org
Fri Apr 11 20:43:10 PDT 2008


Author: tterribe
Date: 2008-04-11 20:43:09 -0700 (Fri, 11 Apr 2008)
New Revision: 14715

Removed:
   trunk/theora/lib/enc/internal.c
Modified:
   trunk/theora/lib/enc/encapiwrapper.c
Log:
Fix th_encode_ycbcr_in() to pad input frames if necessary (the new API does not
 require the caller to do this).
Also add some extra validity checks to th_encode_alloc(), and remove the
 useless copy of enc/internal.c


Modified: trunk/theora/lib/enc/encapiwrapper.c
===================================================================
--- trunk/theora/lib/enc/encapiwrapper.c	2008-04-12 01:04:43 UTC (rev 14714)
+++ trunk/theora/lib/enc/encapiwrapper.c	2008-04-12 03:43:09 UTC (rev 14715)
@@ -2,6 +2,7 @@
 #include "theora/theoraenc.h"
 #include "theora/theora.h"
 #include "codec_internal.h"
+#include "../dec/ocintrin.h"
 
 /*Wrapper to translate the new API into the old API.
   Eventually we need to convert the old functions to support the new API
@@ -48,6 +49,7 @@
   _ci->keyframe_mindistance=8;
   _ci->noise_sensitivity=1;
   _ci->sharpness=0;
+  _ci->quick_p=1;
 }
 
 static int _ilog(unsigned _v){
@@ -58,12 +60,15 @@
 
 
 
-typedef struct th_enc_ctx{
+struct th_enc_ctx{
   /*This is required at the start of the struct for the common functions to
      work.*/
-  th_info      info;
+  th_info        info;
   /*The actual encoder.*/
-  theora_state state;
+  theora_state   state;
+  /*A temporary buffer for input frames.
+    This is needed if the U and V strides differ, or padding is required.*/
+  unsigned char *buf;
 };
 
 
@@ -71,22 +76,41 @@
   theora_info  ci;
   th_enc_ctx  *enc;
   th_info2theora_info(&ci,_info);
-  enc=(th_enc_ctx *)_ogg_malloc(sizeof(*enc));
-  if(theora_encode_init(&enc->state,&ci)<0){
-    _ogg_free(enc);
+  /*Do a bunch of checks the new API does, but the old one didn't.*/
+  if((_info->frame_width&0xF)||(_info->frame_height&0xF)||
+   _info->frame_width>=0x100000||_info->frame_height>=0x100000||
+   _info->pic_x+_info->pic_width>_info->frame_width||
+   _info->pic_y+_info->pic_height>_info->frame_height||
+   _info->pic_x>255||
+   _info->frame_height-_info->pic_height-_info->pic_y>255||
+   _info->colorspace<0||_info->colorspace>=TH_CS_NSPACES||
+   _info->pixel_fmt<0||_info->pixel_fmt>=TH_PF_NFORMATS){
     enc=NULL;
   }
   else{
-    memcpy(&enc->info,_info,sizeof(enc->info));
-    /*Overwrite values theora_encode_init() can change; don't trust the user.*/
-    enc->info.version_major=ci.version_major;
-    enc->info.version_minor=ci.version_minor;
-    enc->info.version_subminor=ci.version_subminor;
-    enc->info.quality=ci.quality;
-    enc->info.target_bitrate=ci.target_bitrate;
-    enc->info.fps_numerator=ci.fps_numerator;
-    enc->info.fps_denominator=ci.fps_denominator;
-    enc->info.keyframe_granule_shift=_ilog(ci.keyframe_frequency_force-1);
+    enc=(th_enc_ctx *)_ogg_malloc(sizeof(*enc));
+    if(theora_encode_init(&enc->state,&ci)<0){
+      _ogg_free(enc);
+      enc=NULL;
+    }
+    else{
+      if(_info->frame_width>_info->pic_width||
+      _info->frame_height>_info->pic_height){
+       enc->buf=_ogg_malloc((3L*_info->frame_height*_info->frame_width>>1)*
+        sizeof(*enc->buf));
+      }
+      else enc->buf=NULL;
+      memcpy(&enc->info,_info,sizeof(enc->info));
+      /*Overwrite values theora_encode_init() can change; don't trust the user.*/
+      enc->info.version_major=ci.version_major;
+      enc->info.version_minor=ci.version_minor;
+      enc->info.version_subminor=ci.version_subminor;
+      enc->info.quality=ci.quality;
+      enc->info.target_bitrate=ci.target_bitrate;
+      enc->info.fps_numerator=ci.fps_numerator;
+      enc->info.fps_denominator=ci.fps_denominator;
+      enc->info.keyframe_granule_shift=_ilog(ci.keyframe_frequency_force-1);
+    }
   }
   return enc;
 }
@@ -135,12 +159,93 @@
   }
 }
 
+/*Copies the picture region of the _src image plane into _dst and pads the rest
+   of _dst using a diffusion extension method.
+  We could do much better (e.g., the DCT-based low frequency extension method
+   in theora-exp's fdct.c) if we were to pad after motion compensation, but
+   that would require significant changes to the encoder.*/
+static unsigned char *th_encode_copy_pad_plane(th_img_plane *_dst,
+ unsigned char *_buf,th_img_plane *_src,
+ ogg_uint32_t _pic_x,ogg_uint32_t _pic_y,
+ ogg_uint32_t _pic_width,ogg_uint32_t _pic_height){
+  size_t buf_sz;
+  _dst->width=_src->width;
+  _dst->height=_src->height;
+  _dst->stride=_src->width;
+  _dst->data=_buf;
+  buf_sz=_dst->width*_dst->height*sizeof(*_dst->data);
+  /*If we have _no_ data, just encode a dull green.*/
+  if(_pic_width==0||_pic_height==0)memset(_dst->data,0,buf_sz);
+  else{
+    unsigned char *dst;
+    unsigned char *src;
+    ogg_uint32_t   x;
+    ogg_uint32_t   y;
+    int            dstride;
+    int            sstride;
+    /*Step 1: Copy the data we do have.*/
+    dstride=_dst->stride;
+    sstride=_src->stride;
+    dst=_dst->data+_pic_y*dstride+_pic_x;
+    src=_src->data+_pic_y*sstride+_pic_x;
+    for(y=0;y<_pic_height;y++){
+      memcpy(dst,src,_pic_width);
+      dst+=dstride;
+      src+=sstride;
+    }
+    /*Step 2: Copy the border into any blocks that are 100% padding.
+      There's probably smarter things we could do than this.*/
+    /*Left side.*/
+    for(x=_pic_x;x-->0;){
+      dst=_dst->data+_pic_y*dstride+x;
+      for(y=0;y<_pic_height;y++){
+        dst[0]=(dst[1]<<1)+(dst-(dstride&-(y>0)))[1]+
+         (dst+(dstride&-(y+1<_pic_height)))[1]+2>>2;
+        dst+=dstride;
+      }
+    }
+    /*Right side.*/
+    for(x=_pic_x+_pic_width;x<_dst->width;x++){
+      dst=_dst->data+_pic_y*dstride+x-1;
+      for(y=0;y<_pic_height;y++){
+        dst[1]=(dst[0]<<1)+(dst-(dstride&-(y>0)))[0]+
+         (dst+(dstride&-(y+1<_pic_height)))[0]+2>>2;
+        dst+=dstride;
+      }
+    }
+    /*Top.*/
+    dst=_dst->data+_pic_y*dstride;
+    for(y=_pic_y;y-->0;){
+      for(x=0;x<_dst->width;x++){
+        (dst-dstride)[x]=(dst[x]<<1)+dst[x-(x>0)]+dst[x+(x+1<_dst->width)]+2>>2;
+      }
+      dst-=dstride;
+    }
+    /*Bottom.*/
+    dst=_dst->data+(_pic_y+_pic_height)*dstride;
+    for(y=_pic_y+_pic_height;y<_dst->height;y++){
+      for(x=0;x<_dst->width;x++){
+        dst[x]=((dst-dstride)[x]<<1)+(dst-dstride)[x-(x>0)]+
+         (dst-dstride)[x+(x+1<_dst->width)]+2>>2;
+      }
+      dst+=dstride;
+    }
+  }
+  _buf+=buf_sz;
+  return _buf;
+}
+
 int th_encode_ycbcr_in(th_enc_ctx *_enc,th_ycbcr_buffer _ycbcr){
-  CP_INSTANCE   *cpi;
-  theora_state  *te;
-  yuv_buffer     yuv;
-  unsigned char *tmpbuf;
-  int            ret;
+  CP_INSTANCE     *cpi;
+  theora_state    *te;
+  th_img_plane    *pycbcr;
+  th_ycbcr_buffer  ycbcr;
+  yuv_buffer       yuv;
+  ogg_uint32_t     pic_width;
+  ogg_uint32_t     pic_height;
+  int              hdec;
+  int              vdec;
+  int              ret;
   if(_enc==NULL||_ycbcr==NULL)return OC_FAULT;
   te=&_enc->state;
   /*theora_encode_YUVin() does not bother to check uv_width and uv_height, and
@@ -149,51 +254,65 @@
      wrong, which will make the developer who passed them fix the problem), but
      our API promises to return an error code instead.*/
   cpi=(CP_INSTANCE *)te->internal_encode;
-  if(_ycbcr[1].width!=_ycbcr[0].width>>!(cpi->pb.info.pixelformat&1)||
-   _ycbcr[1].height!=_ycbcr[0].height>>!(cpi->pb.info.pixelformat&2)||
+  hdec=!(cpi->pb.info.pixelformat&1);
+  vdec=!(cpi->pb.info.pixelformat&2);
+  if(_ycbcr[0].width!=cpi->pb.info.width||
+   _ycbcr[0].height!=cpi->pb.info.height||
+   _ycbcr[1].width!=_ycbcr[0].width>>hdec||
+   _ycbcr[1].height!=_ycbcr[0].height>>vdec||
    _ycbcr[2].width!=_ycbcr[1].width||_ycbcr[2].height!=_ycbcr[1].height){
     return OC_EINVAL;
   }
-  yuv.y_width=_ycbcr[0].width;
-  yuv.y_height=_ycbcr[0].height;
-  yuv.y_stride=_ycbcr[0].stride;
-  yuv.y=_ycbcr[0].data;
-  yuv.uv_width=_ycbcr[1].width;
-  yuv.uv_height=_ycbcr[1].height;
-  if(_ycbcr[1].stride==_ycbcr[2].stride){
-    yuv.uv_stride=_ycbcr[1].stride;
-    yuv.u=_ycbcr[1].data;
-    yuv.v=_ycbcr[2].data;
-    tmpbuf=NULL;
+  pic_width=cpi->pb.info.frame_width;
+  pic_height=cpi->pb.info.frame_height;
+  /*We can only directly use the input buffer if no padding is required (since
+     the new API is documented not to use values outside the picture region)
+     and if the strides for the Cb and Cr planes are the same, since the old
+     API had no way to specify different ones.*/
+  if(_ycbcr[0].width==pic_width&&_ycbcr[0].height==pic_height&&
+   _ycbcr[1].stride==_ycbcr[2].stride){
+    pycbcr=_ycbcr;
   }
   else{
-    unsigned char *src;
-    unsigned char *dst;
-    int            i;
-    /*There's no way to signal different strides for the u and v components
-       when we pass them to theora_encode_YUVin().
-      Therefore we have to allocate a temporary buffer and copy them.*/
-    tmpbuf=(unsigned char *)_ogg_malloc(
-     (yuv.uv_width*yuv.uv_height<<1)*sizeof(*tmpbuf));
-    dst=tmpbuf;
-    yuv.u=dst;
-    src=_ycbcr[1].data;
-    for(i=0;i<yuv.uv_height;i++){
-      memcpy(dst,src,yuv.uv_width);
-      dst+=yuv.uv_width;
-      src+=_ycbcr[1].stride;
+    unsigned char *buf;
+    int            pic_x;
+    int            pic_y;
+    int            pli;
+    pic_x=cpi->pb.info.offset_x;
+    pic_y=cpi->pb.info.offset_y;
+    if(_ycbcr[0].width>pic_width&&_ycbcr[0].height>pic_height){
+      buf=th_encode_copy_pad_plane(ycbcr+0,_enc->buf,_ycbcr+0,
+       pic_x,pic_y,pic_width,pic_height);
     }
-    yuv.v=dst;
-    src=_ycbcr[2].data;
-    for(i=0;i<yuv.uv_height;i++){
-      memcpy(dst,src,yuv.uv_width);
-      dst+=yuv.uv_width;
-      src+=_ycbcr[2].stride;
+    else{
+      /*If only the strides differ, we can still avoid copying the luma plane.*/
+      memcpy(ycbcr+0,_ycbcr+0,sizeof(ycbcr[0]));
+      if(_enc->buf==NULL){
+        _enc->buf=(unsigned char *)_ogg_malloc(
+         (_ycbcr[1].width*_ycbcr[1].height<<1)*sizeof(*_enc->buf));
+      }
+      buf=_enc->buf;
     }
-    yuv.uv_stride=yuv.uv_width;
+    for(pli=1;pli<3;pli++){
+      int x0;
+      int y0;
+      x0=pic_x>>hdec;
+      y0=pic_x>>hdec;
+      buf=th_encode_copy_pad_plane(ycbcr+pli,buf,_ycbcr+pli,
+       x0,y0,(pic_x+pic_width+hdec>>hdec)-x0,(pic_y+pic_height+vdec>>vdec)-y0);
+    }
+    pycbcr=ycbcr;
   }
+  yuv.y_width=pycbcr[0].width;
+  yuv.y_height=pycbcr[0].height;
+  yuv.uv_width=pycbcr[1].width;
+  yuv.uv_height=pycbcr[1].height;
+  yuv.y_stride=pycbcr[0].stride;
+  yuv.y=pycbcr[0].data;
+  yuv.uv_stride=pycbcr[1].stride;
+  yuv.u=pycbcr[1].data;
+  yuv.v=pycbcr[2].data;
   ret=theora_encode_YUVin(te,&yuv);
-  _ogg_free(tmpbuf);
   return ret;
 }
 
@@ -205,6 +324,7 @@
 void th_encode_free(th_enc_ctx *_enc){
   if(_enc!=NULL){
     theora_clear(&_enc->state);
+    _ogg_free(_enc->buf);
     _ogg_free(_enc);
   }
 }

Deleted: trunk/theora/lib/enc/internal.c
===================================================================
--- trunk/theora/lib/enc/internal.c	2008-04-12 01:04:43 UTC (rev 14714)
+++ trunk/theora/lib/enc/internal.c	2008-04-12 03:43:09 UTC (rev 14715)
@@ -1,29 +0,0 @@
-/********************************************************************
- *                                                                  *
- * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   *
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
- * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
- * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
- *                                                                  *
- * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2007                *
- * by the Xiph.Org Foundation http://www.xiph.org/                  *
- *                                                                  *
- ********************************************************************
-
-  function:
-    last mod: $Id$
-
- ********************************************************************/
-
-#include <stdlib.h>
-#include <limits.h>
-#include <string.h>
-#include "../internal.h"
-#include "idct.h"
-
-
-int oc_ilog(unsigned _v){
-  int ret;
-  for(ret=0;_v;ret++)_v>>=1;
-  return ret;
-}



More information about the commits mailing list