예제 #1
0
static sf_count_t
txw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{	BUF_UNION		ubuf ;
	unsigned char	*ucptr ;
	short			sample ;
	int				k, bufferlen, readcount, count ;
	sf_count_t		total = 0 ;
	double			normfact ;

	if (psf->norm_double == SF_TRUE)
		normfact = 1.0 / 0x8000 ;
	else
		normfact = 1.0 / 0x10 ;

	bufferlen = sizeof (ubuf.cbuf) / 3 ;
	bufferlen -= (bufferlen & 1) ;
	while (len > 0)
	{	readcount = (len >= bufferlen) ? bufferlen : len ;
		count = psf_fread (ubuf.cbuf, 3, readcount, psf) ;

		ucptr = ubuf.ucbuf ;
		for (k = 0 ; k < readcount ; k += 2)
		{	sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
			ptr [total + k] = normfact * sample ;
			sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
			ptr [total + k + 1] = normfact * sample ;
			ucptr += 3 ;
			} ;

		total += count ;
		len -= readcount ;
		} ;

	return total ;
} /* txw_read_d */
예제 #2
0
파일: txw.c 프로젝트: joshlong/libcd
static sf_count_t 
txw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{	unsigned char	*ucptr ;
	short			sample ;
	int				k, bufferlen, readcount, count ;
	sf_count_t		total = 0 ;
	float			normfact ;

	if (psf->norm_float == SF_TRUE)
		normfact = 1.0 / 0x8000 ;
	else 
		normfact = 1.0 / 0x10 ;

	bufferlen = sizeof (psf->buffer) / 3 ;
	bufferlen -= (bufferlen & 1) ;
	while (len > 0)
	{	readcount = (len >= bufferlen) ? bufferlen : len ;
		count = psf_fread (psf->buffer, 3, readcount, psf->filedes) ;

		ucptr = (unsigned char *) psf->buffer ;
		for (k = 0 ; k < readcount ; k += 2)
		{	sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
			ptr [total + k] = normfact * sample ;
			sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
			ptr [total + k + 1] = normfact * sample ;
			ucptr += 3 ;
			} ;

		total += count ;
		len -= readcount ;
		} ;

	return total ;
} /* txw_read_f */
예제 #3
0
static sf_count_t
txw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{	BUF_UNION		ubuf ;
	unsigned char	*ucptr ;
	short			sample ;
	int				k, bufferlen, readcount, count ;
	sf_count_t		total = 0 ;

	bufferlen = sizeof (ubuf.cbuf) / 3 ;
	bufferlen -= (bufferlen & 1) ;
	while (len > 0)
	{	readcount = (len >= bufferlen) ? bufferlen : len ;
		count = psf_fread (ubuf.cbuf, 3, readcount, psf) ;

		ucptr = ubuf.ucbuf ;
		for (k = 0 ; k < readcount ; k += 2)
		{	sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
			ptr [total + k] = sample << 16 ;
			sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
			ptr [total + k + 1] = sample << 16 ;
			ucptr += 3 ;
			} ;

		total += count ;
		len -= readcount ;
		} ;

	return total ;
} /* txw_read_i */
예제 #4
0
파일: txw.c 프로젝트: joshlong/libcd
static sf_count_t 
txw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{	unsigned char	*ucptr ;
	short			sample ;
	int				k, bufferlen, readcount, count ;
	sf_count_t		total = 0 ;

	bufferlen = sizeof (psf->buffer) / 3 ;
	bufferlen -= (bufferlen & 1) ;
	while (len > 0)
	{	readcount = (len >= bufferlen) ? bufferlen : len ;
		count = psf_fread (psf->buffer, 3, readcount, psf->filedes) ;

		ucptr = (unsigned char *) psf->buffer ;
		for (k = 0 ; k < readcount ; k += 2)
		{	sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
			ptr [total + k] = sample ;
			sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
			ptr [total + k + 1] = sample ;
			ucptr += 3 ;
			} ;

		total += count ;
		len -= readcount ;
		} ;

	return total ;
} /* txw_read_s */
예제 #5
0
void
wav_w64_analyze (SF_PRIVATE *psf)
{   AUDIO_DETECT ad ;
    int format = 0 ;

    if (psf->is_pipe)
    {   psf_log_printf (psf, "*** Error : Reading from a pipe. Can't analyze data section to figure out real data format.\n\n") ;
        return ;
    } ;

    psf_log_printf (psf, "---------------------------------------------------\n"
                    "Format is known to be broken. Using detection code.\n") ;

    /* Code goes here. */
    ad.endianness = SF_ENDIAN_LITTLE ;
    ad.channels = psf->sf.channels ;

    psf_fseek (psf, 3 * 4 * 50, SEEK_SET) ;

    while (psf_fread (psf->u.ucbuf, 1, 4096, psf) == 4096)
    {   format = audio_detect (psf, &ad, psf->u.ucbuf, 4096) ;
        if (format != 0)
            break ;
    } ;

    /* Seek to start of DATA section. */
    psf_fseek (psf, psf->dataoffset, SEEK_SET) ;

    if (format == 0)
    {   psf_log_printf (psf, "wav_w64_analyze : detection failed.\n") ;
        return ;
    } ;

    switch (format)
    {
    case SF_FORMAT_PCM_32 :
    case SF_FORMAT_FLOAT :
        psf_log_printf (psf, "wav_w64_analyze : found format : 0x%X\n", format) ;
        psf->sf.format = (psf->sf.format & ~SF_FORMAT_SUBMASK) + format ;
        psf->bytewidth = 4 ;
        psf->blockwidth = psf->sf.channels * psf->bytewidth ;
        break ;

    case SF_FORMAT_PCM_24 :
        psf_log_printf (psf, "wav_w64_analyze : found format : 0x%X\n", format) ;
        psf->sf.format = (psf->sf.format & ~SF_FORMAT_SUBMASK) + format ;
        psf->bytewidth = 3 ;
        psf->blockwidth = psf->sf.channels * psf->bytewidth ;
        break ;

    default :
        psf_log_printf (psf, "wav_w64_analyze : unhandled format : 0x%X\n", format) ;
        break ;
    } ;

    return ;
} /* wav_w64_analyze */
예제 #6
0
static void
test_read_or_die (SF_PRIVATE *psf, void *data, sf_count_t bytes, sf_count_t items, sf_count_t new_position, int linenum)
{	sf_count_t	retval ;

	retval = psf_fread (data, bytes, items, psf) ;
	if (retval != items)
	{	printf ("\n\nLine %d: psf_write() returned %ld (should be %ld)\n\n", linenum, (long) retval, (long) items) ;
		exit (1) ;
		} ;

	if ((retval = psf_ftell (psf)) != new_position)
	{	printf ("\n\nLine %d: file length after write is not correct. (%ld should be %ld)\n\n", linenum, (long) retval, (long) new_position) ;
		exit (1) ;
		} ;

	return ;
} /* test_write_or_die */
예제 #7
0
static int
vorbis_length_get_next_page (SF_PRIVATE *psf, ogg_sync_state * osync, ogg_page *page)
{	static const int CHUNK_SIZE = 4500 ;

	while (ogg_sync_pageout (osync, page) <= 0)
	{	char * buffer = ogg_sync_buffer (osync, CHUNK_SIZE) ;
		int bytes = psf_fread (buffer, 1, 4096, psf) ;

		if (bytes <= 0)
		{	ogg_sync_wrote (osync, 0) ;
			return 0 ;
		} ;

		ogg_sync_wrote (osync, bytes) ;
	} ;

	return 1 ;
} /* vorbis_length_get_next_page */
예제 #8
0
파일: caf.c 프로젝트: weiwei22844/sox
static int
caf_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info)
{	int indx ;
	sf_count_t pos ;

	if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0)
		return SFE_UNKNOWN_CHUNK ;

	if (chunk_info->data == NULL)
		return SFE_BAD_CHUNK_DATA_PTR ;

	chunk_info->id_size = psf->rchunks.chunks [indx].id_size ;
	memcpy (chunk_info->id, psf->rchunks.chunks [indx].id, sizeof (chunk_info->id) / sizeof (*chunk_info->id)) ;

	pos = psf_ftell (psf) ;
	psf_fseek (psf, psf->rchunks.chunks [indx].offset, SEEK_SET) ;
	psf_fread (chunk_info->data, SF_MIN (chunk_info->datalen, psf->rchunks.chunks [indx].len), 1, psf) ;
	psf_fseek (psf, pos, SEEK_SET) ;

	return SFE_NO_ERROR ;
} /* caf_get_chunk_data */
예제 #9
0
static int
spx_read_header (SF_PRIVATE * psf)
{	static SpeexStereoState STEREO_INIT = SPEEX_STEREO_STATE_INIT ;

	OGG_PRIVATE* odata = psf->container_data ;
	SPX_PRIVATE* spx = psf->codec_data ;

	ogg_int64_t page_granule = 0 ;
	int stream_init = 0 ;
	int	page_nb_packets = 0 ;
	int packet_count = 0 ;
	int enh_enabled = 1 ;
	int force_mode = -1 ;
	char * data ;
	int nb_read ;
	int lookahead ;

printf ("%s %d\n", __func__, __LINE__) ;

	psf_log_printf (psf, "Speex header\n") ;
	odata->eos = 0 ;

	/* Reset ogg stuff which has already been used in src/ogg.c. */
	ogg_stream_reset (&odata->ostream) ;
	ogg_sync_reset (&odata->osync) ;

	/* Seek to start of stream. */
	psf_fseek (psf, 0, SEEK_SET) ;

	/* Initialize. */
	ogg_sync_init (&odata->osync) ;
	speex_bits_init (&spx->bits) ;

	/* Set defaults. */
	psf->sf.channels = -1 ;
	psf->sf.samplerate = 0 ;
	spx->stereo = STEREO_INIT ;

	/* Get a pointer to the ogg buffer and read data into it. */
	data = ogg_sync_buffer (&odata->osync, OGG_SPX_READ_SIZE) ;
	nb_read = psf_fread (data, 1, OGG_SPX_READ_SIZE, psf) ;
	ogg_sync_wrote (&odata->osync, nb_read) ;

	/* Now we chew on Ogg packets. */
	while (ogg_sync_pageout (&odata->osync, &odata->opage) == 1)
	{	if (stream_init == 0)
		{	ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ;
			stream_init = 1 ;
			} ;

		if (ogg_page_serialno (&odata->opage) != odata->ostream.serialno)
		{	/* so all streams are read. */
			ogg_stream_reset_serialno (&odata->ostream, ogg_page_serialno (&odata->opage)) ;
			} ;

		/*Add page to the bitstream*/
		ogg_stream_pagein (&odata->ostream, &odata->opage) ;
		page_granule = ogg_page_granulepos (&odata->opage) ;
		page_nb_packets = ogg_page_packets (&odata->opage) ;

		/*Extract all available packets*/
		while (odata->eos == 0 && ogg_stream_packetout (&odata->ostream, &odata->opacket) == 1)
		{	if (odata->opacket.bytes >= 8 && memcmp (odata->opacket.packet, "Speex   ", 8) == 0)
			{	spx->serialno = odata->ostream.serialno ;
				} ;

			if (spx->serialno == -1 || odata->ostream.serialno != spx->serialno)
				break ;

			if (packet_count == 0)
			{	spx->state = spx_header_read (psf, &odata->opacket, enh_enabled, force_mode) ;
				if (! spx->state)
					break ;

				speex_decoder_ctl (spx->state, SPEEX_GET_LOOKAHEAD, &lookahead) ;
				if (spx->nframes == 0)
					spx->nframes = 1 ;
				}
			else if (packet_count == 1)
			{	spx_print_comments ((const char*) odata->opacket.packet, odata->opacket.bytes) ;
				}
			else if (packet_count < 2 + spx->header.extra_headers)
			{	/* Ignore extra headers */
				}
			packet_count ++ ;
			} ;
		} ;

	psf_log_printf (psf, "End\n") ;

	psf_log_printf (psf, "packet_count %d\n", packet_count) ;
	psf_log_printf (psf, "page_nb_packets %d\n", page_nb_packets) ;
	psf_log_printf (psf, "page_granule %lld\n", page_granule) ;

	return 0 ;
} /* spx_read_header */
예제 #10
0
static sf_count_t
vorbis_read_sample (SF_PRIVATE *psf, void *ptr, sf_count_t lens, convert_func *transfn)
{	VORBIS_PRIVATE *vdata = psf->codec_data ;
	OGG_PRIVATE *odata = psf->container_data ;
	int len, samples, i = 0 ;
	float **pcm ;

	len = lens / psf->sf.channels ;

	while ((samples = vorbis_synthesis_pcmout (&vdata->vdsp, &pcm)) > 0)
	{	if (samples > len) samples = len ;
		i += transfn (psf, samples, ptr, i, psf->sf.channels, pcm) ;
		len -= samples ;
		/* tell libvorbis how many samples we actually consumed */
		vorbis_synthesis_read (&vdata->vdsp, samples) ;
		vdata->loc += samples ;
		if (len == 0)
			return i ; /* Is this necessary */
	}
	goto start0 ;		/* Jump into the nasty nest */
	while (len > 0 && !odata->eos)
	{	while (len > 0 && !odata->eos)
		{	int result = ogg_sync_pageout (&odata->osync, &odata->opage) ;
			if (result == 0) break ; /* need more data */
			if (result < 0)
			{	/* missing or corrupt data at this page position */
				psf_log_printf (psf, "Corrupt or missing data in bitstream ; continuing...\n") ;
			}
			else
			{	/* can safely ignore errors at this point */
				ogg_stream_pagein (&odata->ostream, &odata->opage) ;
start0:
				while (1)
				{	result = ogg_stream_packetout (&odata->ostream, &odata->opacket) ;
					if (result == 0)
						break ; /* need more data */
					if (result < 0)
					{	/* missing or corrupt data at this page position */
						/* no reason to complain ; already complained above */
					}
					else
					{	/* we have a packet.	Decode it */
						if (vorbis_synthesis (&vdata->vblock, &odata->opacket) == 0) /* test for success! */
							vorbis_synthesis_blockin (&vdata->vdsp, &vdata->vblock) ;
						/*
						** pcm is a multichannel float vector.	 In stereo, for
						** example, pcm [0] is left, and pcm [1] is right.	 samples is
						** the size of each channel.	 Convert the float values
						** (-1.<=range<=1.) to whatever PCM format and write it out.
						*/

						while ((samples = vorbis_synthesis_pcmout (&vdata->vdsp, &pcm)) > 0)
						{	if (samples > len) samples = len ;
							i += transfn (psf, samples, ptr, i, psf->sf.channels, pcm) ;
							len -= samples ;
							/* tell libvorbis how many samples we actually consumed */
							vorbis_synthesis_read (&vdata->vdsp, samples) ;
							vdata->loc += samples ;
							if (len == 0)
								return i ; /* Is this necessary */
						} ;
					}
				}
				if (ogg_page_eos (&odata->opage)) odata->eos = 1 ;
			}
		}
		if (!odata->eos)
		{	char *buffer ;
			int bytes ;
			buffer = ogg_sync_buffer (&odata->osync, 4096) ;
			bytes = psf_fread (buffer, 1, 4096, psf) ;
			ogg_sync_wrote (&odata->osync, bytes) ;
			if (bytes == 0) odata->eos = 1 ;
		}
	}
	return i ;
} /* vorbis_read_sample */
예제 #11
0
static int
vorbis_read_header (SF_PRIVATE *psf, int log_data)
{	OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
	VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
	char *buffer ;
	int	bytes ;
	int i, nn ;

	odata->eos = 0 ;

	/* Weird stuff happens if these aren't called. */
	ogg_stream_reset (&odata->ostream) ;
	ogg_sync_reset (&odata->osync) ;

	/*
	**	Grab some data at the head of the stream.  We want the first page
	**	(which is guaranteed to be small and only contain the Vorbis
	**	stream initial header) We need the first page to get the stream
	**	serialno.
	*/

	/* Expose the buffer */
	buffer = ogg_sync_buffer (&odata->osync, 4096L) ;

	/* Grab the part of the header that has already been read. */
	memcpy (buffer, psf->header, psf->headindex) ;
	bytes = psf->headindex ;

	/* Submit a 4k block to libvorbis' Ogg layer */
	bytes += psf_fread (buffer + psf->headindex, 1, 4096 - psf->headindex, psf) ;
	ogg_sync_wrote (&odata->osync, bytes) ;

	/* Get the first page. */
	if ((nn = ogg_sync_pageout (&odata->osync, &odata->opage)) != 1)
	{	/* Have we simply run out of data?  If so, we're done. */
		if (bytes < 4096)
			return 0 ;

		/* Error case.  Must not be Vorbis data */
		psf_log_printf (psf, "Input does not appear to be an Ogg bitstream.\n") ;
		return SFE_MALFORMED_FILE ;
	} ;

	/*
	**	Get the serial number and set up the rest of decode.
	**	Serialno first ; use it to set up a logical stream.
	*/
	ogg_stream_clear (&odata->ostream) ;
	ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ;

	if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0)
	{	/* Error ; stream version mismatch perhaps. */
		psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ;
		return SFE_MALFORMED_FILE ;
	} ;

	if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1)
	{	/* No page? must not be vorbis. */
		psf_log_printf (psf, "Error reading initial header packet.\n") ;
		return SFE_MALFORMED_FILE ;
	} ;

	/*
	**	This function (vorbis_read_header) gets called multiple times, so the OGG
	**	and vorbis structs have to be cleared every time we pass through to
	**	prevent memory leaks.
	*/
	vorbis_block_clear (&vdata->vblock) ;
	vorbis_dsp_clear (&vdata->vdsp) ;
	vorbis_comment_clear (&vdata->vcomment) ;
	vorbis_info_clear (&vdata->vinfo) ;

	/*
	**	Extract the initial header from the first page and verify that the
	**	Ogg bitstream is in fact Vorbis data.
	**
	**	I handle the initial header first instead of just having the code
	**	read all three Vorbis headers at once because reading the initial
	**	header is an easy way to identify a Vorbis bitstream and it's
	**	useful to see that functionality seperated out.
	*/
	vorbis_info_init (&vdata->vinfo) ;
	vorbis_comment_init (&vdata->vcomment) ;

	if (vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) < 0)
	{	/* Error case ; not a vorbis header. */
		psf_log_printf (psf, "Found Vorbis in stream header, but vorbis_synthesis_headerin failed.\n") ;
		return SFE_MALFORMED_FILE ;
	} ;

	/*
	**	Common Ogg metadata fields?
	**	TITLE, VERSION, ALBUM, TRACKNUMBER, ARTIST, PERFORMER, COPYRIGHT, LICENSE,
	**	ORGANIZATION, DESCRIPTION, GENRE, DATE, LOCATION, CONTACT, ISRC,
	*/

	if (log_data)
	{	int k ;

		for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++)
		{	char *dd ;

			dd = vorbis_comment_query (&vdata->vcomment, vorbis_metatypes [k].name, 0) ;
			if (dd == NULL)
				continue ;
			psf_store_string (psf, vorbis_metatypes [k].id, dd) ;
		} ;
	} ;

	/*
	**	At this point, we're sure we're Vorbis.	We've set up the logical (Ogg)
	**	bitstream decoder. Get the comment and codebook headers and set up the
	**	Vorbis decoder.
	**
	**	The next two packets in order are the comment and codebook headers.
	**	They're likely large and may span multiple pages.  Thus we reead
	**	and submit data until we get our two pacakets, watching that no
	**	pages are missing.  If a page is missing, error out ; losing a
	**	header page is the only place where missing data is fatal.
	*/

	i = 0 ;			/* Count of number of packets read */
	while (i < 2)
	{	int result = ogg_sync_pageout (&odata->osync, &odata->opage) ;
		if (result == 0)
		{	/* Need more data */
			buffer = ogg_sync_buffer (&odata->osync, 4096) ;
			bytes = psf_fread (buffer, 1, 4096, psf) ;

			if (bytes == 0 && i < 2)
			{	psf_log_printf (psf, "End of file before finding all Vorbis headers!\n") ;
				return SFE_MALFORMED_FILE ;
			} ;
			nn = ogg_sync_wrote (&odata->osync, bytes) ;
		}
		else if (result == 1)
		{	/*
			**	Don't complain about missing or corrupt data yet. We'll
			**	catch it at the packet output phase.
			**
			**	We can ignore any errors here as they'll also become apparent
			**	at packetout.
			*/
			nn = ogg_stream_pagein (&odata->ostream, &odata->opage) ;
			while (i < 2)
			{	result = ogg_stream_packetout (&odata->ostream, &odata->opacket) ;
				if (result == 0)
					break ;
				if (result < 0)
				{	/*	Uh oh ; data at some point was corrupted or missing!
					**	We can't tolerate that in a header. Die. */
					psf_log_printf (psf, "Corrupt secondary header.	Exiting.\n") ;
					return SFE_MALFORMED_FILE ;
				} ;

				vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) ;
				i++ ;
			} ;
		} ;
	} ;

	if (log_data)
	{	int printed_metadata_msg = 0 ;
		int k ;

		psf_log_printf (psf, "Bitstream is %d channel, %D Hz\n", vdata->vinfo.channels, vdata->vinfo.rate) ;
		psf_log_printf (psf, "Encoded by : %s\n", vdata->vcomment.vendor) ;

		/* Throw the comments plus a few lines about the bitstream we're decoding. */
		for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++)
		{	char *dd ;

			dd = vorbis_comment_query (&vdata->vcomment, vorbis_metatypes [k].name, 0) ;
			if (dd == NULL)
				continue ;

			if (printed_metadata_msg == 0)
			{	psf_log_printf (psf, "Metadata :\n") ;
				printed_metadata_msg = 1 ;
			} ;

			psf_store_string (psf, vorbis_metatypes [k].id, dd) ;
			psf_log_printf (psf, "  %-10s : %s\n", vorbis_metatypes [k].name, dd) ;
		} ;

		psf_log_printf (psf, "End\n") ;
	} ;

	psf->sf.samplerate	= vdata->vinfo.rate ;
	psf->sf.channels	= vdata->vinfo.channels ;
	psf->sf.format		= SF_FORMAT_OGG | SF_FORMAT_VORBIS ;

	/*	OK, got and parsed all three headers. Initialize the Vorbis
	**	packet->PCM decoder.
	**	Central decode state. */
	vorbis_synthesis_init (&vdata->vdsp, &vdata->vinfo) ;

	/*	Local state for most of the decode so multiple block decodes can
	**	proceed in parallel. We could init multiple vorbis_block structures
	**	for vd here. */
	vorbis_block_init (&vdata->vdsp, &vdata->vblock) ;

	vdata->loc = 0 ;

	return 0 ;
} /* vorbis_read_header */
예제 #12
0
파일: ogg.c 프로젝트: 5in4/libsox.dll
static int
ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE* odata)
{	char *buffer ;
	int	 bytes, nn ;

	/* Call this here so it only gets called once, so no memory is leaked. */
	ogg_sync_init (&odata->osync) ;

	odata->eos = 0 ;

	/* Weird stuff happens if these aren't called. */
	ogg_stream_reset (&odata->ostream) ;
	ogg_sync_reset (&odata->osync) ;

	/*
	**	Grab some data at the head of the stream.  We want the first page
	**	(which is guaranteed to be small and only contain the Vorbis
	**	stream initial header) We need the first page to get the stream
	**	serialno.
	*/

	/* Expose the buffer */
	buffer = ogg_sync_buffer (&odata->osync, 4096L) ;

	/* Grab the part of the header that has already been read. */
	memcpy (buffer, psf->header, psf->headindex) ;
	bytes = psf->headindex ;

	/* Submit a 4k block to libvorbis' Ogg layer */
	bytes += psf_fread (buffer + psf->headindex, 1, 4096 - psf->headindex, psf) ;
	ogg_sync_wrote (&odata->osync, bytes) ;

	/* Get the first page. */
	if ((nn = ogg_sync_pageout (&odata->osync, &odata->opage)) != 1)
	{
		/* Have we simply run out of data?  If so, we're done. */
		if (bytes < 4096)
			return 0 ;

		/* Error case.  Must not be Vorbis data */
		psf_log_printf (psf, "Input does not appear to be an Ogg bitstream.\n") ;
		return SFE_MALFORMED_FILE ;
		} ;

	/*
	**	Get the serial number and set up the rest of decode.
	**	Serialno first ; use it to set up a logical stream.
	*/
	ogg_stream_clear (&odata->ostream) ;
	ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ;

	if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0)
	{	/* Error ; stream version mismatch perhaps. */
		psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ;
		return SFE_MALFORMED_FILE ;
		} ;

	if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1)
	{	/* No page? must not be vorbis. */
		psf_log_printf (psf, "Error reading initial header packet.\n") ;
		return SFE_MALFORMED_FILE ;
		} ;

	odata->codec = ogg_page_classify (psf, &odata->opage) ;

	switch (odata->codec)
	{	case OGG_VORBIS :
			psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ;
			return 0 ;

		case OGG_FLAC :
		case OGG_FLAC0 :
			psf->sf.format = SF_FORMAT_OGGFLAC ;
			return 0 ;

		case OGG_SPEEX :
			psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ;
			return 0 ;

		case OGG_PCM :
			psf_log_printf (psf, "Detected Ogg/PCM data. This is not supported yet.\n") ;
			return SFE_UNIMPLEMENTED ;

		default :
			break ;
		} ;

	psf_log_printf (psf, "This Ogg bitstream contains some uknown data type.\n") ;
	return SFE_UNIMPLEMENTED ;
} /* ogg_stream_classify */