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