~ubuntu-branches/ubuntu/precise/liboggz/precise

« back to all changes in this revision

Viewing changes to src/liboggz/oggz_read.c

  • Committer: Bazaar Package Importer
  • Author(s): Jamie Wilkinson
  • Date: 2005-04-16 01:19:44 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 hoary)
  • Revision ID: james.westby@ubuntu.com-20050416011944-5ipwrrc260ihkpp8
Tags: 0.9.1-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
61
61
#include "oggz_private.h"
62
62
 
63
63
/*#define DEBUG*/
64
 
 
65
 
/*#define DEBUG_BY_READING_PAGES*/
66
 
 
67
 
#define CHUNKSIZE 8500
 
64
/*#define DEBUG_VERBOSE*/
 
65
 
 
66
#define CHUNKSIZE 65536
 
67
 
 
68
#define OGGZ_READ_EMPTY (-404)
68
69
 
69
70
#define oggz_off_t long
70
71
 
80
81
  reader->read_packet = NULL;
81
82
  reader->read_user_data = NULL;
82
83
 
 
84
  reader->read_page = NULL;
 
85
  reader->read_page_user_data = NULL;
 
86
 
83
87
  reader->current_unit = 0;
84
88
 
85
89
  return oggz;
90
94
{
91
95
  OggzReader * reader = &oggz->x.reader;
92
96
 
 
97
  ogg_stream_clear (&reader->ogg_stream);
93
98
  ogg_sync_clear (&reader->ogg_sync);
94
99
 
95
100
  return oggz;
129
134
  return 0;
130
135
}
131
136
 
 
137
int
 
138
oggz_set_read_page (OGGZ * oggz, long serialno, OggzReadPage read_page,
 
139
                    void * user_data)
 
140
{
 
141
  OggzReader * reader;
 
142
  oggz_stream_t * stream;
 
143
 
 
144
  if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
 
145
 
 
146
  reader =  &oggz->x.reader;
 
147
 
 
148
  if (oggz->flags & OGGZ_WRITE) {
 
149
    return OGGZ_ERR_INVALID;
 
150
  }
 
151
 
 
152
  if (serialno == -1) {
 
153
    reader->read_page = read_page;
 
154
    reader->read_page_user_data = user_data;
 
155
  } else {
 
156
    stream = oggz_get_stream (oggz, serialno);
 
157
#if 0
 
158
    if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
 
159
#else
 
160
    if (stream == NULL)
 
161
      stream = oggz_add_stream (oggz, serialno);
 
162
#endif
 
163
 
 
164
    stream->read_page = read_page;
 
165
    stream->read_page_user_data = user_data;
 
166
  }
 
167
 
 
168
  return 0;
 
169
}
 
170
 
132
171
/*
133
172
 * oggz_get_next_page_7 (oggz, og, do_read)
134
173
 *
175
214
      return -2;
176
215
#endif
177
216
    } else if (more < 0) {
178
 
#ifdef DEBUG
 
217
#ifdef DEBUG_VERBOSE
179
218
      printf ("get_next_page: skipped %ld bytes\n", -more);
180
219
#endif
181
220
      page_offset -= more;
182
221
    } else {
183
 
#ifdef DEBUG
 
222
#ifdef DEBUG_VERBOSE
184
223
      printf ("get_next_page: page has %ld bytes\n", more);
185
224
#endif
186
225
      found = 1;
233
272
      serialno = reader->current_serialno;
234
273
 
235
274
      stream = oggz_get_stream (oggz, serialno);
236
 
      
 
275
 
237
276
      if (stream == NULL) {
238
277
        /* new stream ... check bos etc. */
239
278
        if ((stream = oggz_add_stream (oggz, serialno)) == NULL) {
258
297
          oggz_auto (oggz, op, serialno, NULL);
259
298
        }
260
299
 
 
300
        /* set unit on last packet of page */
261
301
        if ((oggz->metric || stream->metric) && granulepos != -1) {
262
302
          reader->current_unit = oggz_get_unit (oggz, serialno, granulepos);
263
303
        }
264
 
#ifndef DEBUG_BY_READING_PAGES
 
304
 
265
305
        if (stream->read_packet) {
266
306
          cb_ret =
267
307
            stream->read_packet (oggz, op, serialno, stream->read_user_data);
269
309
          cb_ret =
270
310
            reader->read_packet (oggz, op, serialno, reader->read_user_data);
271
311
        }
272
 
#endif /* DEBUG_BY_READING_PAGES */
273
312
      }
274
313
      else
275
314
        break;
277
316
    }
278
317
 
279
318
    /* If we've got a stop already, don't read more data in */
280
 
    if (cb_ret != 0) return cb_ret;
 
319
    if (cb_ret == OGGZ_STOP_OK || cb_ret == OGGZ_STOP_ERR) return cb_ret;
281
320
 
282
321
    if(oggz_get_next_page_7 (oggz, &og) < 0)
283
 
      return -404; /* eof. leave unitialized */
 
322
      return OGGZ_READ_EMPTY; /* eof. leave uninitialized */
284
323
 
285
324
    serialno = ogg_page_serialno (&og);
