4 #include "apiwrapper.h"
6 #include "theora/theoraenc.h"
10 static void th_enc_api_clear(th_api_wrapper *_api){
11 if(_api->encode)th_encode_free(_api->encode);
12 memset(_api,0,sizeof(*_api));
15 static void theora_encode_clear(theora_state *_te){
16 if(_te->i!=NULL)theora_info_clear(_te->i);
17 memset(_te,0,sizeof(*_te));
20 static int theora_encode_control(theora_state *_te,int _req,
21 void *_buf,size_t _buf_sz){
22 return th_encode_ctl(((th_api_wrapper *)_te->i->codec_setup)->encode,
26 static ogg_int64_t theora_encode_granule_frame(theora_state *_te,
28 return th_granule_frame(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);
31 static double theora_encode_granule_time(theora_state *_te,ogg_int64_t _gp){
32 return th_granule_time(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);
35 static const oc_state_dispatch_vtable OC_ENC_DISPATCH_VTBL={
36 (oc_state_clear_func)theora_encode_clear,
37 (oc_state_control_func)theora_encode_control,
38 (oc_state_granule_frame_func)theora_encode_granule_frame,
39 (oc_state_granule_time_func)theora_encode_granule_time,
42 int theora_encode_init(theora_state *_te,theora_info *_ci){
45 ogg_uint32_t keyframe_frequency_force;
46 /*Allocate our own combined API wrapper/theora_info struct.
47 We put them both in one malloc'd block so that when the API wrapper is
48 freed, the info struct goes with it.
49 This avoids having to figure out whether or not we need to free the info
50 struct in either theora_info_clear() or theora_clear().*/
51 apiinfo=(th_api_info *)_ogg_malloc(sizeof(*apiinfo));
52 if(apiinfo==NULL)return TH_EFAULT;
53 /*Make our own copy of the info struct, since its lifetime should be
54 independent of the one we were passed in.*/
56 oc_theora_info2th_info(&info,_ci);
57 apiinfo->api.encode=th_encode_alloc(&info);
58 if(apiinfo->api.encode==NULL){
62 apiinfo->api.clear=(oc_setup_clear_func)th_enc_api_clear;
63 /*Provide entry points for ABI compatibility with old decoder shared libs.*/
64 _te->internal_encode=(void *)&OC_ENC_DISPATCH_VTBL;
65 _te->internal_decode=NULL;
67 _te->i=&apiinfo->info;
68 _te->i->codec_setup=&apiinfo->api;
69 /*Set the precise requested keyframe frequency.*/
70 keyframe_frequency_force=_ci->keyframe_auto_p?
71 _ci->keyframe_frequency_force:_ci->keyframe_frequency;
72 th_encode_ctl(apiinfo->api.encode,
73 TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
74 &keyframe_frequency_force,sizeof(keyframe_frequency_force));
75 /*TODO: Additional codec setup using the extra fields in theora_info.*/
79 int theora_encode_YUVin(theora_state *_te,yuv_buffer *_yuv){
83 api=(th_api_wrapper *)_te->i->codec_setup;
84 buf[0].width=_yuv->y_width;
85 buf[0].height=_yuv->y_height;
86 buf[0].stride=_yuv->y_stride;
88 buf[1].width=_yuv->uv_width;
89 buf[1].height=_yuv->uv_height;
90 buf[1].stride=_yuv->uv_stride;
92 buf[2].width=_yuv->uv_width;
93 buf[2].height=_yuv->uv_height;
94 buf[2].stride=_yuv->uv_stride;
96 ret=th_encode_ycbcr_in(api->encode,buf);
98 _te->granulepos=api->encode->state.granpos;
102 int theora_encode_packetout(theora_state *_te,int _last_p,ogg_packet *_op){
104 api=(th_api_wrapper *)_te->i->codec_setup;
105 return th_encode_packetout(api->encode,_last_p,_op);
108 int theora_encode_header(theora_state *_te,ogg_packet *_op){
112 api=(th_api_wrapper *)_te->i->codec_setup;
114 /*If we've already started encoding, fail.*/
115 if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
118 /*Reset the state to make sure we output an info packet.*/
119 enc->packet_state=OC_PACKET_INFO_HDR;
120 ret=th_encode_flushheader(api->encode,NULL,_op);
124 int theora_encode_comment(theora_comment *_tc,ogg_packet *_op){
129 packet_state=OC_PACKET_COMMENT_HDR;
130 oggpackB_writeinit(&opb);
131 ret=oc_state_flushheader(NULL,&packet_state,&opb,NULL,NULL,
132 th_version_string(),(th_comment *)_tc,_op);
134 /*The oggpack_buffer's lifetime ends with this function, so we have to
135 copy out the packet contents.
136 Presumably the application knows it is supposed to free this.
137 This part works nothing like the Vorbis API, and the documentation on it
138 has been wrong for some time, claiming libtheora owned the memory.*/
139 buf=_ogg_malloc(_op->bytes);
145 memcpy(buf,_op->packet,_op->bytes);
150 oggpack_writeclear(&opb);
154 int theora_encode_tables(theora_state *_te,ogg_packet *_op){
158 api=(th_api_wrapper *)_te->i->codec_setup;
160 /*If we've already started encoding, fail.*/
161 if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
164 /*Reset the state to make sure we output a setup packet.*/
165 enc->packet_state=OC_PACKET_SETUP_HDR;
166 ret=th_encode_flushheader(api->encode,NULL,_op);