Coverage Report

Created: 2026-09-14 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vorbis/lib/vorbisfile.c
Line
Count
Source
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-2015             *
9
 * by the Xiph.Org Foundation https://xiph.org/                     *
10
 *                                                                  *
11
 ********************************************************************
12
13
 function: stdio-based convenience library for opening/seeking/decoding
14
15
 ********************************************************************/
16
17
#include <stdlib.h>
18
#include <stdio.h>
19
#include <errno.h>
20
#include <string.h>
21
#include <math.h>
22
23
#include "vorbis/codec.h"
24
25
/* we don't need or want the static callback symbols here */
26
#define OV_EXCLUDE_STATIC_CALLBACKS
27
#include "vorbis/vorbisfile.h"
28
29
#include "os.h"
30
#include "misc.h"
31
32
/* A 'chained bitstream' is a Vorbis bitstream that contains more than
33
   one logical bitstream arranged end to end (the only form of Ogg
34
   multiplexing allowed in a Vorbis bitstream; grouping [parallel
35
   multiplexing] is not allowed in Vorbis) */
36
37
/* A Vorbis file can be played beginning to end (streamed) without
38
   worrying ahead of time about chaining (see decoder_example.c).  If
39
   we have the whole file, however, and want random access
40
   (seeking/scrubbing) or desire to know the total length/time of a
41
   file, we need to account for the possibility of chaining. */
42
43
/* We can handle things a number of ways; we can determine the entire
44
   bitstream structure right off the bat, or find pieces on demand.
45
   This example determines and caches structure for the entire
46
   bitstream, but builds a virtual decoder on the fly when moving
47
   between links in the chain. */
48
49
/* There are also different ways to implement seeking.  Enough
50
   information exists in an Ogg bitstream to seek to
51
   sample-granularity positions in the output.  Or, one can seek by
52
   picking some portion of the stream roughly in the desired area if
53
   we only want coarse navigation through the stream. */
54
55
/*************************************************************************
56
 * Many, many internal helpers.  The intention is not to be confusing;
57
 * rampant duplication and monolithic function implementation would be
58
 * harder to understand anyway.  The high level functions are last.  Begin
59
 * grokking near the end of the file */
60
61
/* read a little more data from the file/pipe into the ogg_sync framer
62
*/
63
0
#define CHUNKSIZE 65536 /* greater-than-page-size granularity seeking */
64
0
#define READSIZE 2048 /* a smaller read size is needed for low-rate streaming. */
65
66
0
static long _get_data(OggVorbis_File *vf){
67
0
  errno=0;
68
0
  if(!(vf->callbacks.read_func))return(-1);
69
0
  if(vf->datasource){
70
0
    char *buffer=ogg_sync_buffer(&vf->oy,READSIZE);
71
0
    long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource);
72
0
    if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
73
0
    if(bytes==0 && errno)return(-1);
74
0
    return(bytes);
75
0
  }else
76
0
    return(0);
77
0
}
78
79
/* save a tiny smidge of verbosity to make the code more readable */
80
0
static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
81
0
  if(vf->datasource){
82
    /* only seek if the file position isn't already there */
83
0
    if(vf->offset != offset){
84
0
      if(!(vf->callbacks.seek_func)||
85
0
         (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1)
86
0
        return OV_EREAD;
87
0
      vf->offset=offset;
88
0
      ogg_sync_reset(&vf->oy);
89
0
    }
90
0
  }else{
91
    /* shouldn't happen unless someone writes a broken callback */
92
0
    return OV_EFAULT;
93
0
  }
94
0
  return 0;
95
0
}
96
97
/* The read/seek functions track absolute position within the stream */
98
99
/* from the head of the stream, get the next page.  boundary specifies
100
   if the function is allowed to fetch more data from the stream (and
101
   how much) or only use internally buffered data.
102
103
   boundary: -1) unbounded search
104
              0) read no additional data; use cached only
105
              n) search for a new page beginning for n bytes
106
107
   return:   <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
108
              n) found a page at absolute offset n */
109
110
static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
111
0
                                  ogg_int64_t boundary){
112
0
  if(boundary>0)boundary+=vf->offset;
113
0
  while(1){
114
0
    long more;
115
116
0
    if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
117
0
    more=ogg_sync_pageseek(&vf->oy,og);
118
119
0
    if(more<0){
120
      /* skipped n bytes */
121
0
      vf->offset-=more;
122
0
    }else{
123
0
      if(more==0){
124
        /* send more paramedics */
125
0
        if(!boundary)return(OV_FALSE);
126
0
        {
127
0
          long ret=_get_data(vf);
128
0
          if(ret==0)return(OV_EOF);
129
0
          if(ret<0)return(OV_EREAD);
130
0
        }
131
0
      }else{
132
        /* got a page.  Return the offset at the page beginning,
133
           advance the internal offset past the page end */
134
0
        ogg_int64_t ret=vf->offset;
135
0
        vf->offset+=more;
136
0
        return(ret);
137
138
0
      }
139
0
    }
140
0
  }
141
0
}
142
143
/* find the latest page beginning before the passed in position. Much
144
   dirtier than the above as Ogg doesn't have any backward search
145
   linkage.  no 'readp' as it will certainly have to read. */
146
/* returns offset or OV_EREAD, OV_FAULT */
147
0
static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_int64_t begin,ogg_page *og){
148
0
  ogg_int64_t end = begin;
149
0
  ogg_int64_t ret;
150
0
  ogg_int64_t offset=-1;
151
152
0
  while(offset==-1){
153
0
    begin-=CHUNKSIZE;
154
0
    if(begin<0)
155
0
      begin=0;
156
157
0
    ret=_seek_helper(vf,begin);
158
0
    if(ret)return(ret);
159
160
0
    while(vf->offset<end){
161
0
      memset(og,0,sizeof(*og));
162
0
      ret=_get_next_page(vf,og,end-vf->offset);
163
0
      if(ret==OV_EREAD)return(OV_EREAD);
164
0
      if(ret<0){
165
0
        break;
166
0
      }else{
167
0
        offset=ret;
168
0
      }
169
0
    }
170
0
  }
171
172
  /* In a fully compliant, non-multiplexed stream, we'll still be
173
     holding the last page.  In multiplexed (or noncompliant streams),
174
     we will probably have to re-read the last page we saw */
175
0
  if(og->header_len==0){
176
0
    ret=_seek_helper(vf,offset);
177
0
    if(ret)return(ret);
178
179
0
    ret=_get_next_page(vf,og,CHUNKSIZE);
180
0
    if(ret<0)
181
      /* this shouldn't be possible */
182
0
      return(OV_EFAULT);
183
0
  }
184
185
0
  return(offset);
186
0
}
187
188
0
static void _add_serialno(ogg_page *og,long **serialno_list, int *n){
189
0
  long s = ogg_page_serialno(og);
190
0
  (*n)++;
191
192
0
  if(*serialno_list){
193
0
    *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n));
194
0
  }else{
195
0
    *serialno_list = _ogg_malloc(sizeof(**serialno_list));
196
0
  }
197
198
0
  (*serialno_list)[(*n)-1] = s;
199
0
}
200
201
/* returns nonzero if found */
202
0
static int _lookup_serialno(long s, long *serialno_list, int n){
203
0
  if(serialno_list){
204
0
    while(n--){
205
0
      if(*serialno_list == s) return 1;
206
0
      serialno_list++;
207
0
    }
208
0
  }
209
0
  return 0;
210
0
}
211
212
0
static int _lookup_page_serialno(ogg_page *og, long *serialno_list, int n){
213
0
  long s = ogg_page_serialno(og);
214
0
  return _lookup_serialno(s,serialno_list,n);
215
0
}
216
217
/* performs the same search as _get_prev_page, but prefers pages of
218
   the specified serial number. If a page of the specified serialno is
219
   spotted during the seek-back-and-read-forward, it will return the
220
   info of last page of the matching serial number instead of the very
221
   last page.  If no page of the specified serialno is seen, it will
222
   return the info of last page and alter *serialno.  */
223
static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, ogg_int64_t begin,
224
                                         long *serial_list, int serial_n,
225
0
                                         int *serialno, ogg_int64_t *granpos){
226
0
  ogg_page og;
227
0
  ogg_int64_t end=begin;
228
0
  ogg_int64_t ret;
229
230
0
  ogg_int64_t prefoffset=-1;
231
0
  ogg_int64_t offset=-1;
232
0
  ogg_int64_t ret_serialno=-1;
233
0
  ogg_int64_t ret_gran=-1;
234
235
0
  while(offset==-1){
236
0
    begin-=CHUNKSIZE;
237
0
    if(begin<0)
238
0
      begin=0;
239
240
0
    ret=_seek_helper(vf,begin);
241
0
    if(ret)return(ret);
242
243
0
    while(vf->offset<end){
244
0
      ret=_get_next_page(vf,&og,end-vf->offset);
245
0
      if(ret==OV_EREAD)return(OV_EREAD);
246
0
      if(ret<0){
247
0
        break;
248
0
      }else{
249
0
        ret_serialno=ogg_page_serialno(&og);
250
0
        ret_gran=ogg_page_granulepos(&og);
251
0
        offset=ret;
252
253
0
        if(ret_serialno == *serialno){
254
0
          prefoffset=ret;
255
0
          *granpos=ret_gran;
256
0
        }
257
258
0
        if(!_lookup_serialno(ret_serialno,serial_list,serial_n)){
259
          /* we fell off the end of the link, which means we seeked
260
             back too far and shouldn't have been looking in that link
261
             to begin with.  If we found the preferred serial number,
262
             forget that we saw it. */
263
0
          prefoffset=-1;
264
0
        }
265
0
      }
266
0
    }
267
    /*We started from the beginning of the stream and found nothing.
268
      This should be impossible unless the contents of the stream changed out
269
      from under us after we read from it.*/
270
0
    if(!begin&&vf->offset<0)return OV_EBADLINK;
271
0
  }
272
273
  /* we're not interested in the page... just the serialno and granpos. */
274
0
  if(prefoffset>=0)return(prefoffset);
275
276
0
  *serialno = ret_serialno;
277
0
  *granpos = ret_gran;
278
0
  return(offset);
279
280
0
}
281
282
/* uses the local ogg_stream storage in vf; this is important for
283
   non-streaming input sources */
284
static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
285
                          long **serialno_list, int *serialno_n,
286
0
                          ogg_page *og_ptr){
287
0
  ogg_page og;
288
0
  ogg_packet op;
289
0
  int i,ret;
290
0
  int allbos=0;
291
292
0
  if(!og_ptr){
293
0
    ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
294
0
    if(llret==OV_EREAD)return(OV_EREAD);
295
0
    if(llret<0)return(OV_ENOTVORBIS);
296
0
    og_ptr=&og;
297
0
  }
298
299
0
  vorbis_info_init(vi);
300
0
  vorbis_comment_init(vc);
301
0
  vf->ready_state=OPENED;
302
303
  /* extract the serialnos of all BOS pages + the first set of vorbis
304
     headers we see in the link */
305
306
0
  while(ogg_page_bos(og_ptr)){
307
0
    if(serialno_list){
308
0
      if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){
309
        /* a dupe serialnumber in an initial header packet set == invalid stream */
310
0
        if(*serialno_list)_ogg_free(*serialno_list);
311
0
        *serialno_list=0;
312
0
        *serialno_n=0;
313
0
        ret=OV_EBADHEADER;
314
0
        goto bail_header;
315
0
      }
316
317
0
      _add_serialno(og_ptr,serialno_list,serialno_n);
318
0
    }
319
320
0
    if(vf->ready_state<STREAMSET){
321
      /* we don't have a vorbis stream in this link yet, so begin
322
         prospective stream setup. We need a stream to get packets */
323
0
      ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr));
324
0
      ogg_stream_pagein(&vf->os,og_ptr);
325
326
0
      if(ogg_stream_packetout(&vf->os,&op) > 0 &&
327
0
         vorbis_synthesis_idheader(&op)){
328
        /* vorbis header; continue setup */
329
0
        vf->ready_state=STREAMSET;
330
0
        if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
331
0
          ret=OV_EBADHEADER;
332
0
          goto bail_header;
333
0
        }
