14280
|
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
|