1 #include <stdlib.h>
2 #include <string.h>
3 #include <limits.h>
4 #include "apiwrapper.h"
5 #include "encint.h"
6 #include "theora/theoraenc.h"
7
8
9
th_enc_api_clear(th_api_wrapper * _api)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));
13 }
14
theora_encode_clear(theora_state * _te)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));
18 }
19
theora_encode_control(theora_state * _te,int _req,void * _buf,size_t _buf_sz)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,
23 _req,_buf,_buf_sz);
24 }
25
theora_encode_granule_frame(theora_state * _te,ogg_int64_t _gp)26 static ogg_int64_t theora_encode_granule_frame(theora_state *_te,
27 ogg_int64_t _gp){
28 return th_granule_frame(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);
29 }
30
theora_encode_granule_time(theora_state * _te,ogg_int64_t _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);
33 }
34
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,
40 };
41
theora_encode_init(theora_state * _te,theora_info * _ci)42 int theora_encode_init(theora_state *_te,theora_info *_ci){
43 th_api_info *apiinfo;
44 th_info info;
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.*/
55 *&apiinfo->info=*_ci;
56 oc_theora_info2th_info(&info,_ci);
57 apiinfo->api.encode=th_encode_alloc(&info);
58 if(apiinfo->api.encode==NULL){
59 _ogg_free(apiinfo);
60 return OC_EINVAL;
61 }
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;
66 _te->granulepos=0;
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.*/
76 return 0;
77 }
78
theora_encode_YUVin(theora_state * _te,yuv_buffer * _yuv)79 int theora_encode_YUVin(theora_state *_te,yuv_buffer *_yuv){
80 th_api_wrapper *api;
81 th_ycbcr_buffer buf;
82 int ret;
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;
87 buf[0].data=_yuv->y;
88 buf[1].width=_yuv->uv_width;
89 buf[1].height=_yuv->uv_height;
90 buf[1].stride=_yuv->uv_stride;
91 buf[1].data=_yuv->u;
92 buf[2].width=_yuv->uv_width;
93 buf[2].height=_yuv->uv_height;
94 buf[2].stride=_yuv->uv_stride;
95 buf[2].data=_yuv->v;
96 ret=th_encode_ycbcr_in(api->encode,buf);
97 if(ret<0)return ret;
98 _te->granulepos=api->encode->state.granpos;
99 return ret;
100 }
101
theora_encode_packetout(theora_state * _te,int _last_p,ogg_packet * _op)102 int theora_encode_packetout(theora_state *_te,int _last_p,ogg_packet *_op){
103 th_api_wrapper *api;
104 api=(th_api_wrapper *)_te->i->codec_setup;
105 return th_encode_packetout(api->encode,_last_p,_op);
106 }
107
theora_encode_header(theora_state * _te,ogg_packet * _op)108 int theora_encode_header(theora_state *_te,ogg_packet *_op){
109 oc_enc_ctx *enc;
110 th_api_wrapper *api;
111 int ret;
112 api=(th_api_wrapper *)_te->i->codec_setup;
113 enc=api->encode;
114 /*If we've already started encoding, fail.*/
115 if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
116 return TH_EINVAL;
117 }
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);
121 return ret>=0?0:ret;
122 }
123
theora_encode_comment(theora_comment * _tc,ogg_packet * _op)124 int theora_encode_comment(theora_comment *_tc,ogg_packet *_op){
125 oggpack_buffer opb;
126 void *buf;
127 int packet_state;
128 int ret;
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);
133 if(ret>=0){
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);
140 if(buf==NULL){
141 _op->packet=NULL;
142 ret=TH_EFAULT;
143 }
144 else{
145 memcpy(buf,_op->packet,_op->bytes);
146 _op->packet=buf;
147 ret=0;
148 }
149 }
150 oggpack_writeclear(&opb);
151 return ret;
152 }
153
theora_encode_tables(theora_state * _te,ogg_packet * _op)154 int theora_encode_tables(theora_state *_te,ogg_packet *_op){
155 oc_enc_ctx *enc;
156 th_api_wrapper *api;
157 int ret;
158 api=(th_api_wrapper *)_te->i->codec_setup;
159 enc=api->encode;
160 /*If we've already started encoding, fail.*/
161 if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
162 return TH_EINVAL;
163 }
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);
167 return ret>=0?0:ret;
168 }
169