334
0
      }
335
0
    }
336
337
    /* get next page */
338
0
    {
339
0
      ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE);
340
0
      if(llret==OV_EREAD){
341
0
        ret=OV_EREAD;
342
0
        goto bail_header;
343
0
      }
344
0
      if(llret<0){
345
0
        ret=OV_ENOTVORBIS;
346
0
        goto bail_header;
347
0
      }
348
349
      /* if this page also belongs to our vorbis stream, submit it and break */
350
0
      if(vf->ready_state==STREAMSET &&
351
0
         vf->os.serialno == ogg_page_serialno(og_ptr)){
352
0
        ogg_stream_pagein(&vf->os,og_ptr);
353
0
        break;
354
0
      }
355
0
    }
356
0
  }
357
358
0
  if(vf->ready_state!=STREAMSET){
359
0
    ret = OV_ENOTVORBIS;
360
0
    goto bail_header;
361
0
  }
362
363
0
  while(1){
364
365
0
    i=0;
366
0
    while(i<2){ /* get a page loop */
367
368
0
      while(i<2){ /* get a packet loop */
369
370
0
        int result=ogg_stream_packetout(&vf->os,&op);
371
0
        if(result==0)break;
372
0
        if(result==-1){
373
0
          ret=OV_EBADHEADER;
374
0
          goto bail_header;
375
0
        }
376
377
0
        if((ret=vorbis_synthesis_headerin(vi,vc,&op)))
378
0
          goto bail_header;
379
380
0
        i++;
381
0
      }
382
383
0
      while(i<2){
384
0
        if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
385
0
          ret=OV_EBADHEADER;
386
0
          goto bail_header;
387
0
        }
388
389
        /* if this page belongs to the correct stream, go parse it */
390
0
        if(vf->os.serialno == ogg_page_serialno(og_ptr)){
391
0
          ogg_stream_pagein(&vf->os,og_ptr);
392
0
          break;
393
0
        }
394
395
        /* if we never see the final vorbis headers before the link
396
           ends, abort */
397
0
        if(ogg_page_bos(og_ptr)){
398
0
          if(allbos){
399
0
            ret = OV_EBADHEADER;
400
0
            goto bail_header;
401
0
          }else
402
0
            allbos=1;
403
0
        }
404
405
        /* otherwise, keep looking */
406
0
      }
407
0
    }
408
409
0
    return 0;
410
0
  }
411
412
0
 bail_header:
413
0
  vorbis_info_clear(vi);
414
0
  vorbis_comment_clear(vc);
415
0
  vf->ready_state=OPENED;
416
417
0
  return ret;
418
0
}
419
420
/* Starting from current cursor position, get initial PCM offset of
421
   next page.  Consumes the page in the process without decoding
422
   audio, however this is only called during stream parsing upon
423
   seekable open. */
424
0
static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){
425
0
  ogg_page    og;
426
0
  ogg_int64_t accumulated=0;
427
0
  long        lastblock=-1;
428
0
  int         result;
429
0
  int         serialno = vf->os.serialno;
430
431
0
  while(1){
432
0
    ogg_packet op;
433
0
    if(_get_next_page(vf,&og,-1)<0)
434
0
      break; /* should not be possible unless the file is truncated/mangled */
435
436
0
    if(ogg_page_bos(&og)) break;
437
0
    if(ogg_page_serialno(&og)!=serialno) continue;
438
439
    /* count blocksizes of all frames in the page */
440
0
    ogg_stream_pagein(&vf->os,&og);
441
0
    while((result=ogg_stream_packetout(&vf->os,&op))){
442
0
      if(result>0){ /* ignore holes */
443
0
        long thisblock=vorbis_packet_blocksize(vi,&op);
444
0
        if(thisblock>=0){
445
0
          if(lastblock!=-1)
446
0
            accumulated+=(lastblock+thisblock)>>2;
447
0
          lastblock=thisblock;
448
0
        }
449
0
      }
450
0
    }
451
452
0
    if(ogg_page_granulepos(&og)!=-1){
453
      /* pcm offset of last packet on the first audio page */
454
0
      accumulated= ogg_page_granulepos(&og)-accumulated;
455
0
      break;
456
0
    }
457
0
  }
458
459
  /* less than zero?  Either a corrupt file or a stream with samples
460
     trimmed off the beginning, a normal occurrence; in both cases set
461
     the offset to zero */
462
0
  if(accumulated<0)accumulated=0;
463
464
0
  return accumulated;
465
0
}
466
467
/* finds each bitstream link one at a time using a bisection search
468
   (has to begin by knowing the offset of the lb's initial page).
469
   Recurses for each link so it can alloc the link storage after
470
   finding them all, then unroll and fill the cache at the same time */
471
static int _bisect_forward_serialno(OggVorbis_File *vf,
472
                                    ogg_int64_t begin,
473
                                    ogg_int64_t searched,
474
                                    ogg_int64_t end,
475
                                    ogg_int64_t endgran,
476
                                    int endserial,
477
                                    long *currentno_list,
478
                                    int  currentnos,
479
0
                                    long m){
480
0
  ogg_int64_t pcmoffset;
481
0
  ogg_int64_t dataoffset=searched;
482
0
  ogg_int64_t endsearched=end;
483
0
  ogg_int64_t next=end;
484
0
  ogg_int64_t searchgran=-1;
485
0
  ogg_page og;
486
0
  ogg_int64_t ret,last;
487
0
  int serialno = vf->os.serialno;
488
489
  /* invariants:
490
     we have the headers and serialnos for the link beginning at 'begin'
491
     we have the offset and granpos of the last page in the file (potentially
492
       not a page we care about)
493
  */
494
495
  /* Is the last page in our list of current serialnumbers? */
496
0
  if(_lookup_serialno(endserial,currentno_list,currentnos)){
497
498
    /* last page is in the starting serialno list, so we've bisected
499
       down to (or just started with) a single link.  Now we need to
500
       find the last vorbis page belonging to the first vorbis stream
501
       for this link. */
502
0
    searched = end;
503
0
    while(endserial != serialno){
504
0
      endserial = serialno;
505
0
      searched=_get_prev_page_serial(vf,searched,currentno_list,currentnos,&endserial,&endgran);
506
0
    }
507
508
0
    vf->links=m+1;
509
0
    if(vf->offsets)_ogg_free(vf->offsets);
510
0
    if(vf->serialnos)_ogg_free(vf->serialnos);
511
0
    if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
512
513
0
    vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
514
0
    vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
515
0
    vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
516
0
    vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
517
0
    vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
518
0
    vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
519
520
0
    vf->offsets[m+1]=end;
521
0
    vf->offsets[m]=begin;
522
0
    vf->pcmlengths[m*2+1]=(endgran<0?0:endgran);
523
524
0
  }else{
525
526
    /* last page is not in the starting stream's serial number list,
527
       so we have multiple links.  Find where the stream that begins
528
       our bisection ends. */
529
530
0
    long *next_serialno_list=NULL;
531
0
    int next_serialnos=0;
532
0
    vorbis_info vi;
533
0
    vorbis_comment vc;
534
0
    int testserial = serialno+1;
535
536
    /* the below guards against garbage seperating the last and
537
       first pages of two links. */
538
0
    while(searched<endsearched){
539
0
      ogg_int64_t bisect;
540
541
0
      if(endsearched-searched<CHUNKSIZE){
542
0
        bisect=searched;
543
0
      }else{
544
0
        bisect=(searched+endsearched)/2;
545
0
      }
546
547
0
      ret=_seek_helper(vf,bisect);
548
0
      if(ret)return(ret);
549
550
0
      last=_get_next_page(vf,&og,-1);
551
0
      if(last==OV_EREAD)return(OV_EREAD);
552
0
      if(last<0 || !_lookup_page_serialno(&og,currentno_list,currentnos)){
553
0
        endsearched=bisect;
554
0
        if(last>=0)next=last;
555
0
      }else{
556
0
        searched=vf->offset;
557
0
      }
558
0
    }
559
560
    /* Bisection point found */
561
    /* for the time being, fetch end PCM offset the simple way */
562
0
    searched = next;
563
0
    while(testserial != serialno){
564
0
      testserial = serialno;
565
0
      searched = _get_prev_page_serial(vf,searched,currentno_list,currentnos,&testserial,&searchgran);
566
0
    }
567
568
0
    ret=_seek_helper(vf,next);
569
0
    if(ret)return(ret);
570
571
0
    ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL);
572
0
    if(ret)return(ret);
573
0
    serialno = vf->os.serialno;
574
0
    dataoffset = vf->offset;
575
576
    /* this will consume a page, however the next bisection always
577
       starts with a raw seek */
578
0
    pcmoffset = _initial_pcmoffset(vf,&vi);
579
580
0
    ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial,
581
0
                                 next_serialno_list,next_serialnos,m+1);
582
0
    if(ret)return(ret);
583
584
0
    if(next_serialno_list)_ogg_free(next_serialno_list);
585
586
0
    vf->offsets[m+1]=next;
587
0
    vf->serialnos[m+1]=serialno;
588
0
    vf->dataoffsets[m+1]=dataoffset;
589
590
0
    vf->vi[m+1]=vi;
591
0
    vf->vc[m+1]=vc;
592
593
0
    vf->pcmlengths[m*2+1]=searchgran;
594
0
    vf->pcmlengths[m*2+2]=pcmoffset;
595
0
    vf->pcmlengths[m*2+3]-=pcmoffset;
596
0
    if(vf->pcmlengths[m*2+3]<0)vf->pcmlengths[m*2+3]=0;
597
0
  }
598
0
  return(0);
599
0
}
600
601
0
static int _make_decode_ready(OggVorbis_File *vf){
602
0
  if(vf->ready_state>STREAMSET)return 0;
603
0
  if(vf->ready_state<STREAMSET)return OV_EFAULT;
604
0
  if(vf->seekable){
605
0
    if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link))
606
0
      return OV_EBADLINK;
607
0
  }else{
608
0
    if(vorbis_synthesis_init(&vf->vd,vf->vi))
609
0
      return OV_EBADLINK;
610
0
  }
611
0
  vorbis_block_init(&vf->vd,&vf->vb);
612
0
  vf->ready_state=INITSET;
613
0
  vf->bittrack=0.f;
614
0
  vf->samptrack=0.f;
615
0
  return 0;
616
0
}
617
618
0
static int _open_seekable2(OggVorbis_File *vf){
619
0
  ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1;
620
0
  int endserial=vf->os.serialno;
621
0
  int serialno=vf->os.serialno;
622
623
  /* we're partially open and have a first link header state in
624
     storage in vf */
625
626
  /* fetch initial PCM offset */
627
0
  ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi);
628
629
  /* we can seek, so set out learning all about this file */
