mirror of
https://github.com/claunia/flac.git
synced 2025-12-16 18:54:26 +00:00
140 lines
4.8 KiB
C
140 lines
4.8 KiB
C
/* libOggFLAC - Free Lossless Audio Codec + Ogg library
|
|
* Copyright (C) 2002,2003 Josh Coalson
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* - Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* - Neither the name of the Xiph.org Foundation nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <string.h> /* for memcpy() */
|
|
#include "FLAC/assert.h"
|
|
#include "private/ogg_decoder_aspect.h"
|
|
|
|
#ifdef min
|
|
#undef min
|
|
#endif
|
|
#define min(x,y) ((x)<(y)?(x):(y))
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Public class methods
|
|
*
|
|
***********************************************************************/
|
|
|
|
FLAC__bool OggFLAC__ogg_decoder_aspect_init(OggFLAC__OggDecoderAspect *aspect)
|
|
{
|
|
aspect->need_serial_number = aspect->use_first_serial_number;
|
|
|
|
/* we will determine the serial number later if necessary */
|
|
if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0)
|
|
return false;
|
|
|
|
if(ogg_sync_init(&aspect->sync_state) != 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void OggFLAC__ogg_decoder_aspect_finish(OggFLAC__OggDecoderAspect *aspect)
|
|
{
|
|
(void)ogg_sync_clear(&aspect->sync_state);
|
|
(void)ogg_stream_clear(&aspect->stream_state);
|
|
}
|
|
|
|
void OggFLAC__ogg_decoder_aspect_set_serial_number(OggFLAC__OggDecoderAspect *aspect, long value)
|
|
{
|
|
aspect->use_first_serial_number = false;
|
|
aspect->serial_number = value;
|
|
}
|
|
|
|
void OggFLAC__ogg_decoder_aspect_set_defaults(OggFLAC__OggDecoderAspect *aspect)
|
|
{
|
|
aspect->use_first_serial_number = true;
|
|
}
|
|
|
|
void OggFLAC__ogg_decoder_aspect_flush(OggFLAC__OggDecoderAspect *aspect)
|
|
{
|
|
(void)ogg_sync_clear(&aspect->sync_state);
|
|
}
|
|
|
|
OggFLAC__OggDecoderAspectReadStatus OggFLAC__ogg_decoder_aspect_read_callback_wrapper(OggFLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], unsigned *bytes, OggFLAC__OggDecoderAspectReadCallbackProxy read_callback, void *decoder, void *client_data)
|
|
{
|
|
static const unsigned OGG_BYTES_CHUNK = 8192;
|
|
unsigned ogg_bytes_to_read, ogg_bytes_read;
|
|
ogg_page page;
|
|
char *oggbuf;
|
|
|
|
/*
|
|
* We have to be careful not to read in more than the
|
|
* FLAC__StreamDecoder says it has room for. We know
|
|
* that the size of the decoded data must be no more
|
|
* than the encoded data we will read.
|
|
*/
|
|
ogg_bytes_to_read = min(*bytes, OGG_BYTES_CHUNK);
|
|
oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read);
|
|
|
|
if(0 == oggbuf)
|
|
return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
|
|
|
|
ogg_bytes_read = ogg_bytes_to_read;
|
|
|
|
switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) {
|
|
case FLAC__STREAM_DECODER_READ_STATUS_CONTINUE:
|
|
break;
|
|
case FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM:
|
|
return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
|
|
case FLAC__STREAM_DECODER_READ_STATUS_ABORT:
|
|
return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
|
|
default:
|
|
FLAC__ASSERT(0);
|
|
}
|
|
|
|
if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0)
|
|
return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
|
|
|
|
*bytes = 0;
|
|
while(ogg_sync_pageout(&aspect->sync_state, &page) == 1) {
|
|
/* grab the serial number if necessary */
|
|
if(aspect->need_serial_number) {
|
|
aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&page);
|
|
aspect->need_serial_number = false;
|
|
}
|
|
if(ogg_stream_pagein(&aspect->stream_state, &page) == 0) {
|
|
ogg_packet packet;
|
|
|
|
while(ogg_stream_packetout(&aspect->stream_state, &packet) == 1) {
|
|
memcpy(buffer, packet.packet, packet.bytes);
|
|
*bytes += packet.bytes;
|
|
buffer += packet.bytes;
|
|
}
|
|
} else {
|
|
return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
|
|
}
|
|
}
|
|
|
|
return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
|
|
}
|