286
325
    reader->current_serialno = serialno; /* XXX: maybe not necessary */
287
326
 
288
327
    stream = oggz_get_stream (oggz, serialno);
289
 
      
 
328
 
290
329
    if (stream == NULL) {
291
330
      /* new stream ... check bos etc. */
292
331
      if ((stream = oggz_add_stream (oggz, serialno)) == NULL) {
296
335
    }
297
336
    os = &stream->ogg_stream;
298
337
 
299
 
#ifdef DEBUG_BY_READING_PAGES
300
338
    {
301
 
      ogg_packet op_debug;
302
 
      op_debug.packet = og.body;
303
 
      op_debug.bytes = og.body_len;
304
 
      op_debug.b_o_s = ogg_page_bos (&og);
305
 
      op_debug.e_o_s = ogg_page_eos (&og);
306
 
      op_debug.granulepos = ogg_page_granulepos (&og);
307
 
      op_debug.packetno = ogg_page_packets (&og);
308
 
 
309
 
      if (stream->read_packet) {
310
 
        cb_ret = stream->read_packet (oggz, &op_debug, serialno,
311
 
                                      stream->read_user_data);
312
 
      } else if (reader->read_packet) {
313
 
        cb_ret = reader->read_packet (oggz, &op_debug, serialno,
314
 
                                      reader->read_user_data);
 
339
      ogg_int64_t granulepos;
 
340
 
 
341
      granulepos = ogg_page_granulepos (&og);
 
342
 
 
343
      if ((oggz->metric || stream->metric) && granulepos != -1) {
 
344
        reader->current_unit = oggz_get_unit (oggz, serialno, granulepos);
 
345
      } else if (granulepos == 0) {
 
346
        reader->current_unit = 0;
315
347
      }
316
348
    }
317
 
#endif
 
349
 
 
350
    if (stream->read_page) {
 
351
      cb_ret =
 
352
        stream->read_page (oggz, &og, serialno, stream->read_page_user_data);
 
353
    } else if (reader->read_page) {
 
354
      cb_ret = reader->read_page (oggz, &og, serialno,
 
355
                                  reader->read_page_user_data);
 
356
    }
318
357
 
319
358
#if 0
320
359
    /* bitrate tracking; add the header's bytes here, the body bytes
346
385
 
347
386
  cb_ret = oggz_read_sync (oggz);
348
387
 
349
 
  /* If there's nothing to read yet, don't flag an error */
350
 
  if (reader->current_unit == 0 && cb_ret == -404) cb_ret = 0;
 
388
#if 0
 
389
  if (cb_ret == OGGZ_READ_EMPTY) {
 
390
    /* If there's nothing to read yet, don't return 0 (eof) */
 
391
    if (reader->current_unit == 0) cb_ret = 0;
 
392
    else {
 
393
#if 0
 
394
      printf ("oggz_read: EMPTY, current_unit %ld != 0\n",
 
395
              reader->current_unit);
 
396
      return 0;
 
397
#endif
 
398
    }
 
399
  }
 
400
#endif
351
401
 
352
 
  while (cb_ret != -1 && cb_ret != 1 && bytes_read > 0 && remaining > 0) {
353
 
    bytes = MIN (remaining, 4096);
 
402
  while (cb_ret != OGGZ_STOP_ERR && cb_ret != OGGZ_STOP_OK &&
 
403
         bytes_read > 0 && remaining > 0) {
 
404
    bytes = MIN (remaining, CHUNKSIZE);
354
405
    buffer = ogg_sync_buffer (&reader->ogg_sync, bytes);
355
406
    if ((bytes_read = (long) oggz_io_read (oggz, buffer, bytes)) == 0) {
356
407
      /* schyeah! */
359
410
      return OGGZ_ERR_SYSTEM;
360
411
    }
361
412
 
362
 
    ogg_sync_wrote (&reader->ogg_sync, bytes_read);
363
 
 
364
 
    remaining -= bytes_read;
365
 
    nread += bytes_read;
366
 
 
367
 
    cb_ret = oggz_read_sync (oggz);
368
 
  }
369
 
 
370
 
  if (cb_ret == -1) oggz_purge (oggz);
 
413
    if (bytes_read > 0) {
 
414
      ogg_sync_wrote (&reader->ogg_sync, bytes_read);
 
415
      
 
416
      remaining -= bytes_read;
 
417
      nread += bytes_read;
 
418
      
 
419
      cb_ret = oggz_read_sync (oggz);
 
420
    }
 
421
  }
 
422
 
 
423
  if (cb_ret == OGGZ_STOP_ERR) oggz_purge (oggz);
 
424
 
 
425
  /* Don't return 0 unless it's actually an EOF condition */
 
426
  if (nread == 0) {
 
427
    switch (bytes_read) {
 
428
    case OGGZ_ERR_IO_AGAIN:
 
429
    case OGGZ_ERR_SYSTEM:
 
430
      return bytes_read; break;
 
431
    default: break;
 
432
    }
 
433
 
 
434
    switch (cb_ret) {
 
435
    case OGGZ_CONTINUE: case OGGZ_READ_EMPTY: 
 
436
#ifdef DEBUG
 
437
      printf ("oggz_read: nread==0, cb_ret==%d, returning 0\n", cb_ret);
 
438
#endif
 
439
      return 0; break;
 
440
    case OGGZ_STOP_ERR: return OGGZ_ERR_READ_STOP_ERR; break;
 
441
    case OGGZ_STOP_OK: default: return OGGZ_ERR_READ_STOP_OK; break;
 
442
    }
 
443
  }
371
444
 
372
445
  return nread;
373
446
}
391
464
 
392
465
  cb_ret = oggz_read_sync (oggz);
393
466
 
394
 
  /* If there's nothing to read yet, don't flag an error */
395
 
  if (reader->current_unit == 0 && cb_ret == -404) cb_ret = 0;
 
467
#if 0
 
468
  if (cb_ret == OGGZ_READ_EMPTY) {
 
469
    /* If there's nothing to read yet, don't return 0 (eof) */
 
470
    if (reader->current_unit == 0) cb_ret = 0;
 
471
    else return 0;
 
472
  }
 
473
#endif
396
474
 
397
475
  while (cb_ret != -1 && cb_ret != 1 && /* !oggz->eos && */ remaining > 0) {
398
476
    bytes = MIN (remaining, 4096);
404
482
    remaining -= bytes;
405
483
    nread += bytes;
406
484
 
407
 
    cb_ret = oggz_read_sync (oggz);    
408
 
  }
409
 
 
410
 
  if (cb_ret == -1) oggz_purge (oggz);
 
485
    cb_ret = oggz_read_sync (oggz);
 
486
  }
 
