spec: Use %license macro to copy license
[platform/upstream/libtheora.git] / lib / encapiwrapper.c
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
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
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
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
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
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
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
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
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
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
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
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 }