Mercurial > mplayer.hg
annotate tremor/info.c @ 21894:449b9fb6f67b
Fix: refmodes 2 and 3 leave useref unchanged
author | reimar |
---|---|
date | Sat, 13 Jan 2007 12:46:27 +0000 |
parents | cd6b211be811 |
children | e83eef58b30a |
rev | line source |
---|---|
14280 | 1 /******************************************************************** |
2 * * | |
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * | |
4 * * | |
19251
cd6b211be811
Replace tremor files that had old headers saying "ALL REDISTRIBUTION
uau
parents:
14280
diff
changeset
|
5 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * |
cd6b211be811
Replace tremor files that had old headers saying "ALL REDISTRIBUTION
uau
parents:
14280
diff
changeset
|
6 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * |
cd6b211be811
Replace tremor files that had old headers saying "ALL REDISTRIBUTION
uau
parents:
14280
diff
changeset
|
7 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * |
cd6b211be811
Replace tremor files that had old headers saying "ALL REDISTRIBUTION
uau
parents:
14280
diff
changeset
|
8 * * |
14280 | 9 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * |
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,op->bytes); | |
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 |