487
 
 
488
  if (cb_ret == OGGZ_STOP_ERR) oggz_purge (oggz);
 
489
 
 
490
  /* Don't return 0 unless it's actually an EOF condition */
 
491
  if (nread == 0) {
 
492
    switch (cb_ret) {
 
493
    case OGGZ_CONTINUE: return 0; break;
 
494
    case OGGZ_READ_EMPTY:
 
495
#ifdef DEBUG
 
496
      printf ("oggz_read_input: OUT EMPTY\n");
 
497
#endif
 
498
      return OGGZ_ERR_READ_STOP_OK;
 
499
      break;
 
500
    case OGGZ_STOP_ERR: return OGGZ_ERR_READ_STOP_ERR; break;
 
501
    case OGGZ_STOP_OK: default: return OGGZ_ERR_READ_STOP_OK; break;
 
502
    }
 
503
  }
411
504
 
412
505
  return nread;
413
506
}
414
507
 
415
 
/* oggz_seek() (and oggz_purge()) related functions from here down */
416
 
 
417
 
/*
418
 
 * The typical usage is:
419
 
 *
420
 
 *   oggz_set_data_start (oggz, oggz_tell (oggz));
421
 
 */
422
 
int
423
 
oggz_set_data_start (OGGZ * oggz, oggz_off_t offset)
424
 
{
425
 
  if (oggz == NULL) return -1;
426
 
 
427
 
  if (offset < 0) return -1;
428
 
 
429
 
  oggz->offset_data_begin = offset;
430
 
 
431
 
  return 0;
432
 
}
433
 
 
434
 
static oggz_off_t
435
 
oggz_tell_raw (OGGZ * oggz)
436
 
{
437
 
  oggz_off_t offset_at;
438
 
 
439
 
  offset_at = oggz_io_tell (oggz);
440
 
 
441
 
  return offset_at;
442
 
}
443
 
 
444
 
/*
445
 
 * seeks and syncs
446
 
 */
447
 
static oggz_off_t
448
 
oggz_seek_raw (OGGZ * oggz, oggz_off_t offset, int whence)
449
 
{
450
 
  OggzReader * reader = &oggz->x.reader;
451
 
  oggz_off_t offset_at;
452
 
 
453
 
  if (oggz_io_seek (oggz, offset, whence) == -1) {
454
 
    return -1;
455
 
  }
456
 
 
457
 
  offset_at = oggz_io_tell (oggz);
458
 
 
459
 
  oggz->offset = offset_at;
460
 
 
461
 
  ogg_sync_reset (&reader->ogg_sync);
462
 
 
463
 
  return offset_at;
464
 
}
465
 
 
466
 
static int
467
 
oggz_stream_reset (void * data)
468
 
{
469
 
  oggz_stream_t * stream = (oggz_stream_t *) data;
470
 
 
471
 
  if (stream->ogg_stream.serialno != -1) {
472
 
    ogg_stream_reset (&stream->ogg_stream);
473
 
  }
474
 
 
475
 
  return 0;
476
 
}
477
 
 
478
 
static void
479
 
oggz_reset_streams (OGGZ * oggz)
480
 
{
481
 
  oggz_vector_foreach (oggz->streams, oggz_stream_reset);
482
 
}
483
 
 
484
 
static long
485
 
oggz_reset_seek (OGGZ * oggz, oggz_off_t offset, ogg_int64_t unit, int whence)
486
 
