[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