Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/genplus-gx/core/tremor/vorbisfile.c
2 views
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: stdio-based convenience library for opening/seeking/decoding
15
last mod: $Id: vorbisfile.c,v 1.6 2003/03/30 23:40:56 xiphmont Exp $
16
17
********************************************************************/
18
19
#include <stdlib.h>
20
#include <stdio.h>
21
#include <errno.h>
22
#include <string.h>
23
#include <math.h>
24
25
#include "ivorbiscodec.h"
26
#include "ivorbisfile.h"
27
28
#include "misc.h"
29
30
/* A 'chained bitstream' is a Vorbis bitstream that contains more than
31
one logical bitstream arranged end to end (the only form of Ogg
32
multiplexing allowed in a Vorbis bitstream; grouping [parallel
33
multiplexing] is not allowed in Vorbis) */
34
35
/* A Vorbis file can be played beginning to end (streamed) without
36
worrying ahead of time about chaining (see decoder_example.c). If
37
we have the whole file, however, and want random access
38
(seeking/scrubbing) or desire to know the total length/time of a
39
file, we need to account for the possibility of chaining. */
40
41
/* We can handle things a number of ways; we can determine the entire
42
bitstream structure right off the bat, or find pieces on demand.
43
This example determines and caches structure for the entire
44
bitstream, but builds a virtual decoder on the fly when moving
45
between links in the chain. */
46
47
/* There are also different ways to implement seeking. Enough
48
information exists in an Ogg bitstream to seek to
49
sample-granularity positions in the output. Or, one can seek by
50
picking some portion of the stream roughly in the desired area if
51
we only want coarse navigation through the stream. */
52
53
/*************************************************************************
54
* Many, many internal helpers. The intention is not to be confusing;
55
* rampant duplication and monolithic function implementation would be
56
* harder to understand anyway. The high level functions are last. Begin
57
* grokking near the end of the file */
58
59
60
/* read a little more data from the file/pipe into the ogg_sync framer */
61
static long _get_data(OggVorbis_File *vf){
62
errno=0;
63
if(vf->datasource){
64
unsigned char *buffer=ogg_sync_bufferin(vf->oy,CHUNKSIZE);
65
long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
66
if(bytes>0)ogg_sync_wrote(vf->oy,bytes);
67
68
#ifndef GEKKO
69
else if(bytes==0 && errno )
70
#else
71
// Not sure what is up with this... appears that EOVERFLOW is set whenever
72
// we read to the end of the file...
73
// original patch by raz0red for Mednafen-Wii
74
else if(bytes==0 && errno && errno != EOVERFLOW )
75
#endif
76
{
77
return(-1);
78
}
79
return(bytes);
80
}else
81
return(0);
82
}
83
84
/* save a tiny smidge of verbosity to make the code more readable */
85
static void _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
86
if(vf->datasource){
87
(vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET);
88
vf->offset=offset;
89
ogg_sync_reset(vf->oy);
90
}else{
91
/* shouldn't happen unless someone writes a broken callback */
92
return;
93
}
94
}
95
96
/* The read/seek functions track absolute position within the stream */
97
98
/* from the head of the stream, get the next page. boundary specifies
99
if the function is allowed to fetch more data from the stream (and
100
how much) or only use internally buffered data.
101
102
boundary: -1) unbounded search
103
0) read no additional data; use cached only
104
n) search for a new page beginning for n bytes
105
106
return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
107
n) found a page at absolute offset n
108
109
produces a refcounted page */
110
111
static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
112
ogg_int64_t boundary){
113
if(boundary>0)boundary+=vf->offset;
114
while(1){
115
long more;
116
117
if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
118
more=ogg_sync_pageseek(vf->oy,og);
119
120
if(more<0){
121
/* skipped n bytes */
122
vf->offset-=more;
123
}else{
124
if(more==0){
125
/* send more paramedics */
126
if(!boundary)return(OV_FALSE);
127
{
128
long ret=_get_data(vf);
129
if(ret==0)return(OV_EOF);
130
if(ret<0)return(OV_EREAD);
131
}
132
}else{
133
/* got a page. Return the offset at the page beginning,
134
advance the internal offset past the page end */
135
ogg_int64_t ret=vf->offset;
136
vf->offset+=more;
137
return(ret);
138
139
}
140
}
141
}
142
}
143
144
/* find the latest page beginning before the current stream cursor
145
position. Much dirtier than the above as Ogg doesn't have any
146
backward search linkage. no 'readp' as it will certainly have to
147
read. */
148
/* returns offset or OV_EREAD, OV_FAULT and produces a refcounted page */
149
150
static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){
151
ogg_int64_t begin=vf->offset;
152
ogg_int64_t end=begin;
153
ogg_int64_t ret;
154
ogg_int64_t offset=-1;
155
156
while(offset==-1){
157
begin-=CHUNKSIZE;
158
if(begin<0)
159
begin=0;
160
_seek_helper(vf,begin);
161
while(vf->offset<end){
162
ret=_get_next_page(vf,og,end-vf->offset);
163
if(ret==OV_EREAD)return(OV_EREAD);
164
if(ret<0){
165
break;
166
}else{
167
offset=ret;
168
}
169
}
170
}
171
172
/* we have the offset. Actually snork and hold the page now */
173
_seek_helper(vf,offset);
174
ret=_get_next_page(vf,og,CHUNKSIZE);
175
if(ret<0)
176
/* this shouldn't be possible */
177
return(OV_EFAULT);
178
179
return(offset);
180
}
181
182
/* finds each bitstream link one at a time using a bisection search
183
(has to begin by knowing the offset of the lb's initial page).
184
Recurses for each link so it can alloc the link storage after
185
finding them all, then unroll and fill the cache at the same time */
186
static int _bisect_forward_serialno(OggVorbis_File *vf,
187
ogg_int64_t begin,
188
ogg_int64_t searched,
189
ogg_int64_t end,
190
ogg_uint32_t currentno,
191
long m){
192
ogg_int64_t endsearched=end;
193
ogg_int64_t next=end;
194
ogg_page og={0,0,0,0};
195
ogg_int64_t ret;
196
197
/* the below guards against garbage seperating the last and
198
first pages of two links. */
199
while(searched<endsearched){
200
ogg_int64_t bisect;
201
202
if(endsearched-searched<CHUNKSIZE){
203
bisect=searched;
204
}else{
205
bisect=(searched+endsearched)/2;
206
}
207
208
_seek_helper(vf,bisect);
209
ret=_get_next_page(vf,&og,-1);
210
if(ret==OV_EREAD)return(OV_EREAD);
211
if(ret<0 || ogg_page_serialno(&og)!=currentno){
212
endsearched=bisect;
213
if(ret>=0)next=ret;
214
}else{
215
searched=ret+og.header_len+og.body_len;
216
}
217
ogg_page_release(&og);
218
}
219
220
_seek_helper(vf,next);
221
ret=_get_next_page(vf,&og,-1);
222
if(ret==OV_EREAD)return(OV_EREAD);
223
224
if(searched>=end || ret<0){
225
ogg_page_release(&og);
226
vf->links=m+1;
227
vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
228
vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
229
vf->offsets[m+1]=searched;
230
}else{
231
ret=_bisect_forward_serialno(vf,next,vf->offset,
232
end,ogg_page_serialno(&og),m+1);
233
ogg_page_release(&og);
234
if(ret==OV_EREAD)return(OV_EREAD);
235
}
236
237
vf->offsets[m]=begin;
238
vf->serialnos[m]=currentno;
239
return(0);
240
}
241
242
/* uses the local ogg_stream storage in vf; this is important for
243
non-streaming input sources */
244
/* consumes the page that's passed in (if any) */
245
246
static int _fetch_headers(OggVorbis_File *vf,
247
vorbis_info *vi,
248
vorbis_comment *vc,
249
ogg_uint32_t *serialno,
250
ogg_page *og_ptr){
251
ogg_page og={0,0,0,0};
252
ogg_packet op={0,0,0,0,0,0};
253
int i,ret;
254
255
if(!og_ptr){
256
ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
257
if(llret==OV_EREAD)return(OV_EREAD);
258
if(llret<0)return OV_ENOTVORBIS;
259
og_ptr=&og;
260
}
261
262
ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr));
263
if(serialno)*serialno=vf->os->serialno;
264
vf->ready_state=STREAMSET;
265
266
/* extract the initial header from the first page and verify that the
267
Ogg bitstream is in fact Vorbis data */
268
269
vorbis_info_init(vi);
270
vorbis_comment_init(vc);
271
272
i=0;
273
while(i<3){
274
ogg_stream_pagein(vf->os,og_ptr);
275
while(i<3){
276
int result=ogg_stream_packetout(vf->os,&op);
277
if(result==0)break;
278
if(result==-1){
279
ret=OV_EBADHEADER;
280
goto bail_header;
281
}
282
if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
283
goto bail_header;
284
}
285
i++;
286
}
287
if(i<3)
288
if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
289
ret=OV_EBADHEADER;
290
goto bail_header;
291
}
292
}
293
294
ogg_packet_release(&op);
295
ogg_page_release(&og);
296
return 0;
297
298
bail_header:
299
ogg_packet_release(&op);
300
ogg_page_release(&og);
301
vorbis_info_clear(vi);
302
vorbis_comment_clear(vc);
303
vf->ready_state=OPENED;
304
305
return ret;
306
}
307
308
/* last step of the OggVorbis_File initialization; get all the
309
vorbis_info structs and PCM positions. Only called by the seekable
310
initialization (local stream storage is hacked slightly; pay
311
attention to how that's done) */
312
313
/* this is void and does not propogate errors up because we want to be
314
able to open and use damaged bitstreams as well as we can. Just
315
watch out for missing information for links in the OggVorbis_File
316
struct */
317
static void _prefetch_all_headers(OggVorbis_File *vf, ogg_int64_t dataoffset){
318
ogg_page og={0,0,0,0};
319
int i;
320
ogg_int64_t ret;
321
322
vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
323
vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
324
vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
325
vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
326
327
for(i=0;i<vf->links;i++){
328
if(i==0){
329
/* we already grabbed the initial header earlier. Just set the offset */
330
vf->dataoffsets[i]=dataoffset;
331
_seek_helper(vf,dataoffset);
332
333
}else{
334
335
/* seek to the location of the initial header */
336
337
_seek_helper(vf,vf->offsets[i]);
338
if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL,NULL)<0){
339
vf->dataoffsets[i]=-1;
340
}else{
341
vf->dataoffsets[i]=vf->offset;
342
}
343
}
344
345
/* fetch beginning PCM offset */
346
347
if(vf->dataoffsets[i]!=-1){
348
ogg_int64_t accumulated=0,pos;
349
long lastblock=-1;
350
int result;
351
352
ogg_stream_reset_serialno(vf->os,vf->serialnos[i]);
353
354
while(1){
355
ogg_packet op={0,0,0,0,0,0};
356
357
ret=_get_next_page(vf,&og,-1);
358
if(ret<0)
359
/* this should not be possible unless the file is
360
truncated/mangled */
361
break;
362
363
if(ogg_page_serialno(&og)!=vf->serialnos[i])
364
break;
365
366
pos=ogg_page_granulepos(&og);
367
368
/* count blocksizes of all frames in the page */
369
ogg_stream_pagein(vf->os,&og);
370
while((result=ogg_stream_packetout(vf->os,&op))){
371
if(result>0){ /* ignore holes */
372
long thisblock=vorbis_packet_blocksize(vf->vi+i,&op);
373
if(lastblock!=-1)
374
accumulated+=(lastblock+thisblock)>>2;
375
lastblock=thisblock;
376
}
377
}
378
ogg_packet_release(&op);
379
380
if(pos!=-1){
381
/* pcm offset of last packet on the first audio page */
382
accumulated= pos-accumulated;
383
break;
384
}
385
}
386
387
/* less than zero? This is a stream with samples trimmed off
388
the beginning, a normal occurrence; set the offset to zero */
389
if(accumulated<0)accumulated=0;
390
391
vf->pcmlengths[i*2]=accumulated;
392
}
393
394
/* get the PCM length of this link. To do this,
395
get the last page of the stream */
396
{
397
ogg_int64_t end=vf->offsets[i+1];
398
_seek_helper(vf,end);
399
400
while(1){
401
ret=_get_prev_page(vf,&og);
402
if(ret<0){
403
/* this should not be possible */
404
vorbis_info_clear(vf->vi+i);
405
vorbis_comment_clear(vf->vc+i);
406
break;
407
}
408
if(ogg_page_granulepos(&og)!=-1){
409
vf->pcmlengths[i*2+1]=ogg_page_granulepos(&og)-vf->pcmlengths[i*2];
410
break;
411
}
412
vf->offset=ret;
413
}
414
}
415
}
416
ogg_page_release(&og);
417
}
418
419
static void _make_decode_ready(OggVorbis_File *vf){
420
if(vf->ready_state!=STREAMSET)return;
421
if(vf->seekable){
422
vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link);
423
}else{
424
vorbis_synthesis_init(&vf->vd,vf->vi);
425
}
426
vorbis_block_init(&vf->vd,&vf->vb);
427
vf->ready_state=INITSET;
428
vf->bittrack=0;
429
vf->samptrack=0;
430
return;
431
}
432
433
static int _open_seekable2(OggVorbis_File *vf){
434
ogg_uint32_t serialno=vf->current_serialno;
435
ogg_uint32_t tempserialno;
436
ogg_int64_t dataoffset=vf->offset, end;
437
ogg_page og={0,0,0,0};
438
439
/* we're partially open and have a first link header state in
440
storage in vf */
441
/* we can seek, so set out learning all about this file */
442
(vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
443
vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
444
445
/* We get the offset for the last page of the physical bitstream.
446
Most OggVorbis files will contain a single logical bitstream */
447
end=_get_prev_page(vf,&og);
448
if(end<0)return(end);
449
450
/* more than one logical bitstream? */
451
tempserialno=ogg_page_serialno(&og);
452
ogg_page_release(&og);
453
454
if(tempserialno!=serialno){
455
456
/* Chained bitstream. Bisect-search each logical bitstream
457
section. Do so based on serial number only */
458
if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0)return(OV_EREAD);
459
460
}else{
461
462
/* Only one logical bitstream */
463
if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return(OV_EREAD);
464
465
}
466
467
/* the initial header memory is referenced by vf after; don't free it */
468
_prefetch_all_headers(vf,dataoffset);
469
return(ov_raw_seek(vf,0));
470
}
471
472
/* clear out the current logical bitstream decoder */
473
static void _decode_clear(OggVorbis_File *vf){
474
vorbis_dsp_clear(&vf->vd);
475
vorbis_block_clear(&vf->vb);
476
vf->ready_state=OPENED;
477
}
478
479
/* fetch and process a packet. Handles the case where we're at a
480
bitstream boundary and dumps the decoding machine. If the decoding
481
machine is unloaded, it loads it. It also keeps pcm_offset up to
482
date (seek and read both use this. seek uses a special hack with
483
readp).
484
485
return: <0) error, OV_HOLE (lost packet) or OV_EOF
486
0) need more data (only if readp==0)
487
1) got a packet
488
*/
489
490
static int _fetch_and_process_packet(OggVorbis_File *vf,
491
int readp,
492
int spanp){
493
ogg_page og={0,0,0,0};
494
ogg_packet op={0,0,0,0,0,0};
495
int ret=0;
496
497
/* handle one packet. Try to fetch it from current stream state */
498
/* extract packets from page */
499
while(1){
500
501
/* process a packet if we can. If the machine isn't loaded,
502
neither is a page */
503
if(vf->ready_state==INITSET){
504
while(1) {
505
int result=ogg_stream_packetout(vf->os,&op);
506
ogg_int64_t granulepos;
507
508
if(result<0){
509
ret=OV_HOLE; /* hole in the data. */
510
goto cleanup;
511
}
512
if(result>0){
513
/* got a packet. process it */
514
granulepos=op.granulepos;
515
if(!vorbis_synthesis(&vf->vb,&op,1)){ /* lazy check for lazy
516
header handling. The
517
header packets aren't
518
audio, so if/when we
519
submit them,
520
vorbis_synthesis will
521
reject them */
522
523
/* suck in the synthesis data and track bitrate */
524
{
525
int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
526
/* for proper use of libvorbis within libvorbisfile,
527
oldsamples will always be zero. */
528
if(oldsamples){
529
ret=OV_EFAULT;
530
goto cleanup;
531
}
532
533
vorbis_synthesis_blockin(&vf->vd,&vf->vb);
534
vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
535
vf->bittrack+=op.bytes*8;
536
}
537
538
/* update the pcm offset. */
539
if(granulepos!=-1 && !op.e_o_s){
540
int link=(vf->seekable?vf->current_link:0);
541
int i,samples;
542
543
/* this packet has a pcm_offset on it (the last packet
544
completed on a page carries the offset) After processing
545
(above), we know the pcm position of the *last* sample
546
ready to be returned. Find the offset of the *first*
547
548
As an aside, this trick is inaccurate if we begin
549
reading anew right at the last page; the end-of-stream
550
granulepos declares the last frame in the stream, and the
551
last packet of the last page may be a partial frame.
552
So, we need a previous granulepos from an in-sequence page
553
to have a reference point. Thus the !op.e_o_s clause
554
above */
555
556
if(vf->seekable && link>0)
557
granulepos-=vf->pcmlengths[link*2];
558
if(granulepos<0)granulepos=0; /* actually, this
559
shouldn't be possible
560
here unless the stream
561
is very broken */
562
563
samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
564
565
granulepos-=samples;
566
for(i=0;i<link;i++)
567
granulepos+=vf->pcmlengths[i*2+1];
568
vf->pcm_offset=granulepos;
569
}
570
ret=1;
571
goto cleanup;
572
}
573
}
574
else
575
break;
576
}
577
}
578
579
if(vf->ready_state>=OPENED){
580
int ret;
581
if(!readp){
582
ret=0;
583
goto cleanup;
584
}
585
if((ret=_get_next_page(vf,&og,-1))<0){
586
ret=OV_EOF; /* eof. leave unitialized */
587
goto cleanup;
588
}
589
590
/* bitrate tracking; add the header's bytes here, the body bytes
591
are done by packet above */
592
vf->bittrack+=og.header_len*8;
593
594
/* has our decoding just traversed a bitstream boundary? */
595
if(vf->ready_state==INITSET){
596
if(vf->current_serialno!=ogg_page_serialno(&og)){
597
if(!spanp){
598
ret=OV_EOF;
599
goto cleanup;
600
}
601
602
_decode_clear(vf);
603
604
if(!vf->seekable){
605
vorbis_info_clear(vf->vi);
606
vorbis_comment_clear(vf->vc);
607
}
608
}
609
}
610
}
611
612
/* Do we need to load a new machine before submitting the page? */
613
/* This is different in the seekable and non-seekable cases.
614
615
In the seekable case, we already have all the header
616
information loaded and cached; we just initialize the machine
617
with it and continue on our merry way.
618
619
In the non-seekable (streaming) case, we'll only be at a
620
boundary if we just left the previous logical bitstream and
621
we're now nominally at the header of the next bitstream
622
*/
623
624
if(vf->ready_state!=INITSET){
625
int link;
626
627
if(vf->ready_state<STREAMSET){
628
if(vf->seekable){
629
vf->current_serialno=ogg_page_serialno(&og);
630
631
/* match the serialno to bitstream section. We use this rather than
632
offset positions to avoid problems near logical bitstream
633
boundaries */
634
for(link=0;link<vf->links;link++)
635
if(vf->serialnos[link]==vf->current_serialno)break;
636
if(link==vf->links){
637
ret=OV_EBADLINK; /* sign of a bogus stream. error out,
638
leave machine uninitialized */
639
goto cleanup;
640
}
641
642
vf->current_link=link;
643
644
ogg_stream_reset_serialno(vf->os,vf->current_serialno);
645
vf->ready_state=STREAMSET;
646
647
}else{
648
/* we're streaming */
649
/* fetch the three header packets, build the info struct */
650
651
int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);
652
if(ret) goto cleanup;
653
vf->current_link++;
654
link=0;
655
}
656
}
657
658
_make_decode_ready(vf);
659
}
660
ogg_stream_pagein(vf->os,&og);
661
}
662
cleanup:
663
ogg_packet_release(&op);
664
ogg_page_release(&og);
665
return ret;
666
}
667
668
/* if, eg, 64 bit stdio is configured by default, this will build with
669
fseek64 */
670
static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
671
if(f==NULL)return(-1);
672
return fseek(f,off,whence);
673
}
674
675
static int _ov_open1(void *f,OggVorbis_File *vf,char *initial,
676
long ibytes, ov_callbacks callbacks){
677
int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);
678
int ret;
679
680
memset(vf,0,sizeof(*vf));
681
vf->datasource=f;
682
vf->callbacks = callbacks;
683
684
/* init the framing state */
685
vf->oy=ogg_sync_create();
686
687
/* perhaps some data was previously read into a buffer for testing
688
against other stream types. Allow initialization from this
689
previously read data (as we may be reading from a non-seekable
690
stream) */
691
if(initial){
692
unsigned char *buffer=ogg_sync_bufferin(vf->oy,ibytes);
693
memcpy(buffer,initial,ibytes);
694
ogg_sync_wrote(vf->oy,ibytes);
695
}
696
697
/* can we seek? Stevens suggests the seek test was portable */
698
if(offsettest!=-1)vf->seekable=1;
699
700
/* No seeking yet; Set up a 'single' (current) logical bitstream
701
entry for partial open */
702
vf->links=1;
703
vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
704
vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
705
vf->os=ogg_stream_create(-1); /* fill in the serialno later */
706
707
/* Try to fetch the headers, maintaining all the storage */
708
if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0){
709
vf->datasource=NULL;
710
ov_clear(vf);
711
}else if(vf->ready_state < PARTOPEN)
712
vf->ready_state=PARTOPEN;
713
return(ret);
714
}
715
716
static int _ov_open2(OggVorbis_File *vf){
717
if(vf->ready_state < OPENED)
718
vf->ready_state=OPENED;
719
if(vf->seekable){
720
int ret=_open_seekable2(vf);
721
if(ret){
722
vf->datasource=NULL;
723
ov_clear(vf);
724
}
725
return(ret);
726
}
727
return 0;
728
}
729
730
731
/* clear out the OggVorbis_File struct */
732
int ov_clear(OggVorbis_File *vf){
733
if(vf){
734
vorbis_block_clear(&vf->vb);
735
vorbis_dsp_clear(&vf->vd);
736
ogg_stream_destroy(vf->os);
737
738
if(vf->vi && vf->links){
739
int i;
740
for(i=0;i<vf->links;i++){
741
vorbis_info_clear(vf->vi+i);
742
vorbis_comment_clear(vf->vc+i);
743
}
744
_ogg_free(vf->vi);
745
_ogg_free(vf->vc);
746
}
747
if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
748
if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
749
if(vf->serialnos)_ogg_free(vf->serialnos);
750
if(vf->offsets)_ogg_free(vf->offsets);
751
ogg_sync_destroy(vf->oy);
752
753
if(vf->datasource)(vf->callbacks.close_func)(vf->datasource);
754
memset(vf,0,sizeof(*vf));
755
}
756
#ifdef DEBUG_LEAKS
757
_VDBG_dump();
758
#endif
759
return(0);
760
}
761
762
/* inspects the OggVorbis file and finds/documents all the logical
763
bitstreams contained in it. Tries to be tolerant of logical
764
bitstream sections that are truncated/woogie.
765
766
return: -1) error
767
0) OK
768
*/
769
770
int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
771
ov_callbacks callbacks){
772
int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
773
if(ret)return ret;
774
return _ov_open2(vf);
775
}
776
777
int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
778
ov_callbacks callbacks = {
779
(size_t (*)(void *, size_t, size_t, void *)) fread,
780
(int (*)(void *, ogg_int64_t, int)) _fseek64_wrap,
781
(int (*)(void *)) fclose,
782
(long (*)(void *)) ftell
783
};
784
785
return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
786
}
787
788
/* Only partially open the vorbis file; test for Vorbisness, and load
789
the headers for the first chain. Do not seek (although test for
790
seekability). Use ov_test_open to finish opening the file, else
791
ov_clear to close/free it. Same return codes as open. */
792
793
int ov_test_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
794
ov_callbacks callbacks)
795
{
796
return _ov_open1(f,vf,initial,ibytes,callbacks);
797
}
798
799
int ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
800
ov_callbacks callbacks = {
801
(size_t (*)(void *, size_t, size_t, void *)) fread,
802
(int (*)(void *, ogg_int64_t, int)) _fseek64_wrap,
803
(int (*)(void *)) fclose,
804
(long (*)(void *)) ftell
805
};
806
807
return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
808
}
809
810
int ov_test_open(OggVorbis_File *vf){
811
if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);
812
return _ov_open2(vf);
813
}
814
815
/* How many logical bitstreams in this physical bitstream? */
816
long ov_streams(OggVorbis_File *vf){
817
return vf->links;
818
}
819
820
/* Is the FILE * associated with vf seekable? */
821
long ov_seekable(OggVorbis_File *vf){
822
return vf->seekable;
823
}
824
825
/* returns the bitrate for a given logical bitstream or the entire
826
physical bitstream. If the file is open for random access, it will
827
find the *actual* average bitrate. If the file is streaming, it
828
returns the nominal bitrate (if set) else the average of the
829
upper/lower bounds (if set) else -1 (unset).
830
831
If you want the actual bitrate field settings, get them from the
832
vorbis_info structs */
833
834
long ov_bitrate(OggVorbis_File *vf,int i){
835
if(vf->ready_state<OPENED)return(OV_EINVAL);
836
if(i>=vf->links)return(OV_EINVAL);
837
if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
838
if(i<0){
839
ogg_int64_t bits=0;
840
int i;
841
for(i=0;i<vf->links;i++)
842
bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
843
/* This once read: return(rint(bits/ov_time_total(vf,-1)));
844
* gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
845
* so this is slightly transformed to make it work.
846
*/
847
return(bits*1000/ov_time_total(vf,-1));
848
}else{
849
if(vf->seekable){
850
/* return the actual bitrate */
851
return((vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i));
852
}else{
853
/* return nominal if set */
854
if(vf->vi[i].bitrate_nominal>0){
855
return vf->vi[i].bitrate_nominal;
856
}else{
857
if(vf->vi[i].bitrate_upper>0){
858
if(vf->vi[i].bitrate_lower>0){
859
return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
860
}else{
861
return vf->vi[i].bitrate_upper;
862
}
863
}
864
return(OV_FALSE);
865
}
866
}
867
}
868
}
869
870
/* returns the actual bitrate since last call. returns -1 if no
871
additional data to offer since last call (or at beginning of stream),
872
EINVAL if stream is only partially open
873
*/
874
long ov_bitrate_instant(OggVorbis_File *vf){
875
int link=(vf->seekable?vf->current_link:0);
876
long ret;
877
if(vf->ready_state<OPENED)return(OV_EINVAL);
878
if(vf->samptrack==0)return(OV_FALSE);
879
ret=vf->bittrack/vf->samptrack*vf->vi[link].rate;
880
vf->bittrack=0;
881
vf->samptrack=0;
882
return(ret);
883
}
884
885
/* Guess */
886
long ov_serialnumber(OggVorbis_File *vf,int i){
887
if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
888
if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
889
if(i<0){
890
return(vf->current_serialno);
891
}else{
892
return(vf->serialnos[i]);
893
}
894
}
895
896
/* returns: total raw (compressed) length of content if i==-1
897
raw (compressed) length of that logical bitstream for i==0 to n
898
OV_EINVAL if the stream is not seekable (we can't know the length)
899
or if stream is only partially open
900
*/
901
ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
902
if(vf->ready_state<OPENED)return(OV_EINVAL);
903
if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
904
if(i<0){
905
ogg_int64_t acc=0;
906
int i;
907
for(i=0;i<vf->links;i++)
908
acc+=ov_raw_total(vf,i);
909
return(acc);
910
}else{
911
return(vf->offsets[i+1]-vf->offsets[i]);
912
}
913
}
914
915
/* returns: total PCM length (samples) of content if i==-1 PCM length
916
(samples) of that logical bitstream for i==0 to n
917
OV_EINVAL if the stream is not seekable (we can't know the
918
length) or only partially open
919
*/
920
ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
921
if(vf->ready_state<OPENED)return(OV_EINVAL);
922
if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
923
if(i<0){
924
ogg_int64_t acc=0;
925
int i;
926
for(i=0;i<vf->links;i++)
927
acc+=ov_pcm_total(vf,i);
928
return(acc);
929
}else{
930
return(vf->pcmlengths[i*2+1]);
931
}
932
}
933
934
/* returns: total milliseconds of content if i==-1
935
milliseconds in that logical bitstream for i==0 to n
936
OV_EINVAL if the stream is not seekable (we can't know the
937
length) or only partially open
938
*/
939
ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){
940
if(vf->ready_state<OPENED)return(OV_EINVAL);
941
if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
942
if(i<0){
943
ogg_int64_t acc=0;
944
int i;
945
for(i=0;i<vf->links;i++)
946
acc+=ov_time_total(vf,i);
947
return(acc);
948
}else{
949
return(((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate);
950
}
951
}
952
953
/* seek to an offset relative to the *compressed* data. This also
954
scans packets to update the PCM cursor. It will cross a logical
955
bitstream boundary, but only if it can't get any packets out of the
956
tail of the bitstream we seek to (so no surprises).
957
958
returns zero on success, nonzero on failure */
959
960
int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
961
ogg_stream_state *work_os=NULL;
962
ogg_page og={0,0,0,0};
963
ogg_packet op={0,0,0,0,0,0};
964
965
if(vf->ready_state<OPENED)return(OV_EINVAL);
966
if(!vf->seekable)
967
return(OV_ENOSEEK); /* don't dump machine if we can't seek */
968
969
if(pos<0 || pos>vf->end)return(OV_EINVAL);
970
971
/* don't yet clear out decoding machine (if it's initialized), in
972
the case we're in the same link. Restart the decode lapping, and
973
let _fetch_and_process_packet deal with a potential bitstream
974
boundary */
975
vf->pcm_offset=-1;
976
ogg_stream_reset_serialno(vf->os,
977
vf->current_serialno); /* must set serialno */
978
vorbis_synthesis_restart(&vf->vd);
979
980
_seek_helper(vf,pos);
981
982
/* we need to make sure the pcm_offset is set, but we don't want to
983
advance the raw cursor past good packets just to get to the first
984
with a granulepos. That's not equivalent behavior to beginning
985
decoding as immediately after the seek position as possible.
986
987
So, a hack. We use two stream states; a local scratch state and
988
the shared vf->os stream state. We use the local state to
989
scan, and the shared state as a buffer for later decode.
990
991
Unfortuantely, on the last page we still advance to last packet
992
because the granulepos on the last page is not necessarily on a
993
packet boundary, and we need to make sure the granpos is
994
correct.
995
*/
996
997
{
998
int lastblock=0;
999
int accblock=0;
1000
int thisblock;
1001
int eosflag=0;
1002
1003
work_os=ogg_stream_create(vf->current_serialno); /* get the memory ready */
1004
while(1){
1005
if(vf->ready_state>=STREAMSET){
1006
/* snarf/scan a packet if we can */
1007
int result=ogg_stream_packetout(work_os,&op);
1008
1009
if(result>0){
1010
1011
if(vf->vi[vf->current_link].codec_setup){
1012
thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1013
if(thisblock<0){
1014
ogg_stream_packetout(vf->os,NULL);
1015
thisblock=0;
1016
}else{
1017
1018
if(eosflag)
1019
ogg_stream_packetout(vf->os,NULL);
1020
else
1021
if(lastblock)accblock+=(lastblock+thisblock)>>2;
1022
}
1023
1024
if(op.granulepos!=-1){
1025
int i,link=vf->current_link;
1026
ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
1027
if(granulepos<0)granulepos=0;
1028
1029
for(i=0;i<link;i++)
1030
granulepos+=vf->pcmlengths[i*2+1];
1031
vf->pcm_offset=granulepos-accblock;
1032
break;
1033
}
1034
lastblock=thisblock;
1035
continue;
1036
}else
1037
ogg_stream_packetout(vf->os,NULL);
1038
}
1039
}
1040
1041
if(!lastblock){
1042
if(_get_next_page(vf,&og,-1)<0){
1043
vf->pcm_offset=ov_pcm_total(vf,-1);
1044
break;
1045
}
1046
}else{
1047
/* huh? Bogus stream with packets but no granulepos */
1048
vf->pcm_offset=-1;
1049
break;
1050
}
1051
1052
/* has our decoding just traversed a bitstream boundary? */
1053
if(vf->ready_state>=STREAMSET)
1054
if(vf->current_serialno!=ogg_page_serialno(&og)){
1055
_decode_clear(vf); /* clear out stream state */
1056
ogg_stream_destroy(work_os);
1057
}
1058
1059
if(vf->ready_state<STREAMSET){
1060
int link;
1061
1062
vf->current_serialno=ogg_page_serialno(&og);
1063
for(link=0;link<vf->links;link++)
1064
if(vf->serialnos[link]==vf->current_serialno)break;
1065
if(link==vf->links)
1066
goto seek_error; /* sign of a bogus stream. error out,
1067
leave machine uninitialized */
1068
1069
vf->current_link=link;
1070
1071
ogg_stream_reset_serialno(vf->os,vf->current_serialno);
1072
ogg_stream_reset_serialno(work_os,vf->current_serialno);
1073
vf->ready_state=STREAMSET;
1074
1075
}
1076
1077
{
1078
ogg_page dup;
1079
ogg_page_dup(&dup,&og);
1080
eosflag=ogg_page_eos(&og);
1081
ogg_stream_pagein(vf->os,&og);
1082
ogg_stream_pagein(work_os,&dup);
1083
}
1084
}
1085
}
1086
1087
ogg_packet_release(&op);
1088
ogg_page_release(&og);
1089
ogg_stream_destroy(work_os);
1090
vf->bittrack=0;
1091
vf->samptrack=0;
1092
return(0);
1093
1094
seek_error:
1095
ogg_packet_release(&op);
1096
ogg_page_release(&og);
1097
1098
/* dump the machine so we're in a known state */
1099
vf->pcm_offset=-1;
1100
ogg_stream_destroy(work_os);
1101
_decode_clear(vf);
1102
return OV_EBADLINK;
1103
}
1104
1105
/* Page granularity seek (faster than sample granularity because we
1106
don't do the last bit of decode to find a specific sample).
1107
1108
Seek to the last [granule marked] page preceeding the specified pos
1109
location, such that decoding past the returned point will quickly
1110
arrive at the requested position. */
1111
int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
1112
int link=-1;
1113
ogg_int64_t result=0;
1114
ogg_int64_t total=ov_pcm_total(vf,-1);
1115
ogg_page og={0,0,0,0};
1116
ogg_packet op={0,0,0,0,0,0};
1117
1118
if(vf->ready_state<OPENED)return(OV_EINVAL);
1119
if(!vf->seekable)return(OV_ENOSEEK);
1120
if(pos<0 || pos>total)return(OV_EINVAL);
1121
1122
/* which bitstream section does this pcm offset occur in? */
1123
for(link=vf->links-1;link>=0;link--){
1124
total-=vf->pcmlengths[link*2+1];
1125
if(pos>=total)break;
1126
}
1127
1128
/* search within the logical bitstream for the page with the highest
1129
pcm_pos preceeding (or equal to) pos. There is a danger here;
1130
missing pages or incorrect frame number information in the
1131
bitstream could make our task impossible. Account for that (it
1132
would be an error condition) */
1133
1134
/* new search algorithm by HB (Nicholas Vinen) */
1135
{
1136
ogg_int64_t end=vf->offsets[link+1];
1137
ogg_int64_t begin=vf->offsets[link];
1138
ogg_int64_t begintime = vf->pcmlengths[link*2];
1139
ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
1140
ogg_int64_t target=pos-total+begintime;
1141
ogg_int64_t best=begin;
1142
1143
while(begin<end){
1144
ogg_int64_t bisect;
1145
1146
if(end-begin<CHUNKSIZE){
1147
bisect=begin;
1148
}else{
1149
/* take a (pretty decent) guess. */
1150
bisect=begin +
1151
(target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE;
1152
if(bisect<=begin)
1153
bisect=begin+1;
1154
}
1155
1156
_seek_helper(vf,bisect);
1157
1158
while(begin<end){
1159
result=_get_next_page(vf,&og,end-vf->offset);
1160
if(result==OV_EREAD) goto seek_error;
1161
if(result<0){
1162
if(bisect<=begin+1)
1163
end=begin; /* found it */
1164
else{
1165
if(bisect==0) goto seek_error;
1166
bisect-=CHUNKSIZE;
1167
if(bisect<=begin)bisect=begin+1;
1168
_seek_helper(vf,bisect);
1169
}
1170
}else{
1171
ogg_int64_t granulepos=ogg_page_granulepos(&og);
1172
if(granulepos==-1)continue;
1173
if(granulepos<target){
1174
best=result; /* raw offset of packet with granulepos */
1175
begin=vf->offset; /* raw offset of next page */
1176
begintime=granulepos;
1177
1178
if(target-begintime>44100)break;
1179
bisect=begin; /* *not* begin + 1 */
1180
}else{
1181
if(bisect<=begin+1)
1182
end=begin; /* found it */
1183
else{
1184
if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
1185
end=result;
1186
bisect-=CHUNKSIZE; /* an endless loop otherwise. */
1187
if(bisect<=begin)bisect=begin+1;
1188
_seek_helper(vf,bisect);
1189
}else{
1190
end=result;
1191
endtime=granulepos;
1192
break;
1193
}
1194
}
1195
}
1196
}
1197
}
1198
}
1199
1200
/* found our page. seek to it, update pcm offset. Easier case than
1201
raw_seek, don't keep packets preceeding granulepos. */
1202
{
1203
1204
/* seek */
1205
_seek_helper(vf,best);
1206
vf->pcm_offset=-1;
1207
1208
if(_get_next_page(vf,&og,-1)<0){
1209
ogg_page_release(&og);
1210
return(OV_EOF); /* shouldn't happen */
1211
}
1212
1213
if(link!=vf->current_link){
1214
/* Different link; dump entire decode machine */
1215
_decode_clear(vf);
1216
1217
vf->current_link=link;
1218
vf->current_serialno=ogg_page_serialno(&og);
1219
vf->ready_state=STREAMSET;
1220
1221
}else{
1222
vorbis_synthesis_restart(&vf->vd);
1223
}
1224
1225
ogg_stream_reset_serialno(vf->os,vf->current_serialno);
1226
ogg_stream_pagein(vf->os,&og);
1227
1228
/* pull out all but last packet; the one with granulepos */
1229
while(1){
1230
result=ogg_stream_packetpeek(vf->os,&op);
1231
if(result==0){
1232
/* !!! the packet finishing this page originated on a
1233
preceeding page. Keep fetching previous pages until we
1234
get one with a granulepos or without the 'continued' flag
1235
set. Then just use raw_seek for simplicity. */
1236
1237
_seek_helper(vf,best);
1238
1239
while(1){
1240
result=_get_prev_page(vf,&og);
1241
if(result<0) goto seek_error;
1242
if(ogg_page_granulepos(&og)>-1 ||
1243
!ogg_page_continued(&og)){
1244
return ov_raw_seek(vf,result);
1245
}
1246
vf->offset=result;
1247
}
1248
}
1249
if(result<0){
1250
result = OV_EBADPACKET;
1251
goto seek_error;
1252
}
1253
if(op.granulepos!=-1){
1254
vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1255
if(vf->pcm_offset<0)vf->pcm_offset=0;
1256
vf->pcm_offset+=total;
1257
break;
1258
}else
1259
result=ogg_stream_packetout(vf->os,NULL);
1260
}
1261
}
1262
}
1263
1264
/* verify result */
1265
if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
1266
result=OV_EFAULT;
1267
goto seek_error;
1268
}
1269
vf->bittrack=0;
1270
vf->samptrack=0;
1271
1272
ogg_page_release(&og);
1273
ogg_packet_release(&op);
1274
return(0);
1275
1276
seek_error:
1277
1278
ogg_page_release(&og);
1279
ogg_packet_release(&op);
1280
1281
/* dump machine so we're in a known state */
1282
vf->pcm_offset=-1;
1283
_decode_clear(vf);
1284
return (int)result;
1285
}
1286
1287
/* seek to a sample offset relative to the decompressed pcm stream
1288
returns zero on success, nonzero on failure */
1289
1290
int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
1291
ogg_packet op={0,0,0,0,0,0};
1292
ogg_page og={0,0,0,0};
1293
int thisblock,lastblock=0;
1294
int ret=ov_pcm_seek_page(vf,pos);
1295
if(ret<0)return(ret);
1296
_make_decode_ready(vf);
1297
1298
/* discard leading packets we don't need for the lapping of the
1299
position we want; don't decode them */
1300
1301
while(1){
1302
1303
int ret=ogg_stream_packetpeek(vf->os,&op);
1304
if(ret>0){
1305
thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1306
if(thisblock<0){
1307
ogg_stream_packetout(vf->os,NULL);
1308
continue; /* non audio packet */
1309
}
1310
if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
1311
1312
if(vf->pcm_offset+((thisblock+
1313
vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
1314
1315
/* remove the packet from packet queue and track its granulepos */
1316
ogg_stream_packetout(vf->os,NULL);
1317
vorbis_synthesis(&vf->vb,&op,0); /* set up a vb with
1318
only tracking, no
1319
pcm_decode */
1320
vorbis_synthesis_blockin(&vf->vd,&vf->vb);
1321
1322
/* end of logical stream case is hard, especially with exact
1323
length positioning. */
1324
1325
if(op.granulepos>-1){
1326
int i;
1327
/* always believe the stream markers */
1328
vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1329
if(vf->pcm_offset<0)vf->pcm_offset=0;
1330
for(i=0;i<vf->current_link;i++)
1331
vf->pcm_offset+=vf->pcmlengths[i*2+1];
1332
}
1333
1334
lastblock=thisblock;
1335
1336
}else{
1337
if(ret<0 && ret!=OV_HOLE)break;
1338
1339
/* suck in a new page */
1340
if(_get_next_page(vf,&og,-1)<0)break;
1341
if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf);
1342
1343
if(vf->ready_state<STREAMSET){
1344
int link;
1345
1346
vf->current_serialno=ogg_page_serialno(&og);
1347
for(link=0;link<vf->links;link++)
1348
if(vf->serialnos[link]==vf->current_serialno)break;
1349
if(link==vf->links){
1350
ogg_page_release(&og);
1351
ogg_packet_release(&op);
1352
return(OV_EBADLINK);
1353
}
1354
vf->current_link=link;
1355
1356
ogg_stream_reset_serialno(vf->os,vf->current_serialno);
1357
vf->ready_state=STREAMSET;
1358
_make_decode_ready(vf);
1359
lastblock=0;
1360
}
1361
1362
ogg_stream_pagein(vf->os,&og);
1363
}
1364
}
1365
1366
vf->bittrack=0;
1367
vf->samptrack=0;
1368
/* discard samples until we reach the desired position. Crossing a
1369
logical bitstream boundary with abandon is OK. */
1370
while(vf->pcm_offset<pos){
1371
ogg_int64_t target=pos-vf->pcm_offset;
1372
long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
1373
1374
if(samples>target)samples=target;
1375
vorbis_synthesis_read(&vf->vd,samples);
1376
vf->pcm_offset+=samples;
1377
1378
if(samples<target)
1379
if(_fetch_and_process_packet(vf,1,1)<=0)
1380
vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
1381
}
1382
1383
ogg_page_release(&og);
1384
ogg_packet_release(&op);
1385
return 0;
1386
}
1387
1388
/* seek to a playback time relative to the decompressed pcm stream
1389
returns zero on success, nonzero on failure */
1390
int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){
1391
/* translate time to PCM position and call ov_pcm_seek */
1392
1393
int link=-1;
1394
ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
1395
ogg_int64_t time_total=ov_time_total(vf,-1);
1396
1397
if(vf->ready_state<OPENED)return(OV_EINVAL);
1398
if(!vf->seekable)return(OV_ENOSEEK);
1399
if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL);
1400
1401
/* which bitstream section does this time offset occur in? */
1402
for(link=vf->links-1;link>=0;link--){
1403
pcm_total-=vf->pcmlengths[link*2+1];
1404
time_total-=ov_time_total(vf,link);
1405
if(milliseconds>=time_total)break;
1406
}
1407
1408
/* enough information to convert time offset to pcm offset */
1409
{
1410
ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
1411
return(ov_pcm_seek(vf,target));
1412
}
1413
}
1414
1415
/* page-granularity version of ov_time_seek
1416
returns zero on success, nonzero on failure */
1417
int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t milliseconds){
1418
/* translate time to PCM position and call ov_pcm_seek */
1419
1420
int link=-1;
1421
ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
1422
ogg_int64_t time_total=ov_time_total(vf,-1);
1423
1424
if(vf->ready_state<OPENED)return(OV_EINVAL);
1425
if(!vf->seekable)return(OV_ENOSEEK);
1426
if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL);
1427
1428
/* which bitstream section does this time offset occur in? */
1429
for(link=vf->links-1;link>=0;link--){
1430
pcm_total-=vf->pcmlengths[link*2+1];
1431
time_total-=ov_time_total(vf,link);
1432
if(milliseconds>=time_total)break;
1433
}
1434
1435
/* enough information to convert time offset to pcm offset */
1436
{
1437
ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
1438
return(ov_pcm_seek_page(vf,target));
1439
}
1440
}
1441
1442
/* tell the current stream offset cursor. Note that seek followed by
1443
tell will likely not give the set offset due to caching */
1444
ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
1445
if(vf->ready_state<OPENED)return(OV_EINVAL);
1446
return(vf->offset);
1447
}
1448
1449
/* return PCM offset (sample) of next PCM sample to be read */
1450
ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
1451
if(vf->ready_state<OPENED)return(OV_EINVAL);
1452
return(vf->pcm_offset);
1453
}
1454
1455
/* return time offset (milliseconds) of next PCM sample to be read */
1456
ogg_int64_t ov_time_tell(OggVorbis_File *vf){
1457
int link=0;
1458
ogg_int64_t pcm_total=0;
1459
ogg_int64_t time_total=0;
1460
1461
if(vf->ready_state<OPENED)return(OV_EINVAL);
1462
if(vf->seekable){
1463
pcm_total=ov_pcm_total(vf,-1);
1464
time_total=ov_time_total(vf,-1);
1465
1466
/* which bitstream section does this time offset occur in? */
1467
for(link=vf->links-1;link>=0;link--){
1468
pcm_total-=vf->pcmlengths[link*2+1];
1469
time_total-=ov_time_total(vf,link);
1470
if(vf->pcm_offset>=pcm_total)break;
1471
}
1472
}
1473
1474
return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate);
1475
}
1476
1477
/* link: -1) return the vorbis_info struct for the bitstream section
1478
currently being decoded
1479
0-n) to request information for a specific bitstream section
1480
1481
In the case of a non-seekable bitstream, any call returns the
1482
current bitstream. NULL in the case that the machine is not
1483
initialized */
1484
1485
vorbis_info *ov_info(OggVorbis_File *vf,int link){
1486
if(vf->seekable){
1487
if(link<0)
1488
if(vf->ready_state>=STREAMSET)
1489
return vf->vi+vf->current_link;
1490
else
1491
return vf->vi;
1492
else
1493
if(link>=vf->links)
1494
return NULL;
1495
else
1496
return vf->vi+link;
1497
}else{
1498
return vf->vi;
1499
}
1500
}
1501
1502
/* grr, strong typing, grr, no templates/inheritence, grr */
1503
vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
1504
if(vf->seekable){
1505
if(link<0)
1506
if(vf->ready_state>=STREAMSET)
1507
return vf->vc+vf->current_link;
1508
else
1509
return vf->vc;
1510
else
1511
if(link>=vf->links)
1512
return NULL;
1513
else
1514
return vf->vc+link;
1515
}else{
1516
return vf->vc;
1517
}
1518
}
1519
1520
/* up to this point, everything could more or less hide the multiple
1521
logical bitstream nature of chaining from the toplevel application
1522
if the toplevel application didn't particularly care. However, at
1523
the point that we actually read audio back, the multiple-section
1524
nature must surface: Multiple bitstream sections do not necessarily
1525
have to have the same number of channels or sampling rate.
1526
1527
ov_read returns the sequential logical bitstream number currently
1528
being decoded along with the PCM data in order that the toplevel
1529
application can take action on channel/sample rate changes. This
1530
number will be incremented even for streamed (non-seekable) streams
1531
(for seekable streams, it represents the actual logical bitstream
1532
index within the physical bitstream. Note that the accessor
1533
functions above are aware of this dichotomy).
1534
1535
input values: buffer) a buffer to hold packed PCM data for return
1536
length) the byte length requested to be placed into buffer
1537
1538
return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
1539
0) EOF
1540
n) number of bytes of PCM actually returned. The
1541
below works on a packet-by-packet basis, so the
1542
return length is not related to the 'length' passed
1543
in, just guaranteed to fit.
1544
1545
*section) set to the logical bitstream number */
1546
1547
long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){
1548
int i,j;
1549
1550
ogg_int32_t **pcm;
1551
long samples;
1552
1553
if(vf->ready_state<OPENED)return(OV_EINVAL);
1554
1555
while(1){
1556
if(vf->ready_state==INITSET){
1557
samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
1558
if(samples)break;
1559
}
1560
1561
/* suck in another packet */
1562
{
1563
int ret=_fetch_and_process_packet(vf,1,1);
1564
if(ret==OV_EOF)
1565
return(0);
1566
if(ret<=0)
1567
return(ret);
1568
}
1569
1570
}
1571
1572
if(samples>0){
1573
1574
/* yay! proceed to pack data into the byte buffer */
1575
1576
long channels=ov_info(vf,-1)->channels;
1577
1578
if(samples>(bytes_req/(2*channels)))
1579
samples=bytes_req/(2*channels);
1580
1581
for(i=0;i<channels;i++) { /* It's faster in this order */
1582
ogg_int32_t *src=pcm[i];
1583
short *dest=((short *)buffer)+i;
1584
for(j=0;j<samples;j++) {
1585
*dest=CLIP_TO_15(src[j]>>9);
1586
dest+=channels;
1587
}
1588
}
1589
1590
vorbis_synthesis_read(&vf->vd,samples);
1591
vf->pcm_offset+=samples;
1592
if(bitstream)*bitstream=vf->current_link;
1593
return(samples*2*channels);
1594
}else{
1595
return(samples);
1596
}
1597
}
1598
1599