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