diff options
Diffstat (limited to 'apps/codecs/Tremor/info.c')
-rw-r--r-- | apps/codecs/Tremor/info.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/apps/codecs/Tremor/info.c b/apps/codecs/Tremor/info.c new file mode 100644 index 0000000000..941695ea8e --- /dev/null +++ b/apps/codecs/Tremor/info.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /******************************************************************** | ||
2 | * * | ||
3 | * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * | ||
4 | * * | ||
5 | * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | ||
6 | * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | ||
7 | * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | ||
8 | * * | ||
9 | * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * | ||
10 | * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * | ||
11 | * * | ||
12 | ******************************************************************** | ||
13 | |||
14 | function: maintain the info structure, info <-> header packets | ||
15 | |||
16 | ********************************************************************/ | ||
17 | |||
18 | /* general handling of the header and the vorbis_info structure (and | ||
19 | substructures) */ | ||
20 | |||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <ctype.h> | ||
24 | #include "ogg.h" | ||
25 | #include "ivorbiscodec.h" | ||
26 | #include "codec_internal.h" | ||
27 | #include "codebook.h" | ||
28 | #include "registry.h" | ||
29 | #include "window.h" | ||
30 | #include "misc.h" | ||
31 | #include "os.h" | ||
32 | |||
33 | /* helpers */ | ||
34 | static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){ | ||
35 | while(bytes--){ | ||
36 | *buf++=oggpack_read(o,8); | ||
37 | } | ||
38 | } | ||
39 | |||
40 | void vorbis_comment_init(vorbis_comment *vc){ | ||
41 | memset(vc,0,sizeof(*vc)); | ||
42 | } | ||
43 | |||
44 | /* This is more or less the same as strncasecmp - but that doesn't exist | ||
45 | * everywhere, and this is a fairly trivial function, so we include it */ | ||
46 | static int tagcompare(const char *s1, const char *s2, int n){ | ||
47 | int c=0; | ||
48 | while(c < n){ | ||
49 | if(toupper(s1[c]) != toupper(s2[c])) | ||
50 | return !0; | ||
51 | c++; | ||
52 | } | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){ | ||
57 | long i; | ||
58 | int found = 0; | ||
59 | int taglen = strlen(tag)+1; /* +1 for the = we append */ | ||
60 | char *fulltag = (char *)alloca(taglen+ 1); | ||
61 | |||
62 | strcpy(fulltag, tag); | ||
63 | strcat(fulltag, "="); | ||
64 | |||
65 | for(i=0;i<vc->comments;i++){ | ||
66 | if(!tagcompare(vc->user_comments[i], fulltag, taglen)){ | ||
67 | if(count == found) | ||
68 | /* We return a pointer to the data, not a copy */ | ||
69 | return vc->user_comments[i] + taglen; | ||
70 | else | ||
71 | found++; | ||
72 | } | ||
73 | } | ||
74 | return NULL; /* didn't find anything */ | ||
75 | } | ||
76 | |||
77 | int vorbis_comment_query_count(vorbis_comment *vc, char *tag){ | ||
78 | int i,count=0; | ||
79 | int taglen = strlen(tag)+1; /* +1 for the = we append */ | ||
80 | char *fulltag = (char *)alloca(taglen+1); | ||
81 | strcpy(fulltag,tag); | ||
82 | strcat(fulltag, "="); | ||
83 | |||
84 | for(i=0;i<vc->comments;i++){ | ||
85 | if(!tagcompare(vc->user_comments[i], fulltag, taglen)) | ||
86 | count++; | ||
87 | } | ||
88 | |||
89 | return count; | ||
90 | } | ||
91 | |||
92 | void vorbis_comment_clear(vorbis_comment *vc){ | ||
93 | if(vc){ | ||
94 | long i; | ||
95 | for(i=0;i<vc->comments;i++) | ||
96 | if(vc->user_comments[i])_ogg_free(vc->user_comments[i]); | ||
97 | if(vc->user_comments)_ogg_free(vc->user_comments); | ||
98 | if(vc->comment_lengths)_ogg_free(vc->comment_lengths); | ||
99 | if(vc->vendor)_ogg_free(vc->vendor); | ||
100 | } | ||
101 | memset(vc,0,sizeof(*vc)); | ||
102 | } | ||
103 | |||
104 | /* blocksize 0 is guaranteed to be short, 1 is guarantted to be long. | ||
105 | They may be equal, but short will never ge greater than long */ | ||
106 | int vorbis_info_blocksize(vorbis_info *vi,int zo){ | ||
107 | codec_setup_info *ci = (codec_setup_info *)vi->codec_setup; | ||
108 | return ci ? ci->blocksizes[zo] : -1; | ||
109 | } | ||
110 | |||
111 | /* used by synthesis, which has a full, alloced vi */ | ||
112 | void vorbis_info_init(vorbis_info *vi){ | ||
113 | memset(vi,0,sizeof(*vi)); | ||
114 | vi->codec_setup=(codec_setup_info *)_ogg_calloc(1,sizeof(codec_setup_info)); | ||
115 | } | ||
116 | |||
117 | void vorbis_info_clear(vorbis_info *vi){ | ||
118 | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; | ||
119 | int i; | ||
120 | |||
121 | if(ci){ | ||
122 | |||
123 | for(i=0;i<ci->modes;i++) | ||
124 | if(ci->mode_param[i])_ogg_free(ci->mode_param[i]); | ||
125 | |||
126 | for(i=0;i<ci->maps;i++) /* unpack does the range checking */ | ||
127 | _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]); | ||
128 | |||
129 | for(i=0;i<ci->floors;i++) /* unpack does the range checking */ | ||
130 | _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]); | ||
131 | |||
132 | for(i=0;i<ci->residues;i++) /* unpack does the range checking */ | ||
133 | _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]); | ||
134 | |||
135 | for(i=0;i<ci->books;i++){ | ||
136 | if(ci->book_param[i]){ | ||
137 | /* knows if the book was not alloced */ | ||
138 | vorbis_staticbook_destroy(ci->book_param[i]); | ||
139 | } | ||
140 | if(ci->fullbooks) | ||
141 | vorbis_book_clear(ci->fullbooks+i); | ||
142 | } | ||
143 | if(ci->fullbooks) | ||
144 | _ogg_free(ci->fullbooks); | ||
145 | |||
146 | _ogg_free(ci); | ||
147 | } | ||
148 | |||
149 | memset(vi,0,sizeof(*vi)); | ||
150 | } | ||
151 | |||
152 | /* Header packing/unpacking ********************************************/ | ||
153 | |||
154 | static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){ | ||
155 | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; | ||
156 | if(!ci)return(OV_EFAULT); | ||
157 | |||
158 | vi->version=oggpack_read(opb,32); | ||
159 | if(vi->version!=0)return(OV_EVERSION); | ||
160 | |||
161 | vi->channels=oggpack_read(opb,8); | ||
162 | vi->rate=oggpack_read(opb,32); | ||
163 | |||
164 | vi->bitrate_upper=oggpack_read(opb,32); | ||
165 | vi->bitrate_nominal=oggpack_read(opb,32); | ||
166 | vi->bitrate_lower=oggpack_read(opb,32); | ||
167 | |||
168 | ci->blocksizes[0]=1<<oggpack_read(opb,4); | ||
169 | ci->blocksizes[1]=1<<oggpack_read(opb,4); | ||
170 | |||
171 | if(vi->rate<1)goto err_out; | ||
172 | if(vi->channels<1)goto err_out; | ||
173 | if(ci->blocksizes[0]<64)goto err_out; | ||
174 | if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out; | ||
175 | if(ci->blocksizes[1]>8192)goto err_out; | ||
176 | |||
177 | if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ | ||
178 | |||
179 | return(0); | ||
180 | err_out: | ||
181 | vorbis_info_clear(vi); | ||
182 | return(OV_EBADHEADER); | ||
183 | } | ||
184 | |||
185 | static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){ | ||
186 | int i; | ||
187 | int vendorlen=oggpack_read(opb,32); | ||
188 | if(vendorlen<0)goto err_out; | ||
189 | vc->vendor=(char *)_ogg_calloc(vendorlen+1,1); | ||
190 | _v_readstring(opb,vc->vendor,vendorlen); | ||
191 | vc->comments=oggpack_read(opb,32); | ||
192 | if(vc->comments<0)goto err_out; | ||
193 | vc->user_comments=(char **)_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments)); | ||
194 | vc->comment_lengths=(int *)_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths)); | ||
195 | |||
196 | for(i=0;i<vc->comments;i++){ | ||
197 | int len=oggpack_read(opb,32); | ||
198 | if(len<0)goto err_out; | ||
199 | vc->comment_lengths[i]=len; | ||
200 | vc->user_comments[i]=(char *)_ogg_calloc(len+1,1); | ||
201 | _v_readstring(opb,vc->user_comments[i],len); | ||
202 | } | ||
203 | if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ | ||
204 | |||
205 | return(0); | ||
206 | err_out: | ||
207 | vorbis_comment_clear(vc); | ||
208 | return(OV_EBADHEADER); | ||
209 | } | ||
210 | |||
211 | /* all of the real encoding details are here. The modes, books, | ||
212 | everything */ | ||
213 | static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ | ||
214 | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; | ||
215 | int i; | ||
216 | if(!ci)return(OV_EFAULT); | ||
217 | |||
218 | /* codebooks */ | ||
219 | ci->books=oggpack_read(opb,8)+1; | ||
220 | /*ci->book_param=_ogg_calloc(ci->books,sizeof(*ci->book_param));*/ | ||
221 | for(i=0;i<ci->books;i++){ | ||
222 | ci->book_param[i]=(static_codebook *)_ogg_calloc(1,sizeof(*ci->book_param[i])); | ||
223 | if(vorbis_staticbook_unpack(opb,ci->book_param[i]))goto err_out; | ||
224 | } | ||
225 | |||
226 | /* time backend settings */ | ||
227 | ci->times=oggpack_read(opb,6)+1; | ||
228 | /*ci->time_type=_ogg_malloc(ci->times*sizeof(*ci->time_type));*/ | ||
229 | /*ci->time_param=_ogg_calloc(ci->times,sizeof(void *));*/ | ||
230 | for(i=0;i<ci->times;i++){ | ||
231 | ci->time_type[i]=oggpack_read(opb,16); | ||
232 | if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out; | ||
233 | /* ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb); | ||
234 | Vorbis I has no time backend */ | ||
235 | /*if(!ci->time_param[i])goto err_out;*/ | ||
236 | } | ||
237 | |||
238 | /* floor backend settings */ | ||
239 | ci->floors=oggpack_read(opb,6)+1; | ||
240 | /*ci->floor_type=_ogg_malloc(ci->floors*sizeof(*ci->floor_type));*/ | ||
241 | /*ci->floor_param=_ogg_calloc(ci->floors,sizeof(void *));*/ | ||
242 | for(i=0;i<ci->floors;i++){ | ||
243 | ci->floor_type[i]=oggpack_read(opb,16); | ||
244 | if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; | ||
245 | ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb); | ||
246 | if(!ci->floor_param[i])goto err_out; | ||
247 | } | ||
248 | |||
249 | /* residue backend settings */ | ||
250 | ci->residues=oggpack_read(opb,6)+1; | ||
251 | /*ci->residue_type=_ogg_malloc(ci->residues*sizeof(*ci->residue_type));*/ | ||
252 | /*ci->residue_param=_ogg_calloc(ci->residues,sizeof(void *));*/ | ||
253 | for(i=0;i<ci->residues;i++){ | ||
254 | ci->residue_type[i]=oggpack_read(opb,16); | ||
255 | if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out; | ||
256 | ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb); | ||
257 | if(!ci->residue_param[i])goto err_out; | ||
258 | } | ||
259 | |||
260 | /* map backend settings */ | ||
261 | ci->maps=oggpack_read(opb,6)+1; | ||
262 | /*ci->map_type=_ogg_malloc(ci->maps*sizeof(*ci->map_type));*/ | ||
263 | /*ci->map_param=_ogg_calloc(ci->maps,sizeof(void *));*/ | ||
264 | for(i=0;i<ci->maps;i++){ | ||
265 | ci->map_type[i]=oggpack_read(opb,16); | ||
266 | if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out; | ||
267 | ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb); | ||
268 | if(!ci->map_param[i])goto err_out; | ||
269 | } | ||
270 | |||
271 | /* mode settings */ | ||
272 | ci->modes=oggpack_read(opb,6)+1; | ||
273 | /*vi->mode_param=_ogg_calloc(vi->modes,sizeof(void *));*/ | ||
274 | for(i=0;i<ci->modes;i++){ | ||
275 | ci->mode_param[i]=(vorbis_info_mode *)_ogg_calloc(1,sizeof(*ci->mode_param[i])); | ||
276 | ci->mode_param[i]->blockflag=oggpack_read(opb,1); | ||
277 | ci->mode_param[i]->windowtype=oggpack_read(opb,16); | ||
278 | ci->mode_param[i]->transformtype=oggpack_read(opb,16); | ||
279 | ci->mode_param[i]->mapping=oggpack_read(opb,8); | ||
280 | |||
281 | if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out; | ||
282 | if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out; | ||
283 | if(ci->mode_param[i]->mapping>=ci->maps)goto err_out; | ||
284 | } | ||
285 | |||
286 | if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ | ||
287 | |||
288 | return(0); | ||
289 | err_out: | ||
290 | vorbis_info_clear(vi); | ||
291 | return(OV_EBADHEADER); | ||
292 | } | ||
293 | |||
294 | /* The Vorbis header is in three packets; the initial small packet in | ||
295 | the first page that identifies basic parameters, a second packet | ||
296 | with bitstream comments and a third packet that holds the | ||
297 | codebook. */ | ||
298 | |||
299 | int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){ | ||
300 | oggpack_buffer opb; | ||
301 | |||
302 | if(op){ | ||
303 | oggpack_readinit(&opb,op->packet); | ||
304 | |||
305 | /* Which of the three types of header is this? */ | ||
306 | /* Also verify header-ness, vorbis */ | ||
307 | { | ||
308 | char buffer[6]; | ||
309 | int packtype=oggpack_read(&opb,8); | ||
310 | memset(buffer,0,6); | ||
311 | _v_readstring(&opb,buffer,6); | ||
312 | if(memcmp(buffer,"vorbis",6)){ | ||
313 | /* not a vorbis header */ | ||
314 | return(OV_ENOTVORBIS); | ||
315 | } | ||
316 | switch(packtype){ | ||
317 | case 0x01: /* least significant *bit* is read first */ | ||
318 | if(!op->b_o_s){ | ||
319 | /* Not the initial packet */ | ||
320 | return(OV_EBADHEADER); | ||
321 | } | ||
322 | if(vi->rate!=0){ | ||
323 | /* previously initialized info header */ | ||
324 | return(OV_EBADHEADER); | ||
325 | } | ||
326 | |||
327 | return(_vorbis_unpack_info(vi,&opb)); | ||
328 | |||
329 | case 0x03: /* least significant *bit* is read first */ | ||
330 | if(vi->rate==0){ | ||
331 | /* um... we didn't get the initial header */ | ||
332 | return(OV_EBADHEADER); | ||
333 | } | ||
334 | |||
335 | return(_vorbis_unpack_comment(vc,&opb)); | ||
336 | |||
337 | case 0x05: /* least significant *bit* is read first */ | ||
338 | if(vi->rate==0 || vc->vendor==NULL){ | ||
339 | /* um... we didn;t get the initial header or comments yet */ | ||
340 | return(OV_EBADHEADER); | ||
341 | } | ||
342 | |||
343 | return(_vorbis_unpack_books(vi,&opb)); | ||
344 | |||
345 | default: | ||
346 | /* Not a valid vorbis header type */ | ||
347 | return(OV_EBADHEADER); | ||
348 | break; | ||
349 | } | ||
350 | } | ||
351 | } | ||
352 | return(OV_EBADHEADER); | ||
353 | } | ||
354 | |||