1 /*
2 ** Copyright (C) 2002-2019 Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** Copyright (C) 2007 John ffitch
4 ** Copyright (C) 2018 Arthur Taylor <art@ified.ca>
5 **
6 ** This program is free software ; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published by
8 ** the Free Software Foundation ; either version 2.1 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY ; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU Lesser General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program ; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 /*
22 ** This file contains code based on OpusFile and Opus-Tools, both by
23 ** Xiph.Org. COPYING from each is identical and is as follows:
24 **
25 ** Copyright (c) 1994-2013 Xiph.Org Foundation and contributors
26 **
27 ** Redistribution and use in source and binary forms, with or without
28 ** modification, are permitted provided that the following conditions
29 ** are met:
30 **
31 ** - Redistributions of source code must retain the above copyright
32 ** notice, this list of conditions and the following disclaimer.
33 **
34 ** - Redistributions in binary form must reproduce the above copyright
35 ** notice, this list of conditions and the following disclaimer in the
36 ** documentation and/or other materials provided with the distribution.
37 **
38 ** - Neither the name of the Xiph.Org Foundation nor the names of its
39 ** contributors may be used to endorse or promote products derived from
40 ** this software without specific prior written permission.
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 ** ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
46 ** OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 */
54
55 #include "sfconfig.h"
56
57 #include <stdio.h>
58 #include <fcntl.h>
59 #include <string.h>
60 #include <ctype.h>
61 #include <time.h>
62 #include <math.h>
63
64 #if HAVE_UNISTD_H
65 #include <unistd.h>
66 #else
67 #include "sf_unistd.h"
68 #endif
69
70 #include "sndfile.h"
71 #include "sfendian.h"
72 #include "common.h"
73
74 #if HAVE_EXTERNAL_XIPH_LIBS
75
76 #include <ogg/ogg.h>
77
78 #include "ogg.h"
79
80 #define OGG_SYNC_READ_SIZE (2048)
81 #define OGG_PAGE_SIZE_MAX (65307)
82 #define OGG_CHUNK_SIZE (65536)
83 #define OGG_CHUNK_SIZE_MAX (1024*1024)
84
85 /*
86 * The Ogg container may seem overly complicated, particularly when used for a
87 * on-disk audio file format. This is probably because Ogg is designed with
88 * streaming rather than storage as a priority, and can handle multiple codec
89 * payloads multiplexed together, then possibly chained on top of that.
90 * Ogg achieves its goals well, but it does lend to a bit of a learning curve,
91 * with many internal structures to push data around in compared to most sound
92 * file formats which only have a header and raw data.
93 *
94 * See
95 * - [https://xiph.org/ogg/doc/oggstream.html]
96 * - [https://xiph.org/ogg/doc/framing.html]
97 *
98 * libogg Memory Management
99 * ===========================================================================
100 *
101 * libOgg's memory management is documented in code, not in headers or external
102 * documentation. What follows is not an attempt to completely document it, but
103 * an explanation of the basics.
104 *
105 * libOgg has two data structures which allocate and manage data buffers: The
106 * ogg_sync_state structure and the ogg_stream_state structure. The remaining
107 * structures of ogg_page and ogg_packet are views into the buffers managed by
108 * the previous structures.
109 *
110 * ogg_sync_state is used for reading purposes. It takes a physical bitstream
111 * and searches for, validates, and returns complete Ogg Pages. The
112 * ogg_sync_state buffers the returned page data, holding at most one
113 * complete page at a time. A returned Ogg page remains valid until any
114 * operation other than ogg_sync_check() is called.
115 *
116 * ogg_stream_state is used for both reading and writing. For reading, the
117 * contents of an ogg_page is copied into the stream state. This data is
118 * buffered to be split or joined as necessary into complete ogg_packets. If,
119 * after copying an ogg_page into an ogg_stream_state, packets are available to
120 * be read, then all of those packets remain in memory and valid until either
121 * the ogg_stream_state is reset, destroyed, or a new ogg_page is read into it.
122 * As the maximum number of packets an Ogg Page may contain is 255, at most 255
123 * packets may be available from an ogg_stream_state at one time.
124 *
125 * For writing, the life cycle of a buffer pointed to by a ogg_packet is the
126 * responsibility of the caller. Packets written into an ogg_stream_state are
127 * buffered until a complete page is ready for writing. Pages for writing out
128 * remain in the ogg_stream_state's buffer and valid until either the
129 * ogg_stream_state is reset, cleared, destroyed. Writing another packet into
130 * the ogg_stream_state might also invalidate such pages, but writing in
131 * packets when a page is ready to be written out is a caller bug anyways.
132 */
133
134 /*-----------------------------------------------------------------------------------------------
135 ** Private function prototypes.
136 */
137
138 static int ogg_close (SF_PRIVATE *psf) ;
139 static int ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE * odata) ;
140 static int ogg_page_classify (SF_PRIVATE * psf, const ogg_page * og) ;
141 static uint64_t ogg_page_search_do_rescale (uint64_t x, uint64_t from, uint64_t to) ;
142 static void ogg_page_search_continued_data (OGG_PRIVATE *odata, ogg_page *page) ;
143
144 /*-----------------------------------------------------------------------------------------------
145 ** Exported functions.
146 */
147
148 int
ogg_read_first_page(SF_PRIVATE * psf,OGG_PRIVATE * odata)149 ogg_read_first_page (SF_PRIVATE *psf, OGG_PRIVATE *odata)
150 { int ret ;
151 char *buffer ;
152
153 /*
154 ** The ogg standard requires that the first pages of a physical ogg
155 ** bitstream be only the first pages of each logical bitstream. These
156 ** pages MUST have the Beginning-Of-Stream bit set, and must contain
157 ** only the stream's relevant header. Currently we only load the first
158 ** page and check that it contains a codec we support as supporting
159 ** multiplexed streams (video+audio(en)+audio(fs)+subtitles, etc) is
160 ** beyond the scope of this library.
161 */
162
163 ret = ogg_sync_fseek (psf, psf->header.indx, SEEK_SET) ;
164 if (ret < 0)
165 return SFE_NOT_SEEKABLE ;
166
167 buffer = ogg_sync_buffer (&odata->osync, psf->header.indx) ;
168 memcpy (buffer, psf->header.ptr, psf->header.indx) ;
169 ogg_sync_wrote (&odata->osync, psf->header.indx) ;
170
171 ret = ogg_sync_next_page (psf, &odata->opage, SF_MAX ((sf_count_t) 0, 4096 - psf->header.indx), NULL) ;
172
173 /* Have we simply run out of data? If so, we're done. */
174 if (ret == 0)
175 return 0 ;
176 if (ret < 0)
177 return psf->error ;
178
179 if (!ogg_page_bos (&odata->opage))
180 { /*
181 ** Error case. Either must not be an Ogg bitstream, or is in the
182 ** middle of a bitstream (live capture), or in the middle of a
183 ** bitstream and no complete page was in the buffer.
184 */
185 psf_log_printf (psf, "Input does not appear to be the start of an Ogg bitstream.\n") ;
186 return SFE_MALFORMED_FILE ;
187 } ;
188
189 /*
190 ** Get the serial number and set up the rest of decode.
191 ** Serialno first ; use it to set up a logical stream.
192 */
193 ogg_stream_reset_serialno (&odata->ostream, ogg_page_serialno (&odata->opage)) ;
194
195 if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0)
196 { /* Error ; stream version mismatch perhaps. */
197 psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ;
198 return SFE_MALFORMED_FILE ;
199 } ;
200
201 if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1)
202 { /* No page? */
203 psf_log_printf (psf, "Error reading initial header page packet.\n") ;
204 return SFE_MALFORMED_FILE ;
205 } ;
206
207 return 0 ;
208 } /* ogg_read_first_page */
209
210 int
ogg_write_page(SF_PRIVATE * psf,ogg_page * page)211 ogg_write_page (SF_PRIVATE *psf, ogg_page *page)
212 { int bytes ;
213
214 bytes = psf_fwrite (page->header, 1, page->header_len, psf) ;
215 bytes += psf_fwrite (page->body, 1, page->body_len, psf) ;
216
217 return bytes == page->header_len + page->body_len ;
218 } /* ogg_write_page */
219
220 sf_count_t
ogg_sync_ftell(SF_PRIVATE * psf)221 ogg_sync_ftell (SF_PRIVATE *psf)
222 { OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ;
223 sf_count_t position ;
224
225 position = psf_ftell (psf) ;
226 if (position >= 0)
227 { /* success */
228 if (position < odata->osync.fill)
229 { /* Really, this should be an assert. */
230 psf->error = SFE_INTERNAL ;
231 return -1 ;
232 }
233 position += (sf_count_t) (odata->osync.returned - odata->osync.fill) ;
234 }
235
236 return position ;
237 } /* ogg_sync_ftell */
238
239 sf_count_t
ogg_sync_fseek(SF_PRIVATE * psf,sf_count_t offset,int whence)240 ogg_sync_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
241 { OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ;
242 sf_count_t ret ;
243
244 ret = psf_fseek (psf, offset, whence) ;
245 if (ret >= 0)
246 { /* success */
247 odata->eos = 0 ;
248 ogg_sync_reset (&odata->osync) ;
249 }
250
251 return ret ;
252 } /* ogg_sync_fseek */
253
254 int
ogg_sync_next_page(SF_PRIVATE * psf,ogg_page * og,sf_count_t readmax,sf_count_t * offset)255 ogg_sync_next_page (SF_PRIVATE * psf, ogg_page *og, sf_count_t readmax, sf_count_t *offset)
256 { OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ;
257 sf_count_t position, nb_read, read_ret ;
258 unsigned char *buffer ;
259 int synced ;
260 int report_hole = 0 ;
261
262 for (position = 0 ; readmax <= 0 || readmax > position ; )
263 { synced = ogg_sync_pageseek (&odata->osync, og) ;
264 if (synced < 0)
265 { /*
266 ** Skipped -synced bytes before finding the start of a page.
267 ** If seeking, we have just landed in the middle of a page.
268 ** Otherwise, warn about junk in the bitstream.
269 ** Page might not yet be ready, hence the continue.
270 */
271 if (!offset)
272 report_hole = 1 ;
273 position -= synced ;
274 continue ;
275 } ;
276
277 if (report_hole)
278 { psf_log_printf (psf, "Ogg : Skipped %d bytes looking for the next page. Corrupted bitstream?!\n", position) ;
279 report_hole = 0 ;
280 } ;
281
282 if (synced > 0)
283 { /* Have a page */
284 if (offset)
285 *offset += position ;
286 return og->header_len + og->body_len ;
287 } ;
288
289 /*
290 ** Else readmax == 0, Out of data. Try to read more in without
291 ** invalidating our boundary (readmax) constraint.
292 */
293 if (readmax == 0)
294 return 0 ;
295 if (readmax > 0)
296 nb_read = SF_MIN ((sf_count_t) OGG_SYNC_READ_SIZE, readmax - position) ;
297 else
298 nb_read = OGG_SYNC_READ_SIZE ;
299 buffer = (unsigned char *) ogg_sync_buffer (&odata->osync, nb_read) ;
300 read_ret = psf_fread (buffer, 1, nb_read, psf) ;
301 if (read_ret == 0)
302 return psf->error ? -1 : 0 ;
303 ogg_sync_wrote (&odata->osync, read_ret) ;
304 } ;
305 return 0 ;
306 } /* ogg_sync_next_page */
307
308 int
ogg_stream_next_page(SF_PRIVATE * psf,OGG_PRIVATE * odata)309 ogg_stream_next_page (SF_PRIVATE *psf, OGG_PRIVATE *odata)
310 { int nn ;
311
312 if (odata->eos)
313 return 0 ;
314
315 for ( ; ; )
316 { nn = ogg_sync_next_page (psf, &odata->opage, -1, NULL) ;
317 if (nn == 0)
318 { psf_log_printf (psf, "Ogg : File ended unexpectedly without an End-Of-Stream flag set.\n") ;
319 odata->eos = 1 ;
320 }
321 if (nn <= 0)
322 return nn ;
323
324 if (ogg_page_serialno (&odata->opage) == odata->ostream.serialno)
325 break ;
326 } ;
327
328 if (ogg_page_eos (&odata->opage))
329 odata->eos = 1 ;
330
331 if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0)
332 { psf->error = SFE_INTERNAL ;
333 return -1 ;
334 }
335
336 return 1 ;
337 } /* ogg_stream_next_page */
338
339 int
ogg_stream_unpack_page(SF_PRIVATE * psf,OGG_PRIVATE * odata)340 ogg_stream_unpack_page (SF_PRIVATE *psf, OGG_PRIVATE *odata)
341 { int nn ;
342 int i ;
343 int found_hole = 0 ;
344 ogg_packet *ppkt = odata->pkt ;
345
346 odata->pkt_indx = 0 ;
347 nn = ogg_stream_packetout (&odata->ostream, ppkt) ;
348 if (nn == 0)
349 { /*
350 ** Steam is out of packets. Read in more pages until there is one, or
351 ** the stream ends, or an error occurs.
352 */
353 for ( ; nn == 0 ; nn = ogg_stream_packetout (&odata->ostream, ppkt))
354 { nn = ogg_stream_next_page (psf, odata) ;
355 if (nn <= 0)
356 { odata->pkt_len = 0 ;
357 return nn ;
358 }
359 }
360 /*
361 ** In the case of the for loop exiting because
362 ** ogg_stream_packetout() == -1, fall-through.
363 */
364 }
365
366 if (nn == -1)
367 { /*
368 ** libOgg found a hole. That is, the next packet found was out of
369 ** sequence. As such, "flush" the hole marker by removing the invalid
370 ** packet, as the valid packets are queued behind it.
371 */
372 psf_log_printf (psf, "Ogg : Warning, libogg reports a hole at %d bytes.\n", ogg_sync_ftell (psf)) ;
373 nn = ogg_stream_packetout (&odata->ostream, ppkt) ;
374 found_hole = 1 ;
375 }
376
377 /*
378 ** Unpack all the packets on the page. It is undocumented (like much of
379 ** libOgg behavior) but all packets from a page read into the stream are
380 ** guarenteed to remain valid in memory until a new page is read into the
381 ** stream.
382 */
383 for (i = 1 ; ; i++)
384 { /* Not an off-by-one, there are 255 not 256 packets max. */
385 if (i == 255)
386 { if (ogg_stream_packetpeek (&odata->ostream, NULL) == 1)
387 { psf->error = SFE_INTERNAL ;
388 return -1 ;
389 }
390 break ;
391 }
392 if (ogg_stream_packetout (&odata->ostream, ++ ppkt) != 1)
393 break ;
394 }
395 odata->pkt_len = i ;
396
397 /* 1 = ok, 2 = ok, and found a hole. */
398 return 1 + found_hole ;
399 } /* ogg_stream_unpack_page */
400
401 sf_count_t
ogg_sync_last_page_before(SF_PRIVATE * psf,OGG_PRIVATE * odata,uint64_t * gp_out,sf_count_t offset,int32_t serialno)402 ogg_sync_last_page_before (SF_PRIVATE *psf, OGG_PRIVATE *odata, uint64_t *gp_out, sf_count_t offset, int32_t serialno)
403 { sf_count_t begin, end, original_end, chunk_size, ret ;
404 sf_count_t position = 0 ;
405 uint64_t gp = -1 ;
406 int left_link ;
407
408 /* Based on code from Xiph.org's Opusfile */
409
410 original_end = end = begin = offset ;
411 offset = -1 ;
412 chunk_size = OGG_CHUNK_SIZE ;
413 do
414 { begin = SF_MAX (begin - chunk_size, (sf_count_t) 0) ;
415 position = ogg_sync_fseek (psf, begin, SEEK_SET) ;
416 if (position < 0)
417 return position ;
418 left_link = 0 ;
419 while (position < end)
420 { ret = ogg_sync_next_page (psf, &odata->opage, end - position, &position) ;
421 if (ret <= 0)
422 return -1 ;
423 if (ogg_page_serialno (&odata->opage) == serialno)
424 { uint64_t page_gp = ogg_page_granulepos (&odata->opage) ;
425 if (page_gp != (uint64_t) -1)
426 { offset = position ;
427 gp = page_gp ;
428 }
429 }
430 else
431 left_link = 1 ;
432 position += ret ;
433 }
434
435 if ((left_link || !begin) && offset < 0)
436 { psf->error = SFE_MALFORMED_FILE ;
437 return -1 ;
438 }
439
440 chunk_size = SF_MIN (2 * chunk_size, (sf_count_t) OGG_CHUNK_SIZE_MAX) ;
441 end = SF_MIN (begin + OGG_PAGE_SIZE_MAX - 1, original_end) ;
442 }
443 while (offset < 0) ;
444
445 *gp_out = gp ;
446 return offset ;
447 } /* ogg_sync_last_page_before */
448
449 int
ogg_stream_seek_page_search(SF_PRIVATE * psf,OGG_PRIVATE * odata,uint64_t target_gp,uint64_t pcm_start,uint64_t pcm_end,uint64_t * best_gp,sf_count_t begin,sf_count_t end)450 ogg_stream_seek_page_search (SF_PRIVATE *psf, OGG_PRIVATE *odata, uint64_t target_gp, uint64_t pcm_start, uint64_t pcm_end, uint64_t *best_gp, sf_count_t begin, sf_count_t end)
451 { ogg_page page ;
452 uint64_t gp ;
453 sf_count_t d0, d1, d2 ;
454 sf_count_t best ;
455 sf_count_t best_start ;
456 sf_count_t boundary ;
457 sf_count_t next_boundary ;
458 sf_count_t page_offset = -1 ;
459 sf_count_t seek_pos = -1 ;
460 sf_count_t bisect ;
461 sf_count_t chunk_size ;
462 int buffering = SF_FALSE ;
463 int force_bisect = SF_FALSE ;
464 int ret ;
465 int has_packets ;
466
467 *best_gp = pcm_start ;
468 best = best_start = begin ;
469 boundary = end ;
470
471 ogg_stream_reset_serialno (&odata->ostream, odata->ostream.serialno) ;
472
473 /*
474 ** This code is based on op_pcm_seek_page() from Opusfile, which is in turn
475 ** based on "new search algorithm by Nicholas Vinen" from libvorbisfile.
476 */
477
478 d2 = d1 = d0 = end - begin ;
479 while (begin < end)
480 { /*
481 ** Figure out if and where to try and seek in the file.
482 */
483 if (end - begin < OGG_CHUNK_SIZE)
484 bisect = begin ;
485 else
486 { /* Update the interval size history */
487 d0 = d1 >> 1 ;
488 d1 = d2 >> 1 ;
489 d2 = (end - begin) >> 1 ;
490 if (force_bisect == SF_TRUE)
491 bisect = begin + ((end - begin) >> 1) ;
492 else
493 { /* Take a decent guess. */
494 bisect = begin + ogg_page_search_do_rescale (target_gp - pcm_start, pcm_end - pcm_start, end - begin) ;
495 }
496 if (bisect - OGG_CHUNK_SIZE < begin)
497 bisect = begin ;
498 else
499 bisect -= OGG_CHUNK_SIZE ;
500 force_bisect = SF_FALSE ;
501 }
502
503 /*
504 ** Avoid an actual fseek if we can (common for final iterations.)
505 */
506 if (seek_pos != bisect)
507 { if (buffering == SF_TRUE)
508 ogg_stream_reset (&odata->ostream) ;
509 buffering = SF_FALSE ;
510 page_offset = -1 ;
511 seek_pos = ogg_sync_fseek (psf, bisect, SEEK_SET) ;
512 if (seek_pos < 0)
513 return seek_pos ;
514 }
515
516 chunk_size = OGG_CHUNK_SIZE ;
517 next_boundary = boundary ;
518
519 /*
520 ** Scan forward, figure out where we landed.
521 ** The ideal case is we see a page that ends before our target followed
522 ** by a page that ends after our target.
523 ** If we are too far before or after, breaking out will bisect what we
524 ** have found so far.
525 */
526 while (begin < end)
527 { ret = ogg_sync_next_page (psf, &page, boundary - seek_pos, &seek_pos) ;
528 if (ret <= 0)
529 return ret ;
530 page_offset = seek_pos ;
531 if (ret == 0)
532 { /*
533 ** There are no more pages in this interval from our stream
534 ** with a granulepos less than our target.
535 */
536 if (bisect <= begin + 1)
537 { /* Scanned the whole interval, so we are done. */
538 end = begin ;
539 }
540 else
541 { /*
542 ** Otherwise, back up one chunk. First discard any data
543 ** from a continued packet.
544 */
545 if (buffering)
546 ogg_stream_reset (&odata->ostream) ;
547 buffering = SF_FALSE ;
548 bisect = SF_MAX (bisect - chunk_size, begin) ;
549 seek_pos = ogg_sync_fseek (psf, bisect, SEEK_SET) ;
550 if (seek_pos < 0)
551 return seek_pos ;
552 /* Bump up the chunk size. */
553 chunk_size = SF_MIN (2 * chunk_size, (sf_count_t) OGG_CHUNK_SIZE_MAX) ;
554 /*
555 ** If we did find a page from another stream or without a
556 ** timestamp, don't read past it.
557 */
558 boundary = next_boundary ;
559 }
560 continue ;
561 }
562
563 /* Found a page. Advance seek_pos past it */
564 seek_pos += page.header_len + page.body_len ;
565 /*
566 ** Save the offset of the first page we found after the seek,
567 ** regardless of the stream it came from or whether or not it has a
568 ** timestamp.
569 */
570 next_boundary = SF_MIN (page_offset, next_boundary) ;
571
572 /* If not from our stream, continue. */
573 if (odata->ostream.serialno != ogg_page_serialno (&page))
574 continue ;
575
576 /*
577 ** The Ogg spec says that a page with a granule pos of -1 must not
578 ** contain and packets which complete, but the lack of biconditional
579 ** wording means that /technically/ a packet which does not complete
580 ** any packets can have a granule pos other than -1. To make matters
581 ** worse, older versions of libogg did just that.
582 */
583 has_packets = ogg_page_packets (&page) > 0 ;
584 gp = has_packets ? ogg_page_granulepos (&page) : -1 ;
585 if (gp == (uint64_t) -1)
586 { if (buffering == SF_TRUE)
587 { if (!has_packets)
588 ogg_stream_pagein (&odata->ostream, &page) ;
589 else
590 { /*
591 ** If packets did end on this page, but we still didn't
592 ** have a valid granule position (in violation of the
593 ** spec!), stop buffering continued packet data.
594 ** Otherwise we might continue past the packet we
595 ** actually wanted.
596 */
597 ogg_stream_reset (&odata->ostream) ;
598 buffering = SF_FALSE ;
599 }
600 }
601 continue ;
602 }
603
604 if (gp < target_gp)
605 { /*
606 ** We found a page that ends before our target. Advance to
607 ** the raw offset of the next page.
608 */
609 begin = seek_pos ;
610 if (pcm_start > gp || pcm_end < gp)
611 break ;
612 /* Save the byte offset of after this page. */
613 best = best_start = begin ;
614 if (buffering)
615 ogg_stream_reset (&odata->ostream) ;
616 /* Check to see if the last packet continues. */
617 if (page.header [27 + page.header [26] - 1] == 255)
618 { ogg_page_search_continued_data (odata, &page) ;
619 /*
620 ** If we have a continued packet, remember the offset of
621 ** this page's start, so that if we do wind up having to
622 ** seek back here later, we can prime the stream with the
623 ** continued packet data. With no continued packet, we
624 ** remember the end of the page.
625 */
626 best_start = page_offset ;
627 } ;
628 /*
629 ** Then force buffering on, so that if a packet starts (but
630 ** does not end) on the next page, we still avoid the extra
631 ** seek back.
632 */
633 buffering = SF_TRUE ;
634 *best_gp = pcm_start = gp ;
635 if (target_gp - gp > 48000)
636 { /* Out by over a second. Try another bisection. */
637 break ;
638 }
639 /* Otherwise, keep scanning forward (do NOT use begin+1). */
640 bisect = begin ;
641 }
642 else
643 { /*
644 ** Found a page that ends after our target. If we had just
645 ** scanned the whole interval before we found it, we're good.
646 */
647 if (bisect <= begin + 1)
648 end = begin ;
649 else
650 { end = bisect ;
651 /*
652 ** In later iterations, don't read past the first page we
653 ** found.
654 */
655 boundary = next_boundary ;
656 /*
657 ** If we're not making much progress shrinking the interval
658 ** size, start forcing straight bisection to limit the
659 ** worst case.
660 */
661 force_bisect = end - begin > d0 * 2 ? SF_TRUE : SF_FALSE ;
662 /*
663 ** Don't let pcm_end get out of range! That could happen
664 ** with an invalid timestamp.
665 */
666 if (pcm_end > gp && pcm_start <= gp)
667 pcm_end = gp ;
668 }
669 break ;
670 }
671 }
672 }
673
674 /*
675 ** If we are buffering, the page we want is currently buffered in the
676 ** Ogg stream structure, or in the Ogg page which has not been submitted.
677 ** If not, we need to seek back and load it again.
678 */
679 if (buffering == SF_FALSE)
680 { if (best_start != page_offset)
681 { page_offset = -1 ;
682 seek_pos = ogg_sync_fseek (psf, best_start, SEEK_SET) ;
683 if (seek_pos < 0)
684 return seek_pos ;
685 }
686 if (best_start < best)
687 { if (page_offset < 0)
688 { ret = ogg_sync_next_page (psf, &page, -1, &seek_pos) ;
689 if (seek_pos != best_start)
690 return -1 ;
691 }
692 ogg_page_search_continued_data (odata, &page) ;
693 page_offset = -1 ;
694 }
695 } ;
696
697 if (page_offset >= 0)
698 ogg_stream_pagein (&odata->ostream, &page) ;
699
700 return 0 ;
701 } /* ogg_stream_seek_page_search */
702
703 int
ogg_open(SF_PRIVATE * psf)704 ogg_open (SF_PRIVATE *psf)
705 { OGG_PRIVATE* odata = calloc (1, sizeof (OGG_PRIVATE)) ;
706 sf_count_t pos = psf_ftell (psf) ;
707 int error = 0 ;
708
709 psf->container_data = odata ;
710 psf->container_close = ogg_close ;
711
712 if (psf->file.mode == SFM_RDWR)
713 return SFE_BAD_MODE_RW ;
714
715 if (psf->file.mode == SFM_READ)
716 if ((error = ogg_stream_classify (psf, odata)) != 0)
717 return error ;
718
719 if (SF_ENDIAN (psf->sf.format) != 0)
720 return SFE_BAD_ENDIAN ;
721
722 switch (psf->sf.format)
723 { case SF_FORMAT_OGG | SF_FORMAT_VORBIS :
724 return ogg_vorbis_open (psf) ;
725
726 case SF_FORMAT_OGGFLAC :
727 /* Reset everything to an initial state. */
728 ogg_sync_clear (&odata->osync) ;
729 ogg_stream_clear (&odata->ostream) ;
730 psf_fseek (psf, pos, SEEK_SET) ;
731 free (psf->container_data) ;
732 psf->container_data = NULL ;
733 psf->container_close = NULL ;
734 return flac_open (psf) ;
735
736 case SF_FORMAT_OGG | SF_FORMAT_OPUS :
737 return ogg_opus_open (psf) ;
738
739 #if ENABLE_EXPERIMENTAL_CODE
740 case SF_FORMAT_OGG | SF_FORMAT_SPEEX :
741 return ogg_speex_open (psf) ;
742
743 case SF_FORMAT_OGG | SF_FORMAT_PCM_16 :
744 case SF_FORMAT_OGG | SF_FORMAT_PCM_24 :
745 return ogg_pcm_open (psf) ;
746 #endif
747
748 default :
749 break ;
750 } ;
751
752 psf_log_printf (psf, "%s : bad psf->sf.format 0x%x.\n", __func__, psf->sf.format) ;
753 return SFE_INTERNAL ;
754 } /* ogg_open */
755
756 /*==============================================================================
757 ** Private functions.
758 */
759
760 static int
ogg_close(SF_PRIVATE * psf)761 ogg_close (SF_PRIVATE *psf)
762 { OGG_PRIVATE* odata = psf->container_data ;
763
764 ogg_sync_clear (&odata->osync) ;
765 ogg_stream_clear (&odata->ostream) ;
766
767 return 0 ;
768 } /* ogg_close */
769
770 static int
ogg_stream_classify(SF_PRIVATE * psf,OGG_PRIVATE * odata)771 ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE* odata)
772 { int error ;
773
774 /* Call this here so it only gets called once, so no memory is leaked. */
775 ogg_sync_init (&odata->osync) ;
776 ogg_stream_init (&odata->ostream, 0) ;
777
778 /* Load the first page in the physical bitstream. */
779 if ((error = ogg_read_first_page (psf, odata)) != 0)
780 return error ;
781
782 odata->codec = ogg_page_classify (psf, &odata->opage) ;
783
784 switch (odata->codec)
785 { case OGG_VORBIS :
786 psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ;
787 return 0 ;
788
789 case OGG_FLAC :
790 case OGG_FLAC0 :
791 psf->sf.format = SF_FORMAT_OGGFLAC ;
792 return 0 ;
793
794 case OGG_SPEEX :
795 psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ;
796 return 0 ;
797
798 case OGG_OPUS :
799 psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ;
800 return 0 ;
801
802 case OGG_PCM :
803 psf_log_printf (psf, "Detected Ogg/PCM data. This is not supported yet.\n") ;
804 return SFE_UNIMPLEMENTED ;
805
806 default :
807 break ;
808 } ;
809
810 psf_log_printf (psf, "This Ogg bitstream contains some uknown data type.\n") ;
811 return SFE_UNIMPLEMENTED ;
812 } /* ogg_stream_classify */
813
814 /*==============================================================================
815 */
816
817 static struct
818 { const char *str, *name ;
819 int len, codec ;
820 } codec_lookup [] =
821 { { "Annodex", "Annodex", 8, OGG_ANNODEX },
822 { "AnxData", "AnxData", 7, OGG_ANXDATA },
823 { "\177FLAC", "Flac1", 5, OGG_FLAC },
824 { "fLaC", "Flac0", 4, OGG_FLAC0 },
825 { "PCM ", "PCM", 8, OGG_PCM },
826 { "Speex", "Speex", 5, OGG_SPEEX },
827 { "\001vorbis", "Vorbis", 7, OGG_VORBIS },
828 { "OpusHead", "Opus", 8, OGG_OPUS },
829 } ;
830
831 static int
ogg_page_classify(SF_PRIVATE * psf,const ogg_page * og)832 ogg_page_classify (SF_PRIVATE * psf, const ogg_page * og)
833 { int k, len ;
834
835 for (k = 0 ; k < ARRAY_LEN (codec_lookup) ; k++)
836 { if (codec_lookup [k].len > og->body_len)
837 continue ;
838
839 if (memcmp (og->body, codec_lookup [k].str, codec_lookup [k].len) == 0)
840 { psf_log_printf (psf, "Ogg stream data : %s\n", codec_lookup [k].name) ;
841 psf_log_printf (psf, "Stream serialno : %u\n", (uint32_t) ogg_page_serialno (og)) ;
842 return codec_lookup [k].codec ;
843 } ;
844 } ;
845
846 len = og->body_len < 8 ? og->body_len : 8 ;
847
848 psf_log_printf (psf, "Ogg_stream data : '") ;
849 for (k = 0 ; k < len ; k++)
850 psf_log_printf (psf, "%c", isprint (og->body [k]) ? og->body [k] : '.') ;
851 psf_log_printf (psf, "' ") ;
852 for (k = 0 ; k < len ; k++)
853 psf_log_printf (psf, " %02x", og->body [k] & 0xff) ;
854 psf_log_printf (psf, "\n") ;
855
856 return 0 ;
857 } /* ogg_page_classify */
858
859 /*
860 ** Scale x from the range [0, from] to the range [0, to]
861 */
862 static uint64_t
ogg_page_search_do_rescale(uint64_t x,uint64_t from,uint64_t to)863 ogg_page_search_do_rescale (uint64_t x, uint64_t from, uint64_t to)
864 { uint64_t frac ;
865 uint64_t ret ;
866 int i ;
867
868 /* I should have paid more attention in CSc 349A: Numerical Analysis */
869 if (x >= from)
870 return to ;
871 if (x == 0)
872 return 0 ;
873 frac = 0 ;
874 for (i = 0 ; i < 63 ; i++)
875 { frac <<= 1 ;
876 if (x >= from >> 1)
877 { x -= from - x ;
878 frac |= 1 ;
879 }
880 else
881 x <<= 1 ;
882 }
883 ret = 0 ;
884 for (i = 0 ; i < 63 ; i++)
885 { if (frac & 1)
886 ret = (ret & to & 1) + (ret >> 1) + (to >> 1) ;
887 else
888 ret >>= 1 ;
889 frac >>= 1 ;
890 }
891 return ret ;
892 } /* ogg_page_search_do_rescale */
893
894 static void
ogg_page_search_continued_data(OGG_PRIVATE * odata,ogg_page * page)895 ogg_page_search_continued_data (OGG_PRIVATE *odata, ogg_page *page)
896 { ogg_stream_pagein (&odata->ostream, page) ;
897 while (ogg_stream_packetout (&odata->ostream, &odata->opacket)) ;
898 } /* ogg_page_search_continued_data */
899
900 #else /* HAVE_EXTERNAL_XIPH_LIBS */
901
902 int
ogg_open(SF_PRIVATE * psf)903 ogg_open (SF_PRIVATE *psf)
904 {
905 psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Vorbis support.\n") ;
906 return SFE_UNIMPLEMENTED ;
907 } /* ogg_open */
908
909 #endif
910