Home | History | Annotate | Download | only in libFLAC
      1 /* libFLAC - Free Lossless Audio Codec
      2  * Copyright (C) 2002,2003,2004,2005,2006,2007  Josh Coalson
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * - Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *
     11  * - Redistributions in binary form must reproduce the above copyright
     12  * notice, this list of conditions and the following disclaimer in the
     13  * documentation and/or other materials provided with the distribution.
     14  *
     15  * - Neither the name of the Xiph.org Foundation nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
     23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #if HAVE_CONFIG_H
     33 #  include <config.h>
     34 #endif
     35 
     36 #include <string.h> /* for memcpy() */
     37 #include "FLAC/assert.h"
     38 #include "private/ogg_decoder_aspect.h"
     39 #include "private/ogg_mapping.h"
     40 
     41 #ifdef max
     42 #undef max
     43 #endif
     44 #define max(x,y) ((x)>(y)?(x):(y))
     45 
     46 /***********************************************************************
     47  *
     48  * Public class methods
     49  *
     50  ***********************************************************************/
     51 
     52 FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect)
     53 {
     54 	/* we will determine the serial number later if necessary */
     55 	if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0)
     56 		return false;
     57 
     58 	if(ogg_sync_init(&aspect->sync_state) != 0)
     59 		return false;
     60 
     61 	aspect->version_major = ~(0u);
     62 	aspect->version_minor = ~(0u);
     63 
     64 	aspect->need_serial_number = aspect->use_first_serial_number;
     65 
     66 	aspect->end_of_stream = false;
     67 	aspect->have_working_page = false;
     68 
     69 	return true;
     70 }
     71 
     72 void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect)
     73 {
     74 	(void)ogg_sync_clear(&aspect->sync_state);
     75 	(void)ogg_stream_clear(&aspect->stream_state);
     76 }
     77 
     78 void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value)
     79 {
     80 	aspect->use_first_serial_number = false;
     81 	aspect->serial_number = value;
     82 }
     83 
     84 void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect)
     85 {
     86 	aspect->use_first_serial_number = true;
     87 }
     88 
     89 void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect)
     90 {
     91 	(void)ogg_stream_reset(&aspect->stream_state);
     92 	(void)ogg_sync_reset(&aspect->sync_state);
     93 	aspect->end_of_stream = false;
     94 	aspect->have_working_page = false;
     95 }
     96 
     97 void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect)
     98 {
     99 	FLAC__ogg_decoder_aspect_flush(aspect);
    100 
    101 	if(aspect->use_first_serial_number)
    102 		aspect->need_serial_number = true;
    103 }
    104 
    105 FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data)
    106 {
    107 	static const size_t OGG_BYTES_CHUNK = 8192;
    108 	const size_t bytes_requested = *bytes;
    109 
    110 	/*
    111 	 * The FLAC decoding API uses pull-based reads, whereas Ogg decoding
    112 	 * is push-based.  In libFLAC, when you ask to decode a frame, the
    113 	 * decoder will eventually call the read callback to supply some data,
    114 	 * but how much it asks for depends on how much free space it has in
    115 	 * its internal buffer.  It does not try to grow its internal buffer
    116 	 * to accomodate a whole frame because then the internal buffer size
    117 	 * could not be limited, which is necessary in embedded applications.
    118 	 *
    119 	 * Ogg however grows its internal buffer until a whole page is present;
    120 	 * only then can you get decoded data out.  So we can't just ask for
    121 	 * the same number of bytes from Ogg, then pass what's decoded down to
    122 	 * libFLAC.  If what libFLAC is asking for will not contain a whole
    123 	 * page, then we will get no data from ogg_sync_pageout(), and at the
    124 	 * same time cannot just read more data from the client for the purpose
    125 	 * of getting a whole decoded page because the decoded size might be
    126 	 * larger than libFLAC's internal buffer.
    127 	 *
    128 	 * Instead, whenever this read callback wrapper is called, we will
    129 	 * continually request data from the client until we have at least one
    130 	 * page, and manage pages internally so that we can send pieces of
    131 	 * pages down to libFLAC in such a way that we obey its size
    132 	 * requirement.  To limit the amount of callbacks, we will always try
    133 	 * to read in enough pages to return the full number of bytes
    134 	 * requested.
    135 	 */
    136 	*bytes = 0;
    137 	while (*bytes < bytes_requested && !aspect->end_of_stream) {
    138 		if (aspect->have_working_page) {
    139 			if (aspect->have_working_packet) {
    140 				size_t n = bytes_requested - *bytes;
    141 				if ((size_t)aspect->working_packet.bytes <= n) {
    142 					/* the rest of the packet will fit in the buffer */
    143 					n = aspect->working_packet.bytes;
    144 					memcpy(buffer, aspect->working_packet.packet, n);
    145 					*bytes += n;
    146 					buffer += n;
    147 					aspect->have_working_packet = false;
    148 				}
    149 				else {
    150 					/* only n bytes of the packet will fit in the buffer */
    151 					memcpy(buffer, aspect->working_packet.packet, n);
    152 					*bytes += n;
    153 					buffer += n;
    154 					aspect->working_packet.packet += n;
    155 					aspect->working_packet.bytes -= n;
    156 				}
    157 			}
    158 			else {
    159 				/* try and get another packet */
    160 				const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet);
    161 				if (ret > 0) {
    162 					aspect->have_working_packet = true;
    163 					/* if it is the first header packet, check for magic and a supported Ogg FLAC mapping version */
    164 					if (aspect->working_packet.bytes > 0 && aspect->working_packet.packet[0] == FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE) {
    165 						const FLAC__byte *b = aspect->working_packet.packet;
    166 						const unsigned header_length =
    167 							FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
    168 							FLAC__OGG_MAPPING_MAGIC_LENGTH +
    169 							FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
    170 							FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
    171 							FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH;
    172 						if (aspect->working_packet.bytes < (long)header_length)
    173 							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
    174 						b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH;
    175 						if (memcmp(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH))
    176 							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
    177 						b += FLAC__OGG_MAPPING_MAGIC_LENGTH;
    178 						aspect->version_major = (unsigned)(*b);
    179 						b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
    180 						aspect->version_minor = (unsigned)(*b);
    181 						if (aspect->version_major != 1)
    182 							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION;
    183 						aspect->working_packet.packet += header_length;
    184 						aspect->working_packet.bytes -= header_length;
    185 					}
    186 				}
    187 				else if (ret == 0) {
    188 					aspect->have_working_page = false;
    189 				}
    190 				else { /* ret < 0 */
    191 					/* lost sync, we'll leave the working page for the next call */
    192 					return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
    193 				}
    194 			}
    195 		}
    196 		else {
    197 			/* try and get another page */
    198 			const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page);
    199 			if (ret > 0) {
    200 				/* got a page, grab the serial number if necessary */
    201 				if(aspect->need_serial_number) {
    202 					aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&aspect->working_page);
    203 					aspect->need_serial_number = false;
    204 				}
    205 				if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) {
    206 					aspect->have_working_page = true;
    207 					aspect->have_working_packet = false;
    208 				}
    209 				/* else do nothing, could be a page from another stream */
    210 			}
    211 			else if (ret == 0) {
    212 				/* need more data */
    213 				const size_t ogg_bytes_to_read = max(bytes_requested - *bytes, OGG_BYTES_CHUNK);
    214 				char *oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read);
    215 
    216 				if(0 == oggbuf) {
    217 					return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
    218 				}
    219 				else {
    220 					size_t ogg_bytes_read = ogg_bytes_to_read;
    221 
    222 					switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) {
    223 						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK:
    224 							break;
    225 						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM:
    226 							aspect->end_of_stream = true;
    227 							break;
    228 						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT:
    229 							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
    230 						default:
    231 							FLAC__ASSERT(0);
    232 					}
    233 
    234 					if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0) {
    235 						/* double protection; this will happen if the read callback returns more bytes than the max requested, which would overflow Ogg's internal buffer */
    236 						FLAC__ASSERT(0);
    237 						return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
    238 					}
    239 				}
    240 			}
    241 			else { /* ret < 0 */
    242 				/* lost sync, bail out */
    243 				return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
    244 			}
    245 		}
    246 	}
    247 
    248 	if (aspect->end_of_stream && *bytes == 0) {
    249 		return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
    250 	}
    251 
    252 	return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
    253 }
    254