|
1 /******************************************************************** |
|
2 * * |
|
3 * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. * |
|
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * |
|
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * |
|
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * |
|
7 * * |
|
8 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 * |
|
9 * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * |
|
10 * * |
|
11 ******************************************************************** |
|
12 |
|
13 function: |
|
14 last mod: $Id: decapiwrapper.c 13596 2007-08-23 20:05:38Z tterribe $ |
|
15 |
|
16 ********************************************************************/ |
|
17 |
|
18 #include <stdlib.h> |
|
19 #include <string.h> |
|
20 #include <limits.h> |
|
21 #include "apiwrapper.h" |
|
22 #include "decint.h" |
|
23 #include "theora/theoradec.h" |
|
24 |
|
25 static void th_dec_api_clear(th_api_wrapper *_api){ |
|
26 if(_api->setup)th_setup_free(_api->setup); |
|
27 if(_api->decode)th_decode_free(_api->decode); |
|
28 memset(_api,0,sizeof(*_api)); |
|
29 } |
|
30 |
|
31 static void theora_decode_clear(theora_state *_td){ |
|
32 if(_td->i!=NULL)theora_info_clear(_td->i); |
|
33 memset(_td,0,sizeof(*_td)); |
|
34 } |
|
35 |
|
36 static int theora_decode_control(theora_state *_td,int _req, |
|
37 void *_buf,size_t _buf_sz){ |
|
38 return th_decode_ctl(((th_api_wrapper *)_td->i->codec_setup)->decode, |
|
39 _req,_buf,_buf_sz); |
|
40 } |
|
41 |
|
42 static ogg_int64_t theora_decode_granule_frame(theora_state *_td, |
|
43 ogg_int64_t _gp){ |
|
44 return th_granule_frame(((th_api_wrapper *)_td->i->codec_setup)->decode,_gp); |
|
45 } |
|
46 |
|
47 static double theora_decode_granule_time(theora_state *_td,ogg_int64_t _gp){ |
|
48 return th_granule_time(((th_api_wrapper *)_td->i->codec_setup)->decode,_gp); |
|
49 } |
|
50 |
|
51 static const oc_state_dispatch_vtable OC_DEC_DISPATCH_VTBL={ |
|
52 (oc_state_clear_func)theora_decode_clear, |
|
53 (oc_state_control_func)theora_decode_control, |
|
54 (oc_state_granule_frame_func)theora_decode_granule_frame, |
|
55 (oc_state_granule_time_func)theora_decode_granule_time, |
|
56 }; |
|
57 |
|
58 static void th_info2theora_info(theora_info *_ci,const th_info *_info){ |
|
59 _ci->version_major=_info->version_major; |
|
60 _ci->version_minor=_info->version_minor; |
|
61 _ci->version_subminor=_info->version_subminor; |
|
62 _ci->width=_info->frame_width; |
|
63 _ci->height=_info->frame_height; |
|
64 _ci->frame_width=_info->pic_width; |
|
65 _ci->frame_height=_info->pic_height; |
|
66 _ci->offset_x=_info->pic_x; |
|
67 _ci->offset_y=_info->pic_y; |
|
68 _ci->fps_numerator=_info->fps_numerator; |
|
69 _ci->fps_denominator=_info->fps_denominator; |
|
70 _ci->aspect_numerator=_info->aspect_numerator; |
|
71 _ci->aspect_denominator=_info->aspect_denominator; |
|
72 switch(_info->colorspace){ |
|
73 case TH_CS_ITU_REC_470M:_ci->colorspace=OC_CS_ITU_REC_470M;break; |
|
74 case TH_CS_ITU_REC_470BG:_ci->colorspace=OC_CS_ITU_REC_470BG;break; |
|
75 default:_ci->colorspace=OC_CS_UNSPECIFIED;break; |
|
76 } |
|
77 switch(_info->pixel_fmt){ |
|
78 case TH_PF_420:_ci->pixelformat=OC_PF_420;break; |
|
79 case TH_PF_422:_ci->pixelformat=OC_PF_422;break; |
|
80 case TH_PF_444:_ci->pixelformat=OC_PF_444;break; |
|
81 default:_ci->pixelformat=OC_PF_RSVD; |
|
82 } |
|
83 _ci->target_bitrate=_info->target_bitrate; |
|
84 _ci->quality=_info->quality; |
|
85 _ci->keyframe_frequency_force=1<<_info->keyframe_granule_shift; |
|
86 } |
|
87 |
|
88 int theora_decode_init(theora_state *_td,theora_info *_ci){ |
|
89 th_api_info *apiinfo; |
|
90 th_api_wrapper *api; |
|
91 th_info info; |
|
92 api=(th_api_wrapper *)_ci->codec_setup; |
|
93 /*Allocate our own combined API wrapper/theora_info struct. |
|
94 We put them both in one malloc'd block so that when the API wrapper is |
|
95 freed, the info struct goes with it. |
|
96 This avoids having to figure out whether or not we need to free the info |
|
97 struct in either theora_info_clear() or theora_clear().*/ |
|
98 apiinfo=(th_api_info *)_ogg_calloc(1,sizeof(*apiinfo)); |
|
99 if(apiinfo==NULL)return OC_FAULT; |
|
100 /*Make our own copy of the info struct, since its lifetime should be |
|
101 independent of the one we were passed in.*/ |
|
102 *&apiinfo->info=*_ci; |
|
103 /*Convert the info struct now instead of saving the the one we decoded with |
|
104 theora_decode_header(), since the user might have modified values (i.e., |
|
105 color space, aspect ratio, etc. can be specified from a higher level). |
|
106 The user also might be doing something "clever" with the header packets if |
|
107 they are not using an Ogg encapsulation.*/ |
|
108 oc_theora_info2th_info(&info,_ci); |
|
109 /*Don't bother to copy the setup info; th_decode_alloc() makes its own copy |
|
110 of the stuff it needs.*/ |
|
111 apiinfo->api.decode=th_decode_alloc(&info,api->setup); |
|
112 if(apiinfo->api.decode==NULL){ |
|
113 _ogg_free(apiinfo); |
|
114 return OC_EINVAL; |
|
115 } |
|
116 apiinfo->api.clear=(oc_setup_clear_func)th_dec_api_clear; |
|
117 _td->internal_encode=NULL; |
|
118 /*Provide entry points for ABI compatibility with old decoder shared libs.*/ |
|
119 _td->internal_decode=(void *)&OC_DEC_DISPATCH_VTBL; |
|
120 _td->granulepos=0; |
|
121 _td->i=&apiinfo->info; |
|
122 _td->i->codec_setup=&apiinfo->api; |
|
123 return 0; |
|
124 } |
|
125 |
|
126 int theora_decode_header(theora_info *_ci,theora_comment *_cc,ogg_packet *_op){ |
|
127 th_api_wrapper *api; |
|
128 th_info info; |
|
129 int ret; |
|
130 api=(th_api_wrapper *)_ci->codec_setup; |
|
131 /*Allocate an API wrapper struct on demand, since it will not also include a |
|
132 theora_info struct like the ones that are used in a theora_state struct.*/ |
|
133 if(api==NULL){ |
|
134 _ci->codec_setup=_ogg_calloc(1,sizeof(*api)); |
|
135 if(_ci->codec_setup==NULL)return OC_FAULT; |
|
136 api=(th_api_wrapper *)_ci->codec_setup; |
|
137 api->clear=(oc_setup_clear_func)th_dec_api_clear; |
|
138 } |
|
139 /*Convert from the theora_info struct instead of saving our own th_info |
|
140 struct between calls. |
|
141 The user might be doing something "clever" with the header packets if they |
|
142 are not using an Ogg encapsulation, and we don't want to break this.*/ |
|
143 oc_theora_info2th_info(&info,_ci); |
|
144 /*We rely on the fact that theora_comment and th_comment structures are |
|
145 actually identical. |
|
146 Take care not to change this fact unless you change the code here as |
|
147 well!*/ |
|
148 ret=th_decode_headerin(&info,(th_comment *)_cc,&api->setup,_op); |
|
149 /*We also rely on the fact that the error return code values are the same, |
|
150 and that the implementations of these two functions return the same set of |
|
151 them. |
|
152 Note that theora_decode_header() really can return OC_NOTFORMAT, even |
|
153 though it is not currently documented to do so.*/ |
|
154 if(ret<0)return ret; |
|
155 th_info2theora_info(_ci,&info); |
|
156 return 0; |
|
157 } |
|
158 |
|
159 int theora_decode_packetin(theora_state *_td,ogg_packet *_op){ |
|
160 th_api_wrapper *api; |
|
161 ogg_int64_t gp; |
|
162 int ret; |
|
163 if(!_td||!_td->i||!_td->i->codec_setup)return OC_FAULT; |
|
164 api=(th_api_wrapper *)_td->i->codec_setup; |
|
165 ret=th_decode_packetin(api->decode,_op,&gp); |
|
166 if(ret<0)return OC_BADPACKET; |
|
167 _td->granulepos=gp; |
|
168 return 0; |
|
169 } |
|
170 |
|
171 int theora_decode_YUVout(theora_state *_td,yuv_buffer *_yuv){ |
|
172 th_api_wrapper *api; |
|
173 th_dec_ctx *decode; |
|
174 th_ycbcr_buffer buf; |
|
175 int ret; |
|
176 if(!_td||!_td->i||!_td->i->codec_setup)return OC_FAULT; |
|
177 api=(th_api_wrapper *)_td->i->codec_setup; |
|
178 decode=(th_dec_ctx *)api->decode; |
|
179 if(!decode)return OC_FAULT; |
|
180 ret=th_decode_ycbcr_out(decode,buf); |
|
181 if(ret>=0){ |
|
182 _yuv->y_width=buf[0].width; |
|
183 _yuv->y_height=buf[0].height; |
|
184 _yuv->y_stride=buf[0].stride; |
|
185 _yuv->uv_width=buf[1].width; |
|
186 _yuv->uv_height=buf[1].height; |
|
187 _yuv->uv_stride=buf[1].stride; |
|
188 _yuv->y=buf[0].data; |
|
189 _yuv->u=buf[1].data; |
|
190 _yuv->v=buf[2].data; |
|
191 } |
|
192 return ret; |
|
193 } |