{
487
 
  OggzReader * reader = &oggz->x.reader;
488
 
 
489
 
  oggz_off_t offset_at;
490
 
 
491
 
  offset_at = oggz_seek_raw (oggz, offset, whence);
492
 
  if (offset_at == -1) return -1;
493
 
 
494
 
  oggz->offset = offset_at;
495
 
 
496
 
#ifdef DEBUG
497
 
  printf ("reset to %ld\n", offset_at);
498
 
#endif
499
 
 
500
 
  if (unit != -1) reader->current_unit = unit;
501
 
 
502
 
  return offset_at;
503
 
}
504
 
 
505
 
static long
506
 
oggz_reset (OGGZ * oggz, oggz_off_t offset, ogg_int64_t unit, int whence)
507
 
{
508
 
  oggz_reset_streams (oggz);
509
 
  return oggz_reset_seek (oggz, offset, unit, whence);
510
 
}
511
 
 
512
 
int
513
 
oggz_purge (OGGZ * oggz)
514
 
{
515
 
  if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
516
 
 
517
 
  if (oggz->flags & OGGZ_WRITE) {
518
 
    return OGGZ_ERR_INVALID;
519
 
  }
520
 
 
521
 
  oggz_reset_streams (oggz);
522
 
 
523
 
  if (oggz->file && oggz_reset (oggz, oggz->offset, -1, SEEK_SET) < 0) {
524
 
    return OGGZ_ERR_SYSTEM;
525
 
  }
526
 
 
527
 
  return 0;
528
 
}
529
 
 
530
 
/*
531
 
 * oggz_get_next_page (oggz, og, do_read)
532
 
 *
533
 
 * retrieves the next page.
534
 
 * returns >= 0 if found; return value is offset of page start
535
 
 * returns -1 on error
536
 
 * returns -2 if EOF was encountered
537
 
 */
538
 
static oggz_off_t
539
 
oggz_get_next_page (OGGZ * oggz, ogg_page * og)
540
 
{
541
 
  OggzReader * reader = &oggz->x.reader;
542
 
  char * buffer;
543
 
  long bytes = 0, more;
544
 
  oggz_off_t page_offset = 0, ret;
545
 
  int found = 0;
546
 
 
547
 
  do {
548
 
    more = ogg_sync_pageseek (&reader->ogg_sync, og);
549
 
 
550
 
    if (more == 0) {
551
 
      page_offset = 0;
552
 
 
553
 
      buffer = ogg_sync_buffer (&reader->ogg_sync, CHUNKSIZE);
554
 
      if ((bytes = (long) oggz_io_read (oggz, buffer, CHUNKSIZE)) == 0) {
555
 
        /* schyeah! */
556
 
      }
557
 
      if (bytes == OGGZ_ERR_SYSTEM) {
558
 
          /*oggz_set_error (oggz, OGGZ_ERR_SYSTEM);*/
559
 
          return -1;
560
 
      }
561
 
 
562
 
      if (bytes == 0) {
563
 
        return -2;
564
 
      } else if (oggz->file && feof (oggz->file)) {
565
 
        clearerr (oggz->file);
566
 
        return -2;
567
 
      }
568
 
 
569
 
      ogg_sync_wrote(&reader->ogg_sync, bytes);
570
 
 
571
 
    } else if (more < 0) {
572
 
#ifdef DEBUG
573
 
      printf ("get_next_page: skipped %ld bytes\n", -more);
574
 
#endif
575
 
      page_offset -= more;
576
 
    } else {
577
 
#ifdef DEBUG
578
 
      printf ("get_next_page: page has %ld bytes\n", more);
579
 
#endif
580
 
      found = 1;
581
 
    }
582
 
 
583
 
  } while (!found);
584
 
 
585
 
  /* Calculate the byte offset of the page which was found */
586
 
  if (bytes > 0) {
587
 
    oggz->offset = oggz_tell_raw (oggz) - bytes + page_offset;
588
 
    ret = oggz->offset;
589
 
  } else {
590
 
    /* didn't need to do any reading -- accumulate the page_offset */
591
 
    ret = oggz->offset + page_offset;
592
 
    oggz->offset += page_offset + more;
593
 
  }
594
 
 
595
 
  return ret;
596
 
}
597
 
 
598
 
static oggz_off_t
599
 
oggz_get_next_start_page (OGGZ * oggz, ogg_page * og)
600
 
{
601
 
  oggz_off_t page_offset;
602
 
  int found = 0;
603
 
 
604
 
  while (!found) {
605
 
    page_offset = oggz_get_next_page (oggz, og);
606
 
 
607
 
    /* Return this value if one of the following conditions is met:
608
 
     *
609
 
     *   page_offset < 0     : error or EOF
610
 
     *   page_offset == 0    : start of stream
611
 
     *   !ogg_page_continued : start of page
612
 
     */
613
 
    if (page_offset <= 0 || !ogg_page_continued (og))
614
 
      found = 1;
615
 
  }
616
 
 
617
 
  return page_offset;
618
 
}
619
 
 
620
 
static oggz_off_t
621
 
oggz_get_prev_start_page (OGGZ * oggz, ogg_page * og,
622
 
                         ogg_int64_t * granule, long * serialno)
623
 
