[xiph-commits] r13844 - trunk/theora-exp/lib
tterribe at svn.xiph.org
tterribe at svn.xiph.org
Sun Sep 16 15:07:03 PDT 2007
Author: tterribe
Date: 2007-09-16 15:07:03 -0700 (Sun, 16 Sep 2007)
New Revision: 13844
Added:
trunk/theora-exp/lib/apiwrapper.h
trunk/theora-exp/lib/decapiwrapper.c
trunk/theora-exp/lib/encapiwrapper.c
Log:
Actually include the new files for r13842.
Added: trunk/theora-exp/lib/apiwrapper.h
===================================================================
--- trunk/theora-exp/lib/apiwrapper.h (rev 0)
+++ trunk/theora-exp/lib/apiwrapper.h 2007-09-16 22:07:03 UTC (rev 13844)
@@ -0,0 +1,37 @@
+#if !defined(_apiwrapper_H)
+# define _apiwrapper_H (1)
+# include <ogg/ogg.h>
+# include <theora/theora.h>
+# include "theora/theoradec.h"
+# include "theora/theoraenc.h"
+# include "internal.h"
+
+typedef struct th_api_wrapper th_api_wrapper;
+typedef struct th_api_info th_api_info;
+
+/*Provide an entry point for the codec setup to clear itself in case we ever
+ want to break pieces off into a common base library shared by encoder and
+ decoder.
+ In addition, this makes several other pieces of the API wrapper cleaner.*/
+typedef void (*oc_setup_clear_func)(void *_ts);
+
+/*Generally only one of these pointers will be non-NULL in any given instance.
+ Technically we do not even really need this struct, since we should be able
+ to figure out which one from "context", but doing it this way makes sure we
+ don't flub it up.*/
+struct th_api_wrapper{
+ oc_setup_clear_func clear;
+ th_setup_info *setup;
+ th_dec_ctx *decode;
+ th_enc_ctx *encode;
+};
+
+struct th_api_info{
+ th_api_wrapper api;
+ theora_info info;
+};
+
+
+void oc_theora_info2th_info(th_info *_info,const theora_info *_ci);
+
+#endif
Added: trunk/theora-exp/lib/decapiwrapper.c
===================================================================
--- trunk/theora-exp/lib/decapiwrapper.c (rev 0)
+++ trunk/theora-exp/lib/decapiwrapper.c 2007-09-16 22:07:03 UTC (rev 13844)
@@ -0,0 +1,170 @@
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "apiwrapper.h"
+#include "theora/theoradec.h"
+
+
+
+static void th_dec_api_clear(th_api_wrapper *_api){
+ if(_api->setup)th_setup_free(_api->setup);
+ if(_api->decode)th_decode_free(_api->decode);
+ memset(_api,0,sizeof(*_api));
+}
+
+static void theora_decode_clear(theora_state *_td){
+ if(_td->i!=NULL)theora_info_clear(_td->i);
+ memset(_td,0,sizeof(*_td));
+}
+
+static int theora_decode_control(theora_state *_td,int _req,
+ void *_buf,size_t _buf_sz){
+ return th_decode_ctl(((th_api_wrapper *)_td->i->codec_setup)->decode,
+ _req,_buf,_buf_sz);
+}
+
+static ogg_int64_t theora_decode_granule_frame(theora_state *_td,
+ ogg_int64_t _gp){
+ return th_granule_frame(((th_api_wrapper *)_td->i->codec_setup)->decode,_gp);
+}
+
+static double theora_decode_granule_time(theora_state *_td,ogg_int64_t _gp){
+ return th_granule_time(((th_api_wrapper *)_td->i->codec_setup)->decode,_gp);
+}
+
+static const oc_state_dispatch_vtbl OC_DEC_DISPATCH_VTBL={
+ (oc_state_clear_func)theora_decode_clear,
+ (oc_state_control_func)theora_decode_control,
+ (oc_state_granule_frame_func)theora_decode_granule_frame,
+ (oc_state_granule_time_func)theora_decode_granule_time,
+};
+
+static void th_info2theora_info(theora_info *_ci,const th_info *_info){
+ _ci->version_major=_info->version_major;
+ _ci->version_minor=_info->version_minor;
+ _ci->version_subminor=_info->version_subminor;
+ _ci->width=_info->frame_width;
+ _ci->height=_info->frame_height;
+ _ci->frame_width=_info->pic_width;
+ _ci->frame_height=_info->pic_height;
+ _ci->offset_x=_info->pic_x;
+ _ci->offset_y=_info->pic_y;
+ _ci->fps_numerator=_info->fps_numerator;
+ _ci->fps_denominator=_info->fps_denominator;
+ _ci->aspect_numerator=_info->aspect_numerator;
+ _ci->aspect_denominator=_info->aspect_denominator;
+ switch(_info->colorspace){
+ case TH_CS_ITU_REC_470M:_ci->colorspace=OC_CS_ITU_REC_470M;break;
+ case TH_CS_ITU_REC_470BG:_ci->colorspace=OC_CS_ITU_REC_470BG;break;
+ default:_ci->colorspace=OC_CS_UNSPECIFIED;break;
+ }
+ switch(_info->pixel_fmt){
+ case TH_PF_420:_ci->pixelformat=OC_PF_420;break;
+ case TH_PF_422:_ci->pixelformat=OC_PF_422;break;
+ case TH_PF_444:_ci->pixelformat=OC_PF_444;break;
+ default:_ci->pixelformat=OC_PF_RSVD;
+ }
+ _ci->target_bitrate=_info->target_bitrate;
+ _ci->quality=_info->quality;
+ _ci->keyframe_frequency_force=1<<_info->keyframe_granule_shift;
+}
+
+int theora_decode_init(theora_state *_td,theora_info *_ci){
+ th_api_info *apiinfo;
+ th_api_wrapper *api;
+ th_info info;
+ api=(th_api_wrapper *)_ci->codec_setup;
+ /*Allocate our own combined API wrapper/theora_info struct.
+ We put them both in one malloc'd block so that when the API wrapper is
+ freed, the info struct goes with it.
+ This avoids having to figure out whether or not we need to free the info
+ struct in either theora_info_clear() or theora_clear().*/
+ apiinfo=(th_api_info *)_ogg_calloc(1,sizeof(*apiinfo));
+ /*Make our own copy of the info struct, since its lifetime should be
+ independent of the one we were passed in.*/
+ *&apiinfo->info=*_ci;
+ /*Convert the info struct now instead of saving the the one we decoded with
+ theora_decode_header(), since the user might have modified values (i.e.,
+ color space, aspect ratio, etc. can be specified from a higher level).
+ The user also might be doing something "clever" with the header packets if
+ they are not using an Ogg encapsulation.*/
+ oc_theora_info2th_info(&info,_ci);
+ /*Don't bother to copy the setup info; th_decode_alloc() makes its own copy
+ of the stuff it needs.*/
+ apiinfo->api.decode=th_decode_alloc(&info,api->setup);
+ if(apiinfo->api.decode==NULL){
+ _ogg_free(apiinfo);
+ return OC_EINVAL;
+ }
+ apiinfo->api.clear=(oc_setup_clear_func)th_dec_api_clear;
+ _td->internal_encode=NULL;
+ /*Provide entry points for ABI compatibility with old decoder shared libs.*/
+ _td->internal_decode=(void *)&OC_DEC_DISPATCH_VTBL;
+ _td->granulepos=0;
+ _td->i=&apiinfo->info;
+ _td->i->codec_setup=&apiinfo->api;
+ return 0;
+}
+
+int theora_decode_header(theora_info *_ci,theora_comment *_cc,ogg_packet *_op){
+ th_api_wrapper *api;
+ th_info info;
+ int ret;
+ api=(th_api_wrapper *)_ci->codec_setup;
+ /*Allocate an API wrapper struct on demand, since it will not also include a
+ theora_info struct like the ones that are used in a theora_state struct.*/
+ if(api==NULL){
+ _ci->codec_setup=_ogg_calloc(1,sizeof(*api));
+ api=(th_api_wrapper *)_ci->codec_setup;
+ api->clear=(oc_setup_clear_func)th_dec_api_clear;
+ }
+ /*Convert from the theora_info struct instead of saving our own th_info
+ struct between calls.
+ The user might be doing something "clever" with the header packets if they
+ are not using an Ogg encapsulation, and we don't want to break this.*/
+ oc_theora_info2th_info(&info,_ci);
+ /*We rely on the fact that theora_comment and th_comment structures are
+ actually identical.
+ Take care not to change this fact unless you change the code here as
+ well!*/
+ ret=th_decode_headerin(&info,(th_comment *)_cc,&api->setup,_op);
+ /*We also rely on the fact that the error return code values are the same,
+ and that the implementations of these two functions return the same set of
+ them.
+ Note that theora_decode_header() really can return OC_NOTFORMAT, even
+ though it is not currently documented to do so.*/
+ if(ret<0)return ret;
+ th_info2theora_info(_ci,&info);
+ return 0;
+}
+
+int theora_decode_packetin(theora_state *_td,ogg_packet *_op){
+ th_api_wrapper *api;
+ ogg_int64_t gp;
+ int ret;
+ api=(th_api_wrapper *)_td->i->codec_setup;
+ ret=th_decode_packetin(api->decode,_op,&gp);
+ if(ret<0)return OC_BADPACKET;
+ _td->granulepos=gp;
+ return 0;
+}
+
+int theora_decode_YUVout(theora_state *_td,yuv_buffer *_yuv){
+ th_api_wrapper *api;
+ th_ycbcr_buffer buf;
+ int ret;
+ api=(th_api_wrapper *)_td->i->codec_setup;
+ ret=th_decode_ycbcr_out(api->decode,buf);
+ if(ret>=0){
+ _yuv->y_width=buf[0].width;
+ _yuv->y_height=buf[0].height;
+ _yuv->y_stride=buf[0].ystride;
+ _yuv->uv_width=buf[1].width;
+ _yuv->uv_height=buf[1].height;
+ _yuv->uv_stride=buf[1].ystride;
+ _yuv->y=buf[0].data;
+ _yuv->u=buf[1].data;
+ _yuv->v=buf[2].data;
+ }
+ return ret;
+}
Added: trunk/theora-exp/lib/encapiwrapper.c
===================================================================
--- trunk/theora-exp/lib/encapiwrapper.c (rev 0)
+++ trunk/theora-exp/lib/encapiwrapper.c 2007-09-16 22:07:03 UTC (rev 13844)
@@ -0,0 +1,154 @@
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "apiwrapper.h"
+#include "theora/theoraenc.h"
+#include "encint.h"
+
+
+
+static void th_enc_api_clear(th_api_wrapper *_api){
+ if(_api->encode)th_encode_free(_api->encode);
+ memset(_api,0,sizeof(*_api));
+}
+
+static void theora_encode_clear(theora_state *_te){
+ if(_te->i!=NULL)theora_info_clear(_te->i);
+ memset(_te,0,sizeof(*_te));
+}
+
+static int theora_encode_control(theora_state *_te,int _req,
+ void *_buf,size_t _buf_sz){
+ return th_encode_ctl(((th_api_wrapper *)_te->i->codec_setup)->encode,
+ _req,_buf,_buf_sz);
+}
+
+static ogg_int64_t theora_encode_granule_frame(theora_state *_te,
+ ogg_int64_t _gp){
+ return th_granule_frame(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);
+}
+
+static double theora_encode_granule_time(theora_state *_te,ogg_int64_t _gp){
+ return th_granule_time(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);
+}
+
+static const oc_state_dispatch_vtbl OC_ENC_DISPATCH_VTBL={
+ (oc_state_clear_func)theora_encode_clear,
+ (oc_state_control_func)theora_encode_control,
+ (oc_state_granule_frame_func)theora_encode_granule_frame,
+ (oc_state_granule_time_func)theora_encode_granule_time,
+};
+
+int theora_encode_init(theora_state *_te,theora_info *_ci){
+ th_api_info *apiinfo;
+ th_info info;
+ /*Allocate our own combined API wrapper/theora_info struct.
+ We put them both in one malloc'd block so that when the API wrapper is
+ freed, the info struct goes with it.
+ This avoids having to figure out whether or not we need to free the info
+ struct in either theora_info_clear() or theora_clear().*/
+ apiinfo=(th_api_info *)_ogg_malloc(sizeof(*apiinfo));
+ /*Make our own copy of the info struct, since its lifetime should be
+ independent of the one we were passed in.*/
+ *&apiinfo->info=*_ci;
+ oc_theora_info2th_info(&info,_ci);
+ apiinfo->api.encode=th_encode_alloc(&info);
+ if(apiinfo->api.encode==NULL){
+ _ogg_free(apiinfo);
+ return OC_EINVAL;
+ }
+ apiinfo->api.clear=(oc_setup_clear_func)th_enc_api_clear;
+ /*Provide entry points for ABI compatibility with old decoder shared libs.*/
+ _te->internal_encode=(void *)&OC_ENC_DISPATCH_VTBL;
+ _te->internal_decode=NULL;
+ _te->granulepos=0;
+ _te->i=&apiinfo->info;
+ _te->i->codec_setup=&apiinfo->api;
+ /*TODO: Additional codec setup using the extra fields in theora_info.*/
+ return 0;
+}
+
+int theora_encode_YUVin(theora_state *_te,yuv_buffer *_yuv){
+ th_api_wrapper *api;
+ th_ycbcr_buffer buf;
+ int ret;
+ api=(th_api_wrapper *)_te->i->codec_setup;
+ buf[0].width=_yuv->y_width;
+ buf[0].height=_yuv->y_height;
+ buf[0].ystride=_yuv->y_stride;
+ buf[0].data=_yuv->y;
+ buf[1].width=_yuv->uv_width;
+ buf[1].height=_yuv->uv_height;
+ buf[1].ystride=_yuv->uv_stride;
+ buf[1].data=_yuv->u;
+ buf[2].width=_yuv->uv_width;
+ buf[2].height=_yuv->uv_height;
+ buf[2].ystride=_yuv->uv_stride;
+ buf[2].data=_yuv->v;
+ ret=th_encode_ycbcr_in(api->encode,buf);
+ if(ret<0)return ret;
+ _te->granulepos=api->encode->state.granpos;
+ return ret;
+}
+
+int theora_encode_packetout(theora_state *_te,int _last_p,ogg_packet *_op){
+ th_api_wrapper *api;
+ api=(th_api_wrapper *)_te->i->codec_setup;
+ return th_encode_packetout(api->encode,_last_p,_op);
+}
+
+int theora_encode_header(theora_state *_te,ogg_packet *_op){
+ oc_enc_ctx *enc;
+ th_api_wrapper *api;
+ int ret;
+ api=(th_api_wrapper *)_te->i->codec_setup;
+ enc=api->encode;
+ /*If we've already started encoding, fail.*/
+ if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
+ return TH_EINVAL;
+ }
+ /*Reset the state to make sure we output an info packet.*/
+ enc->packet_state=OC_PACKET_INFO_HDR;
+ ret=th_encode_flushheader(api->encode,NULL,_op);
+ return ret>=0?0:ret;
+}
+
+int theora_encode_comment(theora_comment *_tc,ogg_packet *_op){
+ oggpack_buffer opb;
+ void *buf;
+ int packet_state;
+ int ret;
+ packet_state=OC_PACKET_COMMENT_HDR;
+ oggpackB_writeinit(&opb);
+ ret=oc_state_flushheader(NULL,&packet_state,&opb,NULL,NULL,NULL,
+ (th_comment *)_tc,_op);
+ if(ret>=0){
+ /*The oggpack_buffer's lifetime ends with this function, so we have to
+ copy out the packet contents.
+ Presumably the application knows it is supposed to free this.
+ This part works nothing like the Vorbis API, and the documentation on it
+ has been wrong for some time, claiming libtheora owned the memory.*/
+ buf=_ogg_malloc(_op->bytes);
+ memcpy(buf,_op->packet,_op->bytes);
+ _op->packet=buf;
+ ret=0;
+ }
+ oggpack_writeclear(&opb);
+ return ret;
+}
+
+int theora_encode_tables(theora_state *_te,ogg_packet *_op){
+ oc_enc_ctx *enc;
+ th_api_wrapper *api;
+ int ret;
+ api=(th_api_wrapper *)_te->i->codec_setup;
+ enc=api->encode;
+ /*If we've already started encoding, fail.*/
+ if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
+ return TH_EINVAL;
+ }
+ /*Reset the state to make sure we output a setup packet.*/
+ enc->packet_state=OC_PACKET_SETUP_HDR;
+ ret=th_encode_flushheader(api->encode,NULL,_op);
+ return ret>=0?0:ret;
+}
More information about the commits
mailing list