1 #include <stdlib.h>
2 #include <string.h>
3 #include <limits.h>
4 #include "apiwrapper.h"
5 #include "encint.h"
6 /* KITWARE_OGGTHEORA_CHANGE make sure we include the right headers */
7 #include "vtkoggtheora/include/theora/theoraenc.h"
8 
9 
10 
th_enc_api_clear(th_api_wrapper * _api)11 static void th_enc_api_clear(th_api_wrapper *_api){
12   if(_api->encode)th_encode_free(_api->encode);
13   memset(_api,0,sizeof(*_api));
14 }
15 
theora_encode_clear(theora_state * _te)16 static void theora_encode_clear(theora_state *_te){
17   if(_te->i!=NULL)theora_info_clear(_te->i);
18   memset(_te,0,sizeof(*_te));
19 }
20 
theora_encode_control(theora_state * _te,int _req,void * _buf,size_t _buf_sz)21 static int theora_encode_control(theora_state *_te,int _req,
22  void *_buf,size_t _buf_sz){
23   return th_encode_ctl(((th_api_wrapper *)_te->i->codec_setup)->encode,
24    _req,_buf,_buf_sz);
25 }
26 
theora_encode_granule_frame(theora_state * _te,ogg_int64_t _gp)27 static ogg_int64_t theora_encode_granule_frame(theora_state *_te,
28  ogg_int64_t _gp){
29   return th_granule_frame(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);
30 }
31 
theora_encode_granule_time(theora_state * _te,ogg_int64_t _gp)32 static double theora_encode_granule_time(theora_state *_te,ogg_int64_t _gp){
33   return th_granule_time(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);
34 }
35 
36 static const oc_state_dispatch_vtable OC_ENC_DISPATCH_VTBL={
37   (oc_state_clear_func)theora_encode_clear,
38   (oc_state_control_func)theora_encode_control,
39   (oc_state_granule_frame_func)theora_encode_granule_frame,
40   (oc_state_granule_time_func)theora_encode_granule_time,
41 };
42 
theora_encode_init(theora_state * _te,theora_info * _ci)43 int theora_encode_init(theora_state *_te,theora_info *_ci){
44   th_api_info *apiinfo;
45   th_info      info;
46   ogg_uint32_t keyframe_frequency_force;
47   /*Allocate our own combined API wrapper/theora_info struct.
48     We put them both in one malloc'd block so that when the API wrapper is
49      freed, the info struct goes with it.
50     This avoids having to figure out whether or not we need to free the info
51      struct in either theora_info_clear() or theora_clear().*/
52   apiinfo=(th_api_info *)_ogg_malloc(sizeof(*apiinfo));
53   if(apiinfo==NULL)return TH_EFAULT;
54   /*Make our own copy of the info struct, since its lifetime should be
55      independent of the one we were passed in.*/
56   *&apiinfo->info=*_ci;
57   oc_theora_info2th_info(&info,_ci);
58   apiinfo->api.encode=th_encode_alloc(&info);
59   if(apiinfo->api.encode==NULL){
60     _ogg_free(apiinfo);
61     return OC_EINVAL;
62   }
63   apiinfo->api.clear=(oc_setup_clear_func)th_enc_api_clear;
64   /*Provide entry points for ABI compatibility with old decoder shared libs.*/
65   _te->internal_encode=(void *)&OC_ENC_DISPATCH_VTBL;
66   _te->internal_decode=NULL;
67   _te->granulepos=0;
68   _te->i=&apiinfo->info;
69   _te->i->codec_setup=&apiinfo->api;
70   /*Set the precise requested keyframe frequency.*/
71   keyframe_frequency_force=_ci->keyframe_auto_p?
72    _ci->keyframe_frequency_force:_ci->keyframe_frequency;
73   th_encode_ctl(apiinfo->api.encode,
74    TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
75    &keyframe_frequency_force,sizeof(keyframe_frequency_force));
76   /*TODO: Additional codec setup using the extra fields in theora_info.*/
77   return 0;
78 }
79 
theora_encode_YUVin(theora_state * _te,yuv_buffer * _yuv)80 int theora_encode_YUVin(theora_state *_te,yuv_buffer *_yuv){
81   th_api_wrapper  *api;
82   th_ycbcr_buffer  buf;
83   int              ret;
84   api=(th_api_wrapper *)_te->i->codec_setup;
85   buf[0].width=_yuv->y_width;
86   buf[0].height=_yuv->y_height;
87   buf[0].stride=_yuv->y_stride;
88   buf[0].data=_yuv->y;
89   buf[1].width=_yuv->uv_width;
90   buf[1].height=_yuv->uv_height;
91   buf[1].stride=_yuv->uv_stride;
92   buf[1].data=_yuv->u;
93   buf[2].width=_yuv->uv_width;
94   buf[2].height=_yuv->uv_height;
95   buf[2].stride=_yuv->uv_stride;
96   buf[2].data=_yuv->v;
97   ret=th_encode_ycbcr_in(api->encode,buf);
98   if(ret<0)return ret;
99   _te->granulepos=api->encode->state.granpos;
100   return ret;
101 }
102 
theora_encode_packetout(theora_state * _te,int _last_p,ogg_packet * _op)103 int theora_encode_packetout(theora_state *_te,int _last_p,ogg_packet *_op){
104   th_api_wrapper *api;
105   api=(th_api_wrapper *)_te->i->codec_setup;
106   return th_encode_packetout(api->encode,_last_p,_op);
107 }
108 
theora_encode_header(theora_state * _te,ogg_packet * _op)109 int theora_encode_header(theora_state *_te,ogg_packet *_op){
110   oc_enc_ctx     *enc;
111   th_api_wrapper *api;
112   int             ret;
113   api=(th_api_wrapper *)_te->i->codec_setup;
114   enc=api->encode;
115   /*If we've already started encoding, fail.*/
116   if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
117     return TH_EINVAL;
118   }
119   /*Reset the state to make sure we output an info packet.*/
120   enc->packet_state=OC_PACKET_INFO_HDR;
121   ret=th_encode_flushheader(api->encode,NULL,_op);
122   return ret>=0?0:ret;
123 }
124 
theora_encode_comment(theora_comment * _tc,ogg_packet * _op)125 int theora_encode_comment(theora_comment *_tc,ogg_packet *_op){
126   oggpack_buffer  opb;
127   void           *buf;
128   int             packet_state;
129   int             ret;
130   packet_state=OC_PACKET_COMMENT_HDR;
131   oggpackB_writeinit(&opb);
132   ret=oc_state_flushheader(NULL,&packet_state,&opb,NULL,NULL,
133    th_version_string(),(th_comment *)_tc,_op);
134   if(ret>=0){
135     /*The oggpack_buffer's lifetime ends with this function, so we have to
136        copy out the packet contents.
137       Presumably the application knows it is supposed to free this.
138       This part works nothing like the Vorbis API, and the documentation on it
139        has been wrong for some time, claiming libtheora owned the memory.*/
140     buf=_ogg_malloc(_op->bytes);
141     if(buf==NULL){
142       _op->packet=NULL;
143       ret=TH_EFAULT;
144     }
145     else{
146       memcpy(buf,_op->packet,_op->bytes);
147       _op->packet=buf;
148       ret=0;
149     }
150   }
151   oggpack_writeclear(&opb);
152   return ret;
153 }
154 
theora_encode_tables(theora_state * _te,ogg_packet * _op)155 int theora_encode_tables(theora_state *_te,ogg_packet *_op){
156   oc_enc_ctx     *enc;
157   th_api_wrapper *api;
158   int             ret;
159   api=(th_api_wrapper *)_te->i->codec_setup;
160   enc=api->encode;
161   /*If we've already started encoding, fail.*/
162   if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
163     return TH_EINVAL;
164   }
165   /*Reset the state to make sure we output a setup packet.*/
166   enc->packet_state=OC_PACKET_SETUP_HDR;
167   ret=th_encode_flushheader(api->encode,NULL,_op);
168   return ret>=0?0:ret;
169 }
170