{
624
 
  oggz_off_t offset_at, offset_start;
625
 
  oggz_off_t page_offset, prev_offset = 0;
626
 
  long granule_at = -1;
627
 
 
628
 
#if 0
629
 
  offset_at = oggz_tell_raw (oggz);
630
 
  if (offset_at == -1) return -1;
631
 
#else
632
 
  offset_at = oggz->offset;
633
 
#endif
634
 
 
635
 
  offset_start = offset_at;
636
 
 
637
 
  do {
638
 
 
639
 
    offset_start = offset_at - CHUNKSIZE;
640
 
    if (offset_start < 0) offset_start = 0;
641
 
 
642
 
    offset_start = oggz_seek_raw (oggz, offset_start, SEEK_SET);
643
 
    if (offset_start == -1) return -1;
644
 
 
645
 
#ifdef DEBUG
646
 
 
647
 
    printf ("[A] offset_at: @%ld\toffset_start: @%ld\n",
648
 
            offset_at, offset_start);
649
 
 
650
 
    printf ("*** get_prev_start_page: seeked to %ld\n", offset_start);
651
 
#endif
652
 
 
653
 
    page_offset = 0;
654
 
 
655
 
    do {
656
 
      prev_offset = page_offset;
657
 
 
658
 
      page_offset = oggz_get_next_start_page (oggz, og);
659
 
      if (page_offset == -1) return -1;
660
 
      if (page_offset == -2) break;
661
 
 
662
 
      granule_at = (long)ogg_page_granulepos (og);
663
 
 
664
 
#ifdef DEBUG
665
 
      printf ("\tGOT page (%ld) @%ld\tat @%ld\n", granule_at,
666
 
              page_offset, offset_at);
667
 
#endif
668
 
 
669
 
      /* Need to stash the granule and serialno of this page because og
670
 
       * will be overwritten by the time we realise this was the desired
671
 
       * prev page */
672
 
      if (page_offset >= 0 && page_offset < offset_at) {
673
 
        *granule = granule_at;
674
 
        *serialno = ogg_page_serialno (og);
675
 
      }
676
 
 
677
 
    } while (page_offset >= 0 && page_offset < offset_at);
678
 
 
679
 
#ifdef DEBUG
680
 
    printf ("[B] offset_at: @%ld\toffset_start: @%ld\n"
681
 
            "prev_offset: @%ld\tpage_offset: @%ld\n",
682
 
            offset_at, offset_start, prev_offset, page_offset);
683
 
#endif
684
 
    /* reset the file offset */
685
 
    offset_at = offset_start;
686
 
 
687
 
  } while (offset_at > 0 && prev_offset == 0);
688
 
 
689
 
  if (offset_at > 0)
690
 
    return prev_offset;
691
 
  else
692
 
    return -1;
693
 
}
694
 
 
695
 
static oggz_off_t
696
 
oggz_scan_for_page (OGGZ * oggz, ogg_page * og, ogg_int64_t unit_target,
697
 
                   oggz_off_t offset_begin, oggz_off_t offset_end)
698
 
{
699
 
  oggz_off_t offset_at, offset_next;
700
 
  oggz_off_t offset_prev = -1;
701
 
  ogg_int64_t granule_at;
702
 
  ogg_int64_t unit_at;
703
 
  long serialno;
704
 
 
705
 
#ifdef DEBUG
706
 
  printf (" SCANNING from %ld...", offset_begin);
707
 
#endif
708
 
 
709
 
  while (1) {
710
 
    offset_at = oggz_seek_raw (oggz, offset_begin, SEEK_SET);
711
 
    if (offset_at == -1) return -1;
712
 
 
713
 
#ifdef DEBUG
714
 
    printf (" scan @%ld\n", offset_at);
715
 
#endif
716
 
 
717
 
    offset_next = oggz_get_next_start_page (oggz, og);
718
 
 
719
 
    if (offset_next < 0) {
720
 
      return offset_next;
721
 
    }
722
 
 
723
 
    if (offset_next == 0 && offset_begin != 0) {
724
 
#ifdef DEBUG
725
 
      printf (" ... scanned past EOF\n");
726
 
#endif
727
 
      return -1;
728
 
    }
729
 
    if (offset_next > offset_end) {
730
 
#ifdef DEBUG
731
 
      printf (" ... scanned to page %ld\n", (long)ogg_page_granulepos (og));
732
 
#endif
733
 
      if (offset_prev != -1) {
734
 
        offset_at = oggz_seek_raw (oggz, offset_prev, SEEK_SET);
735
 
        if (offset_at == -1) return -1;
736
 
 
737
 
        offset_next = oggz_get_next_start_page (oggz, og);
738
 
        if (offset_next < 0) return offset_next;
739
 
 
740
 
        serialno = ogg_page_serialno (og);
741
 
        granule_at = ogg_page_granulepos (og);
742
 
        unit_at = oggz_get_unit (oggz, serialno, granule_at);
743
 
 
744
 
        return offset_at;
745
 
      } else {
746
 
        return -1;
747
 
      }
748
 
    }
749
 
 
750
 
    offset_at = offset_next;
751
 
 
752
 
    serialno = ogg_page_serialno (og);
753
 
    granule_at = ogg_page_granulepos (og);
754
 
    unit_at = oggz_get_unit (oggz, serialno, granule_at);
755
 
 
756
 
    if (unit_at < unit_target) {
757
 
#ifdef DEBUG
758
 
      printf (" scan: (%ld) < (%ld)\n", unit_at, unit_target);
759
 
#endif
760
 
      offset_prev = offset_next;
761
 
      offset_begin = offset_next+1;
762
 
    } else if (unit_at > unit_target) {
763
 
#ifdef DEBUG
764
 
      printf (" scan: (%ld) > (%ld)\n", unit_at, unit_target);
765
 
#endif
766
 
#if 0
767
 
      /* hole ? */
768
 
      offset_at = oggz_seek_raw (oggz, offset_begin, SEEK_SET);
769
 
      if (offset_at == -1) return -1;
770
 
 
771
 
      offset_next = oggz_get_next_start_page (oggz, og);
772
 
      if (offset_next < 0) return offset_next;
773
 
 
774
 
      serialno = ogg_page_serialno (og);
775
 
      granule_at = ogg_page_granulepos (og);
776
 
      unit_at = oggz_get_unit (oggz, serialno, granule_at);
777
 
 
778
 
      break;
779
 
#else
780
 
      return offset_at;
781
 
#endif
782
 
    } else if (unit_at == unit_target) {
783
 
#ifdef DEBUG
784
 
      printf (" scan: (%ld) == (%ld)\n", unit_at, unit_target);
785
 
#endif
786
 
      break;
787
 
    }
788
 
  }
789
 
 
790
 
  return offset_at;
791
 
}
792
 
 
793
 
