Add an API wrapper to the encoder to export the new theora-exp API.
[xiph/unicode.git] / theora / lib / enc / encapiwrapper.c
blob062109c7955c55cde7d829908b60d95f40a93e2c
1 #include <string.h>
2 #include "theora/theoraenc.h"
3 #include "theora/theora.h"
4 #include "codec_internal.h"
6 /*Wrapper to translate the new API into the old API.
7 Eventually we need to convert the old functions to support the new API
8 natively and do the translation the other way.
9 theora-exp already the necessary code to do so.*/
11 static void th_info2theora_info(theora_info *_ci,const th_info *_info){
12 _ci->version_major=_info->version_major;
13 _ci->version_minor=_info->version_minor;
14 _ci->version_subminor=_info->version_subminor;
15 _ci->width=_info->frame_width;
16 _ci->height=_info->frame_height;
17 _ci->frame_width=_info->pic_width;
18 _ci->frame_height=_info->pic_height;
19 _ci->offset_x=_info->pic_x;
20 _ci->offset_y=_info->pic_y;
21 _ci->fps_numerator=_info->fps_numerator;
22 _ci->fps_denominator=_info->fps_denominator;
23 _ci->aspect_numerator=_info->aspect_numerator;
24 _ci->aspect_denominator=_info->aspect_denominator;
25 switch(_info->colorspace){
26 case TH_CS_ITU_REC_470M:_ci->colorspace=OC_CS_ITU_REC_470M;break;
27 case TH_CS_ITU_REC_470BG:_ci->colorspace=OC_CS_ITU_REC_470BG;break;
28 default:_ci->colorspace=OC_CS_UNSPECIFIED;break;
30 switch(_info->pixel_fmt){
31 case TH_PF_420:_ci->pixelformat=OC_PF_420;break;
32 case TH_PF_422:_ci->pixelformat=OC_PF_422;break;
33 case TH_PF_444:_ci->pixelformat=OC_PF_444;break;
34 default:_ci->pixelformat=OC_PF_RSVD;
36 _ci->target_bitrate=_info->target_bitrate;
37 _ci->quality=_info->quality;
38 _ci->keyframe_frequency_force=1<<_info->keyframe_granule_shift;
41 th_enc_ctx *th_encode_alloc(const th_info *_info){
42 theora_info ci;
43 theora_state *te;
44 th_info2theora_info(&ci,_info);
45 te=(theora_state *)_ogg_malloc(sizeof(*te));
46 if(theora_encode_init(te,&ci)<0){
47 _ogg_free(te);
48 te=NULL;
50 return (th_enc_ctx *)te;
53 int th_encode_ctl(th_enc_ctx *_enc,int _req,void *_buf,size_t _buf_sz){
54 return theora_control((theora_state *)_enc,_req,_buf,_buf_sz);
57 int th_encode_flushheader(th_enc_ctx *_enc,th_comment *_comments,
58 ogg_packet *_op){
59 theora_state *te;
60 CP_INSTANCE *cpi;
61 if(_enc==NULL||_op==NULL)return OC_FAULT;
62 te=(theora_state *)_enc;
63 cpi=(CP_INSTANCE *)te->internal_encode;
64 switch(cpi->doneflag){
65 case -3:{
66 theora_encode_header(te,_op);
67 return -cpi->doneflag++;
68 }break;
69 case -2:{
70 if(_comments==NULL)return OC_FAULT;
71 theora_encode_comment((theora_comment *)_comments,_op);
72 #ifndef LIBOGG2
73 /*The old API does not require a theora_state struct when writing the
74 comment header, so it can't use its internal buffer and relies on the
75 application to free it when using libogg 1.
76 The old documentation is wrong on this subject, and this breaks on
77 Windows when linking against multiple versions of libc (which is
78 almost always done when, e.g., using DLLs built with mingw32).
79 The new API _does_ require a th_enc_ctx, and states that libtheora owns
80 the memory.
81 Thus we move the contents of this packet into our internal
82 oggpack_buffer so it can be properly reclaimed.*/
83 oggpackB_reset(cpi->oggbuffer);
84 oggpackB_writecopy(cpi->oggbuffer,_op->packet,_op->bytes*8);
85 _ogg_free(_op->packet);
86 _op->packet=oggpackB_get_buffer(cpi->oggbuffer);
87 #endif
88 return -cpi->doneflag++;
89 }break;
90 case -1:{
91 theora_encode_tables(te,_op);
92 return -cpi->doneflag++;
93 }break;
94 case 0:return 0;
95 default:return OC_EINVAL;
99 int th_encode_ycbcr_in(th_enc_ctx *_enc,th_ycbcr_buffer _ycbcr){
100 CP_INSTANCE *cpi;
101 theora_state *te;
102 yuv_buffer yuv;
103 unsigned char *tmpbuf;
104 int ret;
105 if(_enc==NULL||_ycbcr==NULL)return OC_FAULT;
106 te=(theora_state *)_enc;
107 /*theora_encode_YUVin() does not bother to check uv_width and uv_height, and
108 then uses them.
109 This is arguably okay (it will most likely lead to a crash if they're
110 wrong, which will make the developer who passed them fix the problem), but
111 our API promises to return an error code instead.*/
112 cpi=(CP_INSTANCE *)te->internal_encode;
113 if(_ycbcr[1].width!=_ycbcr[0].width>>!(cpi->pb.info.pixelformat&1)||
114 _ycbcr[1].height!=_ycbcr[0].height>>!(cpi->pb.info.pixelformat&2)||
115 _ycbcr[2].width!=_ycbcr[1].width||_ycbcr[2].height!=_ycbcr[1].height){
116 return OC_EINVAL;
118 yuv.y_width=_ycbcr[0].width;
119 yuv.y_height=_ycbcr[0].height;
120 yuv.y_stride=_ycbcr[0].ystride;
121 yuv.y=_ycbcr[0].data;
122 yuv.uv_width=_ycbcr[1].width;
123 yuv.uv_height=_ycbcr[1].height;
124 if(_ycbcr[1].ystride==_ycbcr[2].ystride){
125 yuv.uv_stride=_ycbcr[1].ystride;
126 yuv.u=_ycbcr[1].data;
127 yuv.v=_ycbcr[2].data;
128 tmpbuf=NULL;
130 else{
131 unsigned char *src;
132 unsigned char *dst;
133 int i;
134 /*There's no way to signal different strides for the u and v components
135 when we pass them to theora_encode_YUVin().
136 Therefore we have to allocate a temporary buffer and copy them.*/
137 tmpbuf=(unsigned char *)_ogg_malloc(
138 (yuv.uv_width*yuv.uv_height<<1)*sizeof(*tmpbuf));
139 dst=tmpbuf;
140 yuv.u=dst;
141 src=_ycbcr[1].data;
142 for(i=0;i<yuv.uv_height;i++){
143 memcpy(dst,src,yuv.uv_width);
144 dst+=yuv.uv_width;
145 src+=_ycbcr[1].ystride;
147 yuv.v=dst;
148 src=_ycbcr[2].data;
149 for(i=0;i<yuv.uv_height;i++){
150 memcpy(dst,src,yuv.uv_width);
151 dst+=yuv.uv_width;
152 src+=_ycbcr[2].ystride;
154 yuv.uv_stride=yuv.uv_width;
156 ret=theora_encode_YUVin(te,&yuv);
157 _ogg_free(tmpbuf);
158 return ret;
161 int th_encode_packetout(th_enc_ctx *_enc,int _last,ogg_packet *_op){
162 if(_enc==NULL)return OC_FAULT;
163 return theora_encode_packetout((theora_state *)_enc,_last,_op);
166 void th_encode_free(th_enc_ctx *_enc){
167 if(_enc!=NULL){
168 theora_clear((theora_state *)_enc);
169 _ogg_free(_enc);