Mercurial > hg > sv-dependency-builds
comparison src/libvorbis-1.3.3/lib/info.c @ 1:05aa0afa9217
Bring in flac, ogg, vorbis
author | Chris Cannam |
---|---|
date | Tue, 19 Mar 2013 17:37:49 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:c7265573341e | 1:05aa0afa9217 |
---|---|
1 /******************************************************************** | |
2 * * | |
3 * THIS FILE IS PART OF THE OggVorbis 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 OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * | |
9 * by the Xiph.Org Foundation http://www.xiph.org/ * | |
10 * * | |
11 ******************************************************************** | |
12 | |
13 function: maintain the info structure, info <-> header packets | |
14 last mod: $Id: info.c 18186 2012-02-03 22:08:44Z xiphmont $ | |
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/ogg.h> | |
25 #include "vorbis/codec.h" | |
26 #include "codec_internal.h" | |
27 #include "codebook.h" | |
28 #include "registry.h" | |
29 #include "window.h" | |
30 #include "psy.h" | |
31 #include "misc.h" | |
32 #include "os.h" | |
33 | |
34 #define GENERAL_VENDOR_STRING "Xiph.Org libVorbis 1.3.3" | |
35 #define ENCODE_VENDOR_STRING "Xiph.Org libVorbis I 20120203 (Omnipresent)" | |
36 | |
37 /* helpers */ | |
38 static int ilog2(unsigned int v){ | |
39 int ret=0; | |
40 if(v)--v; | |
41 while(v){ | |
42 ret++; | |
43 v>>=1; | |
44 } | |
45 return(ret); | |
46 } | |
47 | |
48 static void _v_writestring(oggpack_buffer *o,const char *s, int bytes){ | |
49 | |
50 while(bytes--){ | |
51 oggpack_write(o,*s++,8); | |
52 } | |
53 } | |
54 | |
55 static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){ | |
56 while(bytes--){ | |
57 *buf++=oggpack_read(o,8); | |
58 } | |
59 } | |
60 | |
61 void vorbis_comment_init(vorbis_comment *vc){ | |
62 memset(vc,0,sizeof(*vc)); | |
63 } | |
64 | |
65 void vorbis_comment_add(vorbis_comment *vc,const char *comment){ | |
66 vc->user_comments=_ogg_realloc(vc->user_comments, | |
67 (vc->comments+2)*sizeof(*vc->user_comments)); | |
68 vc->comment_lengths=_ogg_realloc(vc->comment_lengths, | |
69 (vc->comments+2)*sizeof(*vc->comment_lengths)); | |
70 vc->comment_lengths[vc->comments]=strlen(comment); | |
71 vc->user_comments[vc->comments]=_ogg_malloc(vc->comment_lengths[vc->comments]+1); | |
72 strcpy(vc->user_comments[vc->comments], comment); | |
73 vc->comments++; | |
74 vc->user_comments[vc->comments]=NULL; | |
75 } | |
76 | |
77 void vorbis_comment_add_tag(vorbis_comment *vc, const char *tag, const char *contents){ | |
78 char *comment=alloca(strlen(tag)+strlen(contents)+2); /* +2 for = and \0 */ | |
79 strcpy(comment, tag); | |
80 strcat(comment, "="); | |
81 strcat(comment, contents); | |
82 vorbis_comment_add(vc, comment); | |
83 } | |
84 | |
85 /* This is more or less the same as strncasecmp - but that doesn't exist | |
86 * everywhere, and this is a fairly trivial function, so we include it */ | |
87 static int tagcompare(const char *s1, const char *s2, int n){ | |
88 int c=0; | |
89 while(c < n){ | |
90 if(toupper(s1[c]) != toupper(s2[c])) | |
91 return !0; | |
92 c++; | |
93 } | |
94 return 0; | |
95 } | |
96 | |
97 char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count){ | |
98 long i; | |
99 int found = 0; | |
100 int taglen = strlen(tag)+1; /* +1 for the = we append */ | |
101 char *fulltag = alloca(taglen+ 1); | |
102 | |
103 strcpy(fulltag, tag); | |
104 strcat(fulltag, "="); | |
105 | |
106 for(i=0;i<vc->comments;i++){ | |
107 if(!tagcompare(vc->user_comments[i], fulltag, taglen)){ | |
108 if(count == found) | |
109 /* We return a pointer to the data, not a copy */ | |
110 return vc->user_comments[i] + taglen; | |
111 else | |
112 found++; | |
113 } | |
114 } | |
115 return NULL; /* didn't find anything */ | |
116 } | |
117 | |
118 int vorbis_comment_query_count(vorbis_comment *vc, const char *tag){ | |
119 int i,count=0; | |
120 int taglen = strlen(tag)+1; /* +1 for the = we append */ | |
121 char *fulltag = alloca(taglen+1); | |
122 strcpy(fulltag,tag); | |
123 strcat(fulltag, "="); | |
124 | |
125 for(i=0;i<vc->comments;i++){ | |
126 if(!tagcompare(vc->user_comments[i], fulltag, taglen)) | |
127 count++; | |
128 } | |
129 | |
130 return count; | |
131 } | |
132 | |
133 void vorbis_comment_clear(vorbis_comment *vc){ | |
134 if(vc){ | |
135 long i; | |
136 if(vc->user_comments){ | |
137 for(i=0;i<vc->comments;i++) | |
138 if(vc->user_comments[i])_ogg_free(vc->user_comments[i]); | |
139 _ogg_free(vc->user_comments); | |
140 } | |
141 if(vc->comment_lengths)_ogg_free(vc->comment_lengths); | |
142 if(vc->vendor)_ogg_free(vc->vendor); | |
143 memset(vc,0,sizeof(*vc)); | |
144 } | |
145 } | |
146 | |
147 /* blocksize 0 is guaranteed to be short, 1 is guaranteed to be long. | |
148 They may be equal, but short will never ge greater than long */ | |
149 int vorbis_info_blocksize(vorbis_info *vi,int zo){ | |
150 codec_setup_info *ci = vi->codec_setup; | |
151 return ci ? ci->blocksizes[zo] : -1; | |
152 } | |
153 | |
154 /* used by synthesis, which has a full, alloced vi */ | |
155 void vorbis_info_init(vorbis_info *vi){ | |
156 memset(vi,0,sizeof(*vi)); | |
157 vi->codec_setup=_ogg_calloc(1,sizeof(codec_setup_info)); | |
158 } | |
159 | |
160 void vorbis_info_clear(vorbis_info *vi){ | |
161 codec_setup_info *ci=vi->codec_setup; | |
162 int i; | |
163 | |
164 if(ci){ | |
165 | |
166 for(i=0;i<ci->modes;i++) | |
167 if(ci->mode_param[i])_ogg_free(ci->mode_param[i]); | |
168 | |
169 for(i=0;i<ci->maps;i++) /* unpack does the range checking */ | |
170 if(ci->map_param[i]) /* this may be cleaning up an aborted | |
171 unpack, in which case the below type | |
172 cannot be trusted */ | |
173 _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]); | |
174 | |
175 for(i=0;i<ci->floors;i++) /* unpack does the range checking */ | |
176 if(ci->floor_param[i]) /* this may be cleaning up an aborted | |
177 unpack, in which case the below type | |
178 cannot be trusted */ | |
179 _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]); | |
180 | |
181 for(i=0;i<ci->residues;i++) /* unpack does the range checking */ | |
182 if(ci->residue_param[i]) /* this may be cleaning up an aborted | |
183 unpack, in which case the below type | |
184 cannot be trusted */ | |
185 _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]); | |
186 | |
187 for(i=0;i<ci->books;i++){ | |
188 if(ci->book_param[i]){ | |
189 /* knows if the book was not alloced */ | |
190 vorbis_staticbook_destroy(ci->book_param[i]); | |
191 } | |
192 if(ci->fullbooks) | |
193 vorbis_book_clear(ci->fullbooks+i); | |
194 } | |
195 if(ci->fullbooks) | |
196 _ogg_free(ci->fullbooks); | |
197 | |
198 for(i=0;i<ci->psys;i++) | |
199 _vi_psy_free(ci->psy_param[i]); | |
200 | |
201 _ogg_free(ci); | |
202 } | |
203 | |
204 memset(vi,0,sizeof(*vi)); | |
205 } | |
206 | |
207 /* Header packing/unpacking ********************************************/ | |
208 | |
209 static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){ | |
210 codec_setup_info *ci=vi->codec_setup; | |
211 if(!ci)return(OV_EFAULT); | |
212 | |
213 vi->version=oggpack_read(opb,32); | |
214 if(vi->version!=0)return(OV_EVERSION); | |
215 | |
216 vi->channels=oggpack_read(opb,8); | |
217 vi->rate=oggpack_read(opb,32); | |
218 | |
219 vi->bitrate_upper=oggpack_read(opb,32); | |
220 vi->bitrate_nominal=oggpack_read(opb,32); | |
221 vi->bitrate_lower=oggpack_read(opb,32); | |
222 | |
223 ci->blocksizes[0]=1<<oggpack_read(opb,4); | |
224 ci->blocksizes[1]=1<<oggpack_read(opb,4); | |
225 | |
226 if(vi->rate<1)goto err_out; | |
227 if(vi->channels<1)goto err_out; | |
228 if(ci->blocksizes[0]<64)goto err_out; | |
229 if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out; | |
230 if(ci->blocksizes[1]>8192)goto err_out; | |
231 | |
232 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ | |
233 | |
234 return(0); | |
235 err_out: | |
236 vorbis_info_clear(vi); | |
237 return(OV_EBADHEADER); | |
238 } | |
239 | |
240 static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){ | |
241 int i; | |
242 int vendorlen=oggpack_read(opb,32); | |
243 if(vendorlen<0)goto err_out; | |
244 if(vendorlen>opb->storage-8)goto err_out; | |
245 vc->vendor=_ogg_calloc(vendorlen+1,1); | |
246 _v_readstring(opb,vc->vendor,vendorlen); | |
247 i=oggpack_read(opb,32); | |
248 if(i<0)goto err_out; | |
249 if(i>((opb->storage-oggpack_bytes(opb))>>2))goto err_out; | |
250 vc->comments=i; | |
251 vc->user_comments=_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments)); | |
252 vc->comment_lengths=_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths)); | |
253 | |
254 for(i=0;i<vc->comments;i++){ | |
255 int len=oggpack_read(opb,32); | |
256 if(len<0)goto err_out; | |
257 if(len>opb->storage-oggpack_bytes(opb))goto err_out; | |
258 vc->comment_lengths[i]=len; | |
259 vc->user_comments[i]=_ogg_calloc(len+1,1); | |
260 _v_readstring(opb,vc->user_comments[i],len); | |
261 } | |
262 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ | |
263 | |
264 return(0); | |
265 err_out: | |
266 vorbis_comment_clear(vc); | |
267 return(OV_EBADHEADER); | |
268 } | |
269 | |
270 /* all of the real encoding details are here. The modes, books, | |
271 everything */ | |
272 static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ | |
273 codec_setup_info *ci=vi->codec_setup; | |
274 int i; | |
275 if(!ci)return(OV_EFAULT); | |
276 | |
277 /* codebooks */ | |
278 ci->books=oggpack_read(opb,8)+1; | |
279 if(ci->books<=0)goto err_out; | |
280 for(i=0;i<ci->books;i++){ | |
281 ci->book_param[i]=vorbis_staticbook_unpack(opb); | |
282 if(!ci->book_param[i])goto err_out; | |
283 } | |
284 | |
285 /* time backend settings; hooks are unused */ | |
286 { | |
287 int times=oggpack_read(opb,6)+1; | |
288 if(times<=0)goto err_out; | |
289 for(i=0;i<times;i++){ | |
290 int test=oggpack_read(opb,16); | |
291 if(test<0 || test>=VI_TIMEB)goto err_out; | |
292 } | |
293 } | |
294 | |
295 /* floor backend settings */ | |
296 ci->floors=oggpack_read(opb,6)+1; | |
297 if(ci->floors<=0)goto err_out; | |
298 for(i=0;i<ci->floors;i++){ | |
299 ci->floor_type[i]=oggpack_read(opb,16); | |
300 if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; | |
301 ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb); | |
302 if(!ci->floor_param[i])goto err_out; | |
303 } | |
304 | |
305 /* residue backend settings */ | |
306 ci->residues=oggpack_read(opb,6)+1; | |
307 if(ci->residues<=0)goto err_out; | |
308 for(i=0;i<ci->residues;i++){ | |
309 ci->residue_type[i]=oggpack_read(opb,16); | |
310 if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out; | |
311 ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb); | |
312 if(!ci->residue_param[i])goto err_out; | |
313 } | |
314 | |
315 /* map backend settings */ | |
316 ci->maps=oggpack_read(opb,6)+1; | |
317 if(ci->maps<=0)goto err_out; | |
318 for(i=0;i<ci->maps;i++){ | |
319 ci->map_type[i]=oggpack_read(opb,16); | |
320 if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out; | |
321 ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb); | |
322 if(!ci->map_param[i])goto err_out; | |
323 } | |
324 | |
325 /* mode settings */ | |
326 ci->modes=oggpack_read(opb,6)+1; | |
327 if(ci->modes<=0)goto err_out; | |
328 for(i=0;i<ci->modes;i++){ | |
329 ci->mode_param[i]=_ogg_calloc(1,sizeof(*ci->mode_param[i])); | |
330 ci->mode_param[i]->blockflag=oggpack_read(opb,1); | |
331 ci->mode_param[i]->windowtype=oggpack_read(opb,16); | |
332 ci->mode_param[i]->transformtype=oggpack_read(opb,16); | |
333 ci->mode_param[i]->mapping=oggpack_read(opb,8); | |
334 | |
335 if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out; | |
336 if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out; | |
337 if(ci->mode_param[i]->mapping>=ci->maps)goto err_out; | |
338 if(ci->mode_param[i]->mapping<0)goto err_out; | |
339 } | |
340 | |
341 if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ | |
342 | |
343 return(0); | |
344 err_out: | |
345 vorbis_info_clear(vi); | |
346 return(OV_EBADHEADER); | |
347 } | |
348 | |
349 /* Is this packet a vorbis ID header? */ | |
350 int vorbis_synthesis_idheader(ogg_packet *op){ | |
351 oggpack_buffer opb; | |
352 char buffer[6]; | |
353 | |
354 if(op){ | |
355 oggpack_readinit(&opb,op->packet,op->bytes); | |
356 | |
357 if(!op->b_o_s) | |
358 return(0); /* Not the initial packet */ | |
359 | |
360 if(oggpack_read(&opb,8) != 1) | |
361 return 0; /* not an ID header */ | |
362 | |
363 memset(buffer,0,6); | |
364 _v_readstring(&opb,buffer,6); | |
365 if(memcmp(buffer,"vorbis",6)) | |
366 return 0; /* not vorbis */ | |
367 | |
368 return 1; | |
369 } | |
370 | |
371 return 0; | |
372 } | |
373 | |
374 /* The Vorbis header is in three packets; the initial small packet in | |
375 the first page that identifies basic parameters, a second packet | |
376 with bitstream comments and a third packet that holds the | |
377 codebook. */ | |
378 | |
379 int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){ | |
380 oggpack_buffer opb; | |
381 | |
382 if(op){ | |
383 oggpack_readinit(&opb,op->packet,op->bytes); | |
384 | |
385 /* Which of the three types of header is this? */ | |
386 /* Also verify header-ness, vorbis */ | |
387 { | |
388 char buffer[6]; | |
389 int packtype=oggpack_read(&opb,8); | |
390 memset(buffer,0,6); | |
391 _v_readstring(&opb,buffer,6); | |
392 if(memcmp(buffer,"vorbis",6)){ | |
393 /* not a vorbis header */ | |
394 return(OV_ENOTVORBIS); | |
395 } | |
396 switch(packtype){ | |
397 case 0x01: /* least significant *bit* is read first */ | |
398 if(!op->b_o_s){ | |
399 /* Not the initial packet */ | |
400 return(OV_EBADHEADER); | |
401 } | |
402 if(vi->rate!=0){ | |
403 /* previously initialized info header */ | |
404 return(OV_EBADHEADER); | |
405 } | |
406 | |
407 return(_vorbis_unpack_info(vi,&opb)); | |
408 | |
409 case 0x03: /* least significant *bit* is read first */ | |
410 if(vi->rate==0){ | |
411 /* um... we didn't get the initial header */ | |
412 return(OV_EBADHEADER); | |
413 } | |
414 | |
415 return(_vorbis_unpack_comment(vc,&opb)); | |
416 | |
417 case 0x05: /* least significant *bit* is read first */ | |
418 if(vi->rate==0 || vc->vendor==NULL){ | |
419 /* um... we didn;t get the initial header or comments yet */ | |
420 return(OV_EBADHEADER); | |
421 } | |
422 | |
423 return(_vorbis_unpack_books(vi,&opb)); | |
424 | |
425 default: | |
426 /* Not a valid vorbis header type */ | |
427 return(OV_EBADHEADER); | |
428 break; | |
429 } | |
430 } | |
431 } | |
432 return(OV_EBADHEADER); | |
433 } | |
434 | |
435 /* pack side **********************************************************/ | |
436 | |
437 static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){ | |
438 codec_setup_info *ci=vi->codec_setup; | |
439 if(!ci)return(OV_EFAULT); | |
440 | |
441 /* preamble */ | |
442 oggpack_write(opb,0x01,8); | |
443 _v_writestring(opb,"vorbis", 6); | |
444 | |
445 /* basic information about the stream */ | |
446 oggpack_write(opb,0x00,32); | |
447 oggpack_write(opb,vi->channels,8); | |
448 oggpack_write(opb,vi->rate,32); | |
449 | |
450 oggpack_write(opb,vi->bitrate_upper,32); | |
451 oggpack_write(opb,vi->bitrate_nominal,32); | |
452 oggpack_write(opb,vi->bitrate_lower,32); | |
453 | |
454 oggpack_write(opb,ilog2(ci->blocksizes[0]),4); | |
455 oggpack_write(opb,ilog2(ci->blocksizes[1]),4); | |
456 oggpack_write(opb,1,1); | |
457 | |
458 return(0); | |
459 } | |
460 | |
461 static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){ | |
462 int bytes = strlen(ENCODE_VENDOR_STRING); | |
463 | |
464 /* preamble */ | |
465 oggpack_write(opb,0x03,8); | |
466 _v_writestring(opb,"vorbis", 6); | |
467 | |
468 /* vendor */ | |
469 oggpack_write(opb,bytes,32); | |
470 _v_writestring(opb,ENCODE_VENDOR_STRING, bytes); | |
471 | |
472 /* comments */ | |
473 | |
474 oggpack_write(opb,vc->comments,32); | |
475 if(vc->comments){ | |
476 int i; | |
477 for(i=0;i<vc->comments;i++){ | |
478 if(vc->user_comments[i]){ | |
479 oggpack_write(opb,vc->comment_lengths[i],32); | |
480 _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]); | |
481 }else{ | |
482 oggpack_write(opb,0,32); | |
483 } | |
484 } | |
485 } | |
486 oggpack_write(opb,1,1); | |
487 | |
488 return(0); | |
489 } | |
490 | |
491 static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){ | |
492 codec_setup_info *ci=vi->codec_setup; | |
493 int i; | |
494 if(!ci)return(OV_EFAULT); | |
495 | |
496 oggpack_write(opb,0x05,8); | |
497 _v_writestring(opb,"vorbis", 6); | |
498 | |
499 /* books */ | |
500 oggpack_write(opb,ci->books-1,8); | |
501 for(i=0;i<ci->books;i++) | |
502 if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out; | |
503 | |
504 /* times; hook placeholders */ | |
505 oggpack_write(opb,0,6); | |
506 oggpack_write(opb,0,16); | |
507 | |
508 /* floors */ | |
509 oggpack_write(opb,ci->floors-1,6); | |
510 for(i=0;i<ci->floors;i++){ | |
511 oggpack_write(opb,ci->floor_type[i],16); | |
512 if(_floor_P[ci->floor_type[i]]->pack) | |
513 _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb); | |
514 else | |
515 goto err_out; | |
516 } | |
517 | |
518 /* residues */ | |
519 oggpack_write(opb,ci->residues-1,6); | |
520 for(i=0;i<ci->residues;i++){ | |
521 oggpack_write(opb,ci->residue_type[i],16); | |
522 _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb); | |
523 } | |
524 | |
525 /* maps */ | |
526 oggpack_write(opb,ci->maps-1,6); | |
527 for(i=0;i<ci->maps;i++){ | |
528 oggpack_write(opb,ci->map_type[i],16); | |
529 _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb); | |
530 } | |
531 | |
532 /* modes */ | |
533 oggpack_write(opb,ci->modes-1,6); | |
534 for(i=0;i<ci->modes;i++){ | |
535 oggpack_write(opb,ci->mode_param[i]->blockflag,1); | |
536 oggpack_write(opb,ci->mode_param[i]->windowtype,16); | |
537 oggpack_write(opb,ci->mode_param[i]->transformtype,16); | |
538 oggpack_write(opb,ci->mode_param[i]->mapping,8); | |
539 } | |
540 oggpack_write(opb,1,1); | |
541 | |
542 return(0); | |
543 err_out: | |
544 return(-1); | |
545 } | |
546 | |
547 int vorbis_commentheader_out(vorbis_comment *vc, | |
548 ogg_packet *op){ | |
549 | |
550 oggpack_buffer opb; | |
551 | |
552 oggpack_writeinit(&opb); | |
553 if(_vorbis_pack_comment(&opb,vc)){ | |
554 oggpack_writeclear(&opb); | |
555 return OV_EIMPL; | |
556 } | |
557 | |
558 op->packet = _ogg_malloc(oggpack_bytes(&opb)); | |
559 memcpy(op->packet, opb.buffer, oggpack_bytes(&opb)); | |
560 | |
561 op->bytes=oggpack_bytes(&opb); | |
562 op->b_o_s=0; | |
563 op->e_o_s=0; | |
564 op->granulepos=0; | |
565 op->packetno=1; | |
566 | |
567 oggpack_writeclear(&opb); | |
568 return 0; | |
569 } | |
570 | |
571 int vorbis_analysis_headerout(vorbis_dsp_state *v, | |
572 vorbis_comment *vc, | |
573 ogg_packet *op, | |
574 ogg_packet *op_comm, | |
575 ogg_packet *op_code){ | |
576 int ret=OV_EIMPL; | |
577 vorbis_info *vi=v->vi; | |
578 oggpack_buffer opb; | |
579 private_state *b=v->backend_state; | |
580 | |
581 if(!b){ | |
582 ret=OV_EFAULT; | |
583 goto err_out; | |
584 } | |
585 | |
586 /* first header packet **********************************************/ | |
587 | |
588 oggpack_writeinit(&opb); | |
589 if(_vorbis_pack_info(&opb,vi))goto err_out; | |
590 | |
591 /* build the packet */ | |
592 if(b->header)_ogg_free(b->header); | |
593 b->header=_ogg_malloc(oggpack_bytes(&opb)); | |
594 memcpy(b->header,opb.buffer,oggpack_bytes(&opb)); | |
595 op->packet=b->header; | |
596 op->bytes=oggpack_bytes(&opb); | |
597 op->b_o_s=1; | |
598 op->e_o_s=0; | |
599 op->granulepos=0; | |
600 op->packetno=0; | |
601 | |
602 /* second header packet (comments) **********************************/ | |
603 | |
604 oggpack_reset(&opb); | |
605 if(_vorbis_pack_comment(&opb,vc))goto err_out; | |
606 | |
607 if(b->header1)_ogg_free(b->header1); | |
608 b->header1=_ogg_malloc(oggpack_bytes(&opb)); | |
609 memcpy(b->header1,opb.buffer,oggpack_bytes(&opb)); | |
610 op_comm->packet=b->header1; | |
611 op_comm->bytes=oggpack_bytes(&opb); | |
612 op_comm->b_o_s=0; | |
613 op_comm->e_o_s=0; | |
614 op_comm->granulepos=0; | |
615 op_comm->packetno=1; | |
616 | |
617 /* third header packet (modes/codebooks) ****************************/ | |
618 | |
619 oggpack_reset(&opb); | |
620 if(_vorbis_pack_books(&opb,vi))goto err_out; | |
621 | |
622 if(b->header2)_ogg_free(b->header2); | |
623 b->header2=_ogg_malloc(oggpack_bytes(&opb)); | |
624 memcpy(b->header2,opb.buffer,oggpack_bytes(&opb)); | |
625 op_code->packet=b->header2; | |
626 op_code->bytes=oggpack_bytes(&opb); | |
627 op_code->b_o_s=0; | |
628 op_code->e_o_s=0; | |
629 op_code->granulepos=0; | |
630 op_code->packetno=2; | |
631 | |
632 oggpack_writeclear(&opb); | |
633 return(0); | |
634 err_out: | |
635 memset(op,0,sizeof(*op)); | |
636 memset(op_comm,0,sizeof(*op_comm)); | |
637 memset(op_code,0,sizeof(*op_code)); | |
638 | |
639 if(b){ | |
640 oggpack_writeclear(&opb); | |
641 if(b->header)_ogg_free(b->header); | |
642 if(b->header1)_ogg_free(b->header1); | |
643 if(b->header2)_ogg_free(b->header2); | |
644 b->header=NULL; | |
645 b->header1=NULL; | |
646 b->header2=NULL; | |
647 } | |
648 return(ret); | |
649 } | |
650 | |
651 double vorbis_granule_time(vorbis_dsp_state *v,ogg_int64_t granulepos){ | |
652 if(granulepos == -1) return -1; | |
653 | |
654 /* We're not guaranteed a 64 bit unsigned type everywhere, so we | |
655 have to put the unsigned granpo in a signed type. */ | |
656 if(granulepos>=0){ | |
657 return((double)granulepos/v->vi->rate); | |
658 }else{ | |
659 ogg_int64_t granuleoff=0xffffffff; | |
660 granuleoff<<=31; | |
661 granuleoff|=0x7ffffffff; | |
662 return(((double)granulepos+2+granuleoff+granuleoff)/v->vi->rate); | |
663 } | |
664 } | |
665 | |
666 const char *vorbis_version_string(void){ | |
667 return GENERAL_VENDOR_STRING; | |
668 } |