static long
794
 
oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
795
 
{
796
 
  OggzReader * reader = &oggz->x.reader;
797
 
  int fd;
798
 
  struct stat statbuf;
799
 
  oggz_off_t offset_orig, offset_at, offset_guess;
800
 
  oggz_off_t offset_begin, offset_end = -1, offset_next;
801
 
  ogg_int64_t granule_at;
802
 
  ogg_int64_t unit_at, unit_begin = 0, unit_end = -1;
803
 
  long serialno;
804
 
  double guess_ratio;
805
 
  ogg_page * og;
806
 
 
807
 
  if (oggz == NULL) {
808
 
    return -1;
809
 
  }
810
 
 
811
 
  if (unit_target > 0 && !oggz_has_metrics (oggz)) {
812
 
    /* No metric defined */
813
 
    return -1;
814
 
  }
815
 
 
816
 
  if (oggz->file != NULL) { 
817
 
    if ((fd = fileno (oggz->file)) == -1) {
818
 
      /*oggz_set_error (oggz, OGGZ_ERR_SYSTEM);*/
819
 
      return -1;
820
 
    }
821
 
 
822
 
    if (fstat (fd, &statbuf) == -1) {
823
 
      /*oggz_set_error (oggz, OGGZ_ERR_SYSTEM);*/
824
 
      return -1;
825
 
    }
826
 
 
827
 
    if (oggz_stat_regular (statbuf.st_mode)) {
828
 
      offset_end = statbuf.st_size;
829
 
    } else {
830
 
      /*oggz_set_error (oggz, OGGZ_ERR_NOSEEK);*/
831
 
 
832
 
      /* XXX: should be able to just carry on and guess, as per io */
833
 
      /*return -1;*/
834
 
    }
835
 
  } else {
836
 
    oggz_off_t offset_save;
837
 
 
838
 
    if (oggz->io == NULL || oggz->io->seek == NULL) {
839
 
      /* No file, and no io seek method */
840
 
      return -1;
841
 
    }
842
 
 
843
 
    /* Get the offset of the end by querying the io seek method */
844
 
    offset_save = oggz_io_tell (oggz);
845
 
    if (oggz_io_seek (oggz, 0, SEEK_END) == -1) {
846
 
      return -1;
847
 
    }
848
 
    offset_end = oggz_io_tell (oggz);
849
 
    if (oggz_io_seek (oggz, offset_save, SEEK_SET) == -1) {
850
 
      return -1; /* fubar */
851
 
    }
852
 
  }
853
 
 
854
 
  if (unit_target == reader->current_unit) {
855
 
    return (long)reader->current_unit;
856
 
  }
857
 
 
858
 
  if (unit_target == 0) {
859
 
    offset_at = oggz_reset (oggz, oggz->offset_data_begin, 0, SEEK_SET);
860
 
    if (offset_at == -1) return -1;
861
 
    return 0;
862
 
  }
863
 
 
864
 
  offset_at = oggz_tell_raw (oggz);
865
 
  if (offset_at == -1) return -1;
866
 
 
867
 
#if 0
868
 
  offset_orig = offset_at;
869
 
#else
870
 
  offset_orig = oggz->offset;
871
 
#endif
872
 
 
873
 
  offset_begin = 0;
874
 
 
875
 
  unit_at = reader->current_unit;
876
 
  unit_begin = 0;
877
 
  unit_end = -1;
878
 
 
879
 
  og = &oggz->current_page;
880
 
 
881
 
  while (1) {
882
 
 
883
 
#ifdef DEBUG
884
 
    printf ("oggz_read_seek (%ld): (%ld - %ld) [%ld - %ld]\t",
885
 
            unit_target, unit_begin, unit_end, offset_begin, offset_end);
886
 
#endif
887
 
 
888
 
    if (unit_end == -1) {
889
 
      if (unit_at == unit_begin) {
890
 
#ifdef DEBUG
891
 
        printf ("*G1*");
892
 
#endif
893
 
        offset_guess = offset_begin + (offset_end - offset_begin)/2;
894
 
      } else {
895
 
#ifdef DEBUG
896
 
        printf ("*G2*");
897
 
#endif
898
 
        guess_ratio =
899
 
          (double)(unit_target - unit_begin) /
900
 
          (double)(unit_at - unit_begin);
901
 
 
902
 
#ifdef DEBUG
903
 
        printf ("\nguess_ration %f = (%ld - %ld) / (%ld - %ld)\n",
904
 
                guess_ratio, unit_target, unit_begin, unit_at, unit_begin);
905
 
#endif
906
 
 
907
 
        offset_guess = offset_begin +
908
 
          (oggz_off_t)((offset_at - offset_begin) * guess_ratio);
909
 
      }
910
 
    } else if (unit_end <= unit_begin) {
911
 
#ifdef DEBUG
912
 
      printf ("unit_end <= unit_begin\n");
913
 
#endif
914
 
      break;
915
 
    } else {
916
 
#if 1
917
 
      guess_ratio =
918
 
        (double)(unit_target - unit_begin) /
919
 
        (double)(unit_end - unit_begin);
920
 
 
921
 
      offset_guess = offset_begin +
922
 
        (oggz_off_t)((offset_end - offset_begin) * guess_ratio);
923
 
 
924
 
      /*
925
 
      if (offset_guess <= offset_begin) {
926
 
        offset_guess = offset_begin + 1;
927
 
      }
928
 
      */
929
 
#else
930
 
      offset_guess = offset_begin + (offset_end - offset_begin)/2;
931
 
#endif
932
 
    }
933
 
 
934
 
#ifdef DEBUG
935
 
    printf ("%ld ->", offset_guess);
936
 
#endif
937
 
 
938
 
    offset_at = oggz_seek_raw (oggz, offset_guess, SEEK_SET);
939
 
    if (offset_at == -1) {
940
 
      goto notfound;
941
 
    }
942
 
 
943
 
    offset_next = oggz_get_next_start_page (oggz, og);
944
 
 
945
 
#ifdef DEBUG
946
 
    printf ("\n");
947
 
#endif
948
 
 
949
 
    if (offset_next < 0) {
950
 
      goto notfound;
951
 
    }
952
 
 
953
 
    if (offset_next > offset_end) {
954
 
      offset_next = oggz_scan_for_page (oggz, og, unit_target,
955
 
                                        offset_begin, offset_end);
956
 
 
957
 
      if (offset_next < 0) {
958
 
        goto notfound;
959
 
      }
960
 
 
961
 
      offset_at = offset_next;
962
 
      serialno = ogg_page_serialno (og);
963
 
      granule_at = ogg_page_granulepos (og);
964
 
 
965
 
      unit_at = oggz_get_unit (oggz, serialno, granule_at);
966
 
 
967
 
      goto found;
968
 
    }
969
 
 
970
 
    offset_at = offset_next;
971
 
    serialno = ogg_page_serialno (og);
972
 
    granule_at = ogg_page_granulepos (og);
973
 
 
974
 
    unit_at = oggz_get_unit (oggz, serialno, granule_at);
975
 
 
976
 
#ifdef DEBUG
977
 
    printf ("oggz_read_seek (%ld): got page (%ld) @%ld\n", unit_target,
978
 
            unit_at, offset_at);
979
 
#endif
980
 
 
981
 
    if (unit_at < unit_target) {
982
 
      offset_begin = offset_at;
983
 
      unit_begin = unit_at;
984
 
    } else if (unit_at > unit_target) {
985
 
      offset_end = offset_at-1;
986
 
      unit_end = unit_at;
987
 
    } else {
988
 
      break;
989
 
    }
990
 
  }
991
 
 
992
 
 found:
993
 
#ifdef DEBUG
994
 
  printf ("FOUND (%ld)\n", unit_at);
995
 
#endif
996
 
 
997
 
  offset_at = oggz_reset (oggz, offset_at, unit_at, SEEK_SET);
998
 
  if (offset_at == -1) return -1;
999
 
 
1000
 
  return (long)reader->current_unit;
1001
 
 
1002
 
 notfound:
1003
 
#ifdef DEBUG
1004
 
  printf ("NOT FOUND\n");
1005
 
#endif
1006
 
 
1007
 
  oggz_reset (oggz, offset_orig, -1, SEEK_SET);
1008
 
 
1009
 
  return -1;
1010
 
}
1011
 
 
1012
 
static long
1013
 
oggz_seek_end (OGGZ * oggz, ogg_int64_t unit_offset)
1014
 
{
1015
 
  oggz_off_t offset_orig, offset_at, offset_end;
1016
 
  ogg_int64_t granulepos;
1017
 
  ogg_int64_t unit_end;
1018
 
  long serialno;
1019
 
  ogg_page * og;
1020
 
 
1021
 
  og = &oggz->current_page;
1022
 
 
1023
 
  offset_orig = oggz->offset;
1024
 
 
1025
 
  offset_at = oggz_seek_raw (oggz, 0, SEEK_END);
1026
 
  if (offset_at == -1) return -1;
1027
 
 
1028
 
  offset_end = oggz_get_prev_start_page (oggz, og, &granulepos, &serialno);
1029
 
 
1030
 
  unit_end = oggz_get_unit (oggz, serialno, granulepos);
1031
 
 
1032
 
  if (offset_end < 0) {
1033
 
    oggz_reset (oggz, offset_orig, -1, SEEK_SET);
1034
 
    return -1;
1035
 
  }
1036
 
  
1037
 
#ifdef DEBUG
1038
 
  printf ("*** oggz_seek_end: found packet (%ld) at @%ld\n",
1039
 
          unit_end, offset_end);
1040
 
#endif
1041
 
 
1042
 
  return oggz_seek_set (oggz, unit_end + unit_offset);
1043
 
}
1044
 
 
1045
 