630
0
  if(vf->callbacks.seek_func && vf->callbacks.tell_func){
631
0
    (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
632
0
    vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
633
0
  }else{
634
0
    vf->offset=vf->end=-1;
635
0
  }
636
637
  /* If seek_func is implemented, tell_func must also be implemented */
638
0
  if(vf->end==-1) return(OV_EINVAL);
639
640
  /* Get the offset of the last page of the physical bitstream, or, if
641
     we're lucky the last vorbis page of this link as most OggVorbis
642
     files will contain a single logical bitstream */
643
0
  end=_get_prev_page_serial(vf,vf->end,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran);
644
0
  if(end<0)return(end);
645
646
  /* now determine bitstream structure recursively */
647
0
  if(_bisect_forward_serialno(vf,0,dataoffset,end,endgran,endserial,
648
0
                              vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD);
649
650
0
  vf->offsets[0]=0;
651
0
  vf->serialnos[0]=serialno;
652
0
  vf->dataoffsets[0]=dataoffset;
653
0
  vf->pcmlengths[0]=pcmoffset;
654
0
  vf->pcmlengths[1]-=pcmoffset;
655
0
  if(vf->pcmlengths[1]<0)vf->pcmlengths[1]=0;
656
657
0
  return(ov_raw_seek(vf,dataoffset));
658
0
}
659
660
/* clear out the current logical bitstream decoder */
661
0
static void _decode_clear(OggVorbis_File *vf){
662
0
  vorbis_dsp_clear(&vf->vd);
663
0
  vorbis_block_clear(&vf->vb);
664
0
  vf->ready_state=OPENED;
665
0
}
666
667
/* fetch and process a packet.  Handles the case where we're at a
668
   bitstream boundary and dumps the decoding machine.  If the decoding
669
   machine is unloaded, it loads it.  It also keeps pcm_offset up to
670
   date (seek and read both use this.  seek uses a special hack with
671
   readp).
672
673
   return: <0) error, OV_HOLE (lost packet) or OV_EOF
674
            0) need more data (only if readp==0)
675
            1) got a packet
676
*/
677
678
static int _fetch_and_process_packet(OggVorbis_File *vf,
679
                                     ogg_packet *op_in,
680
                                     int readp,
681
0
                                     int spanp){
682
0
  ogg_page og;
683
684
  /* handle one packet.  Try to fetch it from current stream state */
685
  /* extract packets from page */
686
0
  while(1){
687
688
0
    if(vf->ready_state==STREAMSET){
689
0
      int ret=_make_decode_ready(vf);
690
0
      if(ret<0)return ret;
691
0
    }
692
693
    /* process a packet if we can. */
694
695
0
    if(vf->ready_state==INITSET){
696
0
      int hs=vorbis_synthesis_halfrate_p(vf->vi);
697
698
0
      while(1) {
699
0
              ogg_packet op;
700
0
              ogg_packet *op_ptr=(op_in?op_in:&op);
701
0
        int result=ogg_stream_packetout(&vf->os,op_ptr);
702
0
        ogg_int64_t granulepos;
703
704
0
        op_in=NULL;
705
0
        if(result==-1)return(OV_HOLE); /* hole in the data. */
706
0
        if(result>0){
707
          /* got a packet.  process it */
708
0
          granulepos=op_ptr->granulepos;
709
0
          if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy
710
                                                    header handling.  The
711
                                                    header packets aren't
712
                                                    audio, so if/when we
713
                                                    submit them,
714
                                                    vorbis_synthesis will
715
                                                    reject them */
716
717
            /* suck in the synthesis data and track bitrate */
718
0
            {
719
0
              int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
720
              /* for proper use of libvorbis within libvorbisfile,
721
                 oldsamples will always be zero. */
722
0
              if(oldsamples)return(OV_EFAULT);
723
724
0
              vorbis_synthesis_blockin(&vf->vd,&vf->vb);
725
0
              vf->samptrack+=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs);
726
0
              vf->bittrack+=op_ptr->bytes*8;
727
0
            }
728
729
            /* update the pcm offset. */
730
0
            if(granulepos!=-1 && !op_ptr->e_o_s){
731
0
              int link=(vf->seekable?vf->current_link:0);
732
0
              int i,samples;
733
734
              /* this packet has a pcm_offset on it (the last packet
735
                 completed on a page carries the offset) After processing
736
                 (above), we know the pcm position of the *last* sample
737
                 ready to be returned. Find the offset of the *first*
738
739
                 As an aside, this trick is inaccurate if we begin
740
                 reading anew right at the last page; the end-of-stream
741
                 granulepos declares the last frame in the stream, and the
742
                 last packet of the last page may be a partial frame.
743
                 So, we need a previous granulepos from an in-sequence page
744
                 to have a reference point.  Thus the !op_ptr->e_o_s clause
745
                 above */
746
747
0
              if(vf->seekable && link>0)
748
0
                granulepos-=vf->pcmlengths[link*2];
749
0
              if(granulepos<0)granulepos=0; /* actually, this
750
                                               shouldn't be possible
751
                                               here unless the stream
752
                                               is very broken */
753
754
0
              samples=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs);
755
756
0
              granulepos-=samples;
757
0
              for(i=0;i<link;i++)
758
0
                granulepos+=vf->pcmlengths[i*2+1];
759
0
              vf->pcm_offset=granulepos;
760
0
            }
761
0
            return(1);
762
0
          }
763
0
        }
764
0
        else
765
0
          break;
766
0
      }
767
0
    }
768
769
0
    if(vf->ready_state>=OPENED){
770
0
      ogg_int64_t ret;
771
772
0
      while(1){
773
        /* the loop is not strictly necessary, but there's no sense in
774
           doing the extra checks of the larger loop for the common
775
           case in a multiplexed bistream where the page is simply
776
           part of a different logical bitstream; keep reading until
777
           we get one with the correct serialno */
778
779
0
        if(!readp)return(0);
780
0
        if((ret=_get_next_page(vf,&og,-1))<0){
781
0
          return(OV_EOF); /* eof. leave unitialized */
782
0
        }
783
784
        /* bitrate tracking; add the header's bytes here, the body bytes
785
           are done by packet above */
786
0
        vf->bittrack+=og.header_len*8;
787
788
0
        if(vf->ready_state==INITSET){
789
0
          if(vf->current_serialno!=ogg_page_serialno(&og)){
790
791
            /* two possibilities:
792
               1) our decoding just traversed a bitstream boundary
793
               2) another stream is multiplexed into this logical section */
794
795
0
            if(ogg_page_bos(&og)){
796
              /* boundary case */
797
0
              if(!spanp)
798
0
                return(OV_EOF);
799
800
0
              _decode_clear(vf);
801
802
0
              if(!vf->seekable){
803
0
                vorbis_info_clear(vf->vi);
804
0
                vorbis_comment_clear(vf->vc);
805
0
              }
806
0
              break;
807
808
0
            }else
809
0
              continue; /* possibility #2 */
810
0
          }
811
0
        }
812
813
0
        break;
814
0
      }
815
0
    }
816
817
    /* Do we need to load a new machine before submitting the page? */
818
    /* This is different in the seekable and non-seekable cases.
819
820
       In the seekable case, we already have all the header
821
       information loaded and cached; we just initialize the machine
822
       with it and continue on our merry way.
823
824
       In the non-seekable (streaming) case, we'll only be at a
825
       boundary if we just left the previous logical bitstream and
826
       we're now nominally at the header of the next bitstream
827
    */
828
829
0
    if(vf->ready_state!=INITSET){
830
0
      int link;
831
832
0
      if(vf->ready_state<STREAMSET){
833
0
        if(vf->seekable){
834
0
          long serialno = ogg_page_serialno(&og);
835
836
          /* match the serialno to bitstream section.  We use this rather than
837
             offset positions to avoid problems near logical bitstream
838
             boundaries */
839
840
0
          for(link=0;link<vf->links;link++)
841
0
            if(vf->serialnos[link]==serialno)break;
842
843
0
          if(link==vf->links) continue; /* not the desired Vorbis
844
                                           bitstream section; keep
845
                                           trying */
846
847
0
          vf->current_serialno=serialno;
848
0
          vf->current_link=link;
849
850
0
          ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
851
0
          vf->ready_state=STREAMSET;
852
853
0
        }else{
854
          /* we're streaming */
855
          /* fetch the three header packets, build the info struct */
856
857
0
          int ret=_fetch_headers(vf,vf->vi,vf->vc,NULL,NULL,&og);
858
0
          if(ret)return(ret);
859
0
          vf->current_serialno=vf->os.serialno;
860
0
          vf->current_link++;
861
0
          link=0;
862
0
        }
863
0
      }
864
0
    }
865
866
    /* the buffered page is the data we want, and we're ready for it;
867
       add it to the stream state */
868
0
    ogg_stream_pagein(&vf->os,&og);
869
870
0
  }
871
0
}
872
873
/* if, eg, 64 bit stdio is configured by default, this will build with
874
   fseek64 */
875
0
static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
876
0
  if(f==NULL)return(-1);
877
0
  return fseek(f,off,whence);
878
0
}
879
880
static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial,
881
0
                     long ibytes, ov_callbacks callbacks){
882
0
  int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1);
883
0
  long *serialno_list=NULL;
884
0
  int serialno_list_size=0;
885
0
  int ret;
886
887
0
  memset(vf,0,sizeof(*vf));
888
0
  vf->datasource=f;
889
0
  vf->callbacks = callbacks;
890
891
  /* init the framing state */
892
0
  ogg_sync_init(&vf->oy);
893
894
  /* perhaps some data was previously read into a buffer for testing
895
     against other stream types.  Allow initialization from this
896
     previously read data (especially as we may be reading from a
897
     non-seekable stream) */
898
0
  if(initial){
899
0
    char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
900
0
    memcpy(buffer,initial,ibytes);
901
0
    ogg_sync_wrote(&vf->oy,ibytes);
902
0
  }
903
904
  /* can we seek? Stevens suggests the seek test was portable */
905
0
  if(offsettest!=-1)vf->seekable=1;
906
907
  /* No seeking yet; Set up a 'single' (current) logical bitstream
908
     entry for partial open */
909
0
  vf->links=1;
910
0
  vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
911
0
  vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
912
0
  ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
913
914
  /* Fetch all BOS pages, store the vorbis header and all seen serial
915
     numbers, load subsequent vorbis setup headers */
916
0
  if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){
917
0
    vf->datasource=NULL;
918
0
    ov_clear(vf);
919
0
  }else{
920
    /* serial number list for first link needs to be held somewhere
921
       for second stage of seekable stream open; this saves having to
922
       seek/reread first link's serialnumber data then. */
923
0
    vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos));
924
0
    vf->serialnos[0]=vf->current_serialno=vf->os.serialno;
925
0
    vf->serialnos[1]=serialno_list_size;
926
0
    memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos));
927
928
0
    vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets));
929
0
    vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets));
930
0
    vf->offsets[0]=0;
931
0
    vf->dataoffsets[0]=vf->offset;
932
933
0
    vf->ready_state=PARTOPEN;
934
0
  }
935
0
  if(serialno_list)_ogg_free(serialno_list);
936
0
  return(ret);
