xref: /third_party/libsnd/src/ogg.c (revision b815c7f3)
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
138static int		ogg_close (SF_PRIVATE *psf) ;
139static int		ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE * odata) ;
140static int		ogg_page_classify (SF_PRIVATE * psf, const ogg_page * og) ;
141static uint64_t	ogg_page_search_do_rescale (uint64_t x, uint64_t from, uint64_t to) ;
142static void		ogg_page_search_continued_data (OGG_PRIVATE *odata, ogg_page *page) ;
143
144/*-----------------------------------------------------------------------------------------------
145** Exported functions.
146*/
147
148int
149ogg_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	if (buffer == NULL)
169		return SFE_MALLOC_FAILED ;
170	memcpy (buffer, psf->header.ptr, psf->header.indx) ;
171	ogg_sync_wrote (&odata->osync, psf->header.indx) ;
172
173	ret = ogg_sync_next_page (psf, &odata->opage, SF_MAX ((sf_count_t) 0, 4096 - psf->header.indx), NULL) ;
174
175	/* Have we simply run out of data?  If so, we're done. */
176	if (ret == 0)
177		return 0 ;
178	if (ret < 0)
179		return psf->error ;
180
181	if (!ogg_page_bos (&odata->opage))
182	{	/*
183		** Error case. Either must not be an Ogg bitstream, or is in the
184		** middle of a bitstream (live capture), or in the middle of a
185		** bitstream and no complete page was in the buffer.
186		*/
187		psf_log_printf (psf, "Input does not appear to be the start of an Ogg bitstream.\n") ;
188		return SFE_MALFORMED_FILE ;
189		} ;
190
191	/*
192	**	Get the serial number and set up the rest of decode.
193	**	Serialno first ; use it to set up a logical stream.
194	*/
195	ogg_stream_reset_serialno (&odata->ostream, ogg_page_serialno (&odata->opage)) ;
196
197	if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0)
198	{	/* Error ; stream version mismatch perhaps. */
199		psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ;
200		return SFE_MALFORMED_FILE ;
201		} ;
202
203	if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1)
204	{	/* No page? */
205		psf_log_printf (psf, "Error reading initial header page packet.\n") ;
206		return SFE_MALFORMED_FILE ;
207		} ;
208
209	return 0 ;
210} /* ogg_read_first_page */
211
212int
213ogg_write_page (SF_PRIVATE *psf, ogg_page *page)
214{	int bytes ;
215
216	bytes = psf_fwrite (page->header, 1, page->header_len, psf) ;
217	bytes += psf_fwrite (page->body, 1, page->body_len, psf) ;
218
219	return bytes == page->header_len + page->body_len ;
220} /* ogg_write_page */
221
222sf_count_t
223ogg_sync_ftell (SF_PRIVATE *psf)
224{	OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ;
225	sf_count_t position ;
226
227	position = psf_ftell (psf) ;
228	if (position >= 0)
229	{	/* success */
230		if (position < odata->osync.fill)
231		{	/* Really, this should be an assert. */
232			psf->error = SFE_INTERNAL ;
233			return -1 ;
234			}
235		position += (sf_count_t) (odata->osync.returned - odata->osync.fill) ;
236		}
237
238	return position ;
239} /* ogg_sync_ftell */
240
241sf_count_t
242ogg_sync_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
243{	OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ;
244	sf_count_t ret ;
245
246	ret = psf_fseek (psf, offset, whence) ;
247	if (ret >= 0)
248	{	/* success */
249		odata->eos = 0 ;
250		ogg_sync_reset (&odata->osync) ;
251		}
252
253	return ret ;
254} /* ogg_sync_fseek */
255
256int
257ogg_sync_next_page (SF_PRIVATE * psf, ogg_page *og, sf_count_t readmax, sf_count_t *offset)
258{	OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ;
259	sf_count_t position, nb_read, read_ret ;
260	unsigned char *buffer ;
261	int synced ;
262	int report_hole = 0 ;
263
264	for (position = 0 ; readmax <= 0 || readmax > position ; )
265	{	synced = ogg_sync_pageseek (&odata->osync, og) ;
266		if (synced < 0)
267		{	/*
268			** Skipped -synced bytes before finding the start of a page.
269			** If seeking, we have just landed in the middle of a page.
270			** Otherwise, warn about junk in the bitstream.
271			** Page might not yet be ready, hence the continue.
272			*/
273			if (!offset)
274				report_hole = 1 ;
275			position -= synced ;
276			continue ;
277			} ;
278
279		if (report_hole)
280		{	psf_log_printf (psf, "Ogg : Skipped %d bytes looking for the next page. Corrupted bitstream?!\n", position) ;
281			report_hole = 0 ;
282			} ;
283
284		if (synced > 0)
285		{	/* Have a page */
286			if (offset)
287				*offset += position ;
288			return og->header_len + og->body_len ;
289			} ;
290
291		/*
292		** Else readmax == 0, Out of data. Try to read more in without
293		** invalidating our boundary (readmax) constraint.
294		*/
295		if (readmax == 0)
296			return 0 ;
297		if (readmax > 0)
298			nb_read = SF_MIN ((sf_count_t) OGG_SYNC_READ_SIZE, readmax - position) ;
299		else
300			nb_read = OGG_SYNC_READ_SIZE ;
301		buffer = (unsigned char *) ogg_sync_buffer (&odata->osync, nb_read) ;
302		if (buffer == NULL)
303		{	psf->error = SFE_MALLOC_FAILED ;
304			return -1 ;
305			}
306		read_ret = psf_fread (buffer, 1, nb_read, psf) ;
307		if (read_ret == 0)
308			return psf->error ? -1 : 0 ;
309		ogg_sync_wrote (&odata->osync, read_ret) ;
310		} ;
311	return 0 ;
312} /* ogg_sync_next_page */
313
314int
315ogg_stream_next_page (SF_PRIVATE *psf, OGG_PRIVATE *odata)
316{	int nn ;
317
318	if (odata->eos)
319		return 0 ;
320
321	for ( ; ; )
322	{	nn = ogg_sync_next_page (psf, &odata->opage, -1, NULL) ;
323		if (nn == 0)
324		{	psf_log_printf (psf, "Ogg : File ended unexpectedly without an End-Of-Stream flag set.\n") ;
325			odata->eos = 1 ;
326			}
327		if (nn <= 0)
328			return nn ;
329
330		if (ogg_page_serialno (&odata->opage) == odata->ostream.serialno)
331			break ;
332		} ;
333
334	if (ogg_page_eos (&odata->opage))
335		odata->eos = 1 ;
336
337	if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0)
338	{	psf->error = SFE_INTERNAL ;
339		return -1 ;
340		}
341
342	return 1 ;
343} /* ogg_stream_next_page */
344
345int
346ogg_stream_unpack_page (SF_PRIVATE *psf, OGG_PRIVATE *odata)
347{	int nn ;
348	int i ;
349	int found_hole = 0 ;
350	ogg_packet *ppkt = odata->pkt ;
351
352	odata->pkt_indx = 0 ;
353	nn = ogg_stream_packetout (&odata->ostream, ppkt) ;
354	if (nn == 0)
355	{	/*
356		** Steam is out of packets. Read in more pages until there is one, or
357		** the stream ends, or an error occurs.
358		*/
359		for ( ; nn == 0 ; nn = ogg_stream_packetout (&odata->ostream, ppkt))
360		{	nn = ogg_stream_next_page (psf, odata) ;
361			if (nn <= 0)
362			{	odata->pkt_len = 0 ;
363				return nn ;
364				}
365			}
366		/*
367		** In the case of the for loop exiting because
368		** ogg_stream_packetout() == -1, fall-through.
369		*/
370		}
371
372	if (nn == -1)
373	{	/*
374		** libOgg found a hole. That is, the next packet found was out of
375		** sequence. As such, "flush" the hole marker by removing the invalid
376		** packet, as the valid packets are queued behind it.
377		*/
378		psf_log_printf (psf, "Ogg : Warning, libogg reports a hole at %d bytes.\n", ogg_sync_ftell (psf)) ;
379		nn = ogg_stream_packetout (&odata->ostream, ppkt) ;
380		found_hole = 1 ;
381		}
382
383	/*
384	** Unpack all the packets on the page. It is undocumented (like much of
385	** libOgg behavior) but all packets from a page read into the stream are
386	** guarenteed to remain valid in memory until a new page is read into the
387	** stream.
388	*/
389	for (i = 1 ; ; i++)
390	{	/* Not an off-by-one, there are 255 not 256 packets max. */
391		if (i == 255)
392		{	if (ogg_stream_packetpeek (&odata->ostream, NULL) == 1)
393			{	psf->error = SFE_INTERNAL ;
394				return -1 ;
395				}
396			break ;
397			}
398		if (ogg_stream_packetout (&odata->ostream, ++ ppkt) != 1)
399			break ;
400		}
401	odata->pkt_len = i ;
402
403	/* 1 = ok, 2 = ok, and found a hole. */
404	return 1 + found_hole ;
405} /* ogg_stream_unpack_page */
406
407sf_count_t
408ogg_sync_last_page_before (SF_PRIVATE *psf, OGG_PRIVATE *odata, uint64_t *gp_out, sf_count_t offset, int32_t serialno)
409{	sf_count_t begin, end, original_end, chunk_size, ret ;
410	sf_count_t position = 0 ;
411	uint64_t gp = -1 ;
412	int left_link ;
413
414	/* Based on code from Xiph.org's Opusfile */
415
416	original_end = end = begin = offset ;
417	offset = -1 ;
418	chunk_size = OGG_CHUNK_SIZE ;
419	do
420	{	begin = SF_MAX (begin - chunk_size, (sf_count_t) 0) ;
421		position = ogg_sync_fseek (psf, begin, SEEK_SET) ;
422		if (position < 0)
423			return position ;
424		left_link = 0 ;
425		while (position < end)
426		{	ret = ogg_sync_next_page (psf, &odata->opage, end - position, &position) ;
427			if (ret <= 0)
428				return -1 ;
429			if (ogg_page_serialno (&odata->opage) == serialno)
430			{	uint64_t page_gp = ogg_page_granulepos (&odata->opage) ;
431				if (page_gp != (uint64_t) -1)
432				{	offset = position ;
433					gp = page_gp ;
434					}
435				}
436			else
437				left_link = 1 ;
438			position += ret ;
439			}
440
441		if ((left_link || !begin) && offset < 0)
442		{	psf->error = SFE_MALFORMED_FILE ;
443			return -1 ;
444			}
445
446		chunk_size = SF_MIN (2 * chunk_size, (sf_count_t) OGG_CHUNK_SIZE_MAX) ;
447		end = SF_MIN (begin + OGG_PAGE_SIZE_MAX - 1, original_end) ;
448		}
449	while (offset < 0) ;
450
451	*gp_out = gp ;
452	return offset ;
453} /* ogg_sync_last_page_before */
454
455int
456ogg_stream_seek_page_search (SF_PRIVATE *psf, OGG_PRIVATE *odata,
457	uint64_t target_gp, uint64_t pcm_start, uint64_t pcm_end, uint64_t *best_gp,
458	sf_count_t begin, sf_count_t end, uint64_t gp_rate)
459{	ogg_page page ;
460	uint64_t gp ;
461	sf_count_t d0, d1, d2 ;
462	sf_count_t best ;
463	sf_count_t best_start ;
464	sf_count_t boundary ;
465	sf_count_t next_boundary ;
466	sf_count_t page_offset = -1 ;
467	sf_count_t seek_pos = -1 ;
468	sf_count_t bisect ;
469	sf_count_t chunk_size ;
470	int buffering = SF_FALSE ;
471	int force_bisect = SF_FALSE ;
472	int ret ;
473	int has_packets ;
474
475	*best_gp = pcm_start ;
476	best = best_start = begin ;
477	boundary = end ;
478
479	ogg_stream_reset_serialno (&odata->ostream, odata->ostream.serialno) ;
480
481	/*
482	** This code is based on op_pcm_seek_page() from Opusfile, which is in turn
483	** based on "new search algorithm by Nicholas Vinen" from libvorbisfile.
484	*/
485
486	d2 = d1 = d0 = end - begin ;
487	while (begin < end)
488	{	/*
489		** Figure out if and where to try and seek in the file.
490		*/
491		if (end - begin < OGG_CHUNK_SIZE)
492			bisect = begin ;
493		else
494		{	/* Update the interval size history */
495			d0 = d1 >> 1 ;
496			d1 = d2 >> 1 ;
497			d2 = (end - begin) >> 1 ;
498			if (force_bisect == SF_TRUE)
499				bisect = begin + ((end - begin) >> 1) ;
500			else
501			{	/* Take a decent guess. */
502				bisect = begin + ogg_page_search_do_rescale (target_gp - pcm_start, pcm_end - pcm_start, end - begin) ;
503				}
504			if (bisect - OGG_CHUNK_SIZE < begin)
505				bisect = begin ;
506			else
507				bisect -= OGG_CHUNK_SIZE ;
508			force_bisect = SF_FALSE ;
509			}
510
511		/*
512		** Avoid an actual fseek if we can (common for final iterations.)
513		*/
514		if (seek_pos != bisect)
515		{	if (buffering == SF_TRUE)
516				ogg_stream_reset (&odata->ostream) ;
517			buffering = SF_FALSE ;
518			page_offset = -1 ;
519			seek_pos = ogg_sync_fseek (psf, bisect, SEEK_SET) ;
520			if (seek_pos < 0)
521				return seek_pos ;
522			}
523
524		chunk_size = OGG_CHUNK_SIZE ;
525		next_boundary = boundary ;
526
527		/*
528		** Scan forward, figure out where we landed.
529		** The ideal case is we see a page that ends before our target followed
530		** by a page that ends after our target.
531		** If we are too far before or after, breaking out will bisect what we
532		** have found so far.
533		*/
534		while (begin < end)
535		{	ret = ogg_sync_next_page (psf, &page, boundary - seek_pos, &seek_pos) ;
536			if (ret <= 0)
537				return ret ;
538			page_offset = seek_pos ;
539			if (ret == 0)
540			{	/*
541				** There are no more pages in this interval from our stream
542				** with a granulepos less than our target.
543				*/
544				if (bisect <= begin + 1)
545				{	/* Scanned the whole interval, so we are done. */
546					end = begin ;
547					}
548				else
549				{	/*
550					** Otherwise, back up one chunk. First discard any data
551					** from a continued packet.
552					*/
553					if (buffering)
554						ogg_stream_reset (&odata->ostream) ;
555					buffering = SF_FALSE ;
556					bisect = SF_MAX (bisect - chunk_size, begin) ;
557					seek_pos = ogg_sync_fseek (psf, bisect, SEEK_SET) ;
558					if (seek_pos < 0)
559						return seek_pos ;
560					/* Bump up the chunk size. */
561					chunk_size = SF_MIN (2 * chunk_size, (sf_count_t) OGG_CHUNK_SIZE_MAX) ;
562					/*
563					** If we did find a page from another stream or without a
564					** timestamp, don't read past it.
565					*/
566					boundary = next_boundary ;
567					}
568				continue ;
569				}
570
571			/* Found a page. Advance seek_pos past it */
572			seek_pos += page.header_len + page.body_len ;
573			/*
574			** Save the offset of the first page we found after the seek,
575			** regardless of the stream it came from or whether or not it has a
576			** timestamp.
577			*/
578			next_boundary = SF_MIN (page_offset, next_boundary) ;
579
580			/* If not from our stream, continue. */
581			if (odata->ostream.serialno != ogg_page_serialno (&page))
582				continue ;
583
584			/*
585			** The Ogg spec says that a page with a granule pos of -1 must not
586			** contain and packets which complete, but the lack of biconditional
587			** wording means that /technically/ a packet which does not complete
588			** any packets can have a granule pos other than -1. To make matters
589			** worse, older versions of libogg did just that.
590			*/
591			has_packets = ogg_page_packets (&page) > 0 ;
592			gp = has_packets ? ogg_page_granulepos (&page) : -1 ;
593			if (gp == (uint64_t) -1)
594			{	if (buffering == SF_TRUE)
595				{	if (!has_packets)
596						ogg_stream_pagein (&odata->ostream, &page) ;
597					else
598					{	/*
599						** If packets did end on this page, but we still didn't
600						** have a valid granule position (in violation of the
601						** spec!), stop buffering continued packet data.
602						** Otherwise we might continue past the packet we
603						** actually wanted.
604						*/
605						ogg_stream_reset (&odata->ostream) ;
606						buffering = SF_FALSE ;
607						}
608					}
609				continue ;
610				}
611
612			if (gp < target_gp)
613			{	/*
614				** We found a page that ends before our target. Advance to
615				** the raw offset of the next page.
616				*/
617				begin = seek_pos ;
618				if (pcm_start > gp || pcm_end < gp)
619					break ;
620				/* Save the byte offset of after this page. */
621				best = best_start = begin ;
622				if (buffering)
623					ogg_stream_reset (&odata->ostream) ;
624				/* Check to see if the last packet continues. */
625				if (ogg_page_continues (&page))
626				{	ogg_page_search_continued_data (odata, &page) ;
627					/*
628					** If we have a continued packet, remember the offset of
629					** this page's start, so that if we do wind up having to
630					** seek back here later, we can prime the stream with the
631					** continued packet data. With no continued packet, we
632					** remember the end of the page.
633					*/
634					best_start = page_offset ;
635					/*
636					** Then force buffering on, so that if a packet starts (but
637					** does not end) on the next page, we still avoid the extra
638					** seek back.
639					*/
640					buffering = SF_TRUE ;
641				} ;
642				*best_gp = pcm_start = gp ;
643				if (target_gp - gp > gp_rate)
644				{	/* Out by over a second. Try another bisection. */
645					break ;
646					}
647				/* Otherwise, keep scanning forward (do NOT use begin+1). */
648				bisect = begin ;
649				}
650			else
651			{	/*
652				** Found a page that ends after our target. If we had just
653				** scanned the whole interval before we found it, we're good.
654				*/
655				if (bisect <= begin + 1)
656					end = begin ;
657				else
658				{	end = bisect ;
659					/*
660					** In later iterations, don't read past the first page we
661					** found.
662					*/
663					boundary = next_boundary ;
664					/*
665					** If we're not making much progress shrinking the interval
666					** size, start forcing straight bisection to limit the
667					** worst case.
668					*/
669					force_bisect = end - begin > d0 * 2 ? SF_TRUE : SF_FALSE ;
670					/*
671					** Don't let pcm_end get out of range! That could happen
672					** with an invalid timestamp.
673					*/
674					if (pcm_end > gp && pcm_start <= gp)
675						pcm_end = gp ;
676					}
677				break ;
678				}
679			}
680		}
681
682	/*
683	** If we are buffering, the page we want is currently buffered in the
684	** Ogg stream structure, or in the Ogg page which has not been submitted.
685	** If not, we need to seek back and load it again.
686	*/
687	if (buffering == SF_FALSE)
688	{	if (best_start != page_offset)
689		{	page_offset = -1 ;
690			seek_pos = ogg_sync_fseek (psf, best_start, SEEK_SET) ;
691			if (seek_pos < 0)
692				return seek_pos ;
693			}
694		if (best_start < best)
695		{	if (page_offset < 0)
696			{	ret = ogg_sync_next_page (psf, &page, -1, &seek_pos) ;
697				if (seek_pos != best_start)
698					return -1 ;
699				}
700			ogg_page_search_continued_data (odata, &page) ;
701			page_offset = -1 ;
702			}
703		} ;
704
705	if (page_offset >= 0)
706		ogg_stream_pagein (&odata->ostream, &page) ;
707
708	return 0 ;
709} /* ogg_stream_seek_page_search */
710
711int
712ogg_open (SF_PRIVATE *psf)
713{	OGG_PRIVATE* odata = calloc (1, sizeof (OGG_PRIVATE)) ;
714	sf_count_t pos = psf_ftell (psf) ;
715	int	error = 0 ;
716
717	psf->container_data = odata ;
718	psf->container_close = ogg_close ;
719
720	if (psf->file.mode == SFM_RDWR)
721		return SFE_BAD_MODE_RW ;
722
723	if (psf->file.mode == SFM_READ)
724		if ((error = ogg_stream_classify (psf, odata)) != 0)
725			return error ;
726
727	if (SF_ENDIAN (psf->sf.format) != 0)
728		return SFE_BAD_ENDIAN ;
729
730	switch (psf->sf.format)
731	{	case SF_FORMAT_OGG | SF_FORMAT_VORBIS :
732			return ogg_vorbis_open (psf) ;
733
734		case SF_FORMAT_OGGFLAC :
735			/* Reset everything to an initial state. */
736			ogg_sync_clear (&odata->osync) ;
737			ogg_stream_clear (&odata->ostream) ;
738			psf_fseek (psf, pos, SEEK_SET) ;
739			free (psf->container_data) ;
740			psf->container_data = NULL ;
741			psf->container_close = NULL ;
742			return flac_open (psf) ;
743
744		case SF_FORMAT_OGG | SF_FORMAT_OPUS :
745			return ogg_opus_open (psf) ;
746
747#if ENABLE_EXPERIMENTAL_CODE
748		case SF_FORMAT_OGG | SF_FORMAT_SPEEX :
749			return ogg_speex_open (psf) ;
750
751		case SF_FORMAT_OGG | SF_FORMAT_PCM_16 :
752		case SF_FORMAT_OGG | SF_FORMAT_PCM_24 :
753			return ogg_pcm_open (psf) ;
754#endif
755
756		default :
757			break ;
758		} ;
759
760	psf_log_printf (psf, "%s : bad psf->sf.format 0x%x.\n", __func__, psf->sf.format) ;
761	return SFE_INTERNAL ;
762} /* ogg_open */
763
764/*==============================================================================
765** Private functions.
766*/
767
768static int
769ogg_close (SF_PRIVATE *psf)
770{	OGG_PRIVATE* odata = psf->container_data ;
771
772	ogg_sync_clear (&odata->osync) ;
773	ogg_stream_clear (&odata->ostream) ;
774
775	return 0 ;
776} /* ogg_close */
777
778static int
779ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE* odata)
780{	int error ;
781
782	/* Call this here so it only gets called once, so no memory is leaked. */
783	ogg_sync_init (&odata->osync) ;
784	ogg_stream_init (&odata->ostream, 0) ;
785
786	/* Load the first page in the physical bitstream. */
787	if ((error = ogg_read_first_page (psf, odata)) != 0)
788		return error ;
789
790	odata->codec = ogg_page_classify (psf, &odata->opage) ;
791
792	switch (odata->codec)
793	{	case OGG_VORBIS :
794			psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ;
795			return 0 ;
796
797		case OGG_FLAC :
798		case OGG_FLAC0 :
799			psf->sf.format = SF_FORMAT_OGGFLAC ;
800			return 0 ;
801
802		case OGG_SPEEX :
803			psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ;
804			return 0 ;
805
806		case OGG_OPUS :
807			psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ;
808			return 0 ;
809
810		case OGG_PCM :
811			psf_log_printf (psf, "Detected Ogg/PCM data. This is not supported yet.\n") ;
812			return SFE_UNIMPLEMENTED ;
813
814		default :
815			break ;
816		} ;
817
818	psf_log_printf (psf, "This Ogg bitstream contains some uknown data type.\n") ;
819	return SFE_UNIMPLEMENTED ;
820} /* ogg_stream_classify */
821
822/*==============================================================================
823*/
824
825static struct
826{	const char *str, *name ;
827	int len, codec ;
828} codec_lookup [] =
829{	{	"Annodex",		"Annodex",	8, OGG_ANNODEX },
830	{	"AnxData",		"AnxData",	7, OGG_ANXDATA },
831	{	"\177FLAC",		"Flac1",	5, OGG_FLAC },
832	{	"fLaC",			"Flac0",	4, OGG_FLAC0 },
833	{	"PCM     ",		"PCM",		8, OGG_PCM },
834	{	"Speex",		"Speex",	5, OGG_SPEEX },
835	{	"\001vorbis",	"Vorbis",	7, OGG_VORBIS },
836	{	"OpusHead",		"Opus",		8, OGG_OPUS },
837} ;
838
839static int
840ogg_page_classify (SF_PRIVATE * psf, const ogg_page * og)
841{	int k, len ;
842
843	for (k = 0 ; k < ARRAY_LEN (codec_lookup) ; k++)
844	{	if (codec_lookup [k].len > og->body_len)
845			continue ;
846
847		if (memcmp (og->body, codec_lookup [k].str, codec_lookup [k].len) == 0)
848		{	psf_log_printf (psf, "Ogg stream data : %s\n", codec_lookup [k].name) ;
849			psf_log_printf (psf, "Stream serialno : %u\n", (uint32_t) ogg_page_serialno (og)) ;
850			return codec_lookup [k].codec ;
851			} ;
852		} ;
853
854	len = og->body_len < 8 ? og->body_len : 8 ;
855
856	psf_log_printf (psf, "Ogg_stream data : '") ;
857	for (k = 0 ; k < len ; k++)
858		psf_log_printf (psf, "%c", isprint (og->body [k]) ? og->body [k] : '.') ;
859	psf_log_printf (psf, "'     ") ;
860	for (k = 0 ; k < len ; k++)
861		psf_log_printf (psf, " %02x", og->body [k] & 0xff) ;
862	psf_log_printf (psf, "\n") ;
863
864	return 0 ;
865} /* ogg_page_classify */
866
867/*
868** Scale x from the range [0, from] to the range [0, to]
869*/
870static uint64_t
871ogg_page_search_do_rescale (uint64_t x, uint64_t from, uint64_t to)
872{	uint64_t frac ;
873	uint64_t ret ;
874	int i ;
875
876	/* I should have paid more attention in CSc 349A: Numerical Analysis */
877	if (x >= from)
878		return to ;
879	if (x == 0)
880		return 0 ;
881	frac = 0 ;
882	for (i = 0 ; i < 63 ; i++)
883	{	frac <<= 1 ;
884		if (x >= from >> 1)
885		{	x -= from - x ;
886			frac |= 1 ;
887			}
888		else
889			x <<= 1 ;
890		}
891	ret = 0 ;
892	for (i = 0 ; i < 63 ; i++)
893	{	if (frac & 1)
894			ret = (ret & to & 1) + (ret >> 1) + (to >> 1) ;
895		else
896			ret >>= 1 ;
897		frac >>= 1 ;
898		}
899	return ret ;
900} /* ogg_page_search_do_rescale */
901
902static void
903ogg_page_search_continued_data (OGG_PRIVATE *odata, ogg_page *page)
904{	ogg_stream_pagein (&odata->ostream, page) ;
905	while (ogg_stream_packetout (&odata->ostream, &odata->opacket)) ;
906} /* ogg_page_search_continued_data */
907
908#else /* HAVE_EXTERNAL_XIPH_LIBS */
909
910int
911ogg_open	(SF_PRIVATE *psf)
912{
913	psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Vorbis support.\n") ;
914	return SFE_UNIMPLEMENTED ;
915} /* ogg_open */
916
917#endif
918