off_t
1046
 
oggz_seek (OGGZ * oggz, oggz_off_t offset, int whence)
1047
 
{
1048
 
  ogg_int64_t units = -1;
1049
 
 
1050
 
  if (oggz == NULL) return -1;
1051
 
 
1052
 
  if (oggz->flags & OGGZ_WRITE) {
1053
 
    return -1;
1054
 
  }
1055
 
  
1056
 
  if (offset == 0) units = 0;
1057
 
 
1058
 
  return (off_t)oggz_reset (oggz, offset, units, whence);
1059
 
}
1060
 
 
1061
 
long
1062
 
oggz_seek_units (OGGZ * oggz, ogg_int64_t units, int whence)
1063
 
{
1064
 
  OggzReader * reader = &oggz->x.reader;
1065
 
 
1066
 
  if (oggz == NULL) return -1;
1067
 
 
1068
 
  if (oggz->flags & OGGZ_WRITE) {
1069
 
    return -1;
1070
 
  }
1071
 
 
1072
 
  if (!oggz_has_metrics (oggz)) {
1073
 
    return -1;
1074
 
  }
1075
 
 
1076
 
  switch (whence) {
1077
 
  case SEEK_SET:
1078
 
    return oggz_seek_set (oggz, units);
1079
 
    break;
1080
 
  case SEEK_CUR: 
1081
 
    units += reader->current_unit;
1082
 
    return oggz_seek_set (oggz, units);
1083
 
    break;
1084
 
  case SEEK_END:
1085
 
    return oggz_seek_end (oggz, units);
1086
 
    break;
1087
 
  default:
1088
 
    /*oggz_set_error (oggz, OGGZ_EINVALID);*/
1089
 
    return -1;
1090
 
    break;
1091
 
  }
1092
 
}
1093
 
 
1094
 
long
1095
 
oggz_seek_byorder (OGGZ * oggz, void * target)
1096
 
{
1097
 
  return -1;
1098
 
}
1099
 
 
1100
 
long
1101
 
oggz_seek_packets (OGGZ * oggz, long serialno, long packets, int whence)
1102
 
{
1103
 
  return -1;
1104
 
}
1105
508
 
1106
509
#else /* OGGZ_CONFIG_READ */
1107
510
 
1108
511
#include <ogg/ogg.h>
1109
512
#include "oggz_private.h"
1110
513
 
 
514
OGGZ *
 
515
oggz_read_init (OGGZ * oggz)
 
516
{
 
517
  return NULL;
 
518
}
 
519
 
 
520
OGGZ *
 
521
oggz_read_close (OGGZ * oggz)
 
522
{
 
523
  return NULL;
 
524
}
 
525
 
1111
526
int
1112
527
oggz_set_read_callback (OGGZ * oggz, long serialno,
1113
528
                        OggzReadPacket read_packet, void * user_data)
1127
542
  return OGGZ_ERR_DISABLED;
1128
543
}
1129
544
 
1130
 
off_t
1131
 
oggz_seek (OGGZ * oggz, oggz_off_t offset, int whence)
1132
 
{
1133
 
  return OGGZ_ERR_DISABLED;
1134
 
}
1135
 
 
1136
 
long
1137
 
oggz_seek_units (OGGZ * oggz, ogg_int64_t units, int whence)
1138
 
{
1139
 
  return OGGZ_ERR_DISABLED;
1140
 
}
1141
 
 
1142
 
long
1143
 
oggz_seek_byorder (OGGZ * oggz, void * target)
1144
 
{
1145
 
  return OGGZ_ERR_DISABLED;
1146
 
}
1147
 
 
1148
 
long
1149
 
oggz_seek_packets (OGGZ * oggz, long serialno, long packets, int whence)
1150
 
{
1151
 
  return OGGZ_ERR_DISABLED;
1152
 
}
1153
 
 
1154
545
#endif