937
0
}
938
939
0
static int _ov_open2(OggVorbis_File *vf){
940
0
  if(vf->ready_state != PARTOPEN) return OV_EINVAL;
941
0
  vf->ready_state=OPENED;
942
0
  if(vf->seekable){
943
0
    int ret=_open_seekable2(vf);
944
0
    if(ret){
945
0
      vf->datasource=NULL;
946
0
      ov_clear(vf);
947
0
    }
948
0
    return(ret);
949
0
  }else
950
0
    vf->ready_state=STREAMSET;
951
952
0
  return 0;
953
0
}
954
955
956
/* clear out the OggVorbis_File struct */
957
0
int ov_clear(OggVorbis_File *vf){
958
0
  if(vf){
959
0
    vorbis_block_clear(&vf->vb);
960
0
    vorbis_dsp_clear(&vf->vd);
961
0
    ogg_stream_clear(&vf->os);
962
963
0
    if(vf->vi && vf->links){
964
0
      int i;
965
0
      for(i=0;i<vf->links;i++){
966
0
        vorbis_info_clear(vf->vi+i);
967
0
        vorbis_comment_clear(vf->vc+i);
968
0
      }
969
0
      _ogg_free(vf->vi);
970
0
      _ogg_free(vf->vc);
971
0
    }
972
0
    if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
973
0
    if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
974
0
    if(vf->serialnos)_ogg_free(vf->serialnos);
975
0
    if(vf->offsets)_ogg_free(vf->offsets);
976
0
    ogg_sync_clear(&vf->oy);
977
0
    if(vf->datasource && vf->callbacks.close_func)
978
0
      (vf->callbacks.close_func)(vf->datasource);
979
0
    memset(vf,0,sizeof(*vf));
980
0
  }
981
#ifdef DEBUG_LEAKS
982
  _VDBG_dump();
983
#endif
984
0
  return(0);
985
0
}
986
987
/* inspects the OggVorbis file and finds/documents all the logical
988
   bitstreams contained in it.  Tries to be tolerant of logical
989
   bitstream sections that are truncated/woogie.
990
991
   return: -1) error
992
            0) OK
993
*/
994
995
int ov_open_callbacks(void *f,OggVorbis_File *vf,
996
0
    const char *initial,long ibytes,ov_callbacks callbacks){
997
0
  int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
998
0
  if(ret)return ret;
999
0
  return _ov_open2(vf);
1000
0
}
1001
1002
0
int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){
1003
0
  ov_callbacks callbacks = {
1004
0
    (size_t (*)(void *, size_t, size_t, void *))  fread,
1005
0
    (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
1006
0
    (int (*)(void *))                             fclose,
1007
0
    (long (*)(void *))                            ftell
1008
0
  };
1009
1010
0
  return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
1011
0
}
1012
1013
0
int ov_fopen(const char *path,OggVorbis_File *vf){
1014
0
  int ret;
1015
0
  FILE *f = fopen(path,"rb");
1016
0
  if(!f) return -1;
1017
1018
0
  ret = ov_open(f,vf,NULL,0);
1019
0
  if(ret) fclose(f);
1020
0
  return ret;
1021
0
}
1022
1023
1024
/* cheap hack for game usage where downsampling is desirable; there's
1025
   no need for SRC as we can just do it cheaply in libvorbis. */
1026
1027
0
int ov_halfrate(OggVorbis_File *vf,int flag){
1028
0
  int i;
1029
0
  if(vf->vi==NULL)return OV_EINVAL;
1030
0
  if(vf->ready_state>STREAMSET){
1031
    /* clear out stream state; dumping the decode machine is needed to
1032
       reinit the MDCT lookups. */
1033
0
    vorbis_dsp_clear(&vf->vd);
1034
0
    vorbis_block_clear(&vf->vb);
1035
0
    vf->ready_state=STREAMSET;
1036
0
    if(vf->pcm_offset>=0){
1037
0
      ogg_int64_t pos=vf->pcm_offset;
1038
0
      vf->pcm_offset=-1; /* make sure the pos is dumped if unseekable */
1039
0
      ov_pcm_seek(vf,pos);
1040
0
    }
1041
0
  }
1042
1043
0
  for(i=0;i<vf->links;i++){
1044
0
    if(vorbis_synthesis_halfrate(vf->vi+i,flag)){
1045
0
      if(flag) ov_halfrate(vf,0);
1046
0
      return OV_EINVAL;
1047
0
    }
1048
0
  }
1049
0
  return 0;
1050
0
}
1051
1052
0
int ov_halfrate_p(OggVorbis_File *vf){
1053
0
  if(vf->vi==NULL)return OV_EINVAL;
1054
0
  return vorbis_synthesis_halfrate_p(vf->vi);
1055
0
}
1056
1057
/* Only partially open the vorbis file; test for Vorbisness, and load
1058
   the headers for the first chain.  Do not seek (although test for
1059
   seekability).  Use ov_test_open to finish opening the file, else
1060
   ov_clear to close/free it. Same return codes as open.
1061
1062
   Note that vorbisfile does _not_ take ownership of the file if the
1063
   call fails; the calling applicaiton is responsible for closing the file
1064
   if this call returns an error. */
1065
1066
int ov_test_callbacks(void *f,OggVorbis_File *vf,
1067
    const char *initial,long ibytes,ov_callbacks callbacks)
1068
0
{
1069
0
  return _ov_open1(f,vf,initial,ibytes,callbacks);
1070
0
}
1071
1072
0
int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){
1073
0
  ov_callbacks callbacks = {
1074
0
    (size_t (*)(void *, size_t, size_t, void *))  fread,
1075
0
    (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
1076
0
    (int (*)(void *))                             fclose,
1077
0
    (long (*)(void *))                            ftell
1078
0
  };
1079
1080
0
  return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
1081
0
}
1082
1083
0
int ov_test_open(OggVorbis_File *vf){
1084
0
  if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);
1085
0
  return _ov_open2(vf);
1086
0
}
1087
1088
/* How many logical bitstreams in this physical bitstream? */
1089
0
long ov_streams(OggVorbis_File *vf){
1090
0
  return vf->links;
1091
0
}
1092
1093
/* Is the FILE * associated with vf seekable? */
1094
0
long ov_seekable(OggVorbis_File *vf){
1095
0
  return vf->seekable;
1096
0
}
1097
1098
/* returns the bitrate for a given logical bitstream or the entire
1099
   physical bitstream.  If the file is open for random access, it will
1100
   find the *actual* average bitrate.  If the file is streaming, it
1101
   returns the nominal bitrate (if set) else the average of the
1102
   upper/lower bounds (if set) else -1 (unset).
1103
1104
   If you want the actual bitrate field settings, get them from the
1105
   vorbis_info structs */
1106
1107
0
long ov_bitrate(OggVorbis_File *vf,int i){
1108
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1109
0
  if(i>=vf->links)return(OV_EINVAL);
1110
0
  if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
1111
0
  if(i<0){
1112
0
    ogg_int64_t bits=0;
1113
0
    int i;
1114
0
    float br;
1115
0
    for(i=0;i<vf->links;i++)
1116
0
      bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
1117
    /* This once read: return(rint(bits/ov_time_total(vf,-1)));
1118
     * gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
1119
     * so this is slightly transformed to make it work.
1120
     */
1121
0
    br = bits/ov_time_total(vf,-1);
1122
0
    return(rint(br));
1123
0
  }else{
1124
0
    if(vf->seekable){
1125
      /* return the actual bitrate */
1126
0
      return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i)));
1127
0
    }else{
1128
      /* return nominal if set */
1129
0
      if(vf->vi[i].bitrate_nominal>0){
1130
0
        return vf->vi[i].bitrate_nominal;
1131
0
      }else{
1132
0
        if(vf->vi[i].bitrate_upper>0){
1133
0
          if(vf->vi[i].bitrate_lower>0){
1134
0
            return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
1135
0
          }else{
1136
0
            return vf->vi[i].bitrate_upper;
1137
0
          }
1138
0
        }
1139
0
        return(OV_FALSE);
1140
0
      }
1141
0
    }
1142
0
  }
1143
0
}
1144
1145
/* returns the actual bitrate since last call.  returns -1 if no
1146
   additional data to offer since last call (or at beginning of stream),
1147
   EINVAL if stream is only partially open
1148
*/
1149
0
long ov_bitrate_instant(OggVorbis_File *vf){
1150
0
  int link=(vf->seekable?vf->current_link:0);
1151
0
  long ret;
1152
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1153
0
  if(vf->samptrack==0)return(OV_FALSE);
1154
0
  ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5;
1155
0
  vf->bittrack=0.f;
1156
0
  vf->samptrack=0.f;
1157
0
  return(ret);
1158
0
}
1159
1160
/* Guess */
1161
0
long ov_serialnumber(OggVorbis_File *vf,int i){
1162
0
  if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
1163
0
  if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
1164
0
  if(i<0){
1165
0
    return(vf->current_serialno);
1166
0
  }else{
1167
0
    return(vf->serialnos[i]);
1168
0
  }
1169
0
}
1170
1171
/* returns: total raw (compressed) length of content if i==-1
1172
            raw (compressed) length of that logical bitstream for i==0 to n
1173
            OV_EINVAL if the stream is not seekable (we can't know the length)
1174
            or if stream is only partially open
1175
*/
1176
0
ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
1177
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1178
0
  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
1179
0
  if(i<0){
1180
0
    ogg_int64_t acc=0;
1181
0
    int i;
1182
0
    for(i=0;i<vf->links;i++)
1183
0
      acc+=ov_raw_total(vf,i);
1184
0
    return(acc);
1185
0
  }else{
1186
0
    return(vf->offsets[i+1]-vf->offsets[i]);
1187
0
  }
1188
0
}
1189
1190
/* returns: total PCM length (samples) of content if i==-1 PCM length
1191
            (samples) of that logical bitstream for i==0 to n
1192
            OV_EINVAL if the stream is not seekable (we can't know the
1193
            length) or only partially open
1194
*/
1195
0
ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
1196
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1197
0
  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
1198
0
  if(i<0){
1199
0
    ogg_int64_t acc=0;
1200
0
    int i;
1201
0
    for(i=0;i<vf->links;i++)
1202
0
      acc+=ov_pcm_total(vf,i);
1203
0
    return(acc);
1204
0
  }else{
1205
0
    return(vf->pcmlengths[i*2+1]);
1206
0
  }
1207
0
}
1208
1209
/* returns: total seconds of content if i==-1
1210
            seconds in that logical bitstream for i==0 to n
1211
            OV_EINVAL if the stream is not seekable (we can't know the
1212
            length) or only partially open
1213
*/
1214
0
double ov_time_total(OggVorbis_File *vf,int i){
1215
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1216
0
  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
1217
0
  if(i<0){
1218
0
    double acc=0;
1219
0
    int i;
1220
0
    for(i=0;i<vf->links;i++)
1221
0
      acc+=ov_time_total(vf,i);
1222
0
    return(acc);
1223
0
  }else{
1224
0
    return((double)(vf->pcmlengths[i*2+1])/vf->vi[i].rate);
1225
0
  }
1226
0
}
1227
1228
/* seek to an offset relative to the *compressed* data. This also
1229
   scans packets to update the PCM cursor. It will cross a logical
1230
   bitstream boundary, but only if it can't get any packets out of the
1231
   tail of the bitstream we seek to (so no surprises).
1232
1233
   returns zero on success, nonzero on failure */
1234
1235
0
int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
1236
0
  ogg_stream_state work_os;
1237
1238
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1239
0
  if(!vf->seekable)
1240
0
    return(OV_ENOSEEK); /* don't dump machine if we can't seek */
1241
1242
0
  if(pos<0 || pos>vf->end)return(OV_EINVAL);
1243
1244
  /* is the seek position outside our current link [if any]? */
1245
0
  if(vf->ready_state>=STREAMSET){
1246
0
    if(pos<vf->offsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1])
1247
0
      _decode_clear(vf); /* clear out stream state */
1248
0
  }
1249
1250
  /* don't yet clear out decoding machine (if it's initialized), in
1251
     the case we're in the same link.  Restart the decode lapping, and
1252
     let _fetch_and_process_packet deal with a potential bitstream
1253
     boundary */
1254
0
  vf->pcm_offset=-1;
1255
0
  ogg_stream_reset_serialno(&vf->os,
1256
0
                            vf->current_serialno); /* must set serialno */
1257
0
  vorbis_synthesis_restart(&vf->vd);
1258
1259
0
  if(_seek_helper(vf,pos)) {
1260
    /* dump the machine so we're in a known state */
1261
0
    vf->pcm_offset=-1;
1262
0
    _decode_clear(vf);
1263
0
    return OV_EBADLINK;
1264
0
  }
1265
1266
  /* we need to make sure the pcm_offset is set, but we don't want to
1267
     advance the raw cursor past good packets just to get to the first
1268
     with a granulepos.  That's not equivalent behavior to beginning
1269
     decoding as immediately after the seek position as possible.
1270
1271
     So, a hack.  We use two stream states; a local scratch state and
1272
     the shared vf->os stream state.  We use the local state to
1273
     scan, and the shared state as a buffer for later decode.
1274
1275
     Unfortuantely, on the last page we still advance to last packet
1276
     because the granulepos on the last page is not necessarily on a
1277
     packet boundary, and we need to make sure the granpos is
1278
     correct.
1279
  */
1280
1281
0
  {
1282
0
    ogg_page og;
1283
0
    ogg_packet op;
1284
0
    int lastblock=0;
1285
0
    int accblock=0;
1286
0
    int thisblock=0;
1287
0
    int lastflag=0;
1288
0
    int firstflag=0;
1289
0
    ogg_int64_t pagepos=-1;
1290
1291
0
    ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */
1292
0
    ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE
1293
                                   return from not necessarily
1294
                                   starting from the beginning */
1295
1296
0
    while(1){
1297
0
      if(vf->ready_state>=STREAMSET){
1298
        /* snarf/scan a packet if we can */
1299
0
        int result=ogg_stream_packetout(&work_os,&op);
1300
1301
0
        if(result>0){
1302
1303
0
          if(vf->vi[vf->current_link].codec_setup){
1304
0
            thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1305
0
            if(thisblock<0){
1306
0
              ogg_stream_packetout(&vf->os,NULL);
1307
0
              thisblock=0;
1308
0
            }else{
1309
1310
              /* We can't get a guaranteed correct pcm position out of the
1311
                 last page in a stream because it might have a 'short'
1312
                 granpos, which can only be detected in the presence of a
1313
                 preceding page.  However, if the last page is also the first
1314
                 page, the granpos rules of a first page take precedence.  Not
1315
                 only that, but for first==last, the EOS page must be treated
1316
                 as if its a normal first page for the stream to open/play. */
1317
0
              if(lastflag && !firstflag)
1318
0
                ogg_stream_packetout(&vf->os,NULL);
1319
0
              else
1320
0
                if(lastblock)accblock+=(lastblock+thisblock)>>2;
1321
0
            }
1322
1323
0
            if(op.granulepos!=-1){
1324
0
              int i,link=vf->current_link;
1325
0
              ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
1326
0
              if(granulepos<0)granulepos=0;
1327
1328
0
              for(i=0;i<link;i++)
1329
0
                granulepos+=vf->pcmlengths[i*2+1];
1330
0
              vf->pcm_offset=granulepos-accblock;
1331
0
              if(vf->pcm_offset<0)vf->pcm_offset=0;
1332
0
              break;
1333
0
            }
1334
0
            lastblock=thisblock;
1335
0
            continue;
1336
0
          }else
1337
0
            ogg_stream_packetout(&vf->os,NULL);
1338
0
        }
1339
0
      }
1340
1341
0
      if(!lastblock){
1342
0
        pagepos=_get_next_page(vf,&og,-1);
1343
0
        if(pagepos<0){
1344
0
          vf->pcm_offset=ov_pcm_total(vf,-1);
1345
0
          break;
1346
0
        }
1347
0
      }else{
1348
        /* huh?  Bogus stream with packets but no granulepos */
1349
0
        vf->pcm_offset=-1;
1350
0
        break;
1351
0
      }
1352
1353
      /* has our decoding just traversed a bitstream boundary? */
1354
0
      if(vf->ready_state>=STREAMSET){
1355
0
        if(vf->current_serialno!=ogg_page_serialno(&og)){
1356
1357
          /* two possibilities:
1358
             1) our decoding just traversed a bitstream boundary
1359
             2) another stream is multiplexed into this logical section? */
1360
1361
0
          if(ogg_page_bos(&og)){
1362
            /* we traversed */
1363
0
            _decode_clear(vf); /* clear out stream state */
1364
0
            ogg_stream_clear(&work_os);
1365
0
          } /* else, do nothing; next loop will scoop another page */
1366
0
        }
1367
0
      }
1368
1369
0
      if(vf->ready_state<STREAMSET){
1370
0
        int link;
1371
0
        long serialno = ogg_page_serialno(&og);
1372
1373
0
        for(link=0;link<vf->links;link++)
1374
0
          if(vf->serialnos[link]==serialno)break;
1375
1376
0
        if(link==vf->links) continue; /* not the desired Vorbis
1377
                                         bitstream section; keep
1378
                                         trying */
1379
0
        vf->current_link=link;
1380
0
        vf->current_serialno=serialno;
1381
0
        ogg_stream_reset_serialno(&vf->os,serialno);
1382
0
        ogg_stream_reset_serialno(&work_os,serialno);
1383
0
        vf->ready_state=STREAMSET;
1384
0
        firstflag=(pagepos<=vf->dataoffsets[link]);
1385
0
      }
1386
1387
0
      ogg_stream_pagein(&vf->os,&og);
1388
0
      ogg_stream_pagein(&work_os,&og);
1389
0
      lastflag=ogg_page_eos(&og);
1390
1391
0
    }
1392
0
  }
1393
1394
0
  ogg_stream_clear(&work_os);
1395
0
  vf->bittrack=0.f;
1396
0
  vf->samptrack=0.f;
1397
0
  return(0);
1398
0
}
1399
1400
/* Page granularity seek (faster than sample granularity because we
1401
   don't do the last bit of decode to find a specific sample).
1402
1403
   Seek to the last [granule marked] page preceding the specified pos
1404
   location, such that decoding past the returned point will quickly
1405
   arrive at the requested position. */
1406
0
int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
1407
0
  int link=-1;
1408
0
  ogg_int64_t result=0;
1409
0
  ogg_int64_t total=ov_pcm_total(vf,-1);
1410
1411
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1412
0
  if(!vf->seekable)return(OV_ENOSEEK);
1413
1414
0
  if(pos<0 || pos>total)return(OV_EINVAL);
1415
1416
  /* which bitstream section does this pcm offset occur in? */
1417
0
  for(link=vf->links-1;link>=0;link--){
1418
0
    total-=vf->pcmlengths[link*2+1];
1419
0
    if(pos>=total)break;
1420
0
  }
1421
1422
  /* Search within the logical bitstream for the page with the highest
1423
     pcm_pos preceding pos.  If we're looking for a position on the
1424
     first page, bisection will halt without finding our position as
1425
     it's before the first explicit granulepos fencepost. That case is
1426
     handled separately below.
1427
1428
     There is a danger here; missing pages or incorrect frame number
1429
     information in the bitstream could make our task impossible.
1430
     Account for that (it would be an error condition) */
1431
1432
  /* new search algorithm originally by HB (Nicholas Vinen) */
1433
1434
0
  {
1435
0
    ogg_int64_t end=vf->offsets[link+1];
1436
0
    ogg_int64_t begin=vf->dataoffsets[link];
1437
0
    ogg_int64_t begintime = vf->pcmlengths[link*2];
1438
0
    ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
1439
0
    ogg_int64_t target=pos-total+begintime;
1440
0
    ogg_int64_t best=-1;
1441
0
    ogg_int64_t got_page=-1;
1442
1443
0
    ogg_page og;
1444
1445
    /* if we have only one page, there will be no bisection.  Grab the page here */
1446
0
    if(begin==end){
1447
0
      result=_seek_helper(vf,begin);
1448
0
      if(result) goto seek_error;
1449
1450
0
      result=_get_next_page(vf,&og,1);
1451
0
      if(result<0) goto seek_error;
1452
1453
0
      got_page=result;
1454
0
    }
1455
1456
    /* bisection loop */
1457
0
    while(begin<end){
1458
0
      ogg_int64_t bisect;
1459
1460
0
      if(end-begin<CHUNKSIZE){
1461
0
        bisect=begin;
1462
0
      }else{
1463
        /* take a (pretty decent) guess. */
1464
0
        bisect=begin +
1465
0
          (ogg_int64_t)((double)(target-begintime)*(end-begin)/(endtime-begintime))
1466
0
          - CHUNKSIZE;
1467
0
        if(bisect<begin+CHUNKSIZE)
1468
0
          bisect=begin;
1469
0
      }
1470
1471
0
      result=_seek_helper(vf,bisect);
1472
0
      if(result) goto seek_error;
1473
1474
      /* read loop within the bisection loop */
1475
0
      while(begin<end){
1476
0
        result=_get_next_page(vf,&og,end-vf->offset);
1477
0
        if(result==OV_EREAD) goto seek_error;
1478
0
        if(result<0){
1479
          /* there is no next page! */
1480
0
          if(bisect<=begin+1)
1481
              /* No bisection left to perform.  We've either found the
1482
                 best candidate already or failed. Exit loop. */
1483
0
            end=begin;
1484
0
          else{
1485
            /* We tried to load a fraction of the last page; back up a
1486
               bit and try to get the whole last page */
1487
0
            if(bisect==0) goto seek_error;
1488
0
            bisect-=CHUNKSIZE;
1489
1490
            /* don't repeat/loop on a read we've already performed */
1491
0
            if(bisect<=begin)bisect=begin+1;
1492
1493
            /* seek and cntinue bisection */
1494
0
            result=_seek_helper(vf,bisect);
1495
0
            if(result) goto seek_error;
1496
0
          }
1497
0
        }else{
1498
0
          ogg_int64_t granulepos;
1499
1500
          /* only consider pages from primary vorbis stream */
1501
0
          if(ogg_page_serialno(&og)!=vf->serialnos[link])
1502
0
            continue;
1503
1504
          /* got a page. analyze it */
1505
0
          got_page=result;
1506
1507
          /* only consider pages with the granulepos set */
1508
0
          granulepos=ogg_page_granulepos(&og);
1509
0
          if(granulepos==-1)continue;
1510
1511
0
          if(granulepos<target){
1512
            /* this page is a successful candidate! Set state */
1513
1514
0
            best=result;  /* raw offset of packet with granulepos */
1515
0
            begin=vf->offset; /* raw offset of next page */
1516
0
            begintime=granulepos;
1517
1518
            /* if we're before our target but within a short distance,
1519
               don't bisect; read forward */
1520
0
            if(target-begintime>44100)break;
1521
1522
0
            bisect=begin; /* *not* begin + 1 as above */
1523
0
          }else{
1524
1525
            /* This is one of our pages, but the granpos is
1526
               post-target; it is not a bisection return
1527
               candidate. (The only way we'd use it is if it's the
1528
               first page in the stream; we handle that case later
1529
               outside the bisection) */
1530
0
            if(bisect<=begin+1){
1531
              /* No bisection left to perform.  We've either found the
1532
                 best candidate already or failed. Exit loop. */
1533
0
              end=begin;
1534
0
            }else{
1535
0
              if(end==vf->offset){
1536
                /* bisection read to the end; use the known page
1537
                   boundary (result) to update bisection, back up a
1538
                   little bit, and try again */
1539
0
                end=result;
1540
0
                bisect-=CHUNKSIZE;
1541
0
                if(bisect<=begin)bisect=begin+1;
1542
0
                result=_seek_helper(vf,bisect);
1543
0
                if(result) goto seek_error;
1544
0
              }else{
1545
                /* Normal bisection */
1546
0
                end=bisect;
1547
0
                endtime=granulepos;
1548
0
                break;
1549
0
              }
1550
0
            }
1551
0
          }
1552
0
        }
1553
0
      }
1554
0
    }
1555
1556
    /* Out of bisection: did it 'fail?' */
1557
0
    if(best == -1){
1558
1559
      /* Check the 'looking for data in first page' special case;
1560
         bisection would 'fail' because our search target was before the
1561
         first PCM granule position fencepost. */
1562
1563
0
      if(got_page >= 0 &&
1564
0
         begin == vf->dataoffsets[link]){
1565
1566
        /* Yes, this is the beginning-of-stream case. The best candidate is
1567
           right at the beginning of PCM data.  Set state and return. */
1568
1569
0
        vf->pcm_offset=total;
1570
1571
0
        if(link!=vf->current_link){
1572
          /* Different link; dump entire decode machine */
1573
0
          _decode_clear(vf);
1574
1575
0
          vf->current_link=link;
1576
0
          vf->current_serialno=vf->serialnos[link];
1577
0
          vf->ready_state=STREAMSET;
1578
1579
0
        }else{
1580
0
          vorbis_synthesis_restart(&vf->vd);
1581
0
        }
1582
1583
0
        ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
1584
0
        if(got_page!=begin){
1585
          /* If the page we found was not itself the first one (which can
1586
             happen, as we only bisect back to begin+1), we need to go back and
1587
             read the first one. */
1588
0
          result=_seek_helper(vf,begin);
1589
0
          if(result) goto seek_error;
1590
0
          result=_get_next_page(vf,&og,-1);
1591
0
          if(result<0) goto seek_error;
1592
0
        }
1593
0
        ogg_stream_pagein(&vf->os,&og);
1594
1595
0
      }else
1596
0
        goto seek_error;
1597
1598
0
    }else{
1599
1600
      /* Bisection found our page. seek to it, update pcm offset. Easier case than
1601
         raw_seek, don't keep packets preceding granulepos. */
1602
1603
0
      ogg_page og;
1604
0
      ogg_packet op;
1605
1606
      /* seek */
1607
0
      result=_seek_helper(vf,best);
1608
0
      vf->pcm_offset=-1;
1609
0
      if(result) goto seek_error;
1610
0
      result=_get_next_page(vf,&og,-1);
1611
0
      if(result<0) goto seek_error;
1612
1613
0
      if(link!=vf->current_link){
1614
        /* Different link; dump entire decode machine */
1615
0
        _decode_clear(vf);
1616
1617
0
        vf->current_link=link;
1618
0
        vf->current_serialno=vf->serialnos[link];
1619
0
        vf->ready_state=STREAMSET;
1620
1621
0
      }else{
1622
0
        vorbis_synthesis_restart(&vf->vd);
1623
0
      }
1624
1625
0
      ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
1626
0
      ogg_stream_pagein(&vf->os,&og);
1627
1628
      /* pull out all but last packet; the one with granulepos */
1629
0
      while(1){
1630
0
        result=ogg_stream_packetpeek(&vf->os,&op);
1631
0
        if(result==0){
1632
          /* No packet returned; we exited the bisection with 'best'
1633
             pointing to a page with a granule position, so the packet
1634
             finishing this page ('best') originated on a preceding
1635
             page. Keep fetching previous pages until we get one with
1636
             a granulepos or without the 'continued' flag set.  Then
1637
             just use raw_seek for simplicity. */
1638
          /* Do not rewind past the beginning of link data; if we do,
1639
             it's either a bug or a broken stream */
1640
0
          result=best;
1641
0
          while(result>vf->dataoffsets[link]){
1642
0
            result=_get_prev_page(vf,result,&og);
1643
0
            if(result<0) goto seek_error;
1644
0
            if(ogg_page_serialno(&og)==vf->current_serialno &&
1645
0
               (ogg_page_granulepos(&og)>-1 ||
1646
0
                !ogg_page_continued(&og))){
1647
0
              return ov_raw_seek(vf,result);
1648
0
            }
1649
0
          }
1650
0
        }
1651
0
        if(result<0){
1652
0
          result = OV_EBADPACKET;
1653
0
          goto seek_error;
1654
0
        }
1655
0
        if(op.granulepos!=-1){
1656
0
          vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1657
0
          if(vf->pcm_offset<0)vf->pcm_offset=0;
1658
0
          vf->pcm_offset+=total;
1659
0
          break;
1660
0
        }else
1661
0
          result=ogg_stream_packetout(&vf->os,NULL);
1662
0
      }
1663
0
    }
1664
0
  }
1665
1666
  /* verify result */
1667
0
  if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
1668
0
    result=OV_EFAULT;
1669
0
    goto seek_error;
1670
0
  }
1671
0
  vf->bittrack=0.f;
1672
0
  vf->samptrack=0.f;
1673
0
  return(0);
1674
1675
0
 seek_error:
1676
  /* dump machine so we're in a known state */
1677
0
  vf->pcm_offset=-1;
1678
0
  _decode_clear(vf);
1679
0
  return (int)result;
1680
0
}
1681
1682
/* seek to a sample offset relative to the decompressed pcm stream
1683
   returns zero on success, nonzero on failure */
1684
1685
0
int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
1686
0
  int thisblock,lastblock=0;
1687
0
  int ret=ov_pcm_seek_page(vf,pos);
1688
0
  if(ret<0)return(ret);
1689
0
  if((ret=_make_decode_ready(vf)))return ret;
1690
1691
  /* discard leading packets we don't need for the lapping of the
1692
     position we want; don't decode them */
1693
1694
0
  while(1){
1695
0
    ogg_packet op;
1696
0
    ogg_page og;
1697
1698
0
    int ret=ogg_stream_packetpeek(&vf->os,&op);
1699
0
    if(ret>0){
1700
0
      thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1701
0
      if(thisblock<0){
1702
0
        ogg_stream_packetout(&vf->os,NULL);
1703
0
        continue; /* non audio packet */
1704
0
      }
1705
0
      if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
1706
1707
0
      if(vf->pcm_offset+((thisblock+
1708
0
                          vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
1709
1710
      /* remove the packet from packet queue and track its granulepos */
1711
0
      ogg_stream_packetout(&vf->os,NULL);
1712
0
      vorbis_synthesis_trackonly(&vf->vb,&op);  /* set up a vb with
1713
                                                   only tracking, no
1714
                                                   pcm_decode */
1715
0
      vorbis_synthesis_blockin(&vf->vd,&vf->vb);
1716
1717
      /* end of logical stream case is hard, especially with exact
1718
         length positioning. */
1719
1720
0
      if(op.granulepos>-1){
1721
0
        int i;
1722
        /* always believe the stream markers */
1723
0
        vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1724
0
        if(vf->pcm_offset<0)vf->pcm_offset=0;
1725
0
        for(i=0;i<vf->current_link;i++)
1726
0
          vf->pcm_offset+=vf->pcmlengths[i*2+1];
1727
0
      }
1728
1729
0
      lastblock=thisblock;
1730
1731
0
    }else{
1732
0
      if(ret<0 && ret!=OV_HOLE)break;
1733
1734
      /* suck in a new page */
1735
0
      if(_get_next_page(vf,&og,-1)<0)break;
1736
0
      if(ogg_page_bos(&og))_decode_clear(vf);
1737
1738
0
      if(vf->ready_state<STREAMSET){
1739
0
        long serialno=ogg_page_serialno(&og);
1740
0
        int link;
1741
1742
0
        for(link=0;link<vf->links;link++)
1743
0
          if(vf->serialnos[link]==serialno)break;
1744
0
        if(link==vf->links) continue;
1745
0
        vf->current_link=link;
1746
1747
0
        vf->ready_state=STREAMSET;
1748
0
        vf->current_serialno=ogg_page_serialno(&og);
1749
0
        ogg_stream_reset_serialno(&vf->os,serialno);
1750
0
        ret=_make_decode_ready(vf);
1751
0
        if(ret)return ret;
1752
0
        lastblock=0;
1753
0
      }
1754
1755
0
      ogg_stream_pagein(&vf->os,&og);
1756
0
    }
1757
0
  }
1758
1759
0
  vf->bittrack=0.f;
1760
0
  vf->samptrack=0.f;
1761
  /* discard samples until we reach the desired position. Crossing a
1762
     logical bitstream boundary with abandon is OK. */
1763
0
  {
1764
    /* note that halfrate could be set differently in each link, but
1765
       vorbisfile encoforces all links are set or unset */
1766
0
    int hs=vorbis_synthesis_halfrate_p(vf->vi);
1767
0
    while(vf->pcm_offset<((pos>>hs)<<hs)){
1768
0
      ogg_int64_t target=(pos-vf->pcm_offset)>>hs;
1769
0
      long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
1770
1771
0
      if(samples>target)samples=target;
1772
0
      vorbis_synthesis_read(&vf->vd,samples);
1773
0
      vf->pcm_offset+=samples<<hs;
1774
1775
0
      if(samples<target)
1776
0
        if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
1777
0
          vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
1778
0
    }
1779
0
  }
1780
0
  return 0;
1781
0
}
1782
1783
/* seek to a playback time relative to the decompressed pcm stream
1784
   returns zero on success, nonzero on failure */
1785
0
int ov_time_seek(OggVorbis_File *vf,double seconds){
1786
  /* translate time to PCM position and call ov_pcm_seek */
1787
1788
0
  int link=-1;
1789
0
  ogg_int64_t pcm_total=0;
1790
0
  double time_total=0.;
1791
1792
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1793
0
  if(!vf->seekable)return(OV_ENOSEEK);
1794
0
  if(seconds<0)return(OV_EINVAL);
1795
1796
  /* which bitstream section does this time offset occur in? */
1797
0
  for(link=0;link<vf->links;link++){
1798
0
    double addsec = ov_time_total(vf,link);
1799
0
    if(seconds<time_total+addsec)break;
1800
0
    time_total+=addsec;
1801
0
    pcm_total+=vf->pcmlengths[link*2+1];
1802
0
  }
1803
1804
0
  if(link==vf->links)return(OV_EINVAL);
1805
1806
  /* enough information to convert time offset to pcm offset */
1807
0
  {
1808
0
    ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
1809
0
    return(ov_pcm_seek(vf,target));
1810
0
  }
1811
0
}
1812
1813
/* page-granularity version of ov_time_seek
1814
   returns zero on success, nonzero on failure */
1815
0
int ov_time_seek_page(OggVorbis_File *vf,double seconds){
1816
  /* translate time to PCM position and call ov_pcm_seek */
1817
1818
0
  int link=-1;
1819
0
  ogg_int64_t pcm_total=0;
1820
0
  double time_total=0.;
1821
1822
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1823
0
  if(!vf->seekable)return(OV_ENOSEEK);
1824
0
  if(seconds<0)return(OV_EINVAL);
1825
1826
  /* which bitstream section does this time offset occur in? */
1827
0
  for(link=0;link<vf->links;link++){
1828
0
    double addsec = ov_time_total(vf,link);
1829
0
    if(seconds<time_total+addsec)break;
1830
0
    time_total+=addsec;
1831
0
    pcm_total+=vf->pcmlengths[link*2+1];
1832
0
  }
1833
1834
0
  if(link==vf->links)return(OV_EINVAL);
1835
1836
  /* enough information to convert time offset to pcm offset */
1837
0
  {
1838
0
    ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
1839
0
    return(ov_pcm_seek_page(vf,target));
1840
0
  }
1841
0
}
1842
1843
/* tell the current stream offset cursor.  Note that seek followed by
1844
   tell will likely not give the set offset due to caching */
1845
0
ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
1846
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1847
0
  return(vf->offset);
1848
0
}
1849
1850
/* return PCM offset (sample) of next PCM sample to be read */
1851
0
ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
1852
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1853
0
  return(vf->pcm_offset);
1854
0
}
1855
1856
/* return time offset (seconds) of next PCM sample to be read */
1857
0
double ov_time_tell(OggVorbis_File *vf){
1858
0
  int link=0;
1859
0
  ogg_int64_t pcm_total=0;
1860
0
  double time_total=0.f;
1861
1862
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1863
0
  if(vf->seekable){
1864
0
    pcm_total=ov_pcm_total(vf,-1);
1865
0
    time_total=ov_time_total(vf,-1);
1866
1867
    /* which bitstream section does this time offset occur in? */
1868
0
    for(link=vf->links-1;link>=0;link--){
1869
0
      pcm_total-=vf->pcmlengths[link*2+1];
1870
0
      time_total-=ov_time_total(vf,link);
1871
0
      if(vf->pcm_offset>=pcm_total)break;
1872
0
    }
1873
0
  }
1874
1875
0
  return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate);
1876
0
}
1877
1878
/*  link:   -1) return the vorbis_info struct for the bitstream section
1879
                currently being decoded
1880
           0-n) to request information for a specific bitstream section
1881
1882
    In the case of a non-seekable bitstream, any call returns the
1883
    current bitstream.  NULL in the case that the machine is not
1884
    initialized */
1885
1886
0
vorbis_info *ov_info(OggVorbis_File *vf,int link){
1887
0
  if(vf->seekable){
1888
0
    if(link<0)
1889
0
      if(vf->ready_state>=STREAMSET)
1890
0
        return vf->vi+vf->current_link;
1891
0
      else
1892
0
      return vf->vi;
1893
0
    else
1894
0
      if(link>=vf->links)
1895
0
        return NULL;
1896
0
      else
1897
0
        return vf->vi+link;
1898
0
  }else{
1899
0
    return vf->vi;
1900
0
  }
1901
0
}
1902
1903
/* grr, strong typing, grr, no templates/inheritence, grr */
1904
0
vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
1905
0
  if(vf->seekable){
1906
0
    if(link<0)
1907
0
      if(vf->ready_state>=STREAMSET)
1908
0
        return vf->vc+vf->current_link;
1909
0
      else
1910
0
        return vf->vc;
1911
0
    else
1912
0
      if(link>=vf->links)
1913
0
        return NULL;
1914
0
      else
1915
0
        return vf->vc+link;
1916
0
  }else{
1917
0
    return vf->vc;
1918
0
  }
1919
0
}
1920
1921
0
static int host_is_big_endian(void) {
1922
0
  ogg_int32_t pattern = 0xfeedface; /* deadbeef */
1923
0
  unsigned char *bytewise = (unsigned char *)&pattern;
1924
0
  if (bytewise[0] == 0xfe) return 1;
1925
0
  return 0;
1926
0
}
1927
1928
/* up to this point, everything could more or less hide the multiple
1929
   logical bitstream nature of chaining from the toplevel application
1930
   if the toplevel application didn't particularly care.  However, at
1931
   the point that we actually read audio back, the multiple-section
1932
   nature must surface: Multiple bitstream sections do not necessarily
1933
   have to have the same number of channels or sampling rate.
1934
1935
   ov_read returns the sequential logical bitstream number currently
1936
   being decoded along with the PCM data in order that the toplevel
1937
   application can take action on channel/sample rate changes.  This
1938
   number will be incremented even for streamed (non-seekable) streams
1939
   (for seekable streams, it represents the actual logical bitstream
1940
   index within the physical bitstream.  Note that the accessor
1941
   functions above are aware of this dichotomy).
1942
1943
   ov_read_filter is exactly the same as ov_read except that it processes
1944
   the decoded audio data through a filter before packing it into the
1945
   requested format. This gives greater accuracy than applying a filter
1946
   after the audio has been converted into integral PCM.
1947
1948
   input values: buffer) a buffer to hold packed PCM data for return
1949
                 length) the byte length requested to be placed into buffer
1950
                 bigendianp) should the data be packed LSB first (0) or
1951
                             MSB first (1)
1952
                 word) word size for output.  currently 1 (byte) or
1953
                       2 (16 bit short)
1954
1955
   return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
1956
                   0) EOF
1957
                   n) number of bytes of PCM actually returned.  The
1958
                   below works on a packet-by-packet basis, so the
1959
                   return length is not related to the 'length' passed
1960
                   in, just guaranteed to fit.
1961
1962
            *section) set to the logical bitstream number */
1963
1964
long ov_read_filter(OggVorbis_File *vf,char *buffer,int length,
1965
                    int bigendianp,int word,int sgned,int *bitstream,
1966
0
                    void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param){
1967
0
  int i,j;
1968
0
  int host_endian = host_is_big_endian();
1969
0
  int hs;
1970
1971
0
  float **pcm;
1972
0
  long samples;
1973
1974
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
1975
0
  if(word<=0)return(OV_EINVAL);
1976
1977
0
  while(1){
1978
0
    if(vf->ready_state==INITSET){
1979
0
      samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
1980
0
      if(samples)break;
1981
0
    }
1982
1983
    /* suck in another packet */
1984
0
    {
1985
0
      int ret=_fetch_and_process_packet(vf,NULL,1,1);
1986
0
      if(ret==OV_EOF)
1987
0
        return(0);
1988
0
      if(ret<=0)
1989
0
        return(ret);
1990
0
    }
1991
1992
0
  }
1993
1994
0
  if(samples>0){
1995
1996
    /* yay! proceed to pack data into the byte buffer */
1997
1998
0
    long channels=ov_info(vf,-1)->channels;
1999
0
    long bytespersample=word * channels;
2000
0
    vorbis_fpu_control fpu;
2001
2002
0
    if(channels<1||channels>255)return(OV_EINVAL);
2003
0
    if(samples>length/bytespersample)samples=length/bytespersample;
2004
2005
0
    if(samples <= 0)
2006
0
      return OV_EINVAL;
2007
2008
    /* Here. */
2009
0
    if(filter)
2010
0
      filter(pcm,channels,samples,filter_param);
2011
2012
    /* a tight loop to pack each size */
2013
0
    {
2014
0
      int val;
2015
0
      if(word==1){
2016
0
        int off=(sgned?0:128);
2017
0
        vorbis_fpu_setround(&fpu);
2018
0
        for(j=0;j<samples;j++)
2019
0
          for(i=0;i<channels;i++){
2020
0
            val=vorbis_ftoi(pcm[i][j]*128.f);
2021
0
            if(val>127)val=127;
2022
0
            else if(val<-128)val=-128;
2023
0
            *buffer++=val+off;
2024
0
          }
2025
0
        vorbis_fpu_restore(fpu);
2026
0
      }else{
2027
0
        int off=(sgned?0:32768);
2028
2029
0
        if(host_endian==bigendianp){
2030
0
          if(sgned){
2031
2032
0
            vorbis_fpu_setround(&fpu);
2033
0
            for(i=0;i<channels;i++) { /* It's faster in this order */
2034
0
              float *src=pcm[i];
2035
0
              short *dest=((short *)buffer)+i;
2036
0
              for(j=0;j<samples;j++) {
2037
0
                val=vorbis_ftoi(src[j]*32768.f);
2038
0
                if(val>32767)val=32767;
2039
0
                else if(val<-32768)val=-32768;
2040
0
                *dest=val;
2041
0
                dest+=channels;
2042
0
              }
2043
0
            }
2044
0
            vorbis_fpu_restore(fpu);
2045
2046
0
          }else{
2047
2048
0
            vorbis_fpu_setround(&fpu);
2049
0
            for(i=0;i<channels;i++) {
2050
0
              float *src=pcm[i];
2051
0
              short *dest=((short *)buffer)+i;
2052
0
              for(j=0;j<samples;j++) {
2053
0
                val=vorbis_ftoi(src[j]*32768.f);
2054
0
                if(val>32767)val=32767;
2055
0
                else if(val<-32768)val=-32768;
2056
0
                *dest=val+off;
2057
0
                dest+=channels;
2058
0
              }
2059
0
            }
2060
0
            vorbis_fpu_restore(fpu);
2061
2062
0
          }
2063
0
        }else if(bigendianp){
2064
2065
0
          vorbis_fpu_setround(&fpu);
2066
0
          for(j=0;j<samples;j++)
2067
0
            for(i=0;i<channels;i++){
2068
0
              val=vorbis_ftoi(pcm[i][j]*32768.f);
2069
0
              if(val>32767)val=32767;
2070
0
              else if(val<-32768)val=-32768;
2071
0
              val+=off;
2072
0
              *buffer++=(val>>8);
2073
0
              *buffer++=(val&0xff);
2074
0
            }
2075
0
          vorbis_fpu_restore(fpu);
2076
2077
0
        }else{
2078
0
          int val;
2079
0
          vorbis_fpu_setround(&fpu);
2080
0
          for(j=0;j<samples;j++)
2081
0
            for(i=0;i<channels;i++){
2082
0
              val=vorbis_ftoi(pcm[i][j]*32768.f);
2083
0
              if(val>32767)val=32767;
2084
0
              else if(val<-32768)val=-32768;
2085
0
              val+=off;
2086
0
              *buffer++=(val&0xff);
2087
0
              *buffer++=(val>>8);
2088
0
                  }
2089
0
          vorbis_fpu_restore(fpu);
2090
2091
0
        }
2092
0
      }
2093
0
    }
2094
2095
0
    vorbis_synthesis_read(&vf->vd,samples);
2096
0
    hs=vorbis_synthesis_halfrate_p(vf->vi);
2097
0
    vf->pcm_offset+=(samples<<hs);
2098
0
    if(bitstream)*bitstream=vf->current_link;
2099
0
    return(samples*bytespersample);
2100
0
  }else{
2101
0
    return(samples);
2102
0
  }
2103
0
}
2104
2105
long ov_read(OggVorbis_File *vf,char *buffer,int length,
2106
0
             int bigendianp,int word,int sgned,int *bitstream){
2107
0
  return ov_read_filter(vf, buffer, length, bigendianp, word, sgned, bitstream, NULL, NULL);
2108
0
}
2109
2110
/* input values: pcm_channels) a float vector per channel of output
2111
                 length) the sample length being read by the app
2112
2113
   return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
2114
                   0) EOF
2115
                   n) number of samples of PCM actually returned.  The
2116
                   below works on a packet-by-packet basis, so the
2117
                   return length is not related to the 'length' passed
2118
                   in, just guaranteed to fit.
2119
2120
            *section) set to the logical bitstream number */
2121
2122
2123
2124
long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length,
2125
0
                   int *bitstream){
2126
2127
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
2128
2129
0
  while(1){
2130
0
    if(vf->ready_state==INITSET){
2131
0
      float **pcm;
2132
0
      long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
2133
0
      if(samples){
2134
0
        int hs=vorbis_synthesis_halfrate_p(vf->vi);
2135
0
        if(pcm_channels)*pcm_channels=pcm;
2136
0
        if(samples>length)samples=length;
2137
0
        vorbis_synthesis_read(&vf->vd,samples);
2138
0
        vf->pcm_offset+=samples<<hs;
2139
0
        if(bitstream)*bitstream=vf->current_link;
2140
0
        return samples;
2141
2142
0
      }
2143
0
    }
2144
2145
    /* suck in another packet */
2146
0
    {
2147
0
      int ret=_fetch_and_process_packet(vf,NULL,1,1);
2148
0
      if(ret==OV_EOF)return(0);
2149
0
      if(ret<=0)return(ret);
2150
0
    }
2151
2152
0
  }
2153
0
}
2154
2155
extern const float *vorbis_window(vorbis_dsp_state *v,int W);
2156
2157
static void _ov_splice(float **pcm,float **lappcm,
2158
                       int n1, int n2,
2159
                       int ch1, int ch2,
2160
0
                       const float *w1, const float *w2){
2161
0
  int i,j;
2162
0
  const float *w=w1;
2163
0
  int n=n1;
2164
2165
0
  if(n1>n2){
2166
0
    n=n2;
2167
0
    w=w2;
2168
0
  }
2169
2170
  /* splice */
2171
0
  for(j=0;j<ch1 && j<ch2;j++){
2172
0
    float *s=lappcm[j];
2173
0
    float *d=pcm[j];
2174
2175
0
    for(i=0;i<n;i++){
2176
0
      float wd=w[i]*w[i];
2177
0
      float ws=1.-wd;
2178
0
      d[i]=d[i]*wd + s[i]*ws;
2179
0
    }
2180
0
  }
2181
  /* window from zero */
2182
0
  for(;j<ch2;j++){
2183
0
    float *d=pcm[j];
2184
0
    for(i=0;i<n;i++){
2185
0
      float wd=w[i]*w[i];
2186
0
      d[i]=d[i]*wd;
2187
0
    }
2188
0
  }
2189
2190
0
}
2191
2192
/* make sure vf is INITSET */
2193
0
static int _ov_initset(OggVorbis_File *vf){
2194
0
  while(1){
2195
0
    if(vf->ready_state==INITSET)break;
2196
    /* suck in another packet */
2197
0
    {
2198
0
      int ret=_fetch_and_process_packet(vf,NULL,1,0);
2199
0
      if(ret<0 && ret!=OV_HOLE)return(ret);
2200
0
    }
2201
0
  }
2202
0
  return 0;
2203
0
}
2204
2205
/* make sure vf is INITSET and that we have a primed buffer; if
2206
   we're crosslapping at a stream section boundary, this also makes
2207
   sure we're sanity checking against the right stream information */
2208
0
static int _ov_initprime(OggVorbis_File *vf){
2209
0
  vorbis_dsp_state *vd=&vf->vd;
2210
0
  while(1){
2211
0
    if(vf->ready_state==INITSET)
2212
0
      if(vorbis_synthesis_pcmout(vd,NULL))break;
2213
2214
    /* suck in another packet */
2215
0
    {
2216
0
      int ret=_fetch_and_process_packet(vf,NULL,1,0);
2217
0
      if(ret<0 && ret!=OV_HOLE)return(ret);
2218
0
    }
2219
0
  }
2220
0
  return 0;
2221
0
}
2222
2223
/* grab enough data for lapping from vf; this may be in the form of
2224
   unreturned, already-decoded pcm, remaining PCM we will need to
2225
   decode, or synthetic postextrapolation from last packets. */
2226
static void _ov_getlap(OggVorbis_File *vf,vorbis_info *vi,vorbis_dsp_state *vd,
2227
0
                       float **lappcm,int lapsize){
2228
0
  int lapcount=0,i;
2229
0
  float **pcm;
2230
2231
  /* try first to decode the lapping data */
2232
0
  while(lapcount<lapsize){
2233
0
    int samples=vorbis_synthesis_pcmout(vd,&pcm);
2234
0
    if(samples){
2235
0
      if(samples>lapsize-lapcount)samples=lapsize-lapcount;
2236
0
      for(i=0;i<vi->channels;i++)
2237
0
        memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
2238
0
      lapcount+=samples;
2239
0
      vorbis_synthesis_read(vd,samples);
2240
0
    }else{
2241
    /* suck in another packet */
2242
0
      int ret=_fetch_and_process_packet(vf,NULL,1,0); /* do *not* span */
2243
0
      if(ret==OV_EOF)break;
2244
0
    }
2245
0
  }
2246
0
  if(lapcount<lapsize){
2247
    /* failed to get lapping data from normal decode; pry it from the
2248
       postextrapolation buffering, or the second half of the MDCT
2249
       from the last packet */
2250
0
    int samples=vorbis_synthesis_lapout(&vf->vd,&pcm);
2251
0
    if(samples==0){
2252
0
      for(i=0;i<vi->channels;i++)
2253
0
        memset(lappcm[i]+lapcount,0,sizeof(**pcm)*lapsize-lapcount);
2254
0
      lapcount=lapsize;
2255
0
    }else{
2256
0
      if(samples>lapsize-lapcount)samples=lapsize-lapcount;
2257
0
      for(i=0;i<vi->channels;i++)
2258
0
        memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
2259
0
      lapcount+=samples;
2260
0
    }
2261
0
  }
2262
0
}
2263
2264
/* For large channel counts and block sizes, the total lapping buffer
2265
   allocation can approach 4MB, which is larger than the typical stack size.
2266
   We somewhat arbitrarily pick a cutoff of 8 channels (32 kB with a
2267
   blocksize of 8192) for switching to a heap allocation, as that is the
2268
   largest channel count supported by the surround channel mappings. */
2269
0
#define LAPBUF_CHANNELS_CUTOFF (8)
2270
2271
/* this sets up crosslapping of a sample by using trailing data from
2272
   sample 1 and lapping it into the windowing buffer of sample 2 */
2273
0
int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){
2274
0
  vorbis_info *vi1,*vi2;
2275
0
  float *lapbuf;
2276
0
  float **lappcm;
2277
0
  float **pcm;
2278
0
  const float *w1,*w2;
2279
0
  int n1,n2,ch1,i,ret,hs1,hs2;
2280
2281
0
  if(vf1==vf2)return(0); /* degenerate case */
2282
0
  if(vf1->ready_state<OPENED)return(OV_EINVAL);
2283
0
  if(vf2->ready_state<OPENED)return(OV_EINVAL);
2284
2285
  /* the relevant overlap buffers must be pre-checked and pre-primed
2286
     before looking at settings in the event that priming would cross
2287
     a bitstream boundary.  So, do it now */
2288
2289
0
  ret=_ov_initset(vf1);
2290
0
  if(ret)return(ret);
2291
0
  ret=_ov_initprime(vf2);
2292
0
  if(ret)return(ret);
2293
2294
0
  vi1=ov_info(vf1,-1);
2295
0
  vi2=ov_info(vf2,-1);
2296
0
  hs1=ov_halfrate_p(vf1);
2297
0
  hs2=ov_halfrate_p(vf2);
2298
2299
0
  ch1=vi1->channels;
2300
0
  lappcm=alloca(sizeof(*lappcm)*ch1);
2301
0
  n1=vorbis_info_blocksize(vi1,0)>>(1+hs1);
2302
0
  n2=vorbis_info_blocksize(vi2,0)>>(1+hs2);
2303
0
  w1=vorbis_window(&vf1->vd,0);
2304
0
  w2=vorbis_window(&vf2->vd,0);
2305
2306
0
  if(ch1<=LAPBUF_CHANNELS_CUTOFF){
2307
0
    lapbuf=alloca(sizeof(*lapbuf)*n1*ch1);
2308
0
  }else{
2309
0
    lapbuf=_ogg_malloc(sizeof(*lapbuf)*n1*ch1);
2310
0
    if(lapbuf==NULL)return OV_EFAULT;
2311
0
  }
2312
0
  for(i=0;i<ch1;i++)
2313
0
    lappcm[i]=lapbuf+n1*i;
2314
2315
0
  _ov_getlap(vf1,vi1,&vf1->vd,lappcm,n1);
2316
2317
  /* have a lapping buffer from vf1; now to splice it into the lapping
2318
     buffer of vf2 */
2319
  /* consolidate and expose the buffer. */
2320
0
  vorbis_synthesis_lapout(&vf2->vd,&pcm);
2321
2322
#if 0
2323
  _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0);
2324
  _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0);
2325
#endif
2326
2327
  /* splice */
2328
0
  _ov_splice(pcm,lappcm,n1,n2,ch1,vi2->channels,w1,w2);
2329
0
  if(ch1>LAPBUF_CHANNELS_CUTOFF)_ogg_free(lapbuf);
2330
2331
  /* done */
2332
0
  return(0);
2333
0
}
2334
2335
static int _ov_64_seek_lap_finish(OggVorbis_File *vf,ogg_int64_t pos,
2336
                                  int (*localseek)(OggVorbis_File *,
2337
                                  ogg_int64_t),int hs,int n1, int ch1,
2338
0
                                  const float *w1,float **lappcm){
2339
0
  vorbis_info *vi;
2340
0
  float **pcm;
2341
0
  const float *w2;
2342
0
  int n2,ch2;
2343
0
  int ret;
2344
2345
  /* have lapping data; seek and prime the buffer */
2346
0
  ret=localseek(vf,pos);
2347
0
  if(ret)return ret;
2348
0
  ret=_ov_initprime(vf);
2349
0
  if(ret)return(ret);
2350
2351
  /* Guard against cross-link changes; they're perfectly legal */
2352
0
  vi=ov_info(vf,-1);
2353
0
  ch2=vi->channels;
2354
0
  n2=vorbis_info_blocksize(vi,0)>>(1+hs);
2355
0
  w2=vorbis_window(&vf->vd,0);
2356
2357
  /* consolidate and expose the buffer. */
2358
0
  vorbis_synthesis_lapout(&vf->vd,&pcm);
2359
2360
  /* splice */
2361
0
  _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
2362
2363
  /* done */
2364
0
  return(0);
2365
0
}
2366
2367
static int _ov_64_seek_lap(OggVorbis_File *vf,ogg_int64_t pos,
2368
0
                           int (*localseek)(OggVorbis_File *,ogg_int64_t)){
2369
0
  vorbis_info *vi;
2370
0
  float *lapbuf;
2371
0
  float **lappcm;
2372
0
  const float *w1;
2373
0
  int n1,ch1,hs;
2374
0
  int i,ret;
2375
2376
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
2377
0
  ret=_ov_initset(vf);
2378
0
  if(ret)return(ret);
2379
0
  vi=ov_info(vf,-1);
2380
0
  hs=ov_halfrate_p(vf);
2381
2382
0
  ch1=vi->channels;
2383
0
  n1=vorbis_info_blocksize(vi,0)>>(1+hs);
2384
0
  w1=vorbis_window(&vf->vd,0);  /* window arrays from libvorbis are
2385
                                   persistent; even if the decode state
2386
                                   from this link gets dumped, this
2387
                                   window array continues to exist */
2388
2389
0
  lappcm=alloca(sizeof(*lappcm)*ch1);
2390
0
  if(ch1<=LAPBUF_CHANNELS_CUTOFF){
2391
0
    lapbuf=alloca(sizeof(*lapbuf)*n1*ch1);
2392
0
  }else{
2393
0
    lapbuf=_ogg_malloc(sizeof(*lapbuf)*n1*ch1);
2394
0
    if(lapbuf==NULL)return OV_EFAULT;
2395
0
  }
2396
0
  for(i=0;i<ch1;i++)
2397
0
    lappcm[i]=lapbuf+n1*i;
2398
0
  _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
2399
2400
0
  ret=_ov_64_seek_lap_finish(vf,pos,localseek,hs,n1,ch1,w1,lappcm);
2401
0
  if(ch1>LAPBUF_CHANNELS_CUTOFF)_ogg_free(lapbuf);
2402
0
  return(ret);
2403
0
}
2404
2405
0
int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
2406
0
  return _ov_64_seek_lap(vf,pos,ov_raw_seek);
2407
0
}
2408
2409
0
int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
2410
0
  return _ov_64_seek_lap(vf,pos,ov_pcm_seek);
2411
0
}
2412
2413
0
int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos){
2414
0
  return _ov_64_seek_lap(vf,pos,ov_pcm_seek_page);
2415
0
}
2416
2417
static int _ov_d_seek_lap_finish(OggVorbis_File *vf,double pos,
2418
                                 int (*localseek)(OggVorbis_File *,double),
2419
                                 int hs,int n1,int ch1,const float *w1,
2420
0
                                 float **lappcm){
2421
0
  vorbis_info *vi;
2422
0
  float **pcm;
2423
0
  const float *w2;
2424
0
  int n2,ch2;
2425
0
  int ret;
2426
2427
  /* have lapping data; seek and prime the buffer */
2428
0
  ret=localseek(vf,pos);
2429
0
  if(ret)return ret;
2430
0
  ret=_ov_initprime(vf);
2431
0
  if(ret)return(ret);
2432
2433
  /* Guard against cross-link changes; they're perfectly legal */
2434
0
  vi=ov_info(vf,-1);
2435
0
  ch2=vi->channels;
2436
0
  n2=vorbis_info_blocksize(vi,0)>>(1+hs);
2437
0
  w2=vorbis_window(&vf->vd,0);
2438
2439
  /* consolidate and expose the buffer. */
2440
0
  vorbis_synthesis_lapout(&vf->vd,&pcm);
2441
2442
  /* splice */
2443
0
  _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
2444
2445
  /* done */
2446
0
  return(0);
2447
0
}
2448
2449
static int _ov_d_seek_lap(OggVorbis_File *vf,double pos,
2450
0
                           int (*localseek)(OggVorbis_File *,double)){
2451
0
  vorbis_info *vi;
2452
0
  float *lapbuf;
2453
0
  float **lappcm;
2454
0
  const float *w1;
2455
0
  int n1,ch1,hs;
2456
0
  int i,ret;
2457
2458
0
  if(vf->ready_state<OPENED)return(OV_EINVAL);
2459
0
  ret=_ov_initset(vf);
2460
0
  if(ret)return(ret);
2461
0
  vi=ov_info(vf,-1);
2462
0
  hs=ov_halfrate_p(vf);
2463
2464
0
  ch1=vi->channels;
2465
0
  n1=vorbis_info_blocksize(vi,0)>>(1+hs);
2466
0
  w1=vorbis_window(&vf->vd,0);  /* window arrays from libvorbis are
2467
                                   persistent; even if the decode state
2468
                                   from this link gets dumped, this
2469
                                   window array continues to exist */
2470
2471
0
  lappcm=alloca(sizeof(*lappcm)*ch1);
2472
0
  if(ch1<=LAPBUF_CHANNELS_CUTOFF){
2473
0
    lapbuf=alloca(sizeof(*lapbuf)*n1*ch1);
2474
0
  }else{
2475
0
    lapbuf=_ogg_malloc(sizeof(*lapbuf)*n1*ch1);
2476
0
    if(lapbuf==NULL)return OV_EFAULT;
2477
0
  }
2478
0
  for(i=0;i<ch1;i++)
2479
0
    lappcm[i]=lapbuf+n1*i;
2480
0
  _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
2481
2482
0
  ret=_ov_d_seek_lap_finish(vf,pos,localseek,hs,n1,ch1,w1,lappcm);
2483
0
  if(ch1>LAPBUF_CHANNELS_CUTOFF)_ogg_free(lapbuf);
2484
0
  return(ret);
2485
0
}
2486
2487
0
int ov_time_seek_lap(OggVorbis_File *vf,double pos){
2488
0
  return _ov_d_seek_lap(vf,pos,ov_time_seek);
2489
0
}
2490
2491
0
int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){
2492
0
  return _ov_d_seek_lap(vf,pos,ov_time_seek_page);
2493
0
}