diff options
author | ftrvxmtrx <ftrvxmtrx@gmail.com> | 2016-03-05 10:32:47 +0100 |
---|---|---|
committer | ftrvxmtrx <ftrvxmtrx@gmail.com> | 2016-03-05 10:32:47 +0100 |
commit | 2d2ffac86f788ac6bed73d873f837bbd9849a2e4 (patch) | |
tree | b3a2b7ebf1491b6a8ca9cc1b2eb059c51cf39d86 /sys/src/cmd | |
parent | 897da507f4efdf67afb3b589cb9240fe217545af (diff) |
libFLAC: update to 1.3.1
Diffstat (limited to 'sys/src/cmd')
72 files changed, 15891 insertions, 12809 deletions
diff --git a/sys/src/cmd/audio/flacdec/flacdec.c b/sys/src/cmd/audio/flacdec/flacdec.c index f2a530db7..b397279f1 100644 --- a/sys/src/cmd/audio/flacdec/flacdec.c +++ b/sys/src/cmd/audio/flacdec/flacdec.c @@ -8,18 +8,18 @@ static int ifd = -1; static int sts; static FLAC__StreamDecoderReadStatus -decinput(FLAC__StreamDecoder *dec, FLAC__byte buffer[], unsigned *bytes, void *client_data) +decinput(FLAC__StreamDecoder *dec, FLAC__byte buffer[], size_t *bytes, void *client_data) { int n = *bytes; - n = fread(buffer,1,n,stdin); - if(n <= 0){ - *bytes = 0; + n = fread(buffer, 1, n, stdin); + if(n < 0) + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + if(n == 0) return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - } else { - *bytes = n; - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - } + + *bytes = n; + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } static FLAC__StreamDecoderWriteStatus @@ -111,22 +111,13 @@ decerror(FLAC__StreamDecoder *dec, FLAC__StreamDecoderErrorStatus status, void * { } -static void -decmeta(FLAC__StreamDecoder *dec, FLAC__StreamMetadata *metadata, void *client_data) -{ -} - int main(int argc, char *argv[]) { FLAC__bool ok = true; FLAC__StreamDecoder *dec = 0; dec = FLAC__stream_decoder_new(); - FLAC__stream_decoder_set_read_callback(dec, decinput); - FLAC__stream_decoder_set_write_callback(dec, decoutput); - FLAC__stream_decoder_set_error_callback(dec, decerror); - FLAC__stream_decoder_set_metadata_callback(dec, decmeta); - FLAC__stream_decoder_init(dec); + FLAC__stream_decoder_init_stream(dec, decinput, NULL, NULL, NULL, NULL, decoutput, NULL, decerror, NULL); FLAC__stream_decoder_process_until_end_of_stream(dec); FLAC__stream_decoder_finish(dec); diff --git a/sys/src/cmd/audio/libFLAC/FLAC/all.h b/sys/src/cmd/audio/libFLAC/FLAC/all.h index 3f750e3ef..2851cf59c 100644 --- a/sys/src/cmd/audio/libFLAC/FLAC/all.h +++ b/sys/src/cmd/audio/libFLAC/FLAC/all.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,13 +37,9 @@ #include "assert.h" #include "callback.h" -#include "file_decoder.h" -#include "file_encoder.h" #include "format.h" #include "metadata.h" #include "ordinals.h" -#include "seekable_stream_decoder.h" -#include "seekable_stream_encoder.h" #include "stream_decoder.h" #include "stream_encoder.h" @@ -63,7 +60,7 @@ * describing the components of FLAC streams, and functions for * encoding and decoding streams, as well as manipulating FLAC * metadata in files. The public include files will be installed - * in your include area as <include>/FLAC/... + * in your include area (for example /usr/include/FLAC/...). * * By writing a little code and linking against libFLAC, it is * relatively easy to add FLAC support to another program. The @@ -84,11 +81,9 @@ * dependency on a thread library. However, libFLAC does not use * global variables and should be thread-safe. * - * There is also a new libOggFLAC library which wraps around libFLAC - * to provide routines for encoding to and decoding from FLAC streams - * inside an Ogg container. The interfaces are very similar or identical - * to their counterparts in libFLAC. libOggFLAC is also licensed under - * <A HREF="../license.html">Xiph's BSD license</A>. + * libFLAC also supports encoding to and decoding from Ogg FLAC. + * However the metadata editing interfaces currently have limited + * read-only support for Ogg FLAC files. * * \section cpp_api FLAC C++ API * @@ -98,14 +93,10 @@ * equivalent. For the most part, they share the same usage as * their counterparts in libFLAC, and the FLAC C API documentation * can be used as a supplement. The public include files - * for the C++ API will be installed in your include area as - * <include>/FLAC++/... - * - * There is also a new libOggFLAC++ library, which provides classes - * for encoding to and decoding from FLAC streams in an Ogg container. - * The classes are very similar to their counterparts in libFLAC++. + * for the C++ API will be installed in your include area (for + * example /usr/include/FLAC++/...). * - * Both libFLAC++ libOggFLAC++ are also licensed under + * libFLAC++ is also licensed under * <A HREF="../license.html">Xiph's BSD license</A>. * * \section getting_started Getting Started @@ -121,6 +112,15 @@ * individual functions. You can see different views of the individual * functions through the links in top bar across this page. * + * If you prefer a more hands-on approach, you can jump right to some + * <A HREF="../documentation_example_code.html">example code</A>. + * + * \section porting_guide Porting Guide + * + * Starting with FLAC 1.1.3 a \link porting Porting Guide \endlink + * has been introduced which gives detailed instructions on how to + * port your code to newer versions of FLAC. + * * \section embedded_developers Embedded Developers * * libFLAC has grown larger over time as more functionality has been @@ -132,16 +132,229 @@ * It is easiest to just describe the dependencies: * * - All modules depend on the \link flac_format Format \endlink module. - * - The decoders and encoders are independent of each other. - * - The metadata interface requires the file decoder. - * - The decoder and encoder layers depend on the layers below them, but - * not above them; e.g. the seekable stream decoder depends on the stream - * decoder but not the file decoder + * - The decoders and encoders depend on the bitbuffer. + * - The decoder is independent of the encoder. The encoder uses the + * decoder because of the verify feature, but this can be removed if + * not needed. + * - Parts of the metadata interface require the stream decoder (but not + * the encoder). + * - Ogg support is selectable through the compile time macro + * \c FLAC__HAS_OGG. * * For example, if your application only requires the stream decoder, no - * encoders, and no metadata interface, you can remove the seekable stream - * decoder, file decoder, all encoders, and the metadata interface, which - * will greatly reduce the size of the library. + * encoder, and no metadata interface, you can remove the stream encoder + * and the metadata interface, which will greatly reduce the size of the + * library. + * + * Also, there are several places in the libFLAC code with comments marked + * with "OPT:" where a #define can be changed to enable code that might be + * faster on a specific platform. Experimenting with these can yield faster + * binaries. + */ + +/** \defgroup porting Porting Guide for New Versions + * + * This module describes differences in the library interfaces from + * version to version. It assists in the porting of code that uses + * the libraries to newer versions of FLAC. + * + * One simple facility for making porting easier that has been added + * in FLAC 1.1.3 is a set of \c #defines in \c export.h of each + * library's includes (e.g. \c include/FLAC/export.h). The + * \c #defines mirror the libraries' + * <A HREF="http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning">libtool version numbers</A>, + * e.g. in libFLAC there are \c FLAC_API_VERSION_CURRENT, + * \c FLAC_API_VERSION_REVISION, and \c FLAC_API_VERSION_AGE. + * These can be used to support multiple versions of an API during the + * transition phase, e.g. + * + * \code + * #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7 + * legacy code + * #else + * new code + * #endif + * \endcode + * + * The the source will work for multiple versions and the legacy code can + * easily be removed when the transition is complete. + * + * Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in + * include/FLAC/export.h), which can be used to determine whether or not + * the library has been compiled with support for Ogg FLAC. This is + * simpler than trying to call an Ogg init function and catching the + * error. + */ + +/** \defgroup porting_1_1_2_to_1_1_3 Porting from FLAC 1.1.2 to 1.1.3 + * \ingroup porting + * + * \brief + * This module describes porting from FLAC 1.1.2 to FLAC 1.1.3. + * + * The main change between the APIs in 1.1.2 and 1.1.3 is that they have + * been simplified. First, libOggFLAC has been merged into libFLAC and + * libOggFLAC++ has been merged into libFLAC++. Second, both the three + * decoding layers and three encoding layers have been merged into a + * single stream decoder and stream encoder. That is, the functionality + * of FLAC__SeekableStreamDecoder and FLAC__FileDecoder has been merged + * into FLAC__StreamDecoder, and FLAC__SeekableStreamEncoder and + * FLAC__FileEncoder into FLAC__StreamEncoder. Only the + * FLAC__StreamDecoder and FLAC__StreamEncoder remain. What this means + * is there is now a single API that can be used to encode or decode + * streams to/from native FLAC or Ogg FLAC and the single API can work + * on both seekable and non-seekable streams. + * + * Instead of creating an encoder or decoder of a certain layer, now the + * client will always create a FLAC__StreamEncoder or + * FLAC__StreamDecoder. The old layers are now differentiated by the + * initialization function. For example, for the decoder, + * FLAC__stream_decoder_init() has been replaced by + * FLAC__stream_decoder_init_stream(). This init function takes + * callbacks for the I/O, and the seeking callbacks are optional. This + * allows the client to use the same object for seekable and + * non-seekable streams. For decoding a FLAC file directly, the client + * can use FLAC__stream_decoder_init_file() and pass just a filename + * and fewer callbacks; most of the other callbacks are supplied + * internally. For situations where fopen()ing by filename is not + * possible (e.g. Unicode filenames on Windows) the client can instead + * open the file itself and supply the FILE* to + * FLAC__stream_decoder_init_FILE(). The init functions now returns a + * FLAC__StreamDecoderInitStatus instead of FLAC__StreamDecoderState. + * Since the callbacks and client data are now passed to the init + * function, the FLAC__stream_decoder_set_*_callback() functions and + * FLAC__stream_decoder_set_client_data() are no longer needed. The + * rest of the calls to the decoder are the same as before. + * + * There are counterpart init functions for Ogg FLAC, e.g. + * FLAC__stream_decoder_init_ogg_stream(). All the rest of the calls + * and callbacks are the same as for native FLAC. + * + * As an example, in FLAC 1.1.2 a seekable stream decoder would have + * been set up like so: + * + * \code + * FLAC__SeekableStreamDecoder *decoder = FLAC__seekable_stream_decoder_new(); + * if(decoder == NULL) do_something; + * FLAC__seekable_stream_decoder_set_md5_checking(decoder, true); + * [... other settings ...] + * FLAC__seekable_stream_decoder_set_read_callback(decoder, my_read_callback); + * FLAC__seekable_stream_decoder_set_seek_callback(decoder, my_seek_callback); + * FLAC__seekable_stream_decoder_set_tell_callback(decoder, my_tell_callback); + * FLAC__seekable_stream_decoder_set_length_callback(decoder, my_length_callback); + * FLAC__seekable_stream_decoder_set_eof_callback(decoder, my_eof_callback); + * FLAC__seekable_stream_decoder_set_write_callback(decoder, my_write_callback); + * FLAC__seekable_stream_decoder_set_metadata_callback(decoder, my_metadata_callback); + * FLAC__seekable_stream_decoder_set_error_callback(decoder, my_error_callback); + * FLAC__seekable_stream_decoder_set_client_data(decoder, my_client_data); + * if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) do_something; + * \endcode + * + * In FLAC 1.1.3 it is like this: + * + * \code + * FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new(); + * if(decoder == NULL) do_something; + * FLAC__stream_decoder_set_md5_checking(decoder, true); + * [... other settings ...] + * if(FLAC__stream_decoder_init_stream( + * decoder, + * my_read_callback, + * my_seek_callback, // or NULL + * my_tell_callback, // or NULL + * my_length_callback, // or NULL + * my_eof_callback, // or NULL + * my_write_callback, + * my_metadata_callback, // or NULL + * my_error_callback, + * my_client_data + * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; + * \endcode + * + * or you could do; + * + * \code + * [...] + * FILE *file = fopen("somefile.flac","rb"); + * if(file == NULL) do_somthing; + * if(FLAC__stream_decoder_init_FILE( + * decoder, + * file, + * my_write_callback, + * my_metadata_callback, // or NULL + * my_error_callback, + * my_client_data + * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; + * \endcode + * + * or just: + * + * \code + * [...] + * if(FLAC__stream_decoder_init_file( + * decoder, + * "somefile.flac", + * my_write_callback, + * my_metadata_callback, // or NULL + * my_error_callback, + * my_client_data + * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; + * \endcode + * + * Another small change to the decoder is in how it handles unparseable + * streams. Before, when the decoder found an unparseable stream + * (reserved for when the decoder encounters a stream from a future + * encoder that it can't parse), it changed the state to + * \c FLAC__STREAM_DECODER_UNPARSEABLE_STREAM. Now the decoder instead + * drops sync and calls the error callback with a new error code + * \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM. This is + * more robust. If your error callback does not discriminate on the the + * error state, your code does not need to be changed. + * + * The encoder now has a new setting: + * FLAC__stream_encoder_set_apodization(). This is for setting the + * method used to window the data before LPC analysis. You only need to + * add a call to this function if the default is not suitable. There + * are also two new convenience functions that may be useful: + * FLAC__metadata_object_cuesheet_calculate_cddb_id() and + * FLAC__metadata_get_cuesheet(). + * + * The \a bytes parameter to FLAC__StreamDecoderReadCallback, + * FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback + * is now \c size_t instead of \c unsigned. + */ + +/** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4 + * \ingroup porting + * + * \brief + * This module describes porting from FLAC 1.1.3 to FLAC 1.1.4. + * + * There were no changes to any of the interfaces from 1.1.3 to 1.1.4. + * There was a slight change in the implementation of + * FLAC__stream_encoder_set_metadata(); the function now makes a copy + * of the \a metadata array of pointers so the client no longer needs + * to maintain it after the call. The objects themselves that are + * pointed to by the array are still not copied though and must be + * maintained until the call to FLAC__stream_encoder_finish(). + */ + +/** \defgroup porting_1_1_4_to_1_2_0 Porting from FLAC 1.1.4 to 1.2.0 + * \ingroup porting + * + * \brief + * This module describes porting from FLAC 1.1.4 to FLAC 1.2.0. + * + * There were only very minor changes to the interfaces from 1.1.4 to 1.2.0. + * In libFLAC, \c FLAC__format_sample_rate_is_subset() was added. + * In libFLAC++, \c FLAC::Decoder::Stream::get_decode_position() was added. + * + * Finally, value of the constant \c FLAC__FRAME_HEADER_RESERVED_LEN + * has changed to reflect the conversion of one of the reserved bits + * into active use. It used to be \c 2 and now is \c 1. However the + * FLAC frame header length has not changed, so to skip the proper + * number of bits, use \c FLAC__FRAME_HEADER_RESERVED_LEN + + * \c FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN */ /** \defgroup flac FLAC C API diff --git a/sys/src/cmd/audio/libFLAC/FLAC/assert.h b/sys/src/cmd/audio/libFLAC/FLAC/assert.h index cab471a2a..dc9bcef4d 100644 --- a/sys/src/cmd/audio/libFLAC/FLAC/assert.h +++ b/sys/src/cmd/audio/libFLAC/FLAC/assert.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sys/src/cmd/audio/libFLAC/FLAC/callback.h b/sys/src/cmd/audio/libFLAC/FLAC/callback.h index 97582a0f9..ce8787ff4 100644 --- a/sys/src/cmd/audio/libFLAC/FLAC/callback.h +++ b/sys/src/cmd/audio/libFLAC/FLAC/callback.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2004 Josh Coalson + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -68,7 +69,7 @@ * stdio streams to implement the callbacks, you can pass fread, fwrite, and * fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or * FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle - * is required. \warning You generally can NOT directly use fseek or ftell + * is required. \warning You generally CANNOT directly use fseek or ftell * for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems * these use 32-bit offsets and FLAC requires 64-bit offsets to deal with * large files. You will have to find an equivalent function (e.g. ftello), @@ -82,6 +83,9 @@ extern "C" { #endif +/** This is the opaque handle type used by the callbacks. Typically + * this is a \c FILE* or address of a file descriptor. + */ typedef void* FLAC__IOHandle; /** Signature for the read callback. diff --git a/sys/src/cmd/audio/libFLAC/FLAC/export.h b/sys/src/cmd/audio/libFLAC/FLAC/export.h index 5fdf2eaaa..9cc9e137f 100644 --- a/sys/src/cmd/audio/libFLAC/FLAC/export.h +++ b/sys/src/cmd/audio/libFLAC/FLAC/export.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,16 +33,65 @@ #ifndef FLAC__EXPORT_H #define FLAC__EXPORT_H -#if defined(FLAC__NO_DLL) || !defined(_MSC_VER) +/** \file include/FLAC/export.h + * + * \brief + * This module contains #defines and symbols for exporting function + * calls, and providing version information and compiled-in features. + * + * See the \link flac_export export \endlink module. + */ + +/** \defgroup flac_export FLAC/export.h: export symbols + * \ingroup flac + * + * \brief + * This module contains #defines and symbols for exporting function + * calls, and providing version information and compiled-in features. + * + * If you are compiling with MSVC and will link to the static library + * (libFLAC.lib) you should define FLAC__NO_DLL in your project to + * make sure the symbols are exported properly. + * + * \{ + */ + +#if defined(FLAC__NO_DLL) #define FLAC_API +#elif defined(_MSC_VER) +#ifdef FLAC_API_EXPORTS +#define FLAC_API __declspec(dllexport) #else +#define FLAC_API __declspec(dllimport) +#endif + +#elif defined(FLAC__USE_VISIBILITY_ATTR) +#define FLAC_API __attribute__ ((visibility ("default"))) -#ifdef FLAC_API_EXPORTS -#define FLAC_API _declspec(dllexport) #else -#define FLAC_API _declspec(dllimport) +#define FLAC_API #endif + +/** These #defines will mirror the libtool-based library version number, see + * http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning + */ +#define FLAC_API_VERSION_CURRENT 11 +#define FLAC_API_VERSION_REVISION 0 /**< see above */ +#define FLAC_API_VERSION_AGE 3 /**< see above */ + +#ifdef __cplusplus +extern "C" { #endif + +/** \c 1 if the library has been compiled with support for Ogg FLAC, else \c 0. */ +extern FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC; + +#ifdef __cplusplus +} +#endif + +/* \} */ + #endif diff --git a/sys/src/cmd/audio/libFLAC/FLAC/file_decoder.h b/sys/src/cmd/audio/libFLAC/FLAC/file_decoder.h deleted file mode 100644 index 04e05ffba..000000000 --- a/sys/src/cmd/audio/libFLAC/FLAC/file_decoder.h +++ /dev/null @@ -1,660 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 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. - */ - -#ifndef FLAC__FILE_DECODER_H -#define FLAC__FILE_DECODER_H - -#include "export.h" -#include "seekable_stream_decoder.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \file include/FLAC/file_decoder.h - * - * \brief - * This module contains the functions which implement the file - * decoder. - * - * See the detailed documentation in the - * \link flac_file_decoder file decoder \endlink module. - */ - -/** \defgroup flac_file_decoder FLAC/file_decoder.h: file decoder interface - * \ingroup flac_decoder - * - * \brief - * This module contains the functions which implement the file - * decoder. - * - * The basic usage of this decoder is as follows: - * - The program creates an instance of a decoder using - * FLAC__file_decoder_new(). - * - The program overrides the default settings and sets callbacks for - * writing, error reporting, and metadata reporting using - * FLAC__file_decoder_set_*() functions. - * - The program initializes the instance to validate the settings and - * prepare for decoding using FLAC__file_decoder_init(). - * - The program calls the FLAC__file_decoder_process_*() functions - * to decode data, which subsequently calls the callbacks. - * - The program finishes the decoding with FLAC__file_decoder_finish(), - * which flushes the input and output and resets the decoder to the - * uninitialized state. - * - The instance may be used again or deleted with - * FLAC__file_decoder_delete(). - * - * The file decoder is a trivial wrapper around the - * \link flac_seekable_stream_decoder seekable stream decoder \endlink - * meant to simplfy the process of decoding from a standard file. The - * file decoder supplies all but the Write/Metadata/Error callbacks. - * The user needs only to provide the path to the file and the file - * decoder handles the rest. - * - * Like the seekable stream decoder, seeking is exposed through the - * FLAC__file_decoder_seek_absolute() method. At any point after the file - * decoder has been initialized, the user can call this function to seek to - * an exact sample within the file. Subsequently, the first time the write - * callback is called it will be passed a (possibly partial) block starting - * at that sample. - * - * The file decoder also inherits MD5 signature checking from the seekable - * stream decoder. If this is turned on before initialization, - * FLAC__file_decoder_finish() will report when the decoded MD5 signature - * does not match the one stored in the STREAMINFO block. MD5 checking is - * automatically turned off if there is no signature in the STREAMINFO - * block or when a seek is attempted. - * - * Make sure to read the detailed descriptions of the - * \link flac_seekable_stream_decoder seekable stream decoder module \endlink - * and \link flac_stream_decoder stream decoder module \endlink - * since the file decoder inherits much of its behavior from them. - * - * \note - * The "set" functions may only be called when the decoder is in the - * state FLAC__FILE_DECODER_UNINITIALIZED, i.e. after - * FLAC__file_decoder_new() or FLAC__file_decoder_finish(), but - * before FLAC__file_decoder_init(). If this is the case they will - * return \c true, otherwise \c false. - * - * \note - * FLAC__file_decoder_finish() resets all settings to the constructor - * defaults, including the callbacks. - * - * \{ - */ - - -/** State values for a FLAC__FileDecoder - * - * The decoder's state can be obtained by calling FLAC__file_decoder_get_state(). - */ -typedef enum { - - FLAC__FILE_DECODER_OK = 0, - /**< The decoder is in the normal OK state. */ - - FLAC__FILE_DECODER_END_OF_FILE, - /**< The decoder has reached the end of the file. */ - - FLAC__FILE_DECODER_ERROR_OPENING_FILE, - /**< An error occurred opening the input file. */ - - FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR, - /**< An error occurred allocating memory. */ - - FLAC__FILE_DECODER_SEEK_ERROR, - /**< An error occurred while seeking. */ - - FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR, - /**< An error occurred in the underlying seekable stream decoder. */ - - FLAC__FILE_DECODER_ALREADY_INITIALIZED, - /**< FLAC__file_decoder_init() was called when the decoder was already - * initialized, usually because FLAC__file_decoder_finish() was not - * called. - */ - - FLAC__FILE_DECODER_INVALID_CALLBACK, - /**< FLAC__file_decoder_init() was called without all callbacks - * being set. - */ - - FLAC__FILE_DECODER_UNINITIALIZED - /**< The decoder is in the uninitialized state. */ - -} FLAC__FileDecoderState; - -/** Maps a FLAC__FileDecoderState to a C string. - * - * Using a FLAC__FileDecoderState as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__FileDecoderStateString[]; - - -/*********************************************************************** - * - * class FLAC__FileDecoder : public FLAC__StreamDecoder - * - ***********************************************************************/ - -struct FLAC__FileDecoderProtected; -struct FLAC__FileDecoderPrivate; -/** The opaque structure definition for the file decoder type. See the - * \link flac_file_decoder file decoder module \endlink for a detailed - * description. - */ -typedef struct { - struct FLAC__FileDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */ - struct FLAC__FileDecoderPrivate *private_; /* avoid the C++ keyword 'private' */ -} FLAC__FileDecoder; - -/** Signature for the write callback. - * See FLAC__file_decoder_set_write_callback() - * and FLAC__SeekableStreamDecoderWriteCallback for more info. - * - * \param decoder The decoder instance calling the callback. - * \param frame The description of the decoded frame. - * \param buffer An array of pointers to decoded channels of data. - * \param client_data The callee's client data set through - * FLAC__file_decoder_set_client_data(). - * \retval FLAC__StreamDecoderWriteStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderWriteStatus (*FLAC__FileDecoderWriteCallback)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); - -/** Signature for the metadata callback. - * See FLAC__file_decoder_set_metadata_callback() - * and FLAC__SeekableStreamDecoderMetadataCallback for more info. - * - * \param decoder The decoder instance calling the callback. - * \param metadata The decoded metadata block. - * \param client_data The callee's client data set through - * FLAC__file_decoder_set_client_data(). - */ -typedef void (*FLAC__FileDecoderMetadataCallback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); - -/** Signature for the error callback. - * See FLAC__file_decoder_set_error_callback() - * and FLAC__SeekableStreamDecoderErrorCallback for more info. - * - * \param decoder The decoder instance calling the callback. - * \param status The error encountered by the decoder. - * \param client_data The callee's client data set through - * FLAC__file_decoder_set_client_data(). - */ -typedef void (*FLAC__FileDecoderErrorCallback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); - - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -/** Create a new file decoder instance. The instance is created with - * default settings; see the individual FLAC__file_decoder_set_*() - * functions for each setting's default. - * - * \retval FLAC__FileDecoder* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__FileDecoder *FLAC__file_decoder_new(); - -/** Free a decoder instance. Deletes the object pointed to by \a decoder. - * - * \param decoder A pointer to an existing decoder. - * \assert - * \code decoder != NULL \endcode - */ -FLAC_API void FLAC__file_decoder_delete(FLAC__FileDecoder *decoder); - - -/*********************************************************************** - * - * Public class method prototypes - * - ***********************************************************************/ - -/** Set the "MD5 signature checking" flag. - * This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_set_md5_checking(). - * - * \default \c false - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_md5_checking(FLAC__FileDecoder *decoder, FLAC__bool value); - -/** Set the input file name to decode. - * - * \default \c "-" - * \param decoder A decoder instance to set. - * \param value The input file name, or "-" for \c stdin. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, or there was a memory - * allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_filename(FLAC__FileDecoder *decoder, const char *value); - -/** Set the write callback. - * This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_set_write_callback(). - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_write_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderWriteCallback value); - -/** Set the metadata callback. - * This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_set_metadata_callback(). - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderMetadataCallback value); - -/** Set the error callback. - * This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_set_error_callback(). - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_error_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderErrorCallback value); - -/** Set the client data to be passed back to callbacks. - * This value will be supplied to callbacks in their \a client_data - * argument. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_client_data(FLAC__FileDecoder *decoder, void *value); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_set_metadata_respond(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param type See above. - * \assert - * \code decoder != NULL \endcode - * \a type is valid - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond(FLAC__FileDecoder *decoder, FLAC__MetadataType type); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_set_metadata_respond_application(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param id See above. - * \assert - * \code decoder != NULL \endcode - * \code id != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4]); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_set_metadata_respond_all(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond_all(FLAC__FileDecoder *decoder); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_set_metadata_ignore(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param type See above. - * \assert - * \code decoder != NULL \endcode - * \a type is valid - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore(FLAC__FileDecoder *decoder, FLAC__MetadataType type); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_set_metadata_ignore_application(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param id See above. - * \assert - * \code decoder != NULL \endcode - * \code id != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4]); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_set_metadata_ignore_all(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore_all(FLAC__FileDecoder *decoder); - -/** Get the current decoder state. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__FileDecoderState - * The current decoder state. - */ -FLAC_API FLAC__FileDecoderState FLAC__file_decoder_get_state(const FLAC__FileDecoder *decoder); - -/** Get the state of the underlying seekable stream decoder. - * Useful when the file decoder state is - * \c FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__SeekableStreamDecoderState - * The seekable stream decoder state. - */ -FLAC_API FLAC__SeekableStreamDecoderState FLAC__file_decoder_get_seekable_stream_decoder_state(const FLAC__FileDecoder *decoder); - -/** Get the state of the underlying stream decoder. - * Useful when the file decoder state is - * \c FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR and the seekable stream - * decoder state is \c FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderState - * The seekable stream decoder state. - */ -FLAC_API FLAC__StreamDecoderState FLAC__file_decoder_get_stream_decoder_state(const FLAC__FileDecoder *decoder); - -/** Get the current decoder state as a C string. - * This version automatically resolves - * \c FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR by getting the - * seekable stream decoder's state. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval const char * - * The decoder state as a C string. Do not modify the contents. - */ -FLAC_API const char *FLAC__file_decoder_get_resolved_state_string(const FLAC__FileDecoder *decoder); - -/** Get the "MD5 signature checking" flag. - * This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_get_md5_checking(). - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__file_decoder_get_md5_checking(const FLAC__FileDecoder *decoder); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_get_channels(). - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval unsigned - * See above. - */ -FLAC_API unsigned FLAC__file_decoder_get_channels(const FLAC__FileDecoder *decoder); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_get_channel_assignment(). - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__ChannelAssignment - * See above. - */ -FLAC_API FLAC__ChannelAssignment FLAC__file_decoder_get_channel_assignment(const FLAC__FileDecoder *decoder); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_get_bits_per_sample(). - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval unsigned - * See above. - */ -FLAC_API unsigned FLAC__file_decoder_get_bits_per_sample(const FLAC__FileDecoder *decoder); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_get_sample_rate(). - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval unsigned - * See above. - */ -FLAC_API unsigned FLAC__file_decoder_get_sample_rate(const FLAC__FileDecoder *decoder); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_get_blocksize(). - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval unsigned - * See above. - */ -FLAC_API unsigned FLAC__file_decoder_get_blocksize(const FLAC__FileDecoder *decoder); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_get_decode_position(). - * - * \param decoder A decoder instance to query. - * \param position Address at which to return the desired position. - * \assert - * \code decoder != NULL \endcode - * \code position != NULL \endcode - * \retval FLAC__bool - * \c true if successful, \c false if there was an error from - * the 'tell' callback. - */ -FLAC_API FLAC__bool FLAC__file_decoder_get_decode_position(const FLAC__FileDecoder *decoder, FLAC__uint64 *position); - -/** Initialize the decoder instance. - * Should be called after FLAC__file_decoder_new() and - * FLAC__file_decoder_set_*() but before any of the - * FLAC__file_decoder_process_*() functions. Will set and return - * the decoder state, which will be FLAC__FILE_DECODER_OK if - * initialization succeeded. - * - * \param decoder An uninitialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__FileDecoderState - * \c FLAC__FILE_DECODER_OK if initialization was successful; see - * FLAC__FileDecoderState for the meanings of other return values. - */ -FLAC_API FLAC__FileDecoderState FLAC__file_decoder_init(FLAC__FileDecoder *decoder); - -/** Finish the decoding process. - * Flushes the decoding buffer, releases resources, resets the decoder - * settings to their defaults, and returns the decoder state to - * FLAC__FILE_DECODER_UNINITIALIZED. - * - * In the event of a prematurely-terminated decode, it is not strictly - * necessary to call this immediately before FLAC__file_decoder_delete() - * but it is good practice to match every FLAC__file_decoder_init() with - * a FLAC__file_decoder_finish(). - * - * \param decoder An uninitialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if MD5 checking is on AND a STREAMINFO block was available - * AND the MD5 signature in the STREAMINFO block was non-zero AND the - * signature does not match the one computed by the decoder; else - * \c true. - */ -FLAC_API FLAC__bool FLAC__file_decoder_finish(FLAC__FileDecoder *decoder); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_process_single(). - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__file_decoder_process_single(FLAC__FileDecoder *decoder); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_process_until_end_of_metadata(). - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_metadata(FLAC__FileDecoder *decoder); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_process_until_end_of_stream(). - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_file(FLAC__FileDecoder *decoder); - -/** This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_skip_single_frame(). - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__file_decoder_skip_single_frame(FLAC__FileDecoder *decoder); - -/** Flush the input and seek to an absolute sample. - * This is inherited from FLAC__SeekableStreamDecoder; see - * FLAC__seekable_stream_decoder_seek_absolute(). - * - * \param decoder A decoder instance. - * \param sample The target sample number to seek to. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false. - */ -FLAC_API FLAC__bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, FLAC__uint64 sample); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sys/src/cmd/audio/libFLAC/FLAC/file_encoder.h b/sys/src/cmd/audio/libFLAC/FLAC/file_encoder.h deleted file mode 100644 index 147b3e824..000000000 --- a/sys/src/cmd/audio/libFLAC/FLAC/file_encoder.h +++ /dev/null @@ -1,871 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2002,2003,2004 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. - */ - -#ifndef FLAC__FILE_ENCODER_H -#define FLAC__FILE_ENCODER_H - -#include "export.h" -#include "seekable_stream_encoder.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \file include/FLAC/file_encoder.h - * - * \brief - * This module contains the functions which implement the file - * encoder. - * - * See the detailed documentation in the - * \link flac_file_encoder file encoder \endlink module. - */ - -/** \defgroup flac_file_encoder FLAC/file_encoder.h: file encoder interface - * \ingroup flac_encoder - * - * \brief - * This module contains the functions which implement the file - * encoder. - * - * The basic usage of this encoder is as follows: - * - The program creates an instance of an encoder using - * FLAC__file_encoder_new(). - * - The program overrides the default settings using - * FLAC__file_encoder_set_*() functions. - * - The program initializes the instance to validate the settings and - * prepare for encoding using FLAC__file_encoder_init(). - * - The program calls FLAC__file_encoder_process() or - * FLAC__file_encoder_process_interleaved() to encode data, which - * subsequently writes data to the output file. - * - The program finishes the encoding with FLAC__file_encoder_finish(), - * which causes the encoder to encode any data still in its input pipe, - * rewind and write the STREAMINFO metadata to file, and finally reset - * the encoder to the uninitialized state. - * - The instance may be used again or deleted with - * FLAC__file_encoder_delete(). - * - * The file encoder is a wrapper around the - * \link flac_seekable_stream_encoder seekable stream encoder \endlink which supplies all - * callbacks internally; the user need specify only the filename. - * - * Make sure to read the detailed description of the - * \link flac_seekable_stream_encoder seekable stream encoder module \endlink since the - * \link flac_stream_encoder stream encoder module \endlink since the - * file encoder inherits much of its behavior from them. - * - * \note - * The "set" functions may only be called when the encoder is in the - * state FLAC__FILE_ENCODER_UNINITIALIZED, i.e. after - * FLAC__file_encoder_new() or FLAC__file_encoder_finish(), but - * before FLAC__file_encoder_init(). If this is the case they will - * return \c true, otherwise \c false. - * - * \note - * FLAC__file_encoder_finish() resets all settings to the constructor - * defaults. - * - * \{ - */ - - -/** State values for a FLAC__FileEncoder - * - * The encoder's state can be obtained by calling FLAC__file_encoder_get_state(). - */ -typedef enum { - - FLAC__FILE_ENCODER_OK = 0, - /**< The encoder is in the normal OK state. */ - - FLAC__FILE_ENCODER_NO_FILENAME, - /**< FLAC__file_encoder_init() was called without first calling - * FLAC__file_encoder_set_filename(). - */ - - FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR, - /**< An error occurred in the underlying seekable stream encoder; - * check FLAC__file_encoder_get_seekable_stream_encoder_state(). - */ - - FLAC__FILE_ENCODER_FATAL_ERROR_WHILE_WRITING, - /**< A fatal error occurred while writing to the encoded file. */ - - FLAC__FILE_ENCODER_ERROR_OPENING_FILE, - /**< An error occurred opening the output file for writing. */ - - FLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR, - /**< Memory allocation failed. */ - - FLAC__FILE_ENCODER_ALREADY_INITIALIZED, - /**< FLAC__file_encoder_init() was called when the encoder was - * already initialized, usually because - * FLAC__file_encoder_finish() was not called. - */ - - FLAC__FILE_ENCODER_UNINITIALIZED - /**< The encoder is in the uninitialized state. */ - -} FLAC__FileEncoderState; - -/** Maps a FLAC__FileEncoderState to a C string. - * - * Using a FLAC__FileEncoderState as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__FileEncoderStateString[]; - - -/*********************************************************************** - * - * class FLAC__FileEncoder - * - ***********************************************************************/ - -struct FLAC__FileEncoderProtected; -struct FLAC__FileEncoderPrivate; -/** The opaque structure definition for the file encoder type. - * See the \link flac_file_encoder file encoder module \endlink - * for a detailed description. - */ -typedef struct { - struct FLAC__FileEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */ - struct FLAC__FileEncoderPrivate *private_; /* avoid the C++ keyword 'private' */ -} FLAC__FileEncoder; - -/** Signature for the progress callback. - * See FLAC__file_encoder_set_progress_callback() for more info. - * - * \param encoder The encoder instance calling the callback. - * \param bytes_written Bytes written so far. - * \param samples_written Samples written so far. - * \param frames_written Frames written so far. - * \param total_frames_estimate The estimate of the total number of - * frames to be written. - * \param client_data The callee's client data set through - * FLAC__file_encoder_set_client_data(). - */ -typedef void (*FLAC__FileEncoderProgressCallback)(const FLAC__FileEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data); - - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -/** Create a new file encoder instance. The instance is created with - * default settings; see the individual FLAC__file_encoder_set_*() - * functions for each setting's default. - * - * \retval FLAC__FileEncoder* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__FileEncoder *FLAC__file_encoder_new(); - -/** Free an encoder instance. Deletes the object pointed to by \a encoder. - * - * \param encoder A pointer to an existing encoder. - * \assert - * \code encoder != NULL \endcode - */ -FLAC_API void FLAC__file_encoder_delete(FLAC__FileEncoder *encoder); - -/*********************************************************************** - * - * Public class method prototypes - * - ***********************************************************************/ - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_verify(). - * - * \default \c true - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_verify(FLAC__FileEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_streamable_subset(). - * - * \default \c true - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_streamable_subset(FLAC__FileEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_do_mid_side_stereo(). - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_do_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(). - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_loose_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_channels(). - * - * \default \c 2 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_channels(FLAC__FileEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_bits_per_sample(). - * - * \warning - * Do not feed the encoder data that is wider than the value you - * set here or you will generate an invalid stream. - * - * \default \c 16 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_bits_per_sample(FLAC__FileEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_sample_rate(). - * - * \default \c 44100 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_sample_rate(FLAC__FileEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_blocksize(). - * - * \default \c 1152 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_blocksize(FLAC__FileEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_max_lpc_order(). - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_max_lpc_order(FLAC__FileEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_qlp_coeff_precision(). - * - * \note - * In the current implementation, qlp_coeff_precision + bits_per_sample must - * be less than 32. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_qlp_coeff_precision(FLAC__FileEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(). - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_do_qlp_coeff_prec_search(FLAC__FileEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_do_escape_coding(). - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_do_escape_coding(FLAC__FileEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_do_exhaustive_model_search(). - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_do_exhaustive_model_search(FLAC__FileEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_min_residual_partition_order(). - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_min_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_max_residual_partition_order(). - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_max_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_rice_parameter_search_dist(). - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_rice_parameter_search_dist(FLAC__FileEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_total_samples_estimate(). - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_total_samples_estimate(FLAC__FileEncoder *encoder, FLAC__uint64 value); - -/** This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_set_metadata(). - * - * \default \c NULL, 0 - * \param encoder An encoder instance to set. - * \param metadata See above. - * \param num_blocks See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_metadata(FLAC__FileEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks); - -/** Set the output file name encode to. - * - * \note - * The filename is mandatory and must be set before initialization. - * - * \note - * Unlike the FLAC__FileDecoder, the filename does not interpret "-" for - * \c stdout; writing to \c stdout is not relevant in the file encoder. - * - * \default \c NULL - * \param encoder A encoder instance to set. - * \param value The output file name. - * \assert - * \code encoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, or there was a memory - * allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_filename(FLAC__FileEncoder *encoder, const char *value); - -/** Set the progress callback. - * The supplied function will be called when the encoder has finished - * writing a frame. The \c total_frames_estimate argument to the callback - * will be based on the value from - * FLAC__file_encoder_set_total_samples_estimate(). - * - * \note - * Unlike most other callbacks, the progress callback is \b not mandatory - * and need not be set before initialization. - * - * \default \c NULL - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_progress_callback(FLAC__FileEncoder *encoder, FLAC__FileEncoderProgressCallback value); - -/** Set the client data to be passed back to callbacks. - * This value will be supplied to callbacks in their \a client_data - * argument. - * - * \default \c NULL - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__file_encoder_set_client_data(FLAC__FileEncoder *encoder, void *value); - -/** Get the current encoder state. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__FileEncoderState - * The current encoder state. - */ -FLAC_API FLAC__FileEncoderState FLAC__file_encoder_get_state(const FLAC__FileEncoder *encoder); - -/** Get the state of the underlying seekable stream encoder. - * Useful when the file encoder state is - * \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__SeekableStreamEncoderState - * The seekable stream encoder state. - */ -FLAC_API FLAC__SeekableStreamEncoderState FLAC__file_encoder_get_seekable_stream_encoder_state(const FLAC__FileEncoder *encoder); - -/** Get the state of the underlying stream encoder. - * Useful when the file encoder state is - * \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR and the seekable stream - * encoder state is \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamEncoderState - * The seekable stream encoder state. - */ -FLAC_API FLAC__StreamEncoderState FLAC__file_encoder_get_stream_encoder_state(const FLAC__FileEncoder *encoder); - -/** Get the state of the underlying stream encoder's verify decoder. - * Useful when the file encoder state is - * \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR and the seekable stream - * encoder state is \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and - * the stream encoder state is \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamDecoderState - * The stream encoder state. - */ -FLAC_API FLAC__StreamDecoderState FLAC__file_encoder_get_verify_decoder_state(const FLAC__FileEncoder *encoder); - -/** Get the current encoder state as a C string. - * This version automatically resolves - * \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR by getting the - * seekable stream encoder's state. - * - * \param encoder A encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval const char * - * The encoder state as a C string. Do not modify the contents. - */ -FLAC_API const char *FLAC__file_encoder_get_resolved_state_string(const FLAC__FileEncoder *encoder); - -/** Get relevant values about the nature of a verify decoder error. - * Inherited from FLAC__seekable_stream_encoder_get_verify_decoder_error_stats(). - * Useful when the file encoder state is - * \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR and the seekable stream - * encoder state is - * \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and the - * stream encoder state is - * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. - * - * \param encoder An encoder instance to query. - * \param absolute_sample The absolute sample number of the mismatch. - * \param frame_number The number of the frame in which the mismatch occurred. - * \param channel The channel in which the mismatch occurred. - * \param sample The number of the sample (relative to the frame) in - * which the mismatch occurred. - * \param expected The expected value for the sample in question. - * \param got The actual value returned by the decoder. - * \assert - * \code encoder != NULL \endcode - */ -FLAC_API void FLAC__file_encoder_get_verify_decoder_error_stats(const FLAC__FileEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got); - -/** Get the "verify" flag. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_verify(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__file_encoder_set_verify(). - */ -FLAC_API FLAC__bool FLAC__file_encoder_get_verify(const FLAC__FileEncoder *encoder); - -/** Get the "streamable subset" flag. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_streamable_subset(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__file_encoder_set_streamable_subset(). - */ -FLAC_API FLAC__bool FLAC__file_encoder_get_streamable_subset(const FLAC__FileEncoder *encoder); - -/** Get the "mid/side stereo coding" flag. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_do_mid_side_stereo(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__file_encoder_get_do_mid_side_stereo(). - */ -FLAC_API FLAC__bool FLAC__file_encoder_get_do_mid_side_stereo(const FLAC__FileEncoder *encoder); - -/** Get the "adaptive mid/side switching" flag. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_loose_mid_side_stereo(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__file_encoder_set_loose_mid_side_stereo(). - */ -FLAC_API FLAC__bool FLAC__file_encoder_get_loose_mid_side_stereo(const FLAC__FileEncoder *encoder); - -/** Get the number of input channels being processed. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_channels(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__file_encoder_set_channels(). - */ -FLAC_API unsigned FLAC__file_encoder_get_channels(const FLAC__FileEncoder *encoder); - -/** Get the input sample resolution setting. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_bits_per_sample(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__file_encoder_set_bits_per_sample(). - */ -FLAC_API unsigned FLAC__file_encoder_get_bits_per_sample(const FLAC__FileEncoder *encoder); - -/** Get the input sample rate setting. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_sample_rate(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__file_encoder_set_sample_rate(). - */ -FLAC_API unsigned FLAC__file_encoder_get_sample_rate(const FLAC__FileEncoder *encoder); - -/** Get the blocksize setting. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_blocksize(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__file_encoder_set_blocksize(). - */ -FLAC_API unsigned FLAC__file_encoder_get_blocksize(const FLAC__FileEncoder *encoder); - -/** Get the maximum LPC order setting. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_max_lpc_order(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__file_encoder_set_max_lpc_order(). - */ -FLAC_API unsigned FLAC__file_encoder_get_max_lpc_order(const FLAC__FileEncoder *encoder); - -/** Get the quantized linear predictor coefficient precision setting. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_qlp_coeff_precision(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__file_encoder_set_qlp_coeff_precision(). - */ -FLAC_API unsigned FLAC__file_encoder_get_qlp_coeff_precision(const FLAC__FileEncoder *encoder); - -/** Get the qlp coefficient precision search flag. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__file_encoder_set_do_qlp_coeff_prec_search(). - */ -FLAC_API FLAC__bool FLAC__file_encoder_get_do_qlp_coeff_prec_search(const FLAC__FileEncoder *encoder); - -/** Get the "escape coding" flag. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_do_escape_coding(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__file_encoder_set_do_escape_coding(). - */ -FLAC_API FLAC__bool FLAC__file_encoder_get_do_escape_coding(const FLAC__FileEncoder *encoder); - -/** Get the exhaustive model search flag. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_do_exhaustive_model_search(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__file_encoder_set_do_exhaustive_model_search(). - */ -FLAC_API FLAC__bool FLAC__file_encoder_get_do_exhaustive_model_search(const FLAC__FileEncoder *encoder); - -/** Get the minimum residual partition order setting. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_min_residual_partition_order(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__file_encoder_set_min_residual_partition_order(). - */ -FLAC_API unsigned FLAC__file_encoder_get_min_residual_partition_order(const FLAC__FileEncoder *encoder); - -/** Get maximum residual partition order setting. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_max_residual_partition_order(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__file_encoder_set_max_residual_partition_order(). - */ -FLAC_API unsigned FLAC__file_encoder_get_max_residual_partition_order(const FLAC__FileEncoder *encoder); - -/** Get the Rice parameter search distance setting. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_rice_parameter_search_dist(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__file_encoder_set_rice_parameter_search_dist(). - */ -FLAC_API unsigned FLAC__file_encoder_get_rice_parameter_search_dist(const FLAC__FileEncoder *encoder); - -/** Get the previously set estimate of the total samples to be encoded. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_get_total_samples_estimate(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__uint64 - * See FLAC__file_encoder_set_total_samples_estimate(). - */ -FLAC_API FLAC__uint64 FLAC__file_encoder_get_total_samples_estimate(const FLAC__FileEncoder *encoder); - -/** Initialize the encoder instance. - * Should be called after FLAC__file_encoder_new() and - * FLAC__file_encoder_set_*() but before FLAC__file_encoder_process() - * or FLAC__file_encoder_process_interleaved(). Will set and return - * the encoder state, which will be FLAC__FILE_ENCODER_OK if - * initialization succeeded. - * - * \param encoder An uninitialized encoder instance. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__FileEncoderState - * \c FLAC__FILE_ENCODER_OK if initialization was successful; see - * FLAC__FileEncoderState for the meanings of other return values. - */ -FLAC_API FLAC__FileEncoderState FLAC__file_encoder_init(FLAC__FileEncoder *encoder); - -/** Finish the encoding process. - * Flushes the encoding buffer, releases resources, resets the encoder - * settings to their defaults, and returns the encoder state to - * FLAC__FILE_ENCODER_UNINITIALIZED. - * - * In the event of a prematurely-terminated encode, it is not strictly - * necessary to call this immediately before FLAC__file_encoder_delete() - * but it is good practice to match every FLAC__file_encoder_init() - * with a FLAC__file_encoder_finish(). - * - * \param encoder An uninitialized encoder instance. - * \assert - * \code encoder != NULL \endcode - */ -FLAC_API void FLAC__file_encoder_finish(FLAC__FileEncoder *encoder); - -/** Submit data for encoding. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_process(). - * - * \param encoder An initialized encoder instance in the OK state. - * \param buffer An array of pointers to each channel's signal. - * \param samples The number of samples in one channel. - * \assert - * \code encoder != NULL \endcode - * \code FLAC__file_encoder_get_state(encoder) == FLAC__FILE_ENCODER_OK \endcode - * \retval FLAC__bool - * \c true if successful, else \c false; in this case, check the - * encoder state with FLAC__file_encoder_get_state() to see what - * went wrong. - */ -FLAC_API FLAC__bool FLAC__file_encoder_process(FLAC__FileEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples); - -/** Submit data for encoding. - * This is inherited from FLAC__SeekableStreamEncoder; see - * FLAC__seekable_stream_encoder_process_interleaved(). - * - * \param encoder An initialized encoder instance in the OK state. - * \param buffer An array of channel-interleaved data (see above). - * \param samples The number of samples in one channel, the same as for - * FLAC__file_encoder_process(). For example, if - * encoding two channels, \c 1000 \a samples corresponds - * to a \a buffer of 2000 values. - * \assert - * \code encoder != NULL \endcode - * \code FLAC__file_encoder_get_state(encoder) == FLAC__FILE_ENCODER_OK \endcode - * \retval FLAC__bool - * \c true if successful, else \c false; in this case, check the - * encoder state with FLAC__file_encoder_get_state() to see what - * went wrong. - */ -FLAC_API FLAC__bool FLAC__file_encoder_process_interleaved(FLAC__FileEncoder *encoder, const FLAC__int32 buffer[], unsigned samples); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sys/src/cmd/audio/libFLAC/FLAC/format.h b/sys/src/cmd/audio/libFLAC/FLAC/format.h index e003c34fe..7424565b3 100644 --- a/sys/src/cmd/audio/libFLAC/FLAC/format.h +++ b/sys/src/cmd/audio/libFLAC/FLAC/format.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -97,6 +98,10 @@ extern "C" { /** The maximum block size, in samples, permitted by the format. */ #define FLAC__MAX_BLOCK_SIZE (65535u) +/** The maximum block size, in samples, permitted by the FLAC subset for + * sample rates up to 48kHz. */ +#define FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ (4608u) + /** The maximum number of channels permitted by the format. */ #define FLAC__MAX_CHANNELS (8u) @@ -125,6 +130,10 @@ extern "C" { /** The maximum LPC order permitted by the format. */ #define FLAC__MAX_LPC_ORDER (32u) +/** The maximum LPC order permitted by the FLAC subset for sample rates + * up to 48kHz. */ +#define FLAC__SUBSET_MAX_LPC_ORDER_48000HZ (12u) + /** The minimum quantized linear predictor coefficient precision * permitted by the format. */ @@ -153,7 +162,7 @@ extern "C" { extern FLAC_API const char *FLAC__VERSION_STRING; /** The vendor string inserted by the encoder into the VORBIS_COMMENT block. - * This is a nulL-terminated ASCII string; when inserted into the + * This is a NUL-terminated ASCII string; when inserted into the * VORBIS_COMMENT the trailing null is stripped. */ extern FLAC_API const char *FLAC__VENDOR_STRING; @@ -183,9 +192,13 @@ extern FLAC_API const unsigned FLAC__STREAM_SYNC_LEN; /* = 32 bits */ /** An enumeration of the available entropy coding methods. */ typedef enum { - FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0 + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0, /**< Residual is coded by partitioning into contexts, each with it's own - * Rice parameter. */ + * 4-bit Rice parameter. */ + + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 = 1 + /**< Residual is coded by partitioning into contexts, each with it's own + * 5-bit Rice parameter. */ } FLAC__EntropyCodingMethodType; /** Maps a FLAC__EntropyCodingMethodType to a C string. @@ -204,7 +217,9 @@ typedef struct { /**< The Rice parameters for each context. */ unsigned *raw_bits; - /**< Widths for escape-coded partitions. */ + /**< Widths for escape-coded partitions. Will be non-zero for escaped + * partitions and zero for unescaped partitions. + */ unsigned capacity_by_order; /**< The capacity of the \a parameters and \a raw_bits arrays @@ -227,10 +242,13 @@ typedef struct { extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */ extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */ +extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */ extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */ extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; /**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */ +extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER; +/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */ /** Header for the entropy coding method. (c.f. <A HREF="../format.html#residual">format specification</A>) */ @@ -334,14 +352,21 @@ typedef struct { unsigned wasted_bits; } FLAC__Subframe; -extern FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN; /**< == 1 (bit) */ +/** == 1 (bit) + * + * This used to be a zero-padding bit (hence the name + * FLAC__SUBFRAME_ZERO_PAD_LEN) but is now a reserved bit. It still has a + * mandatory value of \c 0 but in the future may take on the value \c 0 or \c 1 + * to mean something else. + */ +extern FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN; extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */ extern FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */ -extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /* = 0x00 */ -extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /* = 0x02 */ -extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /* = 0x10 */ -extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /* = 0x40 */ +extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */ +extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */ +extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */ +extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */ /*****************************************************************************/ @@ -400,7 +425,9 @@ typedef struct { /**< The sample resolution. */ FLAC__FrameNumberType number_type; - /**< The numbering scheme used for the frame. */ + /**< The numbering scheme used for the frame. As a convenience, the + * decoder will always convert a frame number to a sample number because + * the rules are complex. */ union { FLAC__uint32 frame_number; @@ -418,7 +445,8 @@ typedef struct { extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */ extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */ -extern FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 2 (bits) */ +extern FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */ +extern FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */ extern FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */ extern FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */ extern FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */ @@ -473,14 +501,19 @@ typedef enum { /**< <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block */ FLAC__METADATA_TYPE_VORBIS_COMMENT = 4, - /**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block */ + /**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */ FLAC__METADATA_TYPE_CUESHEET = 5, /**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */ - FLAC__METADATA_TYPE_UNDEFINED = 6 + FLAC__METADATA_TYPE_PICTURE = 6, + /**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */ + + FLAC__METADATA_TYPE_UNDEFINED = 7, /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */ + FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE, + /**< No type will ever be greater than this. There is not enough room in the protocol block. */ } FLAC__MetadataType; /** Maps a FLAC__MetadataType to a C string. @@ -583,6 +616,10 @@ typedef struct { /** Vorbis comment entry structure used in VORBIS_COMMENT blocks. (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>) + * + * For convenience, the APIs maintain a trailing NUL character at the end of + * \a entry which is not counted toward \a length, i.e. + * \code strlen(entry) == length \endcode */ typedef struct { FLAC__uint32 length; @@ -634,7 +671,7 @@ typedef struct { /**< The track number. */ char isrc[13]; - /**< Track ISRC. This is a 12-digit alphanumeric code plus a trailing '\0' */ + /**< Track ISRC. This is a 12-digit alphanumeric code plus a trailing \c NUL byte */ unsigned type:1; /**< The track type: 0 for audio, 1 for non-audio. */ @@ -674,7 +711,7 @@ typedef struct { /**< The number of lead-in samples. */ FLAC__bool is_cd; - /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false */ + /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */ unsigned num_tracks; /**< The number of tracks. */ @@ -691,6 +728,98 @@ extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */ +/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */ +typedef enum { + FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */ + FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */ + FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */ + FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */ + FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */ + FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */ + FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */ + FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */ + FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */ + FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */ + FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */ + FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */ + FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */ + FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */ + FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED +} FLAC__StreamMetadata_Picture_Type; + +/** Maps a FLAC__StreamMetadata_Picture_Type to a C string. + * + * Using a FLAC__StreamMetadata_Picture_Type as the index to this array + * will give the string equivalent. The contents should not be + * modified. + */ +extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[]; + +/** FLAC PICTURE structure. (See the + * <A HREF="../format.html#metadata_block_picture">format specification</A> + * for the full description of each field.) + */ +typedef struct { + FLAC__StreamMetadata_Picture_Type type; + /**< The kind of picture stored. */ + + char *mime_type; + /**< Picture data's MIME type, in ASCII printable characters + * 0x20-0x7e, NUL terminated. For best compatibility with players, + * use picture data of MIME type \c image/jpeg or \c image/png. A + * MIME type of '-->' is also allowed, in which case the picture + * data should be a complete URL. In file storage, the MIME type is + * stored as a 32-bit length followed by the ASCII string with no NUL + * terminator, but is converted to a plain C string in this structure + * for convenience. + */ + + FLAC__byte *description; + /**< Picture's description in UTF-8, NUL terminated. In file storage, + * the description is stored as a 32-bit length followed by the UTF-8 + * string with no NUL terminator, but is converted to a plain C string + * in this structure for convenience. + */ + + FLAC__uint32 width; + /**< Picture's width in pixels. */ + + FLAC__uint32 height; + /**< Picture's height in pixels. */ + + FLAC__uint32 depth; + /**< Picture's color depth in bits-per-pixel. */ + + FLAC__uint32 colors; + /**< For indexed palettes (like GIF), picture's number of colors (the + * number of palette entries), or \c 0 for non-indexed (i.e. 2^depth). + */ + + FLAC__uint32 data_length; + /**< Length of binary picture data in bytes. */ + + FLAC__byte *data; + /**< Binary picture data. */ + +} FLAC__StreamMetadata_Picture; + +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */ + + /** Structure that is used when a metadata block of unknown type is loaded. * The contents are opaque. The structure is used only internally to * correctly handle unknown metadata. @@ -721,6 +850,7 @@ typedef struct { FLAC__StreamMetadata_SeekTable seek_table; FLAC__StreamMetadata_VorbisComment vorbis_comment; FLAC__StreamMetadata_CueSheet cue_sheet; + FLAC__StreamMetadata_Picture picture; FLAC__StreamMetadata_Unknown unknown; } data; /**< Polymorphic block data; use the \a type value to determine which @@ -743,9 +873,7 @@ extern FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bit * *****************************************************************************/ -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ -/** Tests that a sample rate is valid for FLAC. Since the rules for valid - * sample rates are slightly complex, they are encapsulated in this function. +/** Tests that a sample rate is valid for FLAC. * * \param sample_rate The sample rate to test for compliance. * \retval FLAC__bool @@ -754,7 +882,76 @@ extern FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bit */ FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate); -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ +/** Tests that a blocksize at the given sample rate is valid for the FLAC + * subset. + * + * \param blocksize The blocksize to test for compliance. + * \param sample_rate The sample rate is needed, since the valid subset + * blocksize depends on the sample rate. + * \retval FLAC__bool + * \c true if the given blocksize conforms to the specification for the + * subset at the given sample rate, else \c false. + */ +FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(unsigned blocksize, unsigned sample_rate); + +/** Tests that a sample rate is valid for the FLAC subset. The subset rules + * for valid sample rates are slightly more complex since the rate has to + * be expressible completely in the frame header. + * + * \param sample_rate The sample rate to test for compliance. + * \retval FLAC__bool + * \c true if the given sample rate conforms to the specification for the + * subset, else \c false. + */ +FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate); + +/** Check a Vorbis comment entry name to see if it conforms to the Vorbis + * comment specification. + * + * Vorbis comment names must be composed only of characters from + * [0x20-0x3C,0x3E-0x7D]. + * + * \param name A NUL-terminated string to be checked. + * \assert + * \code name != NULL \endcode + * \retval FLAC__bool + * \c false if entry name is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name); + +/** Check a Vorbis comment entry value to see if it conforms to the Vorbis + * comment specification. + * + * Vorbis comment values must be valid UTF-8 sequences. + * + * \param value A string to be checked. + * \param length A the length of \a value in bytes. May be + * \c (unsigned)(-1) to indicate that \a value is a plain + * UTF-8 NUL-terminated string. + * \assert + * \code value != NULL \endcode + * \retval FLAC__bool + * \c false if entry name is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length); + +/** Check a Vorbis comment entry to see if it conforms to the Vorbis + * comment specification. + * + * Vorbis comment entries must be of the form 'name=value', and 'name' and + * 'value' must be legal according to + * FLAC__format_vorbiscomment_entry_name_is_legal() and + * FLAC__format_vorbiscomment_entry_value_is_legal() respectively. + * + * \param entry An entry to be checked. + * \param length The length of \a entry in bytes. + * \assert + * \code value != NULL \endcode + * \retval FLAC__bool + * \c false if entry name is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length); + /** Check a seek table to see if it conforms to the FLAC specification. * See the format specification for limits on the contents of the * seek table. @@ -767,7 +964,6 @@ FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate); */ FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table); -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ /** Sort a seek table's seek points according to the format specification. * This includes a "unique-ification" step to remove duplicates, i.e. * seek points with identical \a sample_number values. Duplicate seek @@ -782,7 +978,6 @@ FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_S */ FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table); -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ /** Check a cue sheet to see if it conforms to the FLAC specification. * See the format specification for limits on the contents of the * cue sheet. @@ -803,6 +998,24 @@ FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *se */ FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation); +/** Check picture data to see if it conforms to the FLAC specification. + * See the format specification for limits on the contents of the + * PICTURE block. + * + * \param picture A pointer to existing picture data to be checked. + * \param violation Address of a pointer to a string. If there is a + * violation, a pointer to a string explanation of the + * violation will be returned here. \a violation may be + * \c NULL if you don't need the returned string. Do not + * free the returned string; it will always point to static + * data. + * \assert + * \code picture != NULL \endcode + * \retval FLAC__bool + * \c false if picture data is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation); + /* \} */ #ifdef __cplusplus diff --git a/sys/src/cmd/audio/libFLAC/FLAC/metadata.h b/sys/src/cmd/audio/libFLAC/FLAC/metadata.h index bd80821ae..89515329f 100644 --- a/sys/src/cmd/audio/libFLAC/FLAC/metadata.h +++ b/sys/src/cmd/audio/libFLAC/FLAC/metadata.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,15 +33,16 @@ #ifndef FLAC__METADATA_H #define FLAC__METADATA_H +#include <sys/types.h> /* for off_t */ #include "export.h" #include "callback.h" #include "format.h" -/****************************************************************************** - (For an example of how all these routines are used, see the source - code for the unit tests in src/test_libFLAC/metadata_*.c, or metaflac - in src/metaflac/) -******************************************************************************/ +/* -------------------------------------------------------------------- + (For an example of how all these routines are used, see the source + code for the unit tests in src/test_libFLAC/metadata_*.c, or + metaflac in src/metaflac/) + ------------------------------------------------------------------*/ /** \file include/FLAC/metadata.h * @@ -59,12 +61,16 @@ * \brief * This module provides functions for creating and manipulating FLAC * metadata blocks in memory, and three progressively more powerful - * interfaces for traversing and editing metadata in FLAC files. + * interfaces for traversing and editing metadata in native FLAC files. + * Note that currently only the Chain interface (level 2) supports Ogg + * FLAC files, and it is read-only i.e. no writing back changed + * metadata to file. * * There are three metadata interfaces of increasing complexity: * * Level 0: - * Read-only access to the STREAMINFO and VORBIS_COMMENT blocks. + * Read-only access to the STREAMINFO, VORBIS_COMMENT, CUESHEET, and + * PICTURE blocks. * * Level 1: * Read-write access to all metadata blocks. This level is write- @@ -96,7 +102,8 @@ * * All levels access files via their filenames. In addition, level 2 * has additional alternative read and write functions that take an I/O - * handle and callbacks, for times when access by filename is not possible. + * handle and callbacks, for situations where access by filename is not + * possible. * * In addition to the three interfaces, this module defines functions for * creating and manipulating various metadata objects in memory. As we see @@ -124,15 +131,16 @@ extern "C" { * * \brief * The level 0 interface consists of individual routines to read the - * STREAMINFO and VORBIS_COMMENT blocks, requiring only a filename. + * STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring + * only a filename. * - * It skips any ID3v2 tag at the head of the file. + * They try to skip any ID3v2 tag at the head of the file. * * \{ */ /** Read the STREAMINFO metadata block of the given FLAC file. This function - * will skip any ID3v2 tag at the head of the file. + * will try to skip any ID3v2 tag at the head of the file. * * \param filename The path to the FLAC file to read. * \param streaminfo A pointer to space for the STREAMINFO block. Since @@ -151,7 +159,7 @@ extern "C" { FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo); /** Read the VORBIS_COMMENT metadata block of the given FLAC file. This - * function will skip any ID3v2 tag at the head of the file. + * function will try to skip any ID3v2 tag at the head of the file. * * \param filename The path to the FLAC file to read. * \param tags The address where the returned pointer will be @@ -159,16 +167,75 @@ FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__St * the caller using FLAC__metadata_object_delete(). * \assert * \code filename != NULL \endcode - * \code streaminfo != NULL \endcode + * \code tags != NULL \endcode * \retval FLAC__bool * \c true if a valid VORBIS_COMMENT block was read from \a filename, - * and \a *tags will be set to the address of the tag structure. + * and \a *tags will be set to the address of the metadata structure. * Returns \c false if there was a memory allocation error, a file * decoder error, or the file contained no VORBIS_COMMENT block, and * \a *tags will be set to \c NULL. */ FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags); +/** Read the CUESHEET metadata block of the given FLAC file. This + * function will try to skip any ID3v2 tag at the head of the file. + * + * \param filename The path to the FLAC file to read. + * \param cuesheet The address where the returned pointer will be + * stored. The \a cuesheet object must be deleted by + * the caller using FLAC__metadata_object_delete(). + * \assert + * \code filename != NULL \endcode + * \code cuesheet != NULL \endcode + * \retval FLAC__bool + * \c true if a valid CUESHEET block was read from \a filename, + * and \a *cuesheet will be set to the address of the metadata + * structure. Returns \c false if there was a memory allocation + * error, a file decoder error, or the file contained no CUESHEET + * block, and \a *cuesheet will be set to \c NULL. + */ +FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet); + +/** Read a PICTURE metadata block of the given FLAC file. This + * function will try to skip any ID3v2 tag at the head of the file. + * Since there can be more than one PICTURE block in a file, this + * function takes a number of parameters that act as constraints to + * the search. The PICTURE block with the largest area matching all + * the constraints will be returned, or \a *picture will be set to + * \c NULL if there was no such block. + * + * \param filename The path to the FLAC file to read. + * \param picture The address where the returned pointer will be + * stored. The \a picture object must be deleted by + * the caller using FLAC__metadata_object_delete(). + * \param type The desired picture type. Use \c -1 to mean + * "any type". + * \param mime_type The desired MIME type, e.g. "image/jpeg". The + * string will be matched exactly. Use \c NULL to + * mean "any MIME type". + * \param description The desired description. The string will be + * matched exactly. Use \c NULL to mean "any + * description". + * \param max_width The maximum width in pixels desired. Use + * \c (unsigned)(-1) to mean "any width". + * \param max_height The maximum height in pixels desired. Use + * \c (unsigned)(-1) to mean "any height". + * \param max_depth The maximum color depth in bits-per-pixel desired. + * Use \c (unsigned)(-1) to mean "any depth". + * \param max_colors The maximum number of colors desired. Use + * \c (unsigned)(-1) to mean "any number of colors". + * \assert + * \code filename != NULL \endcode + * \code picture != NULL \endcode + * \retval FLAC__bool + * \c true if a valid PICTURE block was read from \a filename, + * and \a *picture will be set to the address of the metadata + * structure. Returns \c false if there was a memory allocation + * error, a file decoder error, or the file contained no PICTURE + * block, and \a *picture will be set to \c NULL. + */ +FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors); + /* \} */ @@ -184,9 +251,9 @@ FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMe * - Create an iterator using FLAC__metadata_simple_iterator_new() * - Attach it to a file using FLAC__metadata_simple_iterator_init() and check * the exit code. Call FLAC__metadata_simple_iterator_is_writable() to - * see if the file is writable, or read-only access is allowed. + * see if the file is writable, or only read access is allowed. * - Use FLAC__metadata_simple_iterator_next() and - * FLAC__metadata_simple_iterator_prev() to move around the blocks. + * FLAC__metadata_simple_iterator_prev() to traverse the blocks. * This is does not read the actual blocks themselves. * FLAC__metadata_simple_iterator_next() is relatively fast. * FLAC__metadata_simple_iterator_prev() is slower since it needs to search @@ -295,7 +362,7 @@ extern FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[]; * \retval FLAC__Metadata_SimpleIterator* * \c NULL if there was an error allocating memory, else the new instance. */ -FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(); +FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void); /** Free an iterator instance. Deletes the object pointed to by \a iterator. * @@ -378,6 +445,35 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIte */ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator); +/** Returns a flag telling if the current metadata block is the last. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval FLAC__bool + * \c true if the current metadata block is the last in the file, + * else \c false. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator); + +/** Get the offset of the metadata block at the current position. This + * avoids reading the actual block data which can save time for large + * blocks. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval off_t + * The offset of the metadata block at the current iterator position. + * This is the byte offset relative to the beginning of the file of + * the current metadata block's header. + */ +FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator); + /** Get the type of the metadata block at the current position. This * avoids reading the actual block data which can save time for large * blocks. @@ -390,9 +486,50 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIte * \retval FLAC__MetadataType * The type of the metadata block at the current iterator position. */ - FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator); +/** Get the length of the metadata block at the current position. This + * avoids reading the actual block data which can save time for large + * blocks. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval unsigned + * The length of the metadata block at the current iterator position. + * The is same length as that in the + * <a href="http://xiph.org/flac/format.html#metadata_block_header">metadata block header</a>, + * i.e. the length of the metadata body that follows the header. + */ +FLAC_API unsigned FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator); + +/** Get the application ID of the \c APPLICATION block at the current + * position. This avoids reading the actual block data which can save + * time for large blocks. + * + * \param iterator A pointer to an existing initialized iterator. + * \param id A pointer to a buffer of at least \c 4 bytes where + * the ID will be stored. + * \assert + * \code iterator != NULL \endcode + * \code id != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval FLAC__bool + * \c true if the ID was successfully read, else \c false, in which + * case you should check FLAC__metadata_simple_iterator_status() to + * find out why. If the status is + * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, then the + * current metadata block is not an \c APPLICATION block. Otherwise + * if the status is + * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR or + * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, an I/O error + * occurred and the iterator can no longer be used. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id); + /** Get the metadata block at the current position. You can modify the * block but must use FLAC__metadata_simple_iterator_set_block() to * write it back to the FLAC file. @@ -406,7 +543,8 @@ FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const * \a iterator has been successfully initialized with * FLAC__metadata_simple_iterator_init() * \retval FLAC__StreamMetadata* - * The current metadata block. + * The current metadata block, or \c NULL if there was a memory + * allocation error. */ FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator); @@ -521,12 +659,17 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_S * all metadata is read into memory, operated on in memory, and then written * to file, which is more efficient than level 1 when editing multiple blocks. * + * Currently Ogg FLAC is supported for read only, via + * FLAC__metadata_chain_read_ogg() but a subsequent + * FLAC__metadata_chain_write() will fail. + * * The general usage of this interface is: * * - Create a new chain using FLAC__metadata_chain_new(). A chain is a * linked list of FLAC metadata blocks. * - Read all metadata into the the chain from a FLAC file using - * FLAC__metadata_chain_read() and check the status. + * FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and + * check the status. * - Optionally, consolidate the padding using * FLAC__metadata_chain_merge_padding() or * FLAC__metadata_chain_sort_padding(). @@ -548,8 +691,8 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_S * Even though the FLAC file is not open while the chain is being * manipulated, you must not alter the file externally during * this time. The chain assumes the FLAC file will not change - * between the time of FLAC__metadata_chain_read() and - * FLAC__metadata_chain_write(). + * between the time of FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg() + * and FLAC__metadata_chain_write(). * * \note * Do not modify the is_last, length, or type fields of returned @@ -620,11 +763,12 @@ typedef enum { FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH, /**< FLAC__metadata_chain_write() was called on a chain read by - * FLAC__metadata_chain_read_with_callbacks(), or - * FLAC__metadata_chain_write_with_callbacks() or - * FLAC__metadata_chain_write_with_callbacks_and_tempfile() was - * called on a chain read by FLAC__metadata_chain_read(). Matching - * read/write methods must always be used. */ + * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), + * or + * FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile() + * was called on a chain read by + * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). + * Matching read/write methods must always be used. */ FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL /**< FLAC__metadata_chain_write_with_callbacks() was called when the @@ -652,7 +796,7 @@ extern FLAC_API const char * const FLAC__Metadata_ChainStatusString[]; * \retval FLAC__Metadata_Chain* * \c NULL if there was an error allocating memory, else the new instance. */ -FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(); +FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void); /** Free a chain instance. Deletes the object pointed to by \a chain. * @@ -688,6 +832,23 @@ FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_C */ FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename); +/** Read all metadata from an Ogg FLAC file into the chain. + * + * \note Ogg FLAC metadata data writing is not supported yet and + * FLAC__metadata_chain_write() will fail. + * + * \param chain A pointer to an existing chain. + * \param filename The path to the Ogg FLAC file to read. + * \assert + * \code chain != NULL \endcode + * \code filename != NULL \endcode + * \retval FLAC__bool + * \c true if a valid list of metadata blocks was read from + * \a filename, else \c false. On failure, check the status with + * FLAC__metadata_chain_status(). + */ +FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename); + /** Read all metadata from a FLAC stream into the chain via I/O callbacks. * * The \a handle need only be open for reading, but must be seekable. @@ -710,6 +871,31 @@ FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const */ FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); +/** Read all metadata from an Ogg FLAC stream into the chain via I/O callbacks. + * + * The \a handle need only be open for reading, but must be seekable. + * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" + * for Windows). + * + * \note Ogg FLAC metadata data writing is not supported yet and + * FLAC__metadata_chain_write() will fail. + * + * \param chain A pointer to an existing chain. + * \param handle The I/O handle of the Ogg FLAC stream to read. The + * handle will NOT be closed after the metadata is read; + * that is the duty of the caller. + * \param callbacks + * A set of callbacks to use for I/O. The mandatory + * callbacks are \a read, \a seek, and \a tell. + * \assert + * \code chain != NULL \endcode + * \retval FLAC__bool + * \c true if a valid list of metadata blocks was read from + * \a handle, else \c false. On failure, check the status with + * FLAC__metadata_chain_status(). + */ +FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); + /** Checks if writing the given chain would require the use of a * temporary file, or if it could be written in place. * @@ -770,7 +956,8 @@ FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata * be preserved even if the FLAC file is written. * * For this write function to be used, the chain must have been read with - * FLAC__metadata_chain_read(), not FLAC__metadata_chain_read_with_callbacks(). + * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(), not + * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(). * * \param chain A pointer to an existing chain. * \param use_padding See above. @@ -793,7 +980,8 @@ FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC * for Windows). * * For this write function to be used, the chain must have been read with - * FLAC__metadata_chain_read_with_callbacks(), not FLAC__metadata_chain_read(). + * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), + * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned * \c false. * @@ -836,7 +1024,8 @@ FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Cha * truncate it on return). * * For this write function to be used, the chain must have been read with - * FLAC__metadata_chain_read_with_callbacks(), not FLAC__metadata_chain_read(). + * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), + * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned * \c true. * @@ -899,7 +1088,7 @@ FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain); * \retval FLAC__Metadata_Iterator* * \c NULL if there was an error allocating memory, else the new instance. */ -FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(); +FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void); /** Free an iterator instance. Deletes the object pointed to by \a iterator. * @@ -1087,6 +1276,17 @@ FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_It * FLAC__metadata_object_application_set_data(), you will get an assertion * failure. * + * For convenience the FLAC__metadata_object_vorbiscomment_*() functions + * maintain a trailing NUL on each Vorbis comment entry. This is not counted + * toward the length or stored in the stream, but it can make working with plain + * comments (those that don't contain embedded-NULs in the value) easier. + * Entries passed into these functions have trailing NULs added if missing, and + * returned entries are guaranteed to have a trailing NUL. + * + * The FLAC__metadata_object_vorbiscomment_*() functions that take a Vorbis + * comment entry/name/value will first validate that it complies with the Vorbis + * comment specification and return false if it does not. + * * There is no need to recalculate the length field on metadata blocks you * have modified. They will be calculated automatically before they are * written back to a file. @@ -1155,8 +1355,11 @@ FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *b /** Sets the application data of an APPLICATION block. * * If \a copy is \c true, a copy of the data is stored; otherwise, the object - * takes ownership of the pointer. Returns \c false if \a copy == \c true - * and malloc fails. + * takes ownership of the pointer. The existing data will be freed if this + * function is successful, otherwise the original data will remain if \a copy + * is \c true and malloc() fails. + * + * \note It is safe to pass a const pointer to \a data if \a copy is \c true. * * \param object A pointer to an existing APPLICATION object. * \param data A pointer to the data to set. @@ -1168,7 +1371,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *b * \code (data != NULL && length > 0) || * (data == NULL && length == 0 && copy == false) \endcode * \retval FLAC__bool - * \c false if \a copy is \c true and malloc fails, else \c true. + * \c false if \a copy is \c true and malloc() fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy); @@ -1309,11 +1512,40 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC_ * \assert * \code object != NULL \endcode * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code total_samples > 0 \endcode * \retval FLAC__bool * \c false if memory allocation fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples); +/** Append a set of evenly-spaced seek point templates to the end of a + * seek table. + * + * \note + * As with the other ..._seektable_template_... functions, you should + * call FLAC__metadata_object_seektable_template_sort() when finished + * to make the seek table legal. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param samples The number of samples apart to space the placeholder + * points. The first point will be at sample \c 0, the + * second at sample \a samples, then 2*\a samples, and + * so on. As long as \a samples and \a total_samples + * are greater than \c 0, there will always be at least + * one seekpoint at sample \c 0. + * \param total_samples The total number of samples to be encoded; + * the seekpoints will be spaced + * \a samples samples apart. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code samples > 0 \endcode + * \code total_samples > 0 \endcode + * \retval FLAC__bool + * \c false if memory allocation fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples); + /** Sort a seek table's seek points according to the format specification, * removing duplicates. * @@ -1327,15 +1559,20 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_point * \code object != NULL \endcode * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode * \retval FLAC__bool - * \c false if realloc fails, else \c true. + * \c false if realloc() fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact); /** Sets the vendor string in a VORBIS_COMMENT block. * + * For convenience, a trailing NUL is added to the entry if it doesn't have + * one already. + * * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry->entry pointer. Returns \c false if - * \a copy == \c true and malloc fails. + * takes ownership of the \c entry.entry pointer. + * + * \note If this function returns \c false, the caller still owns the + * pointer. * * \param object A pointer to an existing VORBIS_COMMENT object. * \param entry The entry to set the vendor string to. @@ -1343,10 +1580,11 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMe * \assert * \code object != NULL \endcode * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code (entry->entry != NULL && entry->length > 0) || - * (entry->entry == NULL && entry->length == 0) \endcode + * \code (entry.entry != NULL && entry.length > 0) || + * (entry.entry == NULL && entry.length == 0) \endcode * \retval FLAC__bool - * \c false if \a copy is \c true and malloc fails, else \c true. + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); @@ -1363,15 +1601,20 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__ * \code (object->data.vorbis_comment.comments == NULL && object->data.vorbis_comment.num_comments == 0) || * (object->data.vorbis_comment.comments != NULL && object->data.vorbis_comment.num_comments > 0) \endcode * \retval FLAC__bool - * \c false if memory allocation error, else \c true. + * \c false if memory allocation fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments); /** Sets a comment in a VORBIS_COMMENT block. * + * For convenience, a trailing NUL is added to the entry if it doesn't have + * one already. + * * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry->entry pointer. Returns \c false if - * \a copy == \c true and malloc fails. + * takes ownership of the \c entry.entry pointer. + * + * \note If this function returns \c false, the caller still owns the + * pointer. * * \param object A pointer to an existing VORBIS_COMMENT object. * \param comment_num Index into comment array to set. @@ -1381,18 +1624,24 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__St * \code object != NULL \endcode * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode * \code comment_num < object->data.vorbis_comment.num_comments \endcode - * \code (entry->entry != NULL && entry->length > 0) || - * (entry->entry == NULL && entry->length == 0) \endcode + * \code (entry.entry != NULL && entry.length > 0) || + * (entry.entry == NULL && entry.length == 0) \endcode * \retval FLAC__bool - * \c false if \a copy is \c true and malloc fails, else \c true. + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); /** Insert a comment in a VORBIS_COMMENT block at the given index. * + * For convenience, a trailing NUL is added to the entry if it doesn't have + * one already. + * * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry->entry pointer. Returns \c false if - * \a copy == \c true and malloc fails. + * takes ownership of the \c entry.entry pointer. + * + * \note If this function returns \c false, the caller still owns the + * pointer. * * \param object A pointer to an existing VORBIS_COMMENT object. * \param comment_num The index at which to insert the comment. The comments @@ -1405,13 +1654,74 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__Stream * \code object != NULL \endcode * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode * \code object->data.vorbis_comment.num_comments >= comment_num \endcode - * \code (entry->entry != NULL && entry->length > 0) || - * (entry->entry == NULL && entry->length == 0 && copy == false) \endcode + * \code (entry.entry != NULL && entry.length > 0) || + * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode * \retval FLAC__bool - * \c false if \a copy is \c true and malloc fails, else \c true. + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); +/** Appends a comment to a VORBIS_COMMENT block. + * + * For convenience, a trailing NUL is added to the entry if it doesn't have + * one already. + * + * If \a copy is \c true, a copy of the entry is stored; otherwise, the object + * takes ownership of the \c entry.entry pointer. + * + * \note If this function returns \c false, the caller still owns the + * pointer. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param entry The comment to insert. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code (entry.entry != NULL && entry.length > 0) || + * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode + * \retval FLAC__bool + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); + +/** Replaces comments in a VORBIS_COMMENT block with a new one. + * + * For convenience, a trailing NUL is added to the entry if it doesn't have + * one already. + * + * Depending on the the value of \a all, either all or just the first comment + * whose field name(s) match the given entry's name will be replaced by the + * given entry. If no comments match, \a entry will simply be appended. + * + * If \a copy is \c true, a copy of the entry is stored; otherwise, the object + * takes ownership of the \c entry.entry pointer. + * + * \note If this function returns \c false, the caller still owns the + * pointer. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param entry The comment to insert. + * \param all If \c true, all comments whose field name matches + * \a entry's field name will be removed, and \a entry will + * be inserted at the position of the first matching + * comment. If \c false, only the first comment whose + * field name matches \a entry's field name will be + * replaced with \a entry. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code (entry.entry != NULL && entry.length > 0) || + * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode + * \retval FLAC__bool + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy); + /** Delete a comment in a VORBIS_COMMENT block at the given index. * * \param object A pointer to an existing VORBIS_COMMENT object. @@ -1420,30 +1730,67 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__Str * \code object != NULL \endcode * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode * \code object->data.vorbis_comment.num_comments > comment_num \endcode - * \code (entry->entry != NULL && entry->length > 0) || - * (entry->entry == NULL && entry->length == 0 && copy == false) \endcode * \retval FLAC__bool - * \c false if realloc fails, else \c true. + * \c false if realloc() fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num); -/*@@@@ add to unit tests */ +/** Creates a Vorbis comment entry from NUL-terminated name and value strings. + * + * On return, the filled-in \a entry->entry pointer will point to malloc()ed + * memory and shall be owned by the caller. For convenience the entry will + * have a terminating NUL. + * + * \param entry A pointer to a Vorbis comment entry. The entry's + * \c entry pointer should not point to allocated + * memory as it will be overwritten. + * \param field_name The field name in ASCII, \c NUL terminated. + * \param field_value The field value in UTF-8, \c NUL terminated. + * \assert + * \code entry != NULL \endcode + * \code field_name != NULL \endcode + * \code field_value != NULL \endcode + * \retval FLAC__bool + * \c false if malloc() fails, or if \a field_name or \a field_value does + * not comply with the Vorbis comment specification, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value); + +/** Splits a Vorbis comment entry into NUL-terminated name and value strings. + * + * The returned pointers to name and value will be allocated by malloc() + * and shall be owned by the caller. + * + * \param entry An existing Vorbis comment entry. + * \param field_name The address of where the returned pointer to the + * field name will be stored. + * \param field_value The address of where the returned pointer to the + * field value will be stored. + * \assert + * \code (entry.entry != NULL && entry.length > 0) \endcode + * \code memchr(entry.entry, '=', entry.length) != NULL \endcode + * \code field_name != NULL \endcode + * \code field_value != NULL \endcode + * \retval FLAC__bool + * \c false if memory allocation fails or \a entry does not comply with the + * Vorbis comment specification, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value); + /** Check if the given Vorbis comment entry's field name matches the given * field name. * - * \param entry A pointer to an existing Vorbis comment entry. + * \param entry An existing Vorbis comment entry. * \param field_name The field name to check. * \param field_name_length The length of \a field_name, not including the - * terminating \c NULL. + * terminating \c NUL. * \assert - * \code entry != NULL \endcode - * \code (entry->entry != NULL && entry->length > 0) \endcode + * \code (entry.entry != NULL && entry.length > 0) \endcode * \retval FLAC__bool * \c true if the field names match, else \c false */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, unsigned field_name_length); +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length); -/*@@@@ add to unit tests */ /** Find a Vorbis comment with the given field name. * * The search begins at entry number \a offset; use an offset of 0 to @@ -1456,13 +1803,13 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC * \assert * \code object != NULL \endcode * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code field_name != NULL \endcode * \retval int * The offset in the comment array of the first comment whose field * name matches \a field_name, or \c -1 if no match was found. */ FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name); -/*@@@@ add to unit tests */ /** Remove first Vorbis comment matching the given field name. * * \param object A pointer to an existing VORBIS_COMMENT object. @@ -1476,7 +1823,6 @@ FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__Str */ FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name); -/*@@@@ add to unit tests */ /** Remove all Vorbis comments matching the given field name. * * \param object A pointer to an existing VORBIS_COMMENT object. @@ -1497,7 +1843,7 @@ FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__S * \retval FLAC__StreamMetadata_CueSheet_Track* * \c NULL if there was an error allocating memory, else the new instance. */ -FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(); +FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void); /** Create a copy of an existing CUESHEET track object. * @@ -1561,7 +1907,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__St * \code object->data.cue_sheet.num_tracks > track_num \endcode * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode * \retval FLAC__bool - * \c false if realloc fails, else \c true. + * \c false if realloc() fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index); @@ -1585,7 +1931,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__Stre * \code object->data.cue_sheet.num_tracks > track_num \endcode * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode * \retval FLAC__bool - * \c false if realloc fails, else \c true. + * \c false if realloc() fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num); @@ -1604,7 +1950,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC * \code object->data.cue_sheet.num_tracks > track_num \endcode * \code object->data.cue_sheet.tracks[track_num].num_indices > index_num \endcode * \retval FLAC__bool - * \c false if realloc fails, else \c true. + * \c false if realloc() fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num); @@ -1628,8 +1974,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMet /** Sets a track in a CUESHEET block. * * If \a copy is \c true, a copy of the track is stored; otherwise, the object - * takes ownership of the \a track pointer. Returns \c false if - * \a copy == \c true and malloc fails. + * takes ownership of the \a track pointer. * * \param object A pointer to an existing CUESHEET object. * \param track_num Index into track array to set. NOTE: this is not @@ -1642,17 +1987,16 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMet * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode * \code track_num < object->data.cue_sheet.num_tracks \endcode * \code (track->indices != NULL && track->num_indices > 0) || - * (track->indices == NULL && track->num_indices == 0) + * (track->indices == NULL && track->num_indices == 0) \endcode * \retval FLAC__bool - * \c false if \a copy is \c true and malloc fails, else \c true. + * \c false if \a copy is \c true and malloc() fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy); /** Insert a track in a CUESHEET block at the given index. * * If \a copy is \c true, a copy of the track is stored; otherwise, the object - * takes ownership of the \a track pointer. Returns \c false if - * \a copy == \c true and malloc fails. + * takes ownership of the \a track pointer. * * \param object A pointer to an existing CUESHEET object. * \param track_num The index at which to insert the track. NOTE: this @@ -1668,7 +2012,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadat * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode * \code object->data.cue_sheet.num_tracks >= track_num \endcode * \retval FLAC__bool - * \c false if \a copy is \c true and malloc fails, else \c true. + * \c false if \a copy is \c true and malloc() fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy); @@ -1687,7 +2031,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMeta * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode * \code object->data.cue_sheet.num_tracks >= track_num \endcode * \retval FLAC__bool - * \c false if \a copy is \c true and malloc fails, else \c true. + * \c false if \a copy is \c true and malloc() fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num); @@ -1702,7 +2046,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__Stre * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode * \code object->data.cue_sheet.num_tracks > track_num \endcode * \retval FLAC__bool - * \c false if realloc fails, else \c true. + * \c false if realloc() fails, else \c true. */ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num); @@ -1727,6 +2071,108 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMeta */ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation); +/** Calculate and return the CDDB/freedb ID for a cue sheet. The function + * assumes the cue sheet corresponds to a CD; the result is undefined + * if the cuesheet's is_cd bit is not set. + * + * \param object A pointer to an existing CUESHEET object. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \retval FLAC__uint32 + * The unsigned integer representation of the CDDB/freedb ID + */ +FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object); + +/** Sets the MIME type of a PICTURE block. + * + * If \a copy is \c true, a copy of the string is stored; otherwise, the object + * takes ownership of the pointer. The existing string will be freed if this + * function is successful, otherwise the original string will remain if \a copy + * is \c true and malloc() fails. + * + * \note It is safe to pass a const pointer to \a mime_type if \a copy is \c true. + * + * \param object A pointer to an existing PICTURE object. + * \param mime_type A pointer to the MIME type string. The string must be + * ASCII characters 0x20-0x7e, NUL-terminated. No validation + * is done. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \code (mime_type != NULL) \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy); + +/** Sets the description of a PICTURE block. + * + * If \a copy is \c true, a copy of the string is stored; otherwise, the object + * takes ownership of the pointer. The existing string will be freed if this + * function is successful, otherwise the original string will remain if \a copy + * is \c true and malloc() fails. + * + * \note It is safe to pass a const pointer to \a description if \a copy is \c true. + * + * \param object A pointer to an existing PICTURE object. + * \param description A pointer to the description string. The string must be + * valid UTF-8, NUL-terminated. No validation is done. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \code (description != NULL) \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy); + +/** Sets the picture data of a PICTURE block. + * + * If \a copy is \c true, a copy of the data is stored; otherwise, the object + * takes ownership of the pointer. Also sets the \a data_length field of the + * metadata object to what is passed in as the \a length parameter. The + * existing data will be freed if this function is successful, otherwise the + * original data and data_length will remain if \a copy is \c true and + * malloc() fails. + * + * \note It is safe to pass a const pointer to \a data if \a copy is \c true. + * + * \param object A pointer to an existing PICTURE object. + * \param data A pointer to the data to set. + * \param length The length of \a data in bytes. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \code (data != NULL && length > 0) || + * (data == NULL && length == 0 && copy == false) \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy); + +/** Check a PICTURE block to see if it conforms to the FLAC specification. + * See the format specification for limits on the contents of the + * PICTURE block. + * + * \param object A pointer to existing PICTURE block to be checked. + * \param violation Address of a pointer to a string. If there is a + * violation, a pointer to a string explanation of the + * violation will be returned here. \a violation may be + * \c NULL if you don't need the returned string. Do not + * free the returned string; it will always point to static + * data. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \retval FLAC__bool + * \c false if PICTURE block is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation); + /* \} */ #ifdef __cplusplus diff --git a/sys/src/cmd/audio/libFLAC/FLAC/ordinals.h b/sys/src/cmd/audio/libFLAC/FLAC/ordinals.h index 2da155072..b1e1acfce 100644 --- a/sys/src/cmd/audio/libFLAC/FLAC/ordinals.h +++ b/sys/src/cmd/audio/libFLAC/FLAC/ordinals.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,40 +33,44 @@ #ifndef FLAC__ORDINALS_H #define FLAC__ORDINALS_H -#if !defined(_MSC_VER) && !defined(Plan9) -#include <inttypes.h> -#endif +#if defined(_MSC_VER) && _MSC_VER < 1600 + +/* Microsoft Visual Studio earlier than the 2010 version did not provide + * the 1999 ISO C Standard header file <stdint.h>. + */ -typedef signed char FLAC__int8; -typedef unsigned char FLAC__uint8; +typedef __int8 FLAC__int8; +typedef unsigned __int8 FLAC__uint8; -#if defined _MSC_VER typedef __int16 FLAC__int16; typedef __int32 FLAC__int32; typedef __int64 FLAC__int64; typedef unsigned __int16 FLAC__uint16; typedef unsigned __int32 FLAC__uint32; typedef unsigned __int64 FLAC__uint64; -#elif defined Plan9 -typedef short FLAC__int16; -typedef int FLAC__int32; -typedef long long FLAC__int64; -typedef unsigned short FLAC__uint16; -typedef unsigned int FLAC__uint32; -typedef unsigned long long FLAC__uint64; + #else + +/* For MSVC 2010 and everything else which provides <stdint.h>. */ + +#include <stdint.h> + +typedef int8_t FLAC__int8; +typedef uint8_t FLAC__uint8; + typedef int16_t FLAC__int16; typedef int32_t FLAC__int32; typedef int64_t FLAC__int64; typedef uint16_t FLAC__uint16; typedef uint32_t FLAC__uint32; typedef uint64_t FLAC__uint64; + #endif typedef int FLAC__bool; typedef FLAC__uint8 FLAC__byte; -typedef float FLAC__real; + #ifdef true #undef true diff --git a/sys/src/cmd/audio/libFLAC/FLAC/seekable_stream_decoder.h b/sys/src/cmd/audio/libFLAC/FLAC/seekable_stream_decoder.h deleted file mode 100644 index b28f44726..000000000 --- a/sys/src/cmd/audio/libFLAC/FLAC/seekable_stream_decoder.h +++ /dev/null @@ -1,931 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 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. - */ - -#ifndef FLAC__SEEKABLE_STREAM_DECODER_H -#define FLAC__SEEKABLE_STREAM_DECODER_H - -#include "export.h" -#include "stream_decoder.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \file include/FLAC/seekable_stream_decoder.h - * - * \brief - * This module contains the functions which implement the seekable stream - * decoder. - * - * See the detailed documentation in the - * \link flac_seekable_stream_decoder seekable stream decoder \endlink module. - */ - -/** \defgroup flac_seekable_stream_decoder FLAC/seekable_stream_decoder.h: seekable stream decoder interface - * \ingroup flac_decoder - * - * \brief - * This module contains the functions which implement the seekable stream - * decoder. - * - * The basic usage of this decoder is as follows: - * - The program creates an instance of a decoder using - * FLAC__seekable_stream_decoder_new(). - * - The program overrides the default settings and sets callbacks for - * reading, writing, seeking, error reporting, and metadata reporting - * using FLAC__seekable_stream_decoder_set_*() functions. - * - The program initializes the instance to validate the settings and - * prepare for decoding using FLAC__seekable_stream_decoder_init(). - * - The program calls the FLAC__seekable_stream_decoder_process_*() - * functions to decode data, which subsequently calls the callbacks. - * - The program finishes the decoding with - * FLAC__seekable_stream_decoder_finish(), which flushes the input and - * output and resets the decoder to the uninitialized state. - * - The instance may be used again or deleted with - * FLAC__seekable_stream_decoder_delete(). - * - * The seekable stream decoder is a wrapper around the - * \link flac_stream_decoder stream decoder \endlink which also provides - * seeking capability. In addition to the Read/Write/Metadata/Error - * callbacks of the stream decoder, the user must also provide the following: - * - * - Seek callback - This function will be called when the decoder wants to - * seek to an absolute position in the stream. - * - Tell callback - This function will be called when the decoder wants to - * know the current absolute position of the stream. - * - Length callback - This function will be called when the decoder wants - * to know length of the stream. The seeking algorithm currently requires - * that the overall stream length be known. - * - EOF callback - This function will be called when the decoder wants to - * know if it is at the end of the stream. This could be synthesized from - * the tell and length callbacks but it may be more expensive that way, so - * there is a separate callback for it. - * - * Seeking is exposed through the - * FLAC__seekable_stream_decoder_seek_absolute() method. At any point after - * the seekable stream decoder has been initialized, the user can call this - * function to seek to an exact sample within the stream. Subsequently, the - * first time the write callback is called it will be passed a (possibly - * partial) block starting at that sample. - * - * The seekable stream decoder also provides MD5 signature checking. If - * this is turned on before initialization, - * FLAC__seekable_stream_decoder_finish() will report when the decoded MD5 - * signature does not match the one stored in the STREAMINFO block. MD5 - * checking is automatically turned off (until the next - * FLAC__seekable_stream_decoder_reset()) if there is no signature in the - * STREAMINFO block or when a seek is attempted. - * - * Make sure to read the detailed description of the - * \link flac_stream_decoder stream decoder module \endlink since the - * seekable stream decoder inherits much of its behavior. - * - * \note - * The "set" functions may only be called when the decoder is in the - * state FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED, i.e. after - * FLAC__seekable_stream_decoder_new() or - * FLAC__seekable_stream_decoder_finish(), but before - * FLAC__seekable_stream_decoder_init(). If this is the case they will - * return \c true, otherwise \c false. - * - * \note - * FLAC__stream_decoder_finish() resets all settings to the constructor - * defaults, including the callbacks. - * - * \{ - */ - - -/** State values for a FLAC__SeekableStreamDecoder - * - * The decoder's state can be obtained by calling FLAC__seekable_stream_decoder_get_state(). - */ -typedef enum { - - FLAC__SEEKABLE_STREAM_DECODER_OK = 0, - /**< The decoder is in the normal OK state. */ - - FLAC__SEEKABLE_STREAM_DECODER_SEEKING, - /**< The decoder is in the process of seeking. */ - - FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM, - /**< The decoder has reached the end of the stream. */ - - FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR, - /**< An error occurred allocating memory. */ - - FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR, - /**< An error occurred in the underlying stream decoder. */ - - FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR, - /**< The read callback returned an error. */ - - FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR, - /**< An error occurred while seeking or the seek or tell - * callback returned an error. - */ - - FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED, - /**< FLAC__seekable_stream_decoder_init() was called when the - * decoder was already initialized, usually because - * FLAC__seekable_stream_decoder_finish() was not called. - */ - - FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK, - /**< FLAC__seekable_stream_decoder_init() was called without all - * callbacks being set. - */ - - FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED - /**< The decoder is in the uninitialized state. */ - -} FLAC__SeekableStreamDecoderState; - -/** Maps a FLAC__SeekableStreamDecoderState to a C string. - * - * Using a FLAC__SeekableStreamDecoderState as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__SeekableStreamDecoderStateString[]; - - -/** Return values for the FLAC__SeekableStreamDecoder read callback. - */ -typedef enum { - - FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK, - /**< The read was OK and decoding can continue. */ - - FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - -} FLAC__SeekableStreamDecoderReadStatus; - -/** Maps a FLAC__SeekableStreamDecoderReadStatus to a C string. - * - * Using a FLAC__SeekableStreamDecoderReadStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__SeekableStreamDecoderReadStatusString[]; - - -/** Return values for the FLAC__SeekableStreamDecoder seek callback. - */ -typedef enum { - - FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK, - /**< The seek was OK and decoding can continue. */ - - FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - -} FLAC__SeekableStreamDecoderSeekStatus; - -/** Maps a FLAC__SeekableStreamDecoderSeekStatus to a C string. - * - * Using a FLAC__SeekableStreamDecoderSeekStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__SeekableStreamDecoderSeekStatusString[]; - - -/** Return values for the FLAC__SeekableStreamDecoder tell callback. - */ -typedef enum { - - FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK, - /**< The tell was OK and decoding can continue. */ - - FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - -} FLAC__SeekableStreamDecoderTellStatus; - -/** Maps a FLAC__SeekableStreamDecoderTellStatus to a C string. - * - * Using a FLAC__SeekableStreamDecoderTellStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__SeekableStreamDecoderTellStatusString[]; - - -/** Return values for the FLAC__SeekableStreamDecoder length callback. - */ -typedef enum { - - FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK, - /**< The length call was OK and decoding can continue. */ - - FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - -} FLAC__SeekableStreamDecoderLengthStatus; - -/** Maps a FLAC__SeekableStreamDecoderLengthStatus to a C string. - * - * Using a FLAC__SeekableStreamDecoderLengthStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__SeekableStreamDecoderLengthStatusString[]; - - -/*********************************************************************** - * - * class FLAC__SeekableStreamDecoder : public FLAC__StreamDecoder - * - ***********************************************************************/ - -struct FLAC__SeekableStreamDecoderProtected; -struct FLAC__SeekableStreamDecoderPrivate; -/** The opaque structure definition for the seekable stream decoder type. - * See the - * \link flac_seekable_stream_decoder seekable stream decoder module \endlink - * for a detailed description. - */ -typedef struct { - struct FLAC__SeekableStreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */ - struct FLAC__SeekableStreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */ -} FLAC__SeekableStreamDecoder; - -/** Signature for the read callback. - * See FLAC__seekable_stream_decoder_set_read_callback() - * and FLAC__StreamDecoderReadCallback for more info. - * - * \param decoder The decoder instance calling the callback. - * \param buffer A pointer to a location for the callee to store - * data to be decoded. - * \param bytes A pointer to the size of the buffer. - * \param client_data The callee's client data set through - * FLAC__seekable_stream_decoder_set_client_data(). - * \retval FLAC__SeekableStreamDecoderReadStatus - * The callee's return status. - */ -typedef FLAC__SeekableStreamDecoderReadStatus (*FLAC__SeekableStreamDecoderReadCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data); - -/** Signature for the seek callback. - * See FLAC__seekable_stream_decoder_set_seek_callback() for more info. - * - * \param decoder The decoder instance calling the callback. - * \param absolute_byte_offset The offset from the beginning of the stream - * to seek to. - * \param client_data The callee's client data set through - * FLAC__seekable_stream_decoder_set_client_data(). - * \retval FLAC__SeekableStreamDecoderSeekStatus - * The callee's return status. - */ -typedef FLAC__SeekableStreamDecoderSeekStatus (*FLAC__SeekableStreamDecoderSeekCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); - -/** Signature for the tell callback. - * See FLAC__seekable_stream_decoder_set_tell_callback() for more info. - * - * \param decoder The decoder instance calling the callback. - * \param absolute_byte_offset A pointer to storage for the current offset - * from the beginning of the stream. - * \param client_data The callee's client data set through - * FLAC__seekable_stream_decoder_set_client_data(). - * \retval FLAC__SeekableStreamDecoderTellStatus - * The callee's return status. - */ -typedef FLAC__SeekableStreamDecoderTellStatus (*FLAC__SeekableStreamDecoderTellCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); - -/** Signature for the length callback. - * See FLAC__seekable_stream_decoder_set_length_callback() for more info. - * - * \param decoder The decoder instance calling the callback. - * \param stream_length A pointer to storage for the length of the stream - * in bytes. - * \param client_data The callee's client data set through - * FLAC__seekable_stream_decoder_set_client_data(). - * \retval FLAC__SeekableStreamDecoderLengthStatus - * The callee's return status. - */ -typedef FLAC__SeekableStreamDecoderLengthStatus (*FLAC__SeekableStreamDecoderLengthCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); - -/** Signature for the EOF callback. - * See FLAC__seekable_stream_decoder_set_eof_callback() for more info. - * - * \param decoder The decoder instance calling the callback. - * \param client_data The callee's client data set through - * FLAC__seekable_stream_decoder_set_client_data(). - * \retval FLAC__bool - * \c true if the currently at the end of the stream, else \c false. - */ -typedef FLAC__bool (*FLAC__SeekableStreamDecoderEofCallback)(const FLAC__SeekableStreamDecoder *decoder, void *client_data); - -/** Signature for the write callback. - * See FLAC__seekable_stream_decoder_set_write_callback() - * and FLAC__StreamDecoderWriteCallback for more info. - * - * \param decoder The decoder instance calling the callback. - * \param frame The description of the decoded frame. - * \param buffer An array of pointers to decoded channels of data. - * \param client_data The callee's client data set through - * FLAC__seekable_stream_decoder_set_client_data(). - * \retval FLAC__StreamDecoderWriteStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderWriteStatus (*FLAC__SeekableStreamDecoderWriteCallback)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); - -/** Signature for the metadata callback. - * See FLAC__seekable_stream_decoder_set_metadata_callback() - * and FLAC__StreamDecoderMetadataCallback for more info. - * - * \param decoder The decoder instance calling the callback. - * \param metadata The decoded metadata block. - * \param client_data The callee's client data set through - * FLAC__seekable_stream_decoder_set_client_data(). - */ -typedef void (*FLAC__SeekableStreamDecoderMetadataCallback)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); - -/** Signature for the error callback. - * See FLAC__seekable_stream_decoder_set_error_callback() - * and FLAC__StreamDecoderErrorCallback for more info. - * - * \param decoder The decoder instance calling the callback. - * \param status The error encountered by the decoder. - * \param client_data The callee's client data set through - * FLAC__seekable_stream_decoder_set_client_data(). - */ -typedef void (*FLAC__SeekableStreamDecoderErrorCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); - - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -/** Create a new seekable stream decoder instance. The instance is created - * with default settings; see the individual - * FLAC__seekable_stream_decoder_set_*() functions for each setting's - * default. - * - * \retval FLAC__SeekableStreamDecoder* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__SeekableStreamDecoder *FLAC__seekable_stream_decoder_new(); - -/** Free a decoder instance. Deletes the object pointed to by \a decoder. - * - * \param decoder A pointer to an existing decoder. - * \assert - * \code decoder != NULL \endcode - */ -FLAC_API void FLAC__seekable_stream_decoder_delete(FLAC__SeekableStreamDecoder *decoder); - - -/*********************************************************************** - * - * Public class method prototypes - * - ***********************************************************************/ - -/** Set the "MD5 signature checking" flag. If \c true, the decoder will - * compute the MD5 signature of the unencoded audio data while decoding - * and compare it to the signature from the STREAMINFO block, if it - * exists, during FLAC__seekable_stream_decoder_finish(). - * - * MD5 signature checking will be turned off (until the next - * FLAC__seekable_stream_decoder_reset()) if there is no signature in - * the STREAMINFO block or when a seek is attempted. - * - * \default \c false - * \param decoder A decoder instance to set. - * \param value Flag value (see above). - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_md5_checking(FLAC__SeekableStreamDecoder *decoder, FLAC__bool value); - -/** Set the read callback. - * This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_set_read_callback(). - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_read_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderReadCallback value); - -/** Set the seek callback. - * The supplied function will be called when the decoder needs to seek - * the input stream. The decoder will pass the absolute byte offset - * to seek to, 0 meaning the beginning of the stream. - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_seek_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderSeekCallback value); - -/** Set the tell callback. - * The supplied function will be called when the decoder wants to know - * the current position of the stream. The callback should return the - * byte offset from the beginning of the stream. - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_tell_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderTellCallback value); - -/** Set the length callback. - * The supplied function will be called when the decoder wants to know - * the total length of the stream in bytes. - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_length_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderLengthCallback value); - -/** Set the eof callback. - * The supplied function will be called when the decoder needs to know - * if the end of the stream has been reached. - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_eof_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderEofCallback value); - -/** Set the write callback. - * This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_set_write_callback(). - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_write_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderWriteCallback value); - -/** Set the metadata callback. - * This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_set_metadata_callback(). - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderMetadataCallback value); - -/** Set the error callback. - * This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_set_error_callback(). - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_error_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderErrorCallback value); - -/** Set the client data to be passed back to callbacks. - * This value will be supplied to callbacks in their \a client_data - * argument. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_client_data(FLAC__SeekableStreamDecoder *decoder, void *value); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_set_metadata_respond(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param type See above. - * \assert - * \code decoder != NULL \endcode - * \a type is valid - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_set_metadata_respond_application(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param id See above. - * \assert - * \code decoder != NULL \endcode - * \code id != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4]); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_set_metadata_respond_all(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_all(FLAC__SeekableStreamDecoder *decoder); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_set_metadata_ignore(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param type See above. - * \assert - * \code decoder != NULL \endcode - * \a type is valid - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_set_metadata_ignore_application(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param id See above. - * \assert - * \code decoder != NULL \endcode - * \code id != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4]); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_set_metadata_ignore_all(). - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_all(FLAC__SeekableStreamDecoder *decoder); - -/** Get the current decoder state. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__SeekableStreamDecoderState - * The current decoder state. - */ -FLAC_API FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_get_state(const FLAC__SeekableStreamDecoder *decoder); - -/** Get the state of the underlying stream decoder. - * Useful when the seekable stream decoder state is - * \c FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderState - * The stream decoder state. - */ -FLAC_API FLAC__StreamDecoderState FLAC__seekable_stream_decoder_get_stream_decoder_state(const FLAC__SeekableStreamDecoder *decoder); - -/** Get the current decoder state as a C string. - * This version automatically resolves - * \c FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR by getting the - * stream decoder's state. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval const char * - * The decoder state as a C string. Do not modify the contents. - */ -FLAC_API const char *FLAC__seekable_stream_decoder_get_resolved_state_string(const FLAC__SeekableStreamDecoder *decoder); - -/** Get the "MD5 signature checking" flag. - * This is the value of the setting, not whether or not the decoder is - * currently checking the MD5 (remember, it can be turned off automatically - * by a seek). When the decoder is reset the flag will be restored to the - * value returned by this function. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_get_md5_checking(const FLAC__SeekableStreamDecoder *decoder); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_get_channels(). - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval unsigned - * See above. - */ -FLAC_API unsigned FLAC__seekable_stream_decoder_get_channels(const FLAC__SeekableStreamDecoder *decoder); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_get_channel_assignment(). - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__ChannelAssignment - * See above. - */ -FLAC_API FLAC__ChannelAssignment FLAC__seekable_stream_decoder_get_channel_assignment(const FLAC__SeekableStreamDecoder *decoder); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_get_bits_per_sample(). - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval unsigned - * See above. - */ -FLAC_API unsigned FLAC__seekable_stream_decoder_get_bits_per_sample(const FLAC__SeekableStreamDecoder *decoder); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_get_sample_rate(). - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval unsigned - * See above. - */ -FLAC_API unsigned FLAC__seekable_stream_decoder_get_sample_rate(const FLAC__SeekableStreamDecoder *decoder); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_get_blocksize(). - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval unsigned - * See above. - */ -FLAC_API unsigned FLAC__seekable_stream_decoder_get_blocksize(const FLAC__SeekableStreamDecoder *decoder); - -/** Returns the decoder's current read position within the stream. - * The position is the byte offset from the start of the stream. - * Bytes before this position have been fully decoded. Note that - * there may still be undecoded bytes in the decoder's read FIFO. - * The returned position is correct even after a seek. - * - * \param decoder A decoder instance to query. - * \param position Address at which to return the desired position. - * \assert - * \code decoder != NULL \endcode - * \code position != NULL \endcode - * \retval FLAC__bool - * \c true if successful, \c false if there was an error from - * the 'tell' callback. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_get_decode_position(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *position); - -/** Initialize the decoder instance. - * Should be called after FLAC__seekable_stream_decoder_new() and - * FLAC__seekable_stream_decoder_set_*() but before any of the - * FLAC__seekable_stream_decoder_process_*() functions. Will set and return - * the decoder state, which will be FLAC__SEEKABLE_STREAM_DECODER_OK - * if initialization succeeded. - * - * \param decoder An uninitialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__SeekableStreamDecoderState - * \c FLAC__SEEKABLE_STREAM_DECODER_OK if initialization was - * successful; see FLAC__SeekableStreamDecoderState for the meanings - * of other return values. - */ -FLAC_API FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_init(FLAC__SeekableStreamDecoder *decoder); - -/** Finish the decoding process. - * Flushes the decoding buffer, releases resources, resets the decoder - * settings to their defaults, and returns the decoder state to - * FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED. - * - * In the event of a prematurely-terminated decode, it is not strictly - * necessary to call this immediately before - * FLAC__seekable_stream_decoder_delete() but it is good practice to match - * every FLAC__seekable_stream_decoder_init() with a - * FLAC__seekable_stream_decoder_finish(). - * - * \param decoder An uninitialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if MD5 checking is on AND a STREAMINFO block was available - * AND the MD5 signature in the STREAMINFO block was non-zero AND the - * signature does not match the one computed by the decoder; else - * \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_finish(FLAC__SeekableStreamDecoder *decoder); - -/** Flush the stream input. - * The decoder's input buffer will be cleared and the state set to - * \c FLAC__SEEKABLE_STREAM_DECODER_OK. This will also turn off MD5 - * checking. - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false if a memory allocation - * or stream decoder error occurs. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_flush(FLAC__SeekableStreamDecoder *decoder); - -/** Reset the decoding process. - * The decoder's input buffer will be cleared and the state set to - * \c FLAC__SEEKABLE_STREAM_DECODER_OK. This is similar to - * FLAC__seekable_stream_decoder_finish() except that the settings are - * preserved; there is no need to call FLAC__seekable_stream_decoder_init() - * before decoding again. MD5 checking will be restored to its original - * setting. - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false if a memory allocation - * or stream decoder error occurs. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_reset(FLAC__SeekableStreamDecoder *decoder); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_process_single(). - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_single(FLAC__SeekableStreamDecoder *decoder); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_process_until_end_of_metadata(). - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_metadata(FLAC__SeekableStreamDecoder *decoder); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_process_until_end_of_stream(). - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_stream(FLAC__SeekableStreamDecoder *decoder); - -/** This is inherited from FLAC__StreamDecoder; see - * FLAC__stream_decoder_skip_single_frame(). - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_skip_single_frame(FLAC__SeekableStreamDecoder *decoder); - -/** Flush the input and seek to an absolute sample. - * Decoding will resume at the given sample. Note that because of - * this, the next write callback may contain a partial block. - * - * \param decoder A decoder instance. - * \param sample The target sample number to seek to. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_seek_absolute(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 sample); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sys/src/cmd/audio/libFLAC/FLAC/seekable_stream_encoder.h b/sys/src/cmd/audio/libFLAC/FLAC/seekable_stream_encoder.h deleted file mode 100644 index 7b10c01d7..000000000 --- a/sys/src/cmd/audio/libFLAC/FLAC/seekable_stream_encoder.h +++ /dev/null @@ -1,992 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2002,2003,2004 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. - */ - -#ifndef FLAC__SEEKABLE_STREAM_ENCODER_H -#define FLAC__SEEKABLE_STREAM_ENCODER_H - -#include "export.h" -#include "stream_encoder.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \file include/FLAC/seekable_stream_encoder.h - * - * \brief - * This module contains the functions which implement the seekable stream - * encoder. - * - * See the detailed documentation in the - * \link flac_seekable_stream_encoder seekable stream encoder \endlink module. - */ - -/** \defgroup flac_seekable_stream_encoder FLAC/seekable_stream_encoder.h: seekable stream encoder interface - * \ingroup flac_encoder - * - * \brief - * This module contains the functions which implement the seekable stream - * encoder. - * - * The basic usage of this encoder is as follows: - * - The program creates an instance of an encoder using - * FLAC__seekable_stream_encoder_new(). - * - The program overrides the default settings and sets callbacks using - * FLAC__seekable_stream_encoder_set_*() functions. - * - The program initializes the instance to validate the settings and - * prepare for encoding using FLAC__seekable_stream_encoder_init(). - * - The program calls FLAC__seekable_stream_encoder_process() or - * FLAC__seekable_stream_encoder_process_interleaved() to encode data, which - * subsequently calls the callbacks when there is encoder data ready - * to be written. - * - The program finishes the encoding with FLAC__seekable_stream_encoder_finish(), - * which causes the encoder to encode any data still in its input pipe, - * rewrite the metadata with the final encoding statistics, and finally - * reset the encoder to the uninitialized state. - * - The instance may be used again or deleted with - * FLAC__seekable_stream_encoder_delete(). - * - * The seekable stream encoder is a wrapper around the - * \link flac_stream_encoder stream encoder \endlink with callbacks for - * seeking the output and reporting the output stream position. This - * allows the encoder to go back and rewrite some of the metadata after - * encoding if necessary, and provides the metadata callback of the stream - * encoder internally. However, you must provide seek and tell callbacks - * (see FLAC__seekable_stream_encoder_set_seek_callback() and - * FLAC__seekable_stream_encoder_set_tell_callback()). - * - * Make sure to read the detailed description of the - * \link flac_stream_encoder stream encoder module \endlink since the - * seekable stream encoder inherits much of its behavior. - * - * \note - * If you are writing the FLAC data to a file, make sure it is open - * for update (e.g. mode "w+" for stdio streams). This is because after - * the first encoding pass, the encoder will try to seek back to the - * beginning of the stream, to the STREAMINFO block, to write some data - * there. - * - * \note - * The "set" functions may only be called when the encoder is in the - * state FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED, i.e. after - * FLAC__seekable_stream_encoder_new() or FLAC__seekable_stream_encoder_finish(), but - * before FLAC__seekable_stream_encoder_init(). If this is the case they will - * return \c true, otherwise \c false. - * - * \note - * FLAC__seekable_stream_encoder_finish() resets all settings to the constructor - * defaults, including the callbacks. - * - * \{ - */ - - -/** State values for a FLAC__SeekableStreamEncoder - * - * The encoder's state can be obtained by calling FLAC__seekable_stream_encoder_get_state(). - */ -typedef enum { - - FLAC__SEEKABLE_STREAM_ENCODER_OK = 0, - /**< The encoder is in the normal OK state. */ - - FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR, - /**< An error occurred in the underlying stream encoder; - * check FLAC__seekable_stream_encoder_get_stream_encoder_state(). - */ - - FLAC__SEEKABLE_STREAM_ENCODER_MEMORY_ALLOCATION_ERROR, - /**< Memory allocation failed. */ - - FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR, - /**< The write callback returned an error. */ - - FLAC__SEEKABLE_STREAM_ENCODER_READ_ERROR, - /**< The read callback returned an error. */ - - FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR, - /**< The seek callback returned an error. */ - - FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR, - /**< The tell callback returned an error. */ - - FLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED, - /**< FLAC__seekable_stream_encoder_init() was called when the encoder was - * already initialized, usually because - * FLAC__seekable_stream_encoder_finish() was not called. - */ - - FLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK, - /**< FLAC__seekable_stream_encoder_init() was called without all - * callbacks being set. - */ - - FLAC__SEEKABLE_STREAM_ENCODER_INVALID_SEEKTABLE, - /**< An invalid seek table was passed is the metadata to - * FLAC__seekable_stream_encoder_set_metadata(). - */ - - FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED - /**< The encoder is in the uninitialized state. */ - -} FLAC__SeekableStreamEncoderState; - -/** Maps a FLAC__SeekableStreamEncoderState to a C string. - * - * Using a FLAC__SeekableStreamEncoderState as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__SeekableStreamEncoderStateString[]; - - -/** Return values for the FLAC__SeekableStreamEncoder seek callback. - */ -typedef enum { - - FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK, - /**< The seek was OK and encoding can continue. */ - - FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR - /**< An unrecoverable error occurred. The encoder will return from the process call. */ - -} FLAC__SeekableStreamEncoderSeekStatus; - -/** Maps a FLAC__SeekableStreamEncoderSeekStatus to a C string. - * - * Using a FLAC__SeekableStreamEncoderSeekStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__SeekableStreamEncoderSeekStatusString[]; - - -/** Return values for the FLAC__SeekableStreamEncoder tell callback. - */ -typedef enum { - - FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK, - /**< The tell was OK and encoding can continue. */ - - FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR - /**< An unrecoverable error occurred. The encoder will return from the process call. */ - -} FLAC__SeekableStreamEncoderTellStatus; - -/** Maps a FLAC__SeekableStreamEncoderTellStatus to a C string. - * - * Using a FLAC__SeekableStreamEncoderTellStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__SeekableStreamEncoderTellStatusString[]; - - -/*********************************************************************** - * - * class FLAC__SeekableStreamEncoder - * - ***********************************************************************/ - -struct FLAC__SeekableStreamEncoderProtected; -struct FLAC__SeekableStreamEncoderPrivate; -/** The opaque structure definition for the seekable stream encoder type. - * See the \link flac_seekable_stream_encoder seekable stream encoder module \endlink - * for a detailed description. - */ -typedef struct { - struct FLAC__SeekableStreamEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */ - struct FLAC__SeekableStreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */ -} FLAC__SeekableStreamEncoder; - -/** Signature for the seek callback. - * See FLAC__seekable_stream_encoder_set_seek_callback() for more info. - * - * \param encoder The encoder instance calling the callback. - * \param absolute_byte_offset The offset from the beginning of the stream - * to seek to. - * \param client_data The callee's client data set through - * FLAC__seekable_stream_encoder_set_client_data(). - * \retval FLAC__SeekableStreamEncoderSeekStatus - * The callee's return status. - */ -typedef FLAC__SeekableStreamEncoderSeekStatus (*FLAC__SeekableStreamEncoderSeekCallback)(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); - -/** Signature for the tell callback. - * See FLAC__seekable_stream_encoder_set_tell_callback() for more info. - * - * \warning - * The callback must return the true current byte offset of the output to - * which the encoder is writing. If you are buffering the output, make - * sure and take this into account. If you are writing directly to a - * FILE* from your write callback, ftell() is sufficient. If you are - * writing directly to a file descriptor from your write callback, you - * can use lseek(fd, SEEK_CUR, 0). The encoder may later seek back to - * these points to rewrite metadata after encoding. - * - * \param encoder The encoder instance calling the callback. - * \param absolute_byte_offset The address at which to store the current - * position of the output. - * \param client_data The callee's client data set through - * FLAC__seekable_stream_encoder_set_client_data(). - * \retval FLAC__SeekableStreamEncoderTellStatus - * The callee's return status. - */ -typedef FLAC__SeekableStreamEncoderTellStatus (*FLAC__SeekableStreamEncoderTellCallback)(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); - -/** Signature for the write callback. - * See FLAC__seekable_stream_encoder_set_write_callback() - * and FLAC__StreamEncoderWriteCallback for more info. - * - * \param encoder The encoder instance calling the callback. - * \param buffer An array of encoded data of length \a bytes. - * \param bytes The byte length of \a buffer. - * \param samples The number of samples encoded by \a buffer. - * \c 0 has a special meaning; see - * FLAC__stream_encoder_set_write_callback(). - * \param current_frame The number of current frame being encoded. - * \param client_data The callee's client data set through - * FLAC__seekable_stream_encoder_set_client_data(). - * \retval FLAC__StreamEncoderWriteStatus - * The callee's return status. - */ -typedef FLAC__StreamEncoderWriteStatus (*FLAC__SeekableStreamEncoderWriteCallback)(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data); - - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -/** Create a new seekable stream encoder instance. The instance is created with - * default settings; see the individual FLAC__seekable_stream_encoder_set_*() - * functions for each setting's default. - * - * \retval FLAC__SeekableStreamEncoder* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__SeekableStreamEncoder *FLAC__seekable_stream_encoder_new(); - -/** Free an encoder instance. Deletes the object pointed to by \a encoder. - * - * \param encoder A pointer to an existing encoder. - * \assert - * \code encoder != NULL \endcode - */ -FLAC_API void FLAC__seekable_stream_encoder_delete(FLAC__SeekableStreamEncoder *encoder); - -/*********************************************************************** - * - * Public class method prototypes - * - ***********************************************************************/ - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_verify(). - * - * \default \c true - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_verify(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_streamable_subset(). - * - * \default \c true - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_streamable_subset(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_do_mid_side_stereo(). - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_mid_side_stereo(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_loose_mid_side_stereo(). - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_channels(). - * - * \default \c 2 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_channels(FLAC__SeekableStreamEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_bits_per_sample(). - * - * \warning - * Do not feed the encoder data that is wider than the value you - * set here or you will generate an invalid stream. - * - * \default \c 16 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_bits_per_sample(FLAC__SeekableStreamEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_sample_rate(). - * - * \default \c 44100 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_sample_rate(FLAC__SeekableStreamEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_blocksize(). - * - * \default \c 1152 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_blocksize(FLAC__SeekableStreamEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_max_lpc_order(). - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_max_lpc_order(FLAC__SeekableStreamEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_qlp_coeff_precision(). - * - * \note - * In the current implementation, qlp_coeff_precision + bits_per_sample must - * be less than 32. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_qlp_coeff_precision(FLAC__SeekableStreamEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_do_qlp_coeff_prec_search(). - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_do_escape_coding(). - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_escape_coding(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_do_exhaustive_model_search(). - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_exhaustive_model_search(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_min_residual_partition_order(). - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_min_residual_partition_order(FLAC__SeekableStreamEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_max_residual_partition_order(). - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_max_residual_partition_order(FLAC__SeekableStreamEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_rice_parameter_search_dist(). - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_rice_parameter_search_dist(FLAC__SeekableStreamEncoder *encoder, unsigned value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_total_samples_estimate(). - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_total_samples_estimate(FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 value); - -/** This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_metadata(). - * - * \note - * SEEKTABLE blocks are handled specially. Since you will not know - * the values for the seek point stream offsets, you should pass in - * a SEEKTABLE 'template', that is, a SEEKTABLE object with the - * required sample numbers (or placeholder points), with \c 0 for the - * \a frame_samples and \a stream_offset fields for each point. While - * encoding, the encoder will fill them in for you and when encoding - * is finished, it will seek back and write the real values into the - * SEEKTABLE block in the stream. There are helper routines for - * manipulating seektable template blocks; see metadata.h: - * FLAC__metadata_object_seektable_template_*(). - * - * \note - * The encoder instance \b will modify the first \c SEEKTABLE block - * as it transforms the template to a valid seektable while encoding, - * but it is still up to the caller to free all metadata blocks after - * encoding. - * - * \default \c NULL, 0 - * \param encoder An encoder instance to set. - * \param metadata See above. - * \param num_blocks See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_metadata(FLAC__SeekableStreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks); - -/** Set the seek callback. - * The supplied function will be called when the encoder needs to seek - * the output stream. The encoder will pass the absolute byte offset - * to seek to, 0 meaning the beginning of the stream. - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_seek_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderSeekCallback value); - -/** Set the tell callback. - * The supplied function will be called when the encoder needs to know - * the current position of the output stream. - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_tell_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderTellCallback value); - -/** Set the write callback. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_set_write_callback(). - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_write_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderWriteCallback value); - -/** Set the client data to be passed back to callbacks. - * This value will be supplied to callbacks in their \a client_data - * argument. - * - * \default \c NULL - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_client_data(FLAC__SeekableStreamEncoder *encoder, void *value); - -/** Get the current encoder state. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__SeekableStreamEncoderState - * The current encoder state. - */ -FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_get_state(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the state of the underlying stream encoder. - * Useful when the seekable stream encoder state is - * \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamEncoderState - * The stream encoder state. - */ -FLAC_API FLAC__StreamEncoderState FLAC__seekable_stream_encoder_get_stream_encoder_state(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the state of the underlying stream encoder's verify decoder. - * Useful when the seekable stream encoder state is - * \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and the - * stream encoder state is \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamDecoderState - * The stream encoder state. - */ -FLAC_API FLAC__StreamDecoderState FLAC__seekable_stream_encoder_get_verify_decoder_state(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the current encoder state as a C string. - * This version automatically resolves - * \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR by getting the - * stream encoder's state. - * - * \param encoder A encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval const char * - * The encoder state as a C string. Do not modify the contents. - */ -FLAC_API const char *FLAC__seekable_stream_encoder_get_resolved_state_string(const FLAC__SeekableStreamEncoder *encoder); - -/** Get relevant values about the nature of a verify decoder error. - * Inherited from FLAC__stream_encoder_get_verify_decoder_error_stats(). - * Useful when the seekable stream encoder state is - * \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and the - * stream encoder state is - * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. - * - * \param encoder An encoder instance to query. - * \param absolute_sample The absolute sample number of the mismatch. - * \param frame_number The number of the frame in which the mismatch occurred. - * \param channel The channel in which the mismatch occurred. - * \param sample The number of the sample (relative to the frame) in - * which the mismatch occurred. - * \param expected The expected value for the sample in question. - * \param got The actual value returned by the decoder. - * \assert - * \code encoder != NULL \endcode - */ -FLAC_API void FLAC__seekable_stream_encoder_get_verify_decoder_error_stats(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got); - -/** Get the "verify" flag. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_verify(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__seekable_stream_encoder_set_verify(). - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_verify(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the "streamable subset" flag. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_streamable_subset(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__seekable_stream_encoder_set_streamable_subset(). - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_streamable_subset(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the "mid/side stereo coding" flag. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_do_mid_side_stereo(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__seekable_stream_encoder_get_do_mid_side_stereo(). - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_mid_side_stereo(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the "adaptive mid/side switching" flag. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_loose_mid_side_stereo(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(). - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_loose_mid_side_stereo(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the number of input channels being processed. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_channels(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__seekable_stream_encoder_set_channels(). - */ -FLAC_API unsigned FLAC__seekable_stream_encoder_get_channels(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the input sample resolution setting. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_bits_per_sample(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__seekable_stream_encoder_set_bits_per_sample(). - */ -FLAC_API unsigned FLAC__seekable_stream_encoder_get_bits_per_sample(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the input sample rate setting. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_sample_rate(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__seekable_stream_encoder_set_sample_rate(). - */ -FLAC_API unsigned FLAC__seekable_stream_encoder_get_sample_rate(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the blocksize setting. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_blocksize(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__seekable_stream_encoder_set_blocksize(). - */ -FLAC_API unsigned FLAC__seekable_stream_encoder_get_blocksize(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the maximum LPC order setting. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_max_lpc_order(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__seekable_stream_encoder_set_max_lpc_order(). - */ -FLAC_API unsigned FLAC__seekable_stream_encoder_get_max_lpc_order(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the quantized linear predictor coefficient precision setting. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_qlp_coeff_precision(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__seekable_stream_encoder_set_qlp_coeff_precision(). - */ -FLAC_API unsigned FLAC__seekable_stream_encoder_get_qlp_coeff_precision(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the qlp coefficient precision search flag. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_do_qlp_coeff_prec_search(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(). - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the "escape coding" flag. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_do_escape_coding(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__seekable_stream_encoder_set_do_escape_coding(). - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_escape_coding(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the exhaustive model search flag. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_do_exhaustive_model_search(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__seekable_stream_encoder_set_do_exhaustive_model_search(). - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_exhaustive_model_search(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the minimum residual partition order setting. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_min_residual_partition_order(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__seekable_stream_encoder_set_min_residual_partition_order(). - */ -FLAC_API unsigned FLAC__seekable_stream_encoder_get_min_residual_partition_order(const FLAC__SeekableStreamEncoder *encoder); - -/** Get maximum residual partition order setting. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_max_residual_partition_order(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__seekable_stream_encoder_set_max_residual_partition_order(). - */ -FLAC_API unsigned FLAC__seekable_stream_encoder_get_max_residual_partition_order(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the Rice parameter search distance setting. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_rice_parameter_search_dist(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval unsigned - * See FLAC__seekable_stream_encoder_set_rice_parameter_search_dist(). - */ -FLAC_API unsigned FLAC__seekable_stream_encoder_get_rice_parameter_search_dist(const FLAC__SeekableStreamEncoder *encoder); - -/** Get the previously set estimate of the total samples to be encoded. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_get_total_samples_estimate(). - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__uint64 - * See FLAC__seekable_stream_encoder_set_total_samples_estimate(). - */ -FLAC_API FLAC__uint64 FLAC__seekable_stream_encoder_get_total_samples_estimate(const FLAC__SeekableStreamEncoder *encoder); - -/** Initialize the encoder instance. - * Should be called after FLAC__seekable_stream_encoder_new() and - * FLAC__seekable_stream_encoder_set_*() but before FLAC__seekable_stream_encoder_process() - * or FLAC__seekable_stream_encoder_process_interleaved(). Will set and return - * the encoder state, which will be FLAC__SEEKABLE_STREAM_ENCODER_OK if - * initialization succeeded. - * - * The call to FLAC__seekable_stream_encoder_init() currently will also immediately - * call the write callback with the \c fLaC signature and all the encoded - * metadata. - * - * \param encoder An uninitialized encoder instance. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__SeekableStreamEncoderState - * \c FLAC__SEEKABLE_STREAM_ENCODER_OK if initialization was successful; see - * FLAC__SeekableStreamEncoderState for the meanings of other return values. - */ -FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_init(FLAC__SeekableStreamEncoder *encoder); - -/** Finish the encoding process. - * Flushes the encoding buffer, releases resources, resets the encoder - * settings to their defaults, and returns the encoder state to - * FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED. - * - * In the event of a prematurely-terminated encode, it is not strictly - * necessary to call this immediately before FLAC__seekable_stream_encoder_delete() - * but it is good practice to match every FLAC__seekable_stream_encoder_init() - * with a FLAC__seekable_stream_encoder_finish(). - * - * \param encoder An uninitialized encoder instance. - * \assert - * \code encoder != NULL \endcode - */ -FLAC_API void FLAC__seekable_stream_encoder_finish(FLAC__SeekableStreamEncoder *encoder); - -/** Submit data for encoding. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_process(). - * - * \param encoder An initialized encoder instance in the OK state. - * \param buffer An array of pointers to each channel's signal. - * \param samples The number of samples in one channel. - * \assert - * \code encoder != NULL \endcode - * \code FLAC__seekable_stream_encoder_get_state(encoder) == FLAC__SEEKABLE_STREAM_ENCODER_OK \endcode - * \retval FLAC__bool - * \c true if successful, else \c false; in this case, check the - * encoder state with FLAC__seekable_stream_encoder_get_state() to see what - * went wrong. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_process(FLAC__SeekableStreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples); - -/** Submit data for encoding. - * This is inherited from FLAC__StreamEncoder; see - * FLAC__stream_encoder_process_interleaved(). - * - * \param encoder An initialized encoder instance in the OK state. - * \param buffer An array of channel-interleaved data (see above). - * \param samples The number of samples in one channel, the same as for - * FLAC__seekable_stream_encoder_process(). For example, if - * encoding two channels, \c 1000 \a samples corresponds - * to a \a buffer of 2000 values. - * \assert - * \code encoder != NULL \endcode - * \code FLAC__seekable_stream_encoder_get_state(encoder) == FLAC__SEEKABLE_STREAM_ENCODER_OK \endcode - * \retval FLAC__bool - * \c true if successful, else \c false; in this case, check the - * encoder state with FLAC__seekable_stream_encoder_get_state() to see what - * went wrong. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_process_interleaved(FLAC__SeekableStreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h b/sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h index 9c151b962..9bfdd1f5f 100644 --- a/sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h +++ b/sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,6 +33,7 @@ #ifndef FLAC__STREAM_DECODER_H #define FLAC__STREAM_DECODER_H +#include <stdio.h> /* for FILE */ #include "export.h" #include "format.h" @@ -50,28 +52,22 @@ extern "C" { * \link flac_stream_decoder stream decoder \endlink module. */ -/** \defgroup flac_decoder FLAC/ *_decoder.h: decoder interfaces +/** \defgroup flac_decoder FLAC/ \*_decoder.h: decoder interfaces * \ingroup flac * * \brief - * This module describes the three decoder layers provided by libFLAC. - * - * For decoding FLAC streams, libFLAC provides three layers of access. The - * lowest layer is non-seekable stream-level decoding, the next is seekable - * stream-level decoding, and the highest layer is file-level decoding. The - * interfaces are described in the \link flac_stream_decoder stream decoder - * \endlink, \link flac_seekable_stream_decoder seekable stream decoder - * \endlink, and \link flac_file_decoder file decoder \endlink modules - * respectively. Typically you will choose the highest layer that your input - * source will support. - * - * The stream decoder relies on callbacks for all input and output and has no - * provisions for seeking. The seekable stream decoder wraps the stream - * decoder and exposes functions for seeking. However, you must provide - * extra callbacks for seek-related operations on your stream, like seek and - * tell. The file decoder wraps the seekable stream decoder and supplies - * most of the callbacks internally, simplifying the processing of standard - * files. + * This module describes the decoder layers provided by libFLAC. + * + * The stream decoder can be used to decode complete streams either from + * the client via callbacks, or directly from a file, depending on how + * it is initialized. When decoding via callbacks, the client provides + * callbacks for reading FLAC data and writing decoded samples, and + * handling metadata and errors. If the client also supplies seek-related + * callback, the decoder function for sample-accurate seeking within the + * FLAC input is also available. When decoding from a file, the client + * needs only supply a filename or open \c FILE* and write/metadata/error + * callbacks; the rest of the callbacks are supplied internally. For more + * info see the \link flac_stream_decoder stream decoder \endlink module. */ /** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface @@ -81,14 +77,20 @@ extern "C" { * This module contains the functions which implement the stream * decoder. * + * The stream decoder can decode native FLAC, and optionally Ogg FLAC + * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files. + * * The basic usage of this decoder is as follows: * - The program creates an instance of a decoder using * FLAC__stream_decoder_new(). - * - The program overrides the default settings and sets callbacks for - * reading, writing, error reporting, and metadata reporting using + * - The program overrides the default settings using * FLAC__stream_decoder_set_*() functions. * - The program initializes the instance to validate the settings and - * prepare for decoding using FLAC__stream_decoder_init(). + * prepare for decoding using + * - FLAC__stream_decoder_init_stream() or FLAC__stream_decoder_init_FILE() + * or FLAC__stream_decoder_init_file() for native FLAC, + * - FLAC__stream_decoder_init_ogg_stream() or FLAC__stream_decoder_init_ogg_FILE() + * or FLAC__stream_decoder_init_ogg_file() for Ogg FLAC * - The program calls the FLAC__stream_decoder_process_*() functions * to decode data, which subsequently calls the callbacks. * - The program finishes the decoding with FLAC__stream_decoder_finish(), @@ -99,33 +101,25 @@ extern "C" { * * In more detail, the program will create a new instance by calling * FLAC__stream_decoder_new(), then call FLAC__stream_decoder_set_*() - * functions to set the callbacks and client data, and call - * FLAC__stream_decoder_init(). The required callbacks are: - * - * - Read callback - This function will be called when the decoder needs - * more input data. The address of the buffer to be filled is supplied, - * along with the number of bytes the buffer can hold. The callback may - * choose to supply less data and modify the byte count but must be careful - * not to overflow the buffer. The callback then returns a status code - * chosen from FLAC__StreamDecoderReadStatus. - * - Write callback - This function will be called when the decoder has - * decoded a single frame of data. The decoder will pass the frame - * metadata as well as an array of pointers (one for each channel) - * pointing to the decoded audio. - * - Metadata callback - This function will be called when the decoder has - * decoded a metadata block. In a valid FLAC file there will always be - * one STREAMINFO block, followed by zero or more other metadata - * blocks. These will be supplied by the decoder in the same order as - * they appear in the stream and always before the first audio frame - * (i.e. write callback). The metadata block that is passed in must not - * be modified, and it doesn't live beyond the callback, so you should - * make a copy of it with FLAC__metadata_object_clone() if you will need - * it elsewhere. Since metadata blocks can potentially be large, by - * default the decoder only calls the metadata callback for the STREAMINFO - * block; you can instruct the decoder to pass or filter other blocks with - * FLAC__stream_decoder_set_metadata_*() calls. - * - Error callback - This function will be called whenever an error occurs - * during decoding. + * functions to override the default decoder options, and call + * one of the FLAC__stream_decoder_init_*() functions. + * + * There are three initialization functions for native FLAC, one for + * setting up the decoder to decode FLAC data from the client via + * callbacks, and two for decoding directly from a FLAC file. + * + * For decoding via callbacks, use FLAC__stream_decoder_init_stream(). + * You must also supply several callbacks for handling I/O. Some (like + * seeking) are optional, depending on the capabilities of the input. + * + * For decoding directly from a file, use FLAC__stream_decoder_init_FILE() + * or FLAC__stream_decoder_init_file(). Then you must only supply an open + * \c FILE* or filename and fewer callbacks; the decoder will handle + * the other callbacks internally. + * + * There are three similarly-named init functions for decoding from Ogg + * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the + * library has been built with Ogg support. * * Once the decoder is initialized, your program will call one of several * functions to start the decoding process: @@ -136,12 +130,12 @@ extern "C" { * loses sync it will return with only the error callback being called. * - FLAC__stream_decoder_process_until_end_of_metadata() - Tells the decoder * to process the stream from the current location and stop upon reaching - * the first audio frame. The user will get one metadata, write, or error + * the first audio frame. The client will get one metadata, write, or error * callback per metadata block, audio frame, or sync error, respectively. * - FLAC__stream_decoder_process_until_end_of_stream() - Tells the decoder * to process the stream from the current location until the read callback * returns FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM or - * FLAC__STREAM_DECODER_READ_STATUS_ABORT. The user will get one metadata, + * FLAC__STREAM_DECODER_READ_STATUS_ABORT. The client will get one metadata, * write, or error callback per metadata block, audio frame, or sync error, * respectively. * @@ -151,11 +145,23 @@ extern "C" { * instance may be deleted with FLAC__stream_decoder_delete() or initialized * again to decode another stream. * - * Note that the stream decoder has no real concept of stream position, it - * just converts data. To seek within a stream the callbacks have only to - * flush the decoder using FLAC__stream_decoder_flush() and start feeding - * data from the new position through the read callback. The seekable - * stream decoder does just this. + * Seeking is exposed through the FLAC__stream_decoder_seek_absolute() method. + * At any point after the stream decoder has been initialized, the client can + * call this function to seek to an exact sample within the stream. + * Subsequently, the first time the write callback is called it will be + * passed a (possibly partial) block starting at that sample. + * + * If the client cannot seek via the callback interface provided, but still + * has another way of seeking, it can flush the decoder using + * FLAC__stream_decoder_flush() and start feeding data from the new position + * through the read callback. + * + * The stream decoder also provides MD5 signature checking. If this is + * turned on before initialization, FLAC__stream_decoder_finish() will + * report when the decoded MD5 signature does not match the one stored + * in the STREAMINFO block. MD5 checking is automatically turned off + * (until the next FLAC__stream_decoder_reset()) if there is no signature + * in the STREAMINFO block or when a seek is attempted. * * The FLAC__stream_decoder_set_metadata_*() functions deserve special * attention. By default, the decoder only calls the metadata_callback for @@ -163,13 +169,13 @@ extern "C" { * explicitly which blocks to parse and return via the metadata_callback * and/or which to skip. Use a FLAC__stream_decoder_set_metadata_respond_all(), * FLAC__stream_decoder_set_metadata_ignore() ... or FLAC__stream_decoder_set_metadata_ignore_all(), - * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify which - * blocks to return. Remember that some metadata blocks can be big so - * filtering out the ones you don't use can reduce the memory requirements - * of the decoder. Also note the special forms - * FLAC__stream_decoder_set_metadata_respond_application(id) and - * FLAC__stream_decoder_set_metadata_ignore_application(id) for filtering APPLICATION - * blocks based on the application ID. + * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify + * which blocks to return. Remember that metadata blocks can potentially + * be big (for example, cover art) so filtering out the ones you don't + * use can reduce the memory requirements of the decoder. Also note the + * special forms FLAC__stream_decoder_set_metadata_respond_application(id) + * and FLAC__stream_decoder_set_metadata_ignore_application(id) for + * filtering APPLICATION blocks based on the application ID. * * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but * they still can legally be filtered from the metadata_callback. @@ -178,7 +184,7 @@ extern "C" { * The "set" functions may only be called when the decoder is in the * state FLAC__STREAM_DECODER_UNINITIALIZED, i.e. after * FLAC__stream_decoder_new() or FLAC__stream_decoder_finish(), but - * before FLAC__stream_decoder_init(). If this is the case they will + * before FLAC__stream_decoder_init_*(). If this is the case they will * return \c true, otherwise \c false. * * \note @@ -191,7 +197,7 @@ extern "C" { /** State values for a FLAC__StreamDecoder * - * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state(). + * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state(). */ typedef enum { @@ -202,7 +208,9 @@ typedef enum { /**< The decoder is ready to or is in the process of reading metadata. */ FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC, - /**< The decoder is ready to or is in the process of searching for the frame sync code. */ + /**< The decoder is ready to or is in the process of searching for the + * frame sync code. + */ FLAC__STREAM_DECODER_READ_FRAME, /**< The decoder is ready to or is in the process of reading a frame. */ @@ -210,26 +218,28 @@ typedef enum { FLAC__STREAM_DECODER_END_OF_STREAM, /**< The decoder has reached the end of the stream. */ + FLAC__STREAM_DECODER_OGG_ERROR, + /**< An error occurred in the underlying Ogg layer. */ + + FLAC__STREAM_DECODER_SEEK_ERROR, + /**< An error occurred while seeking. The decoder must be flushed + * with FLAC__stream_decoder_flush() or reset with + * FLAC__stream_decoder_reset() before decoding can continue. + */ + FLAC__STREAM_DECODER_ABORTED, /**< The decoder was aborted by the read callback. */ - FLAC__STREAM_DECODER_UNPARSEABLE_STREAM, - /**< The decoder encountered reserved fields in use in the stream. */ - FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR, - /**< An error occurred allocating memory. */ - - FLAC__STREAM_DECODER_ALREADY_INITIALIZED, - /**< FLAC__stream_decoder_init() was called when the decoder was - * already initialized, usually because - * FLAC__stream_decoder_finish() was not called. + /**< An error occurred allocating memory. The decoder is in an invalid + * state and can no longer be used. */ - FLAC__STREAM_DECODER_INVALID_CALLBACK, - /**< FLAC__stream_decoder_init() was called without all callbacks being set. */ - FLAC__STREAM_DECODER_UNINITIALIZED - /**< The decoder is in the uninitialized state. */ + /**< The decoder is in the uninitialized state; one of the + * FLAC__stream_decoder_init_*() functions must be called before samples + * can be processed. + */ } FLAC__StreamDecoderState; @@ -241,6 +251,44 @@ typedef enum { extern FLAC_API const char * const FLAC__StreamDecoderStateString[]; +/** Possible return values for the FLAC__stream_decoder_init_*() functions. + */ +typedef enum { + + FLAC__STREAM_DECODER_INIT_STATUS_OK = 0, + /**< Initialization was successful. */ + + FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER, + /**< The library was not compiled with support for the given container + * format. + */ + + FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS, + /**< A required callback was not supplied. */ + + FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR, + /**< An error occurred allocating memory. */ + + FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE, + /**< fopen() failed in FLAC__stream_decoder_init_file() or + * FLAC__stream_decoder_init_ogg_file(). */ + + FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED + /**< FLAC__stream_decoder_init_*() was called when the decoder was + * already initialized, usually because + * FLAC__stream_decoder_finish() was not called. + */ + +} FLAC__StreamDecoderInitStatus; + +/** Maps a FLAC__StreamDecoderInitStatus to a C string. + * + * Using a FLAC__StreamDecoderInitStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderInitStatusString[]; + + /** Return values for the FLAC__StreamDecoder read callback. */ typedef enum { @@ -249,7 +297,15 @@ typedef enum { /**< The read was OK and decoding can continue. */ FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM, - /**< The read was attempted at the end of the stream. */ + /**< The read was attempted while at the end of the stream. Note that + * the client must only return this value when the read callback was + * called when already at the end of the stream. Otherwise, if the read + * itself moves to the end of the stream, the client should still return + * the data and \c FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, and then on + * the next read callback it should return + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM with a byte count + * of \c 0. + */ FLAC__STREAM_DECODER_READ_STATUS_ABORT /**< An unrecoverable error occurred. The decoder will return from the process call. */ @@ -264,6 +320,75 @@ typedef enum { extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[]; +/** Return values for the FLAC__StreamDecoder seek callback. + */ +typedef enum { + + FLAC__STREAM_DECODER_SEEK_STATUS_OK, + /**< The seek was OK and decoding can continue. */ + + FLAC__STREAM_DECODER_SEEK_STATUS_ERROR, + /**< An unrecoverable error occurred. The decoder will return from the process call. */ + + FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED + /**< Client does not support seeking. */ + +} FLAC__StreamDecoderSeekStatus; + +/** Maps a FLAC__StreamDecoderSeekStatus to a C string. + * + * Using a FLAC__StreamDecoderSeekStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[]; + + +/** Return values for the FLAC__StreamDecoder tell callback. + */ +typedef enum { + + FLAC__STREAM_DECODER_TELL_STATUS_OK, + /**< The tell was OK and decoding can continue. */ + + FLAC__STREAM_DECODER_TELL_STATUS_ERROR, + /**< An unrecoverable error occurred. The decoder will return from the process call. */ + + FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED + /**< Client does not support telling the position. */ + +} FLAC__StreamDecoderTellStatus; + +/** Maps a FLAC__StreamDecoderTellStatus to a C string. + * + * Using a FLAC__StreamDecoderTellStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderTellStatusString[]; + + +/** Return values for the FLAC__StreamDecoder length callback. + */ +typedef enum { + + FLAC__STREAM_DECODER_LENGTH_STATUS_OK, + /**< The length call was OK and decoding can continue. */ + + FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR, + /**< An unrecoverable error occurred. The decoder will return from the process call. */ + + FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED + /**< Client does not support reporting the length. */ + +} FLAC__StreamDecoderLengthStatus; + +/** Maps a FLAC__StreamDecoderLengthStatus to a C string. + * + * Using a FLAC__StreamDecoderLengthStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[]; + + /** Return values for the FLAC__StreamDecoder write callback. */ typedef enum { @@ -284,7 +409,20 @@ typedef enum { extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[]; -/** Possible values passed in to the FLAC__StreamDecoder error callback. +/** Possible values passed back to the FLAC__StreamDecoder error callback. + * \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC is the generic catch- + * all. The rest could be caused by bad sync (false synchronization on + * data that is not the start of a frame) or corrupted data. The error + * itself is the decoder's best guess at what happened assuming a correct + * sync. For example \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER + * could be caused by a correct sync on the start of a frame, but some + * data in the frame header was corrupted. Or it could be the result of + * syncing on a point the stream that looked like the starting of a frame + * but was not. \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM + * could be because the decoder encountered a valid frame made by a future + * version of the encoder which it cannot parse, or because of a false + * sync making it appear as though an encountered frame was generated by + * a future encoder. */ typedef enum { @@ -294,9 +432,12 @@ typedef enum { FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, /**< The decoder encountered a corrupted frame header. */ - FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH + FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH, /**< The frame's data did not match the CRC in the footer. */ + FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM + /**< The decoder encountered reserved fields in use in the stream. */ + } FLAC__StreamDecoderErrorStatus; /** Maps a FLAC__StreamDecoderErrorStatus to a C string. @@ -325,7 +466,37 @@ typedef struct { } FLAC__StreamDecoder; /** Signature for the read callback. - * See FLAC__stream_decoder_set_read_callback() for more info. + * + * A function pointer matching this signature must be passed to + * FLAC__stream_decoder_init*_stream(). The supplied function will be + * called when the decoder needs more input data. The address of the + * buffer to be filled is supplied, along with the number of bytes the + * buffer can hold. The callback may choose to supply less data and + * modify the byte count but must be careful not to overflow the buffer. + * The callback then returns a status code chosen from + * FLAC__StreamDecoderReadStatus. + * + * Here is an example of a read callback for stdio streams: + * \code + * FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * if(*bytes > 0) { + * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file); + * if(ferror(file)) + * return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + * else if(*bytes == 0) + * return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + * else + * return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + * } + * else + * return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + * } + * \endcode + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. * * \param decoder The decoder instance calling the callback. * \param buffer A pointer to a location for the callee to store @@ -337,14 +508,163 @@ typedef struct { * stored (0 in case of error or end-of-stream) before * returning. * \param client_data The callee's client data set through - * FLAC__stream_decoder_set_client_data(). + * FLAC__stream_decoder_init_*(). * \retval FLAC__StreamDecoderReadStatus + * The callee's return status. Note that the callback should return + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM if and only if + * zero bytes were read and there is no more data to be read. + */ +typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); + +/** Signature for the seek callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_decoder_init*_stream(). The supplied function will be + * called when the decoder needs to seek the input stream. The decoder + * will pass the absolute byte offset to seek to, 0 meaning the + * beginning of the stream. + * + * Here is an example of a seek callback for stdio streams: + * \code + * FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * if(file == stdin) + * return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; + * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0) + * return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + * else + * return FLAC__STREAM_DECODER_SEEK_STATUS_OK; + * } + * \endcode + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param absolute_byte_offset The offset from the beginning of the stream + * to seek to. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + * \retval FLAC__StreamDecoderSeekStatus + * The callee's return status. + */ +typedef FLAC__StreamDecoderSeekStatus (*FLAC__StreamDecoderSeekCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); + +/** Signature for the tell callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_decoder_init*_stream(). The supplied function will be + * called when the decoder wants to know the current position of the + * stream. The callback should return the byte offset from the + * beginning of the stream. + * + * Here is an example of a tell callback for stdio streams: + * \code + * FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * off_t pos; + * if(file == stdin) + * return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED; + * else if((pos = ftello(file)) < 0) + * return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + * else { + * *absolute_byte_offset = (FLAC__uint64)pos; + * return FLAC__STREAM_DECODER_TELL_STATUS_OK; + * } + * } + * \endcode + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param absolute_byte_offset A pointer to storage for the current offset + * from the beginning of the stream. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + * \retval FLAC__StreamDecoderTellStatus * The callee's return status. */ -typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data); +typedef FLAC__StreamDecoderTellStatus (*FLAC__StreamDecoderTellCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); + +/** Signature for the length callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_decoder_init*_stream(). The supplied function will be + * called when the decoder wants to know the total length of the stream + * in bytes. + * + * Here is an example of a length callback for stdio streams: + * \code + * FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * struct stat filestats; + * + * if(file == stdin) + * return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; + * else if(fstat(fileno(file), &filestats) != 0) + * return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + * else { + * *stream_length = (FLAC__uint64)filestats.st_size; + * return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; + * } + * } + * \endcode + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param stream_length A pointer to storage for the length of the stream + * in bytes. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + * \retval FLAC__StreamDecoderLengthStatus + * The callee's return status. + */ +typedef FLAC__StreamDecoderLengthStatus (*FLAC__StreamDecoderLengthCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); + +/** Signature for the EOF callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_decoder_init*_stream(). The supplied function will be + * called when the decoder needs to know if the end of the stream has + * been reached. + * + * Here is an example of a EOF callback for stdio streams: + * FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data) + * \code + * { + * FILE *file = ((MyClientData*)client_data)->file; + * return feof(file)? true : false; + * } + * \endcode + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. + * + * \param decoder The decoder instance calling the callback. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_init_*(). + * \retval FLAC__bool + * \c true if the currently at the end of the stream, else \c false. + */ +typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *decoder, void *client_data); /** Signature for the write callback. - * See FLAC__stream_decoder_set_write_callback() for more info. + * + * A function pointer matching this signature must be passed to one of + * the FLAC__stream_decoder_init_*() functions. + * The supplied function will be called when the decoder has decoded a + * single audio frame. The decoder will pass the frame metadata as well + * as an array of pointers (one for each channel) pointing to the + * decoded audio. + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. * * \param decoder The decoder instance calling the callback. * \param frame The description of the decoded frame. See @@ -352,33 +672,57 @@ typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const F * \param buffer An array of pointers to decoded channels of data. * Each pointer will point to an array of signed * samples of length \a frame->header.blocksize. - * Currently, the channel order has no meaning - * except for stereo streams; in this case channel - * 0 is left and 1 is right. + * Channels will be ordered according to the FLAC + * specification; see the documentation for the + * <A HREF="../format.html#frame_header">frame header</A>. * \param client_data The callee's client data set through - * FLAC__stream_decoder_set_client_data(). + * FLAC__stream_decoder_init_*(). * \retval FLAC__StreamDecoderWriteStatus * The callee's return status. */ typedef FLAC__StreamDecoderWriteStatus (*FLAC__StreamDecoderWriteCallback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); /** Signature for the metadata callback. - * See FLAC__stream_decoder_set_metadata_callback() for more info. + * + * A function pointer matching this signature must be passed to one of + * the FLAC__stream_decoder_init_*() functions. + * The supplied function will be called when the decoder has decoded a + * metadata block. In a valid FLAC file there will always be one + * \c STREAMINFO block, followed by zero or more other metadata blocks. + * These will be supplied by the decoder in the same order as they + * appear in the stream and always before the first audio frame (i.e. + * write callback). The metadata block that is passed in must not be + * modified, and it doesn't live beyond the callback, so you should make + * a copy of it with FLAC__metadata_object_clone() if you will need it + * elsewhere. Since metadata blocks can potentially be large, by + * default the decoder only calls the metadata callback for the + * \c STREAMINFO block; you can instruct the decoder to pass or filter + * other blocks with FLAC__stream_decoder_set_metadata_*() calls. + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. * * \param decoder The decoder instance calling the callback. * \param metadata The decoded metadata block. * \param client_data The callee's client data set through - * FLAC__stream_decoder_set_client_data(). + * FLAC__stream_decoder_init_*(). */ typedef void (*FLAC__StreamDecoderMetadataCallback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); /** Signature for the error callback. - * See FLAC__stream_decoder_set_error_callback() for more info. + * + * A function pointer matching this signature must be passed to one of + * the FLAC__stream_decoder_init_*() functions. + * The supplied function will be called whenever an error occurs during + * decoding. + * + * \note In general, FLAC__StreamDecoder functions which change the + * state should not be called on the \a decoder while in the callback. * * \param decoder The decoder instance calling the callback. * \param status The error encountered by the decoder. * \param client_data The callee's client data set through - * FLAC__stream_decoder_set_client_data(). + * FLAC__stream_decoder_init_*(). */ typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); @@ -413,107 +757,45 @@ FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder); * ***********************************************************************/ -/** Set the read callback. - * The supplied function will be called when the decoder needs more input - * data. The address of the buffer to be filled is supplied, along with - * the number of bytes the buffer can hold. The callback may choose to - * supply less data and modify the byte count but must be careful not to - * overflow the buffer. The callback then returns a status code chosen - * from FLAC__StreamDecoderReadStatus. - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_read_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderReadCallback value); - -/** Set the write callback. - * The supplied function will be called when the decoder has decoded a - * single frame of data. The decoder will pass the frame metadata as - * well as an array of pointers (one for each channel) pointing to the - * decoded audio. - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteCallback value); - -/** Set the metadata callback. - * The supplied function will be called when the decoder has decoded a metadata - * block. In a valid FLAC file there will always be one STREAMINFO block, - * followed by zero or more other metadata blocks. These will be supplied - * by the decoder in the same order as they appear in the stream and always - * before the first audio frame (i.e. write callback). The metadata block - * that is passed in must not be modified, and it doesn't live beyond the - * callback, so you should make a copy of it with - * FLAC__metadata_object_clone() if you will need it elsewhere. Since - * metadata blocks can potentially be large, by default the decoder only - * calls the metadata callback for the STREAMINFO block; you can instruct - * the decoder to pass or filter other blocks with - * FLAC__stream_decoder_set_metadata_*() calls. +/** Set the serial number for the FLAC stream within the Ogg container. + * The default behavior is to use the serial number of the first Ogg + * page. Setting a serial number here will explicitly specify which + * stream is to be decoded. * * \note - * The callback is mandatory and must be set before initialization. + * This does not need to be set for native FLAC decoding. * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. + * \default \c use serial number of first page + * \param decoder A decoder instance to set. + * \param serial_number See above. * \assert * \code decoder != NULL \endcode - * \code value != NULL \endcode * \retval FLAC__bool * \c false if the decoder is already initialized, else \c true. */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderMetadataCallback value); +FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number); -/** Set the error callback. - * The supplied function will be called whenever an error occurs during - * decoding. +/** Set the "MD5 signature checking" flag. If \c true, the decoder will + * compute the MD5 signature of the unencoded audio data while decoding + * and compare it to the signature from the STREAMINFO block, if it + * exists, during FLAC__stream_decoder_finish(). * - * \note - * The callback is mandatory and must be set before initialization. + * MD5 signature checking will be turned off (until the next + * FLAC__stream_decoder_reset()) if there is no signature in the + * STREAMINFO block or when a seek is attempted. * - * \default \c NULL - * \param decoder A decoder instance to set. - * \param value See above. - * \assert - * \code decoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_error_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorCallback value); - -/** Set the client data to be passed back to callbacks. - * This value will be supplied to callbacks in their \a client_data - * argument. + * Clients that do not use the MD5 check should leave this off to speed + * up decoding. * - * \default \c NULL + * \default \c false * \param decoder A decoder instance to set. - * \param value See above. + * \param value Flag value (see above). * \assert * \code decoder != NULL \endcode * \retval FLAC__bool * \c false if the decoder is already initialized, else \c true. */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_client_data(FLAC__StreamDecoder *decoder, void *value); +FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value); /** Direct the decoder to pass on all metadata blocks of type \a type. * @@ -617,6 +899,32 @@ FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__Str */ FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder); +/** Get the "MD5 signature checking" flag. + * This is the value of the setting, not whether or not the decoder is + * currently checking the MD5 (remember, it can be turned off automatically + * by a seek). When the decoder is reset the flag will be restored to the + * value returned by this function. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * See above. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder); + +/** Get the total number of samples in the stream being decoded. + * Will only be valid after decoding has started and will contain the + * value from the \c STREAMINFO block. A value of \c 0 means "unknown". + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval unsigned + * See above. + */ +FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder); + /** Get the current number of channels in the stream being decoded. * Will only be valid after decoding has started and will contain the * value from the most recently decoded frame header. @@ -677,22 +985,368 @@ FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder */ FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder); -/** Initialize the decoder instance. - * Should be called after FLAC__stream_decoder_new() and +/** Returns the decoder's current read position within the stream. + * The position is the byte offset from the start of the stream. + * Bytes before this position have been fully decoded. Note that + * there may still be undecoded bytes in the decoder's read FIFO. + * The returned position is correct even after a seek. + * + * \warning This function currently only works for native FLAC, + * not Ogg FLAC streams. + * + * \param decoder A decoder instance to query. + * \param position Address at which to return the desired position. + * \assert + * \code decoder != NULL \endcode + * \code position != NULL \endcode + * \retval FLAC__bool + * \c true if successful, \c false if the stream is not native FLAC, + * or there was an error from the 'tell' callback or it returned + * \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position); + +/** Initialize the decoder instance to decode native FLAC streams. + * + * This flavor of initialization sets up the decoder to decode from a + * native FLAC stream. I/O is performed via callbacks to the client. + * For decoding from a plain file via filename or open FILE*, + * FLAC__stream_decoder_init_file() and FLAC__stream_decoder_init_FILE() + * provide a simpler interface. + * + * This function should be called after FLAC__stream_decoder_new() and * FLAC__stream_decoder_set_*() but before any of the * FLAC__stream_decoder_process_*() functions. Will set and return the * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA * if initialization succeeded. * - * \param decoder An uninitialized decoder instance. + * \param decoder An uninitialized decoder instance. + * \param read_callback See FLAC__StreamDecoderReadCallback. This + * pointer must not be \c NULL. + * \param seek_callback See FLAC__StreamDecoderSeekCallback. This + * pointer may be \c NULL if seeking is not + * supported. If \a seek_callback is not \c NULL then a + * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied. + * Alternatively, a dummy seek callback that just + * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param tell_callback See FLAC__StreamDecoderTellCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy tell callback that just + * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param length_callback See FLAC__StreamDecoderLengthCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a length_callback must also be supplied. + * Alternatively, a dummy length callback that just + * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param eof_callback See FLAC__StreamDecoderEofCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a eof_callback must also be supplied. + * Alternatively, a dummy length callback that just + * returns \c false + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. * \assert * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderState - * \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA if initialization was - * successful; see FLAC__StreamDecoderState for the meanings of other - * return values. + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadCallback read_callback, + FLAC__StreamDecoderSeekCallback seek_callback, + FLAC__StreamDecoderTellCallback tell_callback, + FLAC__StreamDecoderLengthCallback length_callback, + FLAC__StreamDecoderEofCallback eof_callback, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); + +/** Initialize the decoder instance to decode Ogg FLAC streams. + * + * This flavor of initialization sets up the decoder to decode from a + * FLAC stream in an Ogg container. I/O is performed via callbacks to the + * client. For decoding from a plain file via filename or open FILE*, + * FLAC__stream_decoder_init_ogg_file() and FLAC__stream_decoder_init_ogg_FILE() + * provide a simpler interface. + * + * This function should be called after FLAC__stream_decoder_new() and + * FLAC__stream_decoder_set_*() but before any of the + * FLAC__stream_decoder_process_*() functions. Will set and return the + * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + * if initialization succeeded. + * + * \note Support for Ogg FLAC in the library is optional. If this + * library has been built without support for Ogg FLAC, this function + * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. + * + * \param decoder An uninitialized decoder instance. + * \param read_callback See FLAC__StreamDecoderReadCallback. This + * pointer must not be \c NULL. + * \param seek_callback See FLAC__StreamDecoderSeekCallback. This + * pointer may be \c NULL if seeking is not + * supported. If \a seek_callback is not \c NULL then a + * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied. + * Alternatively, a dummy seek callback that just + * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param tell_callback See FLAC__StreamDecoderTellCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy tell callback that just + * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param length_callback See FLAC__StreamDecoderLengthCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a length_callback must also be supplied. + * Alternatively, a dummy length callback that just + * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param eof_callback See FLAC__StreamDecoderEofCallback. This + * pointer may be \c NULL if not supported by the client. If + * \a seek_callback is not \c NULL then a + * \a eof_callback must also be supplied. + * Alternatively, a dummy length callback that just + * returns \c false + * may also be supplied, all though this is slightly + * less efficient for the decoder. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadCallback read_callback, + FLAC__StreamDecoderSeekCallback seek_callback, + FLAC__StreamDecoderTellCallback tell_callback, + FLAC__StreamDecoderLengthCallback length_callback, + FLAC__StreamDecoderEofCallback eof_callback, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); + +/** Initialize the decoder instance to decode native FLAC files. + * + * This flavor of initialization sets up the decoder to decode from a + * plain native FLAC file. For non-stdio streams, you must use + * FLAC__stream_decoder_init_stream() and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_decoder_new() and + * FLAC__stream_decoder_set_*() but before any of the + * FLAC__stream_decoder_process_*() functions. Will set and return the + * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + * if initialization succeeded. + * + * \param decoder An uninitialized decoder instance. + * \param file An open FLAC file. The file should have been + * opened with mode \c "rb" and rewound. The file + * becomes owned by the decoder and should not be + * manipulated by the client while decoding. + * Unless \a file is \c stdin, it will be closed + * when FLAC__stream_decoder_finish() is called. + * Note however that seeking will not work when + * decoding from \c stdout since it is not seekable. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code decoder != NULL \endcode + * \code file != NULL \endcode + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE( + FLAC__StreamDecoder *decoder, + FILE *file, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); + +/** Initialize the decoder instance to decode Ogg FLAC files. + * + * This flavor of initialization sets up the decoder to decode from a + * plain Ogg FLAC file. For non-stdio streams, you must use + * FLAC__stream_decoder_init_ogg_stream() and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_decoder_new() and + * FLAC__stream_decoder_set_*() but before any of the + * FLAC__stream_decoder_process_*() functions. Will set and return the + * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + * if initialization succeeded. + * + * \note Support for Ogg FLAC in the library is optional. If this + * library has been built without support for Ogg FLAC, this function + * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. + * + * \param decoder An uninitialized decoder instance. + * \param file An open FLAC file. The file should have been + * opened with mode \c "rb" and rewound. The file + * becomes owned by the decoder and should not be + * manipulated by the client while decoding. + * Unless \a file is \c stdin, it will be closed + * when FLAC__stream_decoder_finish() is called. + * Note however that seeking will not work when + * decoding from \c stdout since it is not seekable. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code decoder != NULL \endcode + * \code file != NULL \endcode + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE( + FLAC__StreamDecoder *decoder, + FILE *file, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); + +/** Initialize the decoder instance to decode native FLAC files. + * + * This flavor of initialization sets up the decoder to decode from a plain + * native FLAC file. If POSIX fopen() semantics are not sufficient, (for + * example, with Unicode filenames on Windows), you must use + * FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream() + * and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_decoder_new() and + * FLAC__stream_decoder_set_*() but before any of the + * FLAC__stream_decoder_process_*() functions. Will set and return the + * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + * if initialization succeeded. + * + * \param decoder An uninitialized decoder instance. + * \param filename The name of the file to decode from. The file will + * be opened with fopen(). Use \c NULL to decode from + * \c stdin. Note that \c stdin is not seekable. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file( + FLAC__StreamDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); + +/** Initialize the decoder instance to decode Ogg FLAC files. + * + * This flavor of initialization sets up the decoder to decode from a plain + * Ogg FLAC file. If POSIX fopen() semantics are not sufficient, (for + * example, with Unicode filenames on Windows), you must use + * FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream() + * and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_decoder_new() and + * FLAC__stream_decoder_set_*() but before any of the + * FLAC__stream_decoder_process_*() functions. Will set and return the + * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA + * if initialization succeeded. + * + * \note Support for Ogg FLAC in the library is optional. If this + * library has been built without support for Ogg FLAC, this function + * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. + * + * \param decoder An uninitialized decoder instance. + * \param filename The name of the file to decode from. The file will + * be opened with fopen(). Use \c NULL to decode from + * \c stdin. Note that \c stdin is not seekable. + * \param write_callback See FLAC__StreamDecoderWriteCallback. This + * pointer must not be \c NULL. + * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param error_callback See FLAC__StreamDecoderErrorCallback. This + * pointer must not be \c NULL. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__StreamDecoderInitStatus + * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamDecoderInitStatus for the meanings of other return values. */ -FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *decoder); +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file( + FLAC__StreamDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +); /** Finish the decoding process. * Flushes the decoding buffer, releases resources, resets the decoder @@ -701,25 +1355,32 @@ FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder * * In the event of a prematurely-terminated decode, it is not strictly * necessary to call this immediately before FLAC__stream_decoder_delete() - * but it is good practice to match every FLAC__stream_decoder_init() + * but it is good practice to match every FLAC__stream_decoder_init_*() * with a FLAC__stream_decoder_finish(). * * \param decoder An uninitialized decoder instance. * \assert * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c false if MD5 checking is on AND a STREAMINFO block was available + * AND the MD5 signature in the STREAMINFO block was non-zero AND the + * signature does not match the one computed by the decoder; else + * \c true. */ -FLAC_API void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder); +FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder); /** Flush the stream input. * The decoder's input buffer will be cleared and the state set to - * \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC. + * \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC. This will also turn + * off MD5 checking. * * \param decoder A decoder instance. * \assert * \code decoder != NULL \endcode * \retval FLAC__bool * \c true if successful, else \c false if a memory allocation - * error occurs. + * error occurs (in which case the state will be set to + * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR). */ FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder); @@ -727,15 +1388,32 @@ FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder); * The decoder's input buffer will be cleared and the state set to * \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA. This is similar to * FLAC__stream_decoder_finish() except that the settings are - * preserved; there is no need to call FLAC__stream_decoder_init() - * before decoding again. + * preserved; there is no need to call FLAC__stream_decoder_init_*() + * before decoding again. MD5 checking will be restored to its original + * setting. + * + * If the decoder is seekable, or was initialized with + * FLAC__stream_decoder_init*_FILE() or FLAC__stream_decoder_init*_file(), + * the decoder will also attempt to seek to the beginning of the file. + * If this rewind fails, this function will return \c false. It follows + * that FLAC__stream_decoder_reset() cannot be used when decoding from + * \c stdin. + * + * If the decoder was initialized with FLAC__stream_encoder_init*_stream() + * and is not seekable (i.e. no seek callback was provided or the seek + * callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it + * is the duty of the client to start feeding data from the beginning of + * the stream on the next FLAC__stream_decoder_process() or + * FLAC__stream_decoder_process_interleaved() call. * * \param decoder A decoder instance. * \assert * \code decoder != NULL \endcode * \retval FLAC__bool - * \c true if successful, else \c false if a memory allocation - * error occurs. + * \c true if successful, else \c false if a memory allocation occurs + * (in which case the state will be set to + * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) or a seek error + * occurs (the state will be unchanged). */ FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder); @@ -747,16 +1425,14 @@ FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder); * * As the decoder needs more input it will call the read callback. * Depending on what was decoded, the metadata or write callback will be - * called with the decoded metadata block or audio frame, unless an error - * occurred. If the decoder loses sync it will call the error callback - * instead. + * called with the decoded metadata block or audio frame. * * Unless there is a fatal read error or end of stream, this function * will return once one whole frame is decoded. In other words, if the * stream is not synchronized or points to a corrupt frame header, the * decoder will continue to try and resync until it gets to a valid * frame, then decode one frame, then return. If the decoder points to - * frame whose frame CRC in the frame footer does not match the + * a frame whose frame CRC in the frame footer does not match the * computed frame CRC, this function will issue a * FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the * error callback, and return, having decoded one complete, although @@ -767,11 +1443,10 @@ FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder); * \assert * \code decoder != NULL \endcode * \retval FLAC__bool - * \c false if any read or write error occurred (except - * \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true; - * in any case, check the decoder state with - * FLAC__stream_decoder_get_state() to see what went wrong or to - * check for lost synchronization (a sign of stream corruption). + * \c false if any fatal read, write, or memory allocation error + * occurred (meaning decoding must stop), else \c true; for more + * information about the decoder, check the decoder state with + * FLAC__stream_decoder_get_state(). */ FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder); @@ -783,18 +1458,16 @@ FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *dec * * As the decoder needs more input it will call the read callback. * As each metadata block is decoded, the metadata callback will be called - * with the decoded metadata. If the decoder loses sync it will call the - * error callback. + * with the decoded metadata. * * \param decoder An initialized decoder instance. * \assert * \code decoder != NULL \endcode * \retval FLAC__bool - * \c false if any read or write error occurred (except - * \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true; - * in any case, check the decoder state with - * FLAC__stream_decoder_get_state() to see what went wrong or to - * check for lost synchronization (a sign of stream corruption). + * \c false if any fatal read, write, or memory allocation error + * occurred (meaning decoding must stop), else \c true; for more + * information about the decoder, check the decoder state with + * FLAC__stream_decoder_get_state(). */ FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder); @@ -806,18 +1479,16 @@ FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__Str * * As the decoder needs more input it will call the read callback. * As each metadata block and frame is decoded, the metadata or write - * callback will be called with the decoded metadata or frame. If the - * decoder loses sync it will call the error callback. + * callback will be called with the decoded metadata or frame. * * \param decoder An initialized decoder instance. * \assert * \code decoder != NULL \endcode * \retval FLAC__bool - * \c false if any read or write error occurred (except - * \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true; - * in any case, check the decoder state with - * FLAC__stream_decoder_get_state() to see what went wrong or to - * check for lost synchronization (a sign of stream corruption). + * \c false if any fatal read, write, or memory allocation error + * occurred (meaning decoding must stop), else \c true; for more + * information about the decoder, check the decoder state with + * FLAC__stream_decoder_get_state(). */ FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder); @@ -836,15 +1507,14 @@ FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__Strea * same way that FLAC__stream_decoder_process_single() will return once * one whole frame is decoded. * - * This function, when used from the higher FLAC__SeekableStreamDecoder - * layer, can be used in more quickly determining FLAC frame boundaries - * when decoding of the actual data is not needed, for example when a - * application is separating a FLAC stream into frames for editing or - * storing in a container. To do this, the application can use - * FLAC__seekable_stream_decoder_skip_single_frame() to quickly advance + * This function can be used in more quickly determining FLAC frame + * boundaries when decoding of the actual data is not needed, for + * example when an application is separating a FLAC stream into frames + * for editing or storing in a container. To do this, the application + * can use FLAC__stream_decoder_skip_single_frame() to quickly advance * to the next frame, then use - * FLAC__seekable_stream_decoder_get_decode_position() to find the new - * frame boundary. + * FLAC__stream_decoder_get_decode_position() to find the new frame + * boundary. * * This function should only be called when the stream has advanced * past all the metadata, otherwise it will return \c false. @@ -854,16 +1524,33 @@ FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__Strea * \assert * \code decoder != NULL \endcode * \retval FLAC__bool - * \c false if any read or write error occurred (except - * \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), or if the decoder + * \c false if any fatal read, write, or memory allocation error + * occurred (meaning decoding must stop), or if the decoder * is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or - * FLAC__STREAM_DECODER_READ_METADATA state, else \c true; - * in any case, check the decoder state with - * FLAC__stream_decoder_get_state() to see what went wrong or to - * check for lost synchronization (a sign of stream corruption). + * FLAC__STREAM_DECODER_READ_METADATA state, else \c true; for more + * information about the decoder, check the decoder state with + * FLAC__stream_decoder_get_state(). */ FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder); +/** Flush the input and seek to an absolute sample. + * Decoding will resume at the given sample. Note that because of + * this, the next write callback may contain a partial block. The + * client must support seeking the input or this function will fail + * and return \c false. Furthermore, if the decoder state is + * \c FLAC__STREAM_DECODER_SEEK_ERROR, then the decoder must be flushed + * with FLAC__stream_decoder_flush() or reset with + * FLAC__stream_decoder_reset() before decoding can continue. + * + * \param decoder A decoder instance. + * \param sample The target sample number to seek to. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__bool + * \c true if successful, else \c false. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample); + /* \} */ #ifdef __cplusplus diff --git a/sys/src/cmd/audio/libFLAC/FLAC/stream_encoder.h b/sys/src/cmd/audio/libFLAC/FLAC/stream_encoder.h index 9eeaee92e..efc213aee 100644 --- a/sys/src/cmd/audio/libFLAC/FLAC/stream_encoder.h +++ b/sys/src/cmd/audio/libFLAC/FLAC/stream_encoder.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,6 +33,7 @@ #ifndef FLAC__STREAM_ENCODER_H #define FLAC__STREAM_ENCODER_H +#include <stdio.h> /* for FILE */ #include "export.h" #include "format.h" #include "stream_decoder.h" @@ -51,33 +53,23 @@ extern "C" { * \link flac_stream_encoder stream encoder \endlink module. */ -/** \defgroup flac_encoder FLAC/ *_encoder.h: encoder interfaces +/** \defgroup flac_encoder FLAC/ \*_encoder.h: encoder interfaces * \ingroup flac * * \brief - * This module describes the two encoder layers provided by libFLAC. - * - * For encoding FLAC streams, libFLAC provides three layers of access. The - * lowest layer is non-seekable stream-level encoding, the next is seekable - * stream-level encoding, and the highest layer is file-level encoding. The - * interfaces are described in the \link flac_stream_encoder stream encoder - * \endlink, \link flac_seekable_stream_encoder seekable stream encoder - * \endlink, and \link flac_file_encoder file encoder \endlink modules - * respectively. Typically you will choose the highest layer that your input - * source will support. - * The stream encoder relies on callbacks for writing the data and - * metadata. The file encoder provides these callbacks internally and you - * need only supply the filename. - * - * The stream encoder relies on callbacks for writing the data and has no - * provisions for seeking the output. The seekable stream encoder wraps - * the stream encoder and also automaticallay handles the writing back of - * metadata discovered while encoding. However, you must provide extra - * callbacks for seek-related operations on your output, like seek and - * tell. The file encoder wraps the seekable stream encoder and supplies - * all of the callbacks internally, simplifying the processing of standard - * files. The only callback exposed is for progress reporting, and that - * is optional. + * This module describes the encoder layers provided by libFLAC. + * + * The stream encoder can be used to encode complete streams either to the + * client via callbacks, or directly to a file, depending on how it is + * initialized. When encoding via callbacks, the client provides a write + * callback which will be called whenever FLAC data is ready to be written. + * If the client also supplies a seek callback, the encoder will also + * automatically handle the writing back of metadata discovered while + * encoding, like stream info, seek points offsets, etc. When encoding to + * a file, the client needs only supply a filename or open \c FILE* and an + * optional progress callback for periodic notification of progress; the + * write and seek callbacks are supplied internally. For more info see the + * \link flac_stream_encoder stream encoder \endlink module. */ /** \defgroup flac_stream_encoder FLAC/stream_encoder.h: stream encoder interface @@ -87,76 +79,115 @@ extern "C" { * This module contains the functions which implement the stream * encoder. * + * The stream encoder can encode to native FLAC, and optionally Ogg FLAC + * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files. + * * The basic usage of this encoder is as follows: * - The program creates an instance of an encoder using * FLAC__stream_encoder_new(). - * - The program overrides the default settings and sets callbacks using - * FLAC__stream_encoder_set_*() functions. + * - The program overrides the default settings using + * FLAC__stream_encoder_set_*() functions. At a minimum, the following + * functions should be called: + * - FLAC__stream_encoder_set_channels() + * - FLAC__stream_encoder_set_bits_per_sample() + * - FLAC__stream_encoder_set_sample_rate() + * - FLAC__stream_encoder_set_ogg_serial_number() (if encoding to Ogg FLAC) + * - FLAC__stream_encoder_set_total_samples_estimate() (if known) + * - If the application wants to control the compression level or set its own + * metadata, then the following should also be called: + * - FLAC__stream_encoder_set_compression_level() + * - FLAC__stream_encoder_set_verify() + * - FLAC__stream_encoder_set_metadata() + * - The rest of the set functions should only be called if the client needs + * exact control over how the audio is compressed; thorough understanding + * of the FLAC format is necessary to achieve good results. * - The program initializes the instance to validate the settings and - * prepare for encoding using FLAC__stream_encoder_init(). + * prepare for encoding using + * - FLAC__stream_encoder_init_stream() or FLAC__stream_encoder_init_FILE() + * or FLAC__stream_encoder_init_file() for native FLAC + * - FLAC__stream_encoder_init_ogg_stream() or FLAC__stream_encoder_init_ogg_FILE() + * or FLAC__stream_encoder_init_ogg_file() for Ogg FLAC * - The program calls FLAC__stream_encoder_process() or * FLAC__stream_encoder_process_interleaved() to encode data, which * subsequently calls the callbacks when there is encoder data ready * to be written. * - The program finishes the encoding with FLAC__stream_encoder_finish(), * which causes the encoder to encode any data still in its input pipe, - * call the metadata callback with the final encoding statistics, and - * finally reset the encoder to the uninitialized state. + * update the metadata with the final encoding statistics if output + * seeking is possible, and finally reset the encoder to the + * uninitialized state. * - The instance may be used again or deleted with * FLAC__stream_encoder_delete(). * * In more detail, the stream encoder functions similarly to the * \link flac_stream_decoder stream decoder \endlink, but has fewer - * callbacks and more options. Typically the user will create a new + * callbacks and more options. Typically the client will create a new * instance by calling FLAC__stream_encoder_new(), then set the necessary - * parameters and callbacks with FLAC__stream_encoder_set_*(), and - * initialize it by calling FLAC__stream_encoder_init(). + * parameters with FLAC__stream_encoder_set_*(), and initialize it by + * calling one of the FLAC__stream_encoder_init_*() functions. * * Unlike the decoders, the stream encoder has many options that can * affect the speed and compression ratio. When setting these parameters * you should have some basic knowledge of the format (see the - * <A HREF="../documentation.html#format">user-level documentation</A> + * <A HREF="../documentation_format_overview.html">user-level documentation</A> * or the <A HREF="../format.html">formal description</A>). The * FLAC__stream_encoder_set_*() functions themselves do not validate the - * values as many are interdependent. The FLAC__stream_encoder_init() - * function will do this, so make sure to pay attention to the state - * returned by FLAC__stream_encoder_init() to make sure that it is - * FLAC__STREAM_ENCODER_OK. Any parameters that are not set before - * FLAC__stream_encoder_init() will take on the defaults from the - * constructor. - * - * The user must provide function pointers for the following callbacks: - * - * - Write callback - This function is called by the encoder anytime there - * is raw encoded data to write. It may include metadata mixed with - * encoded audio frames and the data is not guaranteed to be aligned on - * frame or metadata block boundaries. - * - Metadata callback - This function is called once at the end of - * encoding with the populated STREAMINFO structure. This is so file - * encoders can seek back to the beginning of the file and write the - * STREAMINFO block with the correct statistics after encoding (like - * minimum/maximum frame size). - * - * The call to FLAC__stream_encoder_init() currently will also immediately + * values as many are interdependent. The FLAC__stream_encoder_init_*() + * functions will do this, so make sure to pay attention to the state + * returned by FLAC__stream_encoder_init_*() to make sure that it is + * FLAC__STREAM_ENCODER_INIT_STATUS_OK. Any parameters that are not set + * before FLAC__stream_encoder_init_*() will take on the defaults from + * the constructor. + * + * There are three initialization functions for native FLAC, one for + * setting up the encoder to encode FLAC data to the client via + * callbacks, and two for encoding directly to a file. + * + * For encoding via callbacks, use FLAC__stream_encoder_init_stream(). + * You must also supply a write callback which will be called anytime + * there is raw encoded data to write. If the client can seek the output + * it is best to also supply seek and tell callbacks, as this allows the + * encoder to go back after encoding is finished to write back + * information that was collected while encoding, like seek point offsets, + * frame sizes, etc. + * + * For encoding directly to a file, use FLAC__stream_encoder_init_FILE() + * or FLAC__stream_encoder_init_file(). Then you must only supply a + * filename or open \c FILE*; the encoder will handle all the callbacks + * internally. You may also supply a progress callback for periodic + * notification of the encoding progress. + * + * There are three similarly-named init functions for encoding to Ogg + * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the + * library has been built with Ogg support. + * + * The call to FLAC__stream_encoder_init_*() currently will also immediately * call the write callback several times, once with the \c fLaC signature, - * and once for each encoded metadata block. + * and once for each encoded metadata block. Note that for Ogg FLAC + * encoding you will usually get at least twice the number of callbacks than + * with native FLAC, one for the Ogg page header and one for the page body. * - * After initializing the instance, the user may feed audio data to the + * After initializing the instance, the client may feed audio data to the * encoder in one of two ways: * - * - Channel separate, through FLAC__stream_encoder_process() - The user + * - Channel separate, through FLAC__stream_encoder_process() - The client * will pass an array of pointers to buffers, one for each channel, to * the encoder, each of the same length. The samples need not be - * block-aligned. + * block-aligned, but each channel should have the same number of samples. * - Channel interleaved, through - * FLAC__stream_encoder_process_interleaved() - The user will pass a single + * FLAC__stream_encoder_process_interleaved() - The client will pass a single * pointer to data that is channel-interleaved (i.e. channel0_sample0, * channel1_sample0, ... , channelN_sample0, channel0_sample1, ...). * Again, the samples need not be block-aligned but they must be * sample-aligned, i.e. the first value should be channel0_sample0 and * the last value channelN_sampleM. * - * When the user is finished encoding data, it calls + * Note that for either process call, each sample in the buffers should be a + * signed integer, right-justified to the resolution set by + * FLAC__stream_encoder_set_bits_per_sample(). For example, if the resolution + * is 16 bits per sample, the samples should all be in the range [-32768,32767]. + * + * When the client is finished encoding data, it calls * FLAC__stream_encoder_finish(), which causes the encoder to encode any * data still in its input pipe, and call the metadata callback with the * final encoding statistics. Then the instance may be deleted with @@ -177,28 +208,49 @@ extern "C" { * for the specification of metadata blocks and their lengths. * * \note + * If you are writing the FLAC data to a file via callbacks, make sure it + * is open for update (e.g. mode "w+" for stdio streams). This is because + * after the first encoding pass, the encoder will try to seek back to the + * beginning of the stream, to the STREAMINFO block, to write some data + * there. (If using FLAC__stream_encoder_init*_file() or + * FLAC__stream_encoder_init*_FILE(), the file is managed internally.) + * + * \note * The "set" functions may only be called when the encoder is in the * state FLAC__STREAM_ENCODER_UNINITIALIZED, i.e. after * FLAC__stream_encoder_new() or FLAC__stream_encoder_finish(), but - * before FLAC__stream_encoder_init(). If this is the case they will + * before FLAC__stream_encoder_init_*(). If this is the case they will * return \c true, otherwise \c false. * * \note * FLAC__stream_encoder_finish() resets all settings to the constructor - * defaults, including the callbacks. + * defaults. * * \{ */ -/** State values for a FLAC__StreamEncoder +/** State values for a FLAC__StreamEncoder. + * + * The encoder's state can be obtained by calling FLAC__stream_encoder_get_state(). * - * The encoder's state can be obtained by calling FLAC__stream_encoder_get_state(). + * If the encoder gets into any other state besides \c FLAC__STREAM_ENCODER_OK + * or \c FLAC__STREAM_ENCODER_UNINITIALIZED, it becomes invalid for encoding and + * must be deleted with FLAC__stream_encoder_delete(). */ typedef enum { FLAC__STREAM_ENCODER_OK = 0, - /**< The encoder is in the normal OK state. */ + /**< The encoder is in the normal OK state and samples can be processed. */ + + FLAC__STREAM_ENCODER_UNINITIALIZED, + /**< The encoder is in the uninitialized state; one of the + * FLAC__stream_encoder_init_*() functions must be called before samples + * can be processed. + */ + + FLAC__STREAM_ENCODER_OGG_ERROR, + /**< An error occurred in the underlying Ogg layer. */ FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR, /**< An error occurred in the underlying verify stream decoder; @@ -210,49 +262,78 @@ typedef enum { * audio signal and the decoded audio signal. */ - FLAC__STREAM_ENCODER_INVALID_CALLBACK, - /**< The encoder was initialized before setting all the required callbacks. */ + FLAC__STREAM_ENCODER_CLIENT_ERROR, + /**< One of the callbacks returned a fatal error. */ - FLAC__STREAM_ENCODER_INVALID_NUMBER_OF_CHANNELS, + FLAC__STREAM_ENCODER_IO_ERROR, + /**< An I/O error occurred while opening/reading/writing a file. + * Check \c errno. + */ + + FLAC__STREAM_ENCODER_FRAMING_ERROR, + /**< An error occurred while writing the stream; usually, the + * write_callback returned an error. + */ + + FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR + /**< Memory allocation failed. */ + +} FLAC__StreamEncoderState; + +/** Maps a FLAC__StreamEncoderState to a C string. + * + * Using a FLAC__StreamEncoderState as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamEncoderStateString[]; + + +/** Possible return values for the FLAC__stream_encoder_init_*() functions. + */ +typedef enum { + + FLAC__STREAM_ENCODER_INIT_STATUS_OK = 0, + /**< Initialization was successful. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR, + /**< General failure to set up encoder; call FLAC__stream_encoder_get_state() for cause. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER, + /**< The library was not compiled with support for the given container + * format. + */ + + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS, + /**< A required callback was not supplied. */ + + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS, /**< The encoder has an invalid setting for number of channels. */ - FLAC__STREAM_ENCODER_INVALID_BITS_PER_SAMPLE, + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE, /**< The encoder has an invalid setting for bits-per-sample. * FLAC supports 4-32 bps but the reference encoder currently supports * only up to 24 bps. */ - FLAC__STREAM_ENCODER_INVALID_SAMPLE_RATE, + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE, /**< The encoder has an invalid setting for the input sample rate. */ - FLAC__STREAM_ENCODER_INVALID_BLOCK_SIZE, + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE, /**< The encoder has an invalid setting for the block size. */ - FLAC__STREAM_ENCODER_INVALID_MAX_LPC_ORDER, + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER, /**< The encoder has an invalid setting for the maximum LPC order. */ - FLAC__STREAM_ENCODER_INVALID_QLP_COEFF_PRECISION, + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION, /**< The encoder has an invalid setting for the precision of the quantized linear predictor coefficients. */ - FLAC__STREAM_ENCODER_MID_SIDE_CHANNELS_MISMATCH, - /**< Mid/side coding was specified but the number of channels is not equal to 2. */ - - FLAC__STREAM_ENCODER_MID_SIDE_SAMPLE_SIZE_MISMATCH, - /**< Deprecated. */ - - FLAC__STREAM_ENCODER_ILLEGAL_MID_SIDE_FORCE, - /**< Loose mid/side coding was specified but mid/side coding was not. */ - - FLAC__STREAM_ENCODER_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER, + FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER, /**< The specified block size is less than the maximum LPC order. */ - FLAC__STREAM_ENCODER_NOT_STREAMABLE, - /**< The encoder is bound to the "streamable subset" but other settings violate it. */ + FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE, + /**< The encoder is bound to the <A HREF="../format.html#subset">Subset</A> but other settings violate it. */ - FLAC__STREAM_ENCODER_FRAMING_ERROR, - /**< An error occurred while writing the stream; usually, the write_callback returned an error. */ - - FLAC__STREAM_ENCODER_INVALID_METADATA, + FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA, /**< The metadata input to the encoder is invalid, in one of the following ways: * - FLAC__stream_encoder_set_metadata() was called with a null pointer but a block count > 0 * - One of the metadata blocks contains an undefined type @@ -261,32 +342,47 @@ typedef enum { * - It contains more than one SEEKTABLE block or more than one VORBIS_COMMENT block */ - FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING, - /**< An error occurred while writing the stream; usually, the write_callback returned an error. */ - - FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_WRITING, - /**< The write_callback returned an error. */ - - FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR, - /**< Memory allocation failed. */ - - FLAC__STREAM_ENCODER_ALREADY_INITIALIZED, - /**< FLAC__stream_encoder_init() was called when the encoder was + FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED + /**< FLAC__stream_encoder_init_*() was called when the encoder was * already initialized, usually because * FLAC__stream_encoder_finish() was not called. */ - FLAC__STREAM_ENCODER_UNINITIALIZED - /**< The encoder is in the uninitialized state. */ +} FLAC__StreamEncoderInitStatus; -} FLAC__StreamEncoderState; +/** Maps a FLAC__StreamEncoderInitStatus to a C string. + * + * Using a FLAC__StreamEncoderInitStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamEncoderInitStatusString[]; -/** Maps a FLAC__StreamEncoderState to a C string. + +/** Return values for the FLAC__StreamEncoder read callback. + */ +typedef enum { + + FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE, + /**< The read was OK and decoding can continue. */ + + FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM, + /**< The read was attempted at the end of the stream. */ + + FLAC__STREAM_ENCODER_READ_STATUS_ABORT, + /**< An unrecoverable error occurred. */ + + FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED + /**< Client does not support reading back from the output. */ + +} FLAC__StreamEncoderReadStatus; + +/** Maps a FLAC__StreamEncoderReadStatus to a C string. * - * Using a FLAC__StreamEncoderState as the index to this array + * Using a FLAC__StreamEncoderReadStatus as the index to this array * will give the string equivalent. The contents should not be modified. */ -extern FLAC_API const char * const FLAC__StreamEncoderStateString[]; +extern FLAC_API const char * const FLAC__StreamEncoderReadStatusString[]; + /** Return values for the FLAC__StreamEncoder write callback. */ @@ -308,6 +404,52 @@ typedef enum { extern FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[]; +/** Return values for the FLAC__StreamEncoder seek callback. + */ +typedef enum { + + FLAC__STREAM_ENCODER_SEEK_STATUS_OK, + /**< The seek was OK and encoding can continue. */ + + FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR, + /**< An unrecoverable error occurred. */ + + FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED + /**< Client does not support seeking. */ + +} FLAC__StreamEncoderSeekStatus; + +/** Maps a FLAC__StreamEncoderSeekStatus to a C string. + * + * Using a FLAC__StreamEncoderSeekStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[]; + + +/** Return values for the FLAC__StreamEncoder tell callback. + */ +typedef enum { + + FLAC__STREAM_ENCODER_TELL_STATUS_OK, + /**< The tell was OK and encoding can continue. */ + + FLAC__STREAM_ENCODER_TELL_STATUS_ERROR, + /**< An unrecoverable error occurred. */ + + FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED + /**< Client does not support seeking. */ + +} FLAC__StreamEncoderTellStatus; + +/** Maps a FLAC__StreamEncoderTellStatus to a C string. + * + * Using a FLAC__StreamEncoderTellStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamEncoderTellStatusString[]; + + /*********************************************************************** * * class FLAC__StreamEncoder @@ -325,33 +467,216 @@ typedef struct { struct FLAC__StreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */ } FLAC__StreamEncoder; +/** Signature for the read callback. + * + * A function pointer matching this signature must be passed to + * FLAC__stream_encoder_init_ogg_stream() if seeking is supported. + * The supplied function will be called when the encoder needs to read back + * encoded data. This happens during the metadata callback, when the encoder + * has to read, modify, and rewrite the metadata (e.g. seekpoints) gathered + * while encoding. The address of the buffer to be filled is supplied, along + * with the number of bytes the buffer can hold. The callback may choose to + * supply less data and modify the byte count but must be careful not to + * overflow the buffer. The callback then returns a status code chosen from + * FLAC__StreamEncoderReadStatus. + * + * Here is an example of a read callback for stdio streams: + * \code + * FLAC__StreamEncoderReadStatus read_cb(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * if(*bytes > 0) { + * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file); + * if(ferror(file)) + * return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; + * else if(*bytes == 0) + * return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM; + * else + * return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE; + * } + * else + * return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; + * } + * \endcode + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. + * + * \param encoder The encoder instance calling the callback. + * \param buffer A pointer to a location for the callee to store + * data to be encoded. + * \param bytes A pointer to the size of the buffer. On entry + * to the callback, it contains the maximum number + * of bytes that may be stored in \a buffer. The + * callee must set it to the actual number of bytes + * stored (0 in case of error or end-of-stream) before + * returning. + * \param client_data The callee's client data set through + * FLAC__stream_encoder_set_client_data(). + * \retval FLAC__StreamEncoderReadStatus + * The callee's return status. + */ +typedef FLAC__StreamEncoderReadStatus (*FLAC__StreamEncoderReadCallback)(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data); + /** Signature for the write callback. - * See FLAC__stream_encoder_set_write_callback() for more info. + * + * A function pointer matching this signature must be passed to + * FLAC__stream_encoder_init*_stream(). The supplied function will be called + * by the encoder anytime there is raw encoded data ready to write. It may + * include metadata mixed with encoded audio frames and the data is not + * guaranteed to be aligned on frame or metadata block boundaries. + * + * The only duty of the callback is to write out the \a bytes worth of data + * in \a buffer to the current position in the output stream. The arguments + * \a samples and \a current_frame are purely informational. If \a samples + * is greater than \c 0, then \a current_frame will hold the current frame + * number that is being written; otherwise it indicates that the write + * callback is being called to write metadata. + * + * \note + * Unlike when writing to native FLAC, when writing to Ogg FLAC the + * write callback will be called twice when writing each audio + * frame; once for the page header, and once for the page body. + * When writing the page header, the \a samples argument to the + * write callback will be \c 0. + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. * * \param encoder The encoder instance calling the callback. * \param buffer An array of encoded data of length \a bytes. * \param bytes The byte length of \a buffer. * \param samples The number of samples encoded by \a buffer. - * \c 0 has a special meaning; see - * FLAC__stream_encoder_set_write_callback(). + * \c 0 has a special meaning; see above. * \param current_frame The number of the current frame being encoded. * \param client_data The callee's client data set through - * FLAC__stream_encoder_set_client_data(). + * FLAC__stream_encoder_init_*(). * \retval FLAC__StreamEncoderWriteStatus * The callee's return status. */ -typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data); +typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data); + +/** Signature for the seek callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_encoder_init*_stream(). The supplied function will be called + * when the encoder needs to seek the output stream. The encoder will pass + * the absolute byte offset to seek to, 0 meaning the beginning of the stream. + * + * Here is an example of a seek callback for stdio streams: + * \code + * FLAC__StreamEncoderSeekStatus seek_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * if(file == stdin) + * return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED; + * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0) + * return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; + * else + * return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; + * } + * \endcode + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. + * + * \param encoder The encoder instance calling the callback. + * \param absolute_byte_offset The offset from the beginning of the stream + * to seek to. + * \param client_data The callee's client data set through + * FLAC__stream_encoder_init_*(). + * \retval FLAC__StreamEncoderSeekStatus + * The callee's return status. + */ +typedef FLAC__StreamEncoderSeekStatus (*FLAC__StreamEncoderSeekCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); + +/** Signature for the tell callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_encoder_init*_stream(). The supplied function will be called + * when the encoder needs to know the current position of the output stream. + * + * \warning + * The callback must return the true current byte offset of the output to + * which the encoder is writing. If you are buffering the output, make + * sure and take this into account. If you are writing directly to a + * FILE* from your write callback, ftell() is sufficient. If you are + * writing directly to a file descriptor from your write callback, you + * can use lseek(fd, SEEK_CUR, 0). The encoder may later seek back to + * these points to rewrite metadata after encoding. + * + * Here is an example of a tell callback for stdio streams: + * \code + * FLAC__StreamEncoderTellStatus tell_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) + * { + * FILE *file = ((MyClientData*)client_data)->file; + * off_t pos; + * if(file == stdin) + * return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED; + * else if((pos = ftello(file)) < 0) + * return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; + * else { + * *absolute_byte_offset = (FLAC__uint64)pos; + * return FLAC__STREAM_ENCODER_TELL_STATUS_OK; + * } + * } + * \endcode + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. + * + * \param encoder The encoder instance calling the callback. + * \param absolute_byte_offset The address at which to store the current + * position of the output. + * \param client_data The callee's client data set through + * FLAC__stream_encoder_init_*(). + * \retval FLAC__StreamEncoderTellStatus + * The callee's return status. + */ +typedef FLAC__StreamEncoderTellStatus (*FLAC__StreamEncoderTellCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); /** Signature for the metadata callback. - * See FLAC__stream_encoder_set_metadata_callback() for more info. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_encoder_init*_stream(). The supplied function will be called + * once at the end of encoding with the populated STREAMINFO structure. This + * is so the client can seek back to the beginning of the file and write the + * STREAMINFO block with the correct statistics after encoding (like + * minimum/maximum frame size and total samples). + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. * * \param encoder The encoder instance calling the callback. * \param metadata The final populated STREAMINFO block. * \param client_data The callee's client data set through - * FLAC__stream_encoder_set_client_data(). + * FLAC__stream_encoder_init_*(). */ typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data); +/** Signature for the progress callback. + * + * A function pointer matching this signature may be passed to + * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE(). + * The supplied function will be called when the encoder has finished + * writing a frame. The \c total_frames_estimate argument to the + * callback will be based on the value from + * FLAC__stream_encoder_set_total_samples_estimate(). + * + * \note In general, FLAC__StreamEncoder functions which change the + * state should not be called on the \a encoder while in the callback. + * + * \param encoder The encoder instance calling the callback. + * \param bytes_written Bytes written so far. + * \param samples_written Samples written so far. + * \param frames_written Frames written so far. + * \param total_frames_estimate The estimate of the total number of + * frames to be written. + * \param client_data The callee's client data set through + * FLAC__stream_encoder_init_*(). + */ +typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data); + /*********************************************************************** * @@ -366,7 +691,7 @@ typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *e * \retval FLAC__StreamEncoder* * \c NULL if there was an error allocating memory, else the new instance. */ -FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(); +FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void); /** Free an encoder instance. Deletes the object pointed to by \a encoder. * @@ -383,6 +708,25 @@ FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder); * ***********************************************************************/ +/** Set the serial number for the FLAC stream to use in the Ogg container. + * + * \note + * This does not need to be set for native FLAC encoding. + * + * \note + * It is recommended to set a serial number explicitly as the default of '0' + * may collide with other streams. + * + * \default \c 0 + * \param encoder An encoder instance to set. + * \param serial_number See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long serial_number); + /** Set the "verify" flag. If \c true, the encoder will verify it's own * encoded output by feeding it through an internal decoder and comparing * the original signal against the decoded signal. If a mismatch occurs, @@ -399,9 +743,9 @@ FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder); */ FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value); -/** Set the "streamable subset" flag. If \c true, the encoder will comply - * with the subset (see the format specification) and will check the - * settings during FLAC__stream_encoder_init() to see if all settings +/** Set the <A HREF="../format.html#subset">Subset</A> flag. If \c true, + * the encoder will comply with the Subset and will check the + * settings during FLAC__stream_encoder_init_*() to see if all settings * comply. If \c false, the settings may take advantage of the full * range that the format allows. * @@ -417,35 +761,6 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder */ FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value); -/** Set to \c true to enable mid-side encoding on stereo input. The - * number of channels must be 2. Set to \c false to use only - * independent channel coding. - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value Flag value (see above). - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value); - -/** Set to \c true to enable adaptive switching between mid-side and - * left-right encoding on stereo input. The number of channels must - * be 2. Set to \c false to use exhaustive searching. In either - * case, the mid/side stereo setting must be \c true. - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value Flag value (see above). - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value); - /** Set the number of channels to be encoded. * * \default \c 2 @@ -486,9 +801,75 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder */ FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value); +/** Set the compression level + * + * The compression level is roughly proportional to the amount of effort + * the encoder expends to compress the file. A higher level usually + * means more computation but higher compression. The default level is + * suitable for most applications. + * + * Currently the levels range from \c 0 (fastest, least compression) to + * \c 8 (slowest, most compression). A value larger than \c 8 will be + * treated as \c 8. + * + * This function automatically calls the following other \c _set_ + * functions with appropriate values, so the client does not need to + * unless it specifically wants to override them: + * - FLAC__stream_encoder_set_do_mid_side_stereo() + * - FLAC__stream_encoder_set_loose_mid_side_stereo() + * - FLAC__stream_encoder_set_apodization() + * - FLAC__stream_encoder_set_max_lpc_order() + * - FLAC__stream_encoder_set_qlp_coeff_precision() + * - FLAC__stream_encoder_set_do_qlp_coeff_prec_search() + * - FLAC__stream_encoder_set_do_escape_coding() + * - FLAC__stream_encoder_set_do_exhaustive_model_search() + * - FLAC__stream_encoder_set_min_residual_partition_order() + * - FLAC__stream_encoder_set_max_residual_partition_order() + * - FLAC__stream_encoder_set_rice_parameter_search_dist() + * + * The actual values set for each level are: + * <table> + * <tr> + * <td><b>level</b></td> + * <td>do mid-side stereo</td> + * <td>loose mid-side stereo</td> + * <td>apodization</td> + * <td>max lpc order</td> + * <td>qlp coeff precision</td> + * <td>qlp coeff prec search</td> + * <td>escape coding</td> + * <td>exhaustive model search</td> + * <td>min residual partition order</td> + * <td>max residual partition order</td> + * <td>rice parameter search dist</td> + * </tr> + * <tr> <td><b>0</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr> + * <tr> <td><b>1</b></td> <td>true</td> <td>true</td> <td>tukey(0.5)<td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr> + * <tr> <td><b>2</b></td> <td>true</td> <td>false</td> <td>tukey(0.5)<td> <td>0</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr> + * <tr> <td><b>3</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td> <td>6</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr> + * <tr> <td><b>4</b></td> <td>true</td> <td>true</td> <td>tukey(0.5)<td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr> + * <tr> <td><b>5</b></td> <td>true</td> <td>false</td> <td>tukey(0.5)<td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>5</td> <td>0</td> </tr> + * <tr> <td><b>6</b></td> <td>true</td> <td>false</td> <td>tukey(0.5);partial_tukey(2)<td> <td>8</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr> + * <tr> <td><b>7</b></td> <td>true</td> <td>false</td> <td>tukey(0.5);partial_tukey(2)<td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr> + * <tr> <td><b>8</b></td> <td>true</td> <td>false</td> <td>tukey(0.5);partial_tukey(2);punchout_tukey(3)</td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr> + * </table> + * + * \default \c 5 + * \param encoder An encoder instance to set. + * \param value See above. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value); + /** Set the blocksize to use while encoding. * - * \default \c 1152 + * The number of samples to use per frame. Use \c 0 to let the encoder + * estimate a blocksize; this is usually best. + * + * \default \c 0 * \param encoder An encoder instance to set. * \param value See above. * \assert @@ -498,6 +879,102 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *en */ FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value); +/** Set to \c true to enable mid-side encoding on stereo input. The + * number of channels must be 2 for this to have any effect. Set to + * \c false to use only independent channel coding. + * + * \default \c false + * \param encoder An encoder instance to set. + * \param value Flag value (see above). + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value); + +/** Set to \c true to enable adaptive switching between mid-side and + * left-right encoding on stereo input. Set to \c false to use + * exhaustive searching. Setting this to \c true requires + * FLAC__stream_encoder_set_do_mid_side_stereo() to also be set to + * \c true in order to have any effect. + * + * \default \c false + * \param encoder An encoder instance to set. + * \param value Flag value (see above). + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value); + +/** Sets the apodization function(s) the encoder will use when windowing + * audio data for LPC analysis. + * + * The \a specification is a plain ASCII string which specifies exactly + * which functions to use. There may be more than one (up to 32), + * separated by \c ';' characters. Some functions take one or more + * comma-separated arguments in parentheses. + * + * The available functions are \c bartlett, \c bartlett_hann, + * \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop, + * \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall, + * \c rectangle, \c triangle, \c tukey(P), \c partial_tukey(n[/ov[/P]]), + * \c punchout_tukey(n[/ov[/P]]), \c welch. + * + * For \c gauss(STDDEV), STDDEV specifies the standard deviation + * (0<STDDEV<=0.5). + * + * For \c tukey(P), P specifies the fraction of the window that is + * tapered (0<=P<=1). P=0 corresponds to \c rectangle and P=1 + * corresponds to \c hann. + * + * Specifying \c partial_tukey or \c punchout_tukey works a little + * different. These do not specify a single apodization function, but + * a series of them with some overlap. partial_tukey specifies a series + * of small windows (all treated separately) while punchout_tukey + * specifies a series of windows that have a hole in them. In this way, + * the predictor is constructed with only a part of the block, which + * helps in case a block consists of dissimilar parts. + * + * The three parameters that can be specified for the functions are + * n, ov and P. n is the number of functions to add, ov is the overlap + * of the windows in case of partial_tukey and the overlap in the gaps + * in case of punchout_tukey. P is the fraction of the window that is + * tapered, like with a regular tukey window. The function can be + * specified with only a number, a number and an overlap, or a number + * an overlap and a P, for example, partial_tukey(3), partial_tukey(3/0.3) + * and partial_tukey(3/0.3/0.5) are all valid. ov should be smaller than 1 + * and can be negative. + * + * Example specifications are \c "blackman" or + * \c "hann;triangle;tukey(0.5);tukey(0.25);tukey(0.125)" + * + * Any function that is specified erroneously is silently dropped. Up + * to 32 functions are kept, the rest are dropped. If the specification + * is empty the encoder defaults to \c "tukey(0.5)". + * + * When more than one function is specified, then for every subframe the + * encoder will try each of them separately and choose the window that + * results in the smallest compressed subframe. + * + * Note that each function specified causes the encoder to occupy a + * floating point array in which to store the window. Also note that the + * values of P, STDDEV and ov are locale-specific, so if the comma + * separator specified by the locale is a comma, a comma should be used. + * + * \default \c "tukey(0.5)" + * \param encoder An encoder instance to set. + * \param specification See above. + * \assert + * \code encoder != NULL \endcode + * \code specification != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification); + /** Set the maximum LPC order, or \c 0 to use only the fixed predictors. * * \default \c 0 @@ -645,14 +1122,15 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__Stream /** Set the metadata blocks to be emitted to the stream before encoding. * A value of \c NULL, \c 0 implies no metadata; otherwise, supply an * array of pointers to metadata blocks. The array is non-const since - * the encoder may need to change the \a is_last flag inside them. - * Otherwise, the encoder will not modify or free the blocks. It is up - * to the caller to free the metadata blocks after encoding. + * the encoder may need to change the \a is_last flag inside them, and + * in some cases update seek point offsets. Otherwise, the encoder will + * not modify or free the blocks. It is up to the caller to free the + * metadata blocks after encoding finishes. * * \note - * The encoder stores only the \a metadata pointer; the passed-in array - * must survive at least until after FLAC__stream_encoder_init() returns. - * Do not modify the array or free the blocks until then. + * The encoder stores only copies of the pointers in the \a metadata array; + * the metadata blocks themselves must survive at least until after + * FLAC__stream_encoder_finish() returns. Do not free the blocks until then. * * \note * The STREAMINFO block is always written and no STREAMINFO block may @@ -660,11 +1138,35 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__Stream * * \note * By default the encoder does not create a SEEKTABLE. If one is supplied - * in the \a metadata array it will be written verbatim. However by itself - * this is not very useful as the user will not know the stream offsets for - * the seekpoints ahead of time. You must use the seekable stream encoder - * to generate a legal seektable - * (see FLAC__seekable_stream_encoder_set_metadata()) + * in the \a metadata array, but the client has specified that it does not + * support seeking, then the SEEKTABLE will be written verbatim. However + * by itself this is not very useful as the client will not know the stream + * offsets for the seekpoints ahead of time. In order to get a proper + * seektable the client must support seeking. See next note. + * + * \note + * SEEKTABLE blocks are handled specially. Since you will not know + * the values for the seek point stream offsets, you should pass in + * a SEEKTABLE 'template', that is, a SEEKTABLE object with the + * required sample numbers (or placeholder points), with \c 0 for the + * \a frame_samples and \a stream_offset fields for each point. If the + * client has specified that it supports seeking by providing a seek + * callback to FLAC__stream_encoder_init_stream() or both seek AND read + * callback to FLAC__stream_encoder_init_ogg_stream() (or by using + * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE()), + * then while it is encoding the encoder will fill the stream offsets in + * for you and when encoding is finished, it will seek back and write the + * real values into the SEEKTABLE block in the stream. There are helper + * routines for manipulating seektable template blocks; see metadata.h: + * FLAC__metadata_object_seektable_template_*(). If the client does + * not support seeking, the SEEKTABLE will have inaccurate offsets which + * will slow down or remove the ability to seek in the FLAC stream. + * + * \note + * The encoder instance \b will modify the first \c SEEKTABLE block + * as it transforms the template to a valid seektable while encoding, + * but it is still up to the caller to free all metadata blocks after + * encoding. * * \note * A VORBIS_COMMENT block may be supplied. The vendor string in it @@ -674,6 +1176,19 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__Stream * block is present in the \a metadata array, libFLAC will write an * empty one, containing only the vendor string. * + * \note The Ogg FLAC mapping requires that the VORBIS_COMMENT block be + * the second metadata block of the stream. The encoder already supplies + * the STREAMINFO block automatically. If \a metadata does not contain a + * VORBIS_COMMENT block, the encoder will supply that too. Otherwise, if + * \a metadata does contain a VORBIS_COMMENT block and it is not the + * first, the init function will reorder \a metadata by moving the + * VORBIS_COMMENT block to the front; the relative ordering of the other + * blocks will remain as they were. + * + * \note The Ogg FLAC mapping limits the number of metadata blocks per + * stream to \c 65535. If \a num_blocks exceeds this the function will + * return \c false. + * * \default \c NULL, 0 * \param encoder An encoder instance to set. * \param metadata See above. @@ -682,71 +1197,11 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__Stream * \code encoder != NULL \endcode * \retval FLAC__bool * \c false if the encoder is already initialized, else \c true. + * \c false if the encoder is already initialized, or if + * \a num_blocks > 65535 if encoding to Ogg FLAC, else \c true. */ FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks); -/** Set the write callback. - * The supplied function will be called by the encoder anytime there is raw - * encoded data ready to write. It may include metadata mixed with encoded - * audio frames and the data is not guaranteed to be aligned on frame or - * metadata block boundaries. - * - * The only duty of the callback is to write out the \a bytes worth of data - * in \a buffer to the current position in the output stream. The arguments - * \a samples and \a current_frame are purely informational. If \a samples - * is greater than \c 0, then \a current_frame will hold the current frame - * number that is being written; otherwise, the write callback is being called - * to write metadata. - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_write_callback(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteCallback value); - -/** Set the metadata callback. - * The supplied function will be called once at the end of encoding with - * the populated STREAMINFO structure. This is so file encoders can seek - * back to the beginning of the file and write the STREAMINFO block with - * the correct statistics after encoding (like minimum/maximum frame size - * and total samples). - * - * \note - * The callback is mandatory and must be set before initialization. - * - * \default \c NULL - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata_callback(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderMetadataCallback value); - -/** Set the client data to be passed back to callbacks. - * This value will be supplied to callbacks in their \a client_data - * argument. - * - * \default \c NULL - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_client_data(FLAC__StreamEncoder *encoder, void *value); - /** Get the current encoder state. * * \param encoder An encoder instance to query. @@ -811,7 +1266,7 @@ FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__St */ FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder); -/** Get the "streamable subset" flag. +/** Get the <A HREF="../format.html#subset>Subset</A> flag. * * \param encoder An encoder instance to query. * \assert @@ -821,26 +1276,6 @@ FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *e */ FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder); -/** Get the "mid/side stereo coding" flag. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__stream_encoder_get_do_mid_side_stereo(). - */ -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder); - -/** Get the "adaptive mid/side switching" flag. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__stream_encoder_set_loose_mid_side_stereo(). - */ -FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder); - /** Get the number of input channels being processed. * * \param encoder An encoder instance to query. @@ -881,6 +1316,26 @@ FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder */ FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder); +/** Get the "mid/side stereo coding" flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_get_do_mid_side_stereo(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder); + +/** Get the "adaptive mid/side switching" flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_loose_mid_side_stereo(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder); + /** Get the maximum LPC order setting. * * \param encoder An encoder instance to query. @@ -964,7 +1419,7 @@ FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC /** Get the previously set estimate of the total samples to be encoded. * The encoder merely mimics back the value given to * FLAC__stream_encoder_set_total_samples_estimate() since it has no - * other way of knowing how many samples the user will encode. + * other way of knowing how many samples the client will encode. * * \param encoder An encoder instance to set. * \assert @@ -974,25 +1429,270 @@ FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC */ FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder); -/** Initialize the encoder instance. - * Should be called after FLAC__stream_encoder_new() and +/** Initialize the encoder instance to encode native FLAC streams. + * + * This flavor of initialization sets up the encoder to encode to a + * native FLAC stream. I/O is performed via callbacks to the client. + * For encoding to a plain file via filename or open \c FILE*, + * FLAC__stream_encoder_init_file() and FLAC__stream_encoder_init_FILE() + * provide a simpler interface. + * + * This function should be called after FLAC__stream_encoder_new() and * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() - * or FLAC__stream_encoder_process_interleaved(). Will set and return - * the encoder state, which will be FLAC__STREAM_ENCODER_OK if + * or FLAC__stream_encoder_process_interleaved(). * initialization succeeded. * - * The call to FLAC__stream_encoder_init() currently will also immediately - * call the write callback several times, once with the \c fLaC signature, - * and once for each encoded metadata block. + * The call to FLAC__stream_encoder_init_stream() currently will also + * immediately call the write callback several times, once with the \c fLaC + * signature, and once for each encoded metadata block. + * + * \param encoder An uninitialized encoder instance. + * \param write_callback See FLAC__StreamEncoderWriteCallback. This + * pointer must not be \c NULL. + * \param seek_callback See FLAC__StreamEncoderSeekCallback. This + * pointer may be \c NULL if seeking is not + * supported. The encoder uses seeking to go back + * and write some some stream statistics to the + * STREAMINFO block; this is recommended but not + * necessary to create a valid FLAC stream. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy seek callback that just + * returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the encoder. + * \param tell_callback See FLAC__StreamEncoderTellCallback. This + * pointer may be \c NULL if seeking is not + * supported. If \a seek_callback is \c NULL then + * this argument will be ignored. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy tell callback that just + * returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the encoder. + * \param metadata_callback See FLAC__StreamEncoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. If the client provides a seek callback, + * this function is not necessary as the encoder + * will automatically seek back and update the + * STREAMINFO block. It may also be \c NULL if the + * client does not support seeking, since it will + * have no way of going back to update the + * STREAMINFO. However the client can still supply + * a callback if it would like to know the details + * from the STREAMINFO. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data); + +/** Initialize the encoder instance to encode Ogg FLAC streams. + * + * This flavor of initialization sets up the encoder to encode to a FLAC + * stream in an Ogg container. I/O is performed via callbacks to the + * client. For encoding to a plain file via filename or open \c FILE*, + * FLAC__stream_encoder_init_ogg_file() and FLAC__stream_encoder_init_ogg_FILE() + * provide a simpler interface. * - * \param encoder An uninitialized encoder instance. + * This function should be called after FLAC__stream_encoder_new() and + * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() + * or FLAC__stream_encoder_process_interleaved(). + * initialization succeeded. + * + * The call to FLAC__stream_encoder_init_ogg_stream() currently will also + * immediately call the write callback several times to write the metadata + * packets. + * + * \param encoder An uninitialized encoder instance. + * \param read_callback See FLAC__StreamEncoderReadCallback. This + * pointer must not be \c NULL if \a seek_callback + * is non-NULL since they are both needed to be + * able to write data back to the Ogg FLAC stream + * in the post-encode phase. + * \param write_callback See FLAC__StreamEncoderWriteCallback. This + * pointer must not be \c NULL. + * \param seek_callback See FLAC__StreamEncoderSeekCallback. This + * pointer may be \c NULL if seeking is not + * supported. The encoder uses seeking to go back + * and write some some stream statistics to the + * STREAMINFO block; this is recommended but not + * necessary to create a valid FLAC stream. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy seek callback that just + * returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the encoder. + * \param tell_callback See FLAC__StreamEncoderTellCallback. This + * pointer may be \c NULL if seeking is not + * supported. If \a seek_callback is \c NULL then + * this argument will be ignored. If + * \a seek_callback is not \c NULL then a + * \a tell_callback must also be supplied. + * Alternatively, a dummy tell callback that just + * returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED + * may also be supplied, all though this is slightly + * less efficient for the encoder. + * \param metadata_callback See FLAC__StreamEncoderMetadataCallback. This + * pointer may be \c NULL if the callback is not + * desired. If the client provides a seek callback, + * this function is not necessary as the encoder + * will automatically seek back and update the + * STREAMINFO block. It may also be \c NULL if the + * client does not support seeking, since it will + * have no way of going back to update the + * STREAMINFO. However the client can still supply + * a callback if it would like to know the details + * from the STREAMINFO. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. * \assert * \code encoder != NULL \endcode - * \retval FLAC__StreamEncoderState - * \c FLAC__STREAM_ENCODER_OK if initialization was successful; see - * FLAC__StreamEncoderState for the meanings of other return values. + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderReadCallback read_callback, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data); + +/** Initialize the encoder instance to encode native FLAC files. + * + * This flavor of initialization sets up the encoder to encode to a + * plain native FLAC file. For non-stdio streams, you must use + * FLAC__stream_encoder_init_stream() and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_encoder_new() and + * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() + * or FLAC__stream_encoder_process_interleaved(). + * initialization succeeded. + * + * \param encoder An uninitialized encoder instance. + * \param file An open file. The file should have been opened + * with mode \c "w+b" and rewound. The file + * becomes owned by the encoder and should not be + * manipulated by the client while encoding. + * Unless \a file is \c stdout, it will be closed + * when FLAC__stream_encoder_finish() is called. + * Note however that a proper SEEKTABLE cannot be + * created when encoding to \c stdout since it is + * not seekable. + * \param progress_callback See FLAC__StreamEncoderProgressCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code encoder != NULL \endcode + * \code file != NULL \endcode + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. */ -FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder *encoder); +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); + +/** Initialize the encoder instance to encode Ogg FLAC files. + * + * This flavor of initialization sets up the encoder to encode to a + * plain Ogg FLAC file. For non-stdio streams, you must use + * FLAC__stream_encoder_init_ogg_stream() and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_encoder_new() and + * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() + * or FLAC__stream_encoder_process_interleaved(). + * initialization succeeded. + * + * \param encoder An uninitialized encoder instance. + * \param file An open file. The file should have been opened + * with mode \c "w+b" and rewound. The file + * becomes owned by the encoder and should not be + * manipulated by the client while encoding. + * Unless \a file is \c stdout, it will be closed + * when FLAC__stream_encoder_finish() is called. + * Note however that a proper SEEKTABLE cannot be + * created when encoding to \c stdout since it is + * not seekable. + * \param progress_callback See FLAC__StreamEncoderProgressCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code encoder != NULL \endcode + * \code file != NULL \endcode + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); + +/** Initialize the encoder instance to encode native FLAC files. + * + * This flavor of initialization sets up the encoder to encode to a plain + * FLAC file. If POSIX fopen() semantics are not sufficient (for example, + * with Unicode filenames on Windows), you must use + * FLAC__stream_encoder_init_FILE(), or FLAC__stream_encoder_init_stream() + * and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_encoder_new() and + * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() + * or FLAC__stream_encoder_process_interleaved(). + * initialization succeeded. + * + * \param encoder An uninitialized encoder instance. + * \param filename The name of the file to encode to. The file will + * be opened with fopen(). Use \c NULL to encode to + * \c stdout. Note however that a proper SEEKTABLE + * cannot be created when encoding to \c stdout since + * it is not seekable. + * \param progress_callback See FLAC__StreamEncoderProgressCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); + +/** Initialize the encoder instance to encode Ogg FLAC files. + * + * This flavor of initialization sets up the encoder to encode to a plain + * Ogg FLAC file. If POSIX fopen() semantics are not sufficient (for example, + * with Unicode filenames on Windows), you must use + * FLAC__stream_encoder_init_ogg_FILE(), or FLAC__stream_encoder_init_ogg_stream() + * and provide callbacks for the I/O. + * + * This function should be called after FLAC__stream_encoder_new() and + * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() + * or FLAC__stream_encoder_process_interleaved(). + * initialization succeeded. + * + * \param encoder An uninitialized encoder instance. + * \param filename The name of the file to encode to. The file will + * be opened with fopen(). Use \c NULL to encode to + * \c stdout. Note however that a proper SEEKTABLE + * cannot be created when encoding to \c stdout since + * it is not seekable. + * \param progress_callback See FLAC__StreamEncoderProgressCallback. This + * pointer may be \c NULL if the callback is not + * desired. + * \param client_data This value will be supplied to callbacks in their + * \a client_data argument. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__StreamEncoderInitStatus + * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; + * see FLAC__StreamEncoderInitStatus for the meanings of other return values. + */ +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); /** Finish the encoding process. * Flushes the encoding buffer, releases resources, resets the encoder @@ -1001,22 +1701,40 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder * one or more write callbacks before returning, and will generate * a metadata callback. * + * Note that in the course of processing the last frame, errors can + * occur, so the caller should be sure to check the return value to + * ensure the file was encoded properly. + * * In the event of a prematurely-terminated encode, it is not strictly * necessary to call this immediately before FLAC__stream_encoder_delete() - * but it is good practice to match every FLAC__stream_encoder_init() + * but it is good practice to match every FLAC__stream_encoder_init_*() * with a FLAC__stream_encoder_finish(). * * \param encoder An uninitialized encoder instance. * \assert * \code encoder != NULL \endcode + * \retval FLAC__bool + * \c false if an error occurred processing the last frame; or if verify + * mode is set (see FLAC__stream_encoder_set_verify()), there was a + * verify mismatch; else \c true. If \c false, caller should check the + * state with FLAC__stream_encoder_get_state() for more information + * about the error. */ -FLAC_API void FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder); +FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder); /** Submit data for encoding. * This version allows you to supply the input data via an array of * pointers, each pointer pointing to an array of \a samples samples * representing one channel. The samples need not be block-aligned, - * but each channel should have the same number of samples. + * but each channel should have the same number of samples. Each sample + * should be a signed integer, right-justified to the resolution set by + * FLAC__stream_encoder_set_bits_per_sample(). For example, if the + * resolution is 16 bits per sample, the samples should all be in the + * range [-32768,32767]. + * + * For applications where channel order is important, channels must + * follow the order as described in the + * <A HREF="../format.html#frame_header">frame header</A>. * * \param encoder An initialized encoder instance in the OK state. * \param buffer An array of pointers to each channel's signal. @@ -1037,7 +1755,15 @@ FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, c * channel1_sample0, ... , channelN_sample0, channel0_sample1, ...). * The samples need not be block-aligned but they must be * sample-aligned, i.e. the first value should be channel0_sample0 - * and the last value channelN_sampleM. + * and the last value channelN_sampleM. Each sample should be a signed + * integer, right-justified to the resolution set by + * FLAC__stream_encoder_set_bits_per_sample(). For example, if the + * resolution is 16 bits per sample, the samples should all be in the + * range [-32768,32767]. + * + * For applications where channel order is important, channels must + * follow the order as described in the + * <A HREF="../format.html#frame_header">frame header</A>. * * \param encoder An initialized encoder instance in the OK state. * \param buffer An array of channel-interleaved data (see above). diff --git a/sys/src/cmd/audio/libFLAC/bitbuffer.c b/sys/src/cmd/audio/libFLAC/bitbuffer.c deleted file mode 100644 index 312ed7f96..000000000 --- a/sys/src/cmd/audio/libFLAC/bitbuffer.c +++ /dev/null @@ -1,2530 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 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 <stdlib.h> /* for malloc() */ -#include <string.h> /* for memcpy(), memset() */ -#include "private/bitbuffer.h" -#include "private/bitmath.h" -#include "private/crc.h" -#include "FLAC/assert.h" - -/* - * Along the way you will see two versions of some functions, selected - * by a FLAC__NO_MANUAL_INLINING macro. One is the simplified, more - * readable, and slow version, and the other is the same function - * where crucial parts have been manually inlined and are much faster. - * - */ - -/* - * This should be at least twice as large as the largest number of blurbs - * required to represent any 'number' (in any encoding) you are going to - * read. With FLAC this is on the order of maybe a few hundred bits. - * If the buffer is smaller than that, the decoder won't be able to read - * in a whole number that is in a variable length encoding (e.g. Rice). - * - * The number we are actually using here is based on what would be the - * approximate maximum size of a verbatim frame at the default block size, - * for CD audio (4096 sample * 4 bytes per sample), plus some wiggle room. - * 32kbytes sounds reasonable. For kicks we subtract out 64 bytes for any - * alignment or malloc overhead. - * - * Increase this number to decrease the number of read callbacks, at the - * expense of using more memory. Or decrease for the reverse effect, - * keeping in mind the limit from the first paragraph. - */ -static const unsigned FLAC__BITBUFFER_DEFAULT_CAPACITY = ((65536 - 64) * 8) / FLAC__BITS_PER_BLURB; /* blurbs */ - -#if FLAC__BITS_PER_BLURB == 8 -#define FLAC__BITS_PER_BLURB_LOG2 3 -#define FLAC__BYTES_PER_BLURB 1 -#define FLAC__BLURB_ALL_ONES ((FLAC__byte)0xff) -#define FLAC__BLURB_TOP_BIT_ONE ((FLAC__byte)0x80) -#define BLURB_BIT_TO_MASK(b) (((FLAC__blurb)'\x80') >> (b)) -#define CRC16_UPDATE_BLURB(bb, blurb, crc) FLAC__CRC16_UPDATE((blurb), (crc)); -#elif FLAC__BITS_PER_BLURB == 32 -#define FLAC__BITS_PER_BLURB_LOG2 5 -#define FLAC__BYTES_PER_BLURB 4 -#define FLAC__BLURB_ALL_ONES ((FLAC__uint32)0xffffffff) -#define FLAC__BLURB_TOP_BIT_ONE ((FLAC__uint32)0x80000000) -#define BLURB_BIT_TO_MASK(b) (((FLAC__blurb)0x80000000) >> (b)) -#define CRC16_UPDATE_BLURB(bb, blurb, crc) crc16_update_blurb((bb), (blurb)); -#else -/* ERROR, only sizes of 8 and 32 are supported */ -#endif - -#define FLAC__BLURBS_TO_BITS(blurbs) ((blurbs) << FLAC__BITS_PER_BLURB_LOG2) - -#ifdef min -#undef min -#endif -#define min(x,y) ((x)<(y)?(x):(y)) -#ifdef max -#undef max -#endif -#define max(x,y) ((x)>(y)?(x):(y)) - -/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */ -#ifdef _MSC_VER -#define FLAC__U64L(x) x -#else -#define FLAC__U64L(x) x##LLU -#endif - -#ifndef FLaC__INLINE -#define FLaC__INLINE -#endif - -struct FLAC__BitBuffer { - FLAC__blurb *buffer; - unsigned capacity; /* in blurbs */ - unsigned blurbs, bits; - unsigned total_bits; /* must always == FLAC__BITS_PER_BLURB*blurbs+bits */ - unsigned consumed_blurbs, consumed_bits; - unsigned total_consumed_bits; /* must always == FLAC__BITS_PER_BLURB*consumed_blurbs+consumed_bits */ - FLAC__uint16 read_crc16; -#if FLAC__BITS_PER_BLURB == 32 - unsigned crc16_align; -#endif - FLAC__blurb save_head, save_tail; -}; - -#if FLAC__BITS_PER_BLURB == 32 -static void crc16_update_blurb(FLAC__BitBuffer *bb, FLAC__blurb blurb) -{ - if(bb->crc16_align == 0) { - FLAC__CRC16_UPDATE(blurb >> 24, bb->read_crc16); - FLAC__CRC16_UPDATE((blurb >> 16) & 0xff, bb->read_crc16); - FLAC__CRC16_UPDATE((blurb >> 8) & 0xff, bb->read_crc16); - FLAC__CRC16_UPDATE(blurb & 0xff, bb->read_crc16); - } - else if(bb->crc16_align == 8) { - FLAC__CRC16_UPDATE((blurb >> 16) & 0xff, bb->read_crc16); - FLAC__CRC16_UPDATE((blurb >> 8) & 0xff, bb->read_crc16); - FLAC__CRC16_UPDATE(blurb & 0xff, bb->read_crc16); - } - else if(bb->crc16_align == 16) { - FLAC__CRC16_UPDATE((blurb >> 8) & 0xff, bb->read_crc16); - FLAC__CRC16_UPDATE(blurb & 0xff, bb->read_crc16); - } - else if(bb->crc16_align == 24) { - FLAC__CRC16_UPDATE(blurb & 0xff, bb->read_crc16); - } - bb->crc16_align = 0; -} -#endif - -/* - * WATCHOUT: The current implentation is not friendly to shrinking, i.e. it - * does not shift left what is consumed, it just chops off the end, whether - * there is unconsumed data there or not. This is OK because currently we - * never shrink the buffer, but if this ever changes, we'll have to do some - * fixups here. - */ -static FLAC__bool bitbuffer_resize_(FLAC__BitBuffer *bb, unsigned new_capacity) -{ - FLAC__blurb *new_buffer; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - if(bb->capacity == new_capacity) - return true; - - new_buffer = (FLAC__blurb*)calloc(new_capacity, sizeof(FLAC__blurb)); - if(new_buffer == 0) - return false; - memcpy(new_buffer, bb->buffer, sizeof(FLAC__blurb)*min(bb->blurbs+(bb->bits?1:0), new_capacity)); - if(new_capacity < bb->blurbs+(bb->bits?1:0)) { - bb->blurbs = new_capacity; - bb->bits = 0; - bb->total_bits = FLAC__BLURBS_TO_BITS(new_capacity); - } - if(new_capacity < bb->consumed_blurbs+(bb->consumed_bits?1:0)) { - bb->consumed_blurbs = new_capacity; - bb->consumed_bits = 0; - bb->total_consumed_bits = FLAC__BLURBS_TO_BITS(new_capacity); - } - free(bb->buffer); /* we've already asserted above that (0 != bb->buffer) */ - bb->buffer = new_buffer; - bb->capacity = new_capacity; - return true; -} - -static FLAC__bool bitbuffer_grow_(FLAC__BitBuffer *bb, unsigned min_blurbs_to_add) -{ - unsigned new_capacity; - - FLAC__ASSERT(min_blurbs_to_add > 0); - - new_capacity = max(bb->capacity * 2, bb->capacity + min_blurbs_to_add); - return bitbuffer_resize_(bb, new_capacity); -} - -static FLAC__bool bitbuffer_ensure_size_(FLAC__BitBuffer *bb, unsigned bits_to_add) -{ - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - if(FLAC__BLURBS_TO_BITS(bb->capacity) < bb->total_bits + bits_to_add) - return bitbuffer_grow_(bb, (bits_to_add >> FLAC__BITS_PER_BLURB_LOG2) + 2); - else - return true; -} - -static FLAC__bool bitbuffer_read_from_client_(FLAC__BitBuffer *bb, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - unsigned bytes; - FLAC__byte *target; - - /* first shift the unconsumed buffer data toward the front as much as possible */ - if(bb->total_consumed_bits >= FLAC__BITS_PER_BLURB) { - unsigned l = 0, r = bb->consumed_blurbs, r_end = bb->blurbs + (bb->bits? 1:0); - for( ; r < r_end; l++, r++) - bb->buffer[l] = bb->buffer[r]; - for( ; l < r_end; l++) - bb->buffer[l] = 0; - bb->blurbs -= bb->consumed_blurbs; - bb->total_bits -= FLAC__BLURBS_TO_BITS(bb->consumed_blurbs); - bb->consumed_blurbs = 0; - bb->total_consumed_bits = bb->consumed_bits; - } - - /* grow if we need to */ - if(bb->capacity <= 1) { - if(!bitbuffer_resize_(bb, 16)) - return false; - } - - /* set the target for reading, taking into account blurb alignment */ -#if FLAC__BITS_PER_BLURB == 8 - /* blurb == byte, so no gyrations necessary: */ - target = bb->buffer + bb->blurbs; - bytes = bb->capacity - bb->blurbs; -#elif FLAC__BITS_PER_BLURB == 32 - /* @@@ WATCHOUT: code currently only works for big-endian: */ - FLAC__ASSERT((bb->bits & 7) == 0); - target = (FLAC__byte*)(bb->buffer + bb->blurbs) + (bb->bits >> 3); - bytes = ((bb->capacity - bb->blurbs) << 2) - (bb->bits >> 3); /* i.e. (bb->capacity - bb->blurbs) * FLAC__BYTES_PER_BLURB - (bb->bits / 8) */ -#else - FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */ -#endif - - /* finally, read in some data */ - if(!read_callback(target, &bytes, client_data)) - return false; - - /* now we have to handle partial blurb cases: */ -#if FLAC__BITS_PER_BLURB == 8 - /* blurb == byte, so no gyrations necessary: */ - bb->blurbs += bytes; - bb->total_bits += FLAC__BLURBS_TO_BITS(bytes); -#elif FLAC__BITS_PER_BLURB == 32 - /* @@@ WATCHOUT: code currently only works for big-endian: */ - { - const unsigned aligned_bytes = (bb->bits >> 3) + bytes; - bb->blurbs += (aligned_bytes >> 2); /* i.e. aligned_bytes / FLAC__BYTES_PER_BLURB */ - bb->bits = (aligned_bytes & 3u) << 3; /* i.e. (aligned_bytes % FLAC__BYTES_PER_BLURB) * 8 */ - bb->total_bits += (bytes << 3); - } -#else - FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */ -#endif - return true; -} - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -FLAC__BitBuffer *FLAC__bitbuffer_new(void) -{ - FLAC__BitBuffer *bb = (FLAC__BitBuffer*)calloc(1, sizeof(FLAC__BitBuffer)); - - /* calloc() implies: - memset(bb, 0, sizeof(FLAC__BitBuffer)); - bb->buffer = 0; - bb->capacity = 0; - bb->blurbs = bb->bits = bb->total_bits = 0; - bb->consumed_blurbs = bb->consumed_bits = bb->total_consumed_bits = 0; - */ - return bb; -} - -void FLAC__bitbuffer_delete(FLAC__BitBuffer *bb) -{ - FLAC__ASSERT(0 != bb); - - FLAC__bitbuffer_free(bb); - free(bb); -} - -/*********************************************************************** - * - * Public class methods - * - ***********************************************************************/ - -FLAC__bool FLAC__bitbuffer_init(FLAC__BitBuffer *bb) -{ - FLAC__ASSERT(0 != bb); - - bb->buffer = 0; - bb->capacity = 0; - bb->blurbs = bb->bits = bb->total_bits = 0; - bb->consumed_blurbs = bb->consumed_bits = bb->total_consumed_bits = 0; - - return FLAC__bitbuffer_clear(bb); -} - -FLAC__bool FLAC__bitbuffer_init_from(FLAC__BitBuffer *bb, const FLAC__byte buffer[], unsigned bytes) -{ - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(bytes > 0); - - if(!FLAC__bitbuffer_init(bb)) - return false; - - if(!bitbuffer_ensure_size_(bb, bytes << 3)) - return false; - - FLAC__ASSERT(0 != buffer); - /* @@@ WATCHOUT: code currently only works for 8-bits-per-blurb inclusive-or big-endian: */ - memcpy((FLAC__byte*)bb->buffer, buffer, sizeof(FLAC__byte)*bytes); - bb->blurbs = bytes / FLAC__BYTES_PER_BLURB; - bb->bits = (bytes % FLAC__BYTES_PER_BLURB) << 3; - bb->total_bits = bytes << 3; - return true; -} - -FLAC__bool FLAC__bitbuffer_concatenate_aligned(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src) -{ - unsigned bits_to_add = src->total_bits - src->total_consumed_bits; - - FLAC__ASSERT(0 != dest); - FLAC__ASSERT(0 != src); - - if(bits_to_add == 0) - return true; - if(dest->bits != src->consumed_bits) - return false; - if(!bitbuffer_ensure_size_(dest, bits_to_add)) - return false; - if(dest->bits == 0) { - memcpy(dest->buffer+dest->blurbs, src->buffer+src->consumed_blurbs, sizeof(FLAC__blurb)*(src->blurbs-src->consumed_blurbs + ((src->bits)? 1:0))); - } - else if(dest->bits + bits_to_add > FLAC__BITS_PER_BLURB) { - dest->buffer[dest->blurbs] <<= (FLAC__BITS_PER_BLURB - dest->bits); - dest->buffer[dest->blurbs] |= (src->buffer[src->consumed_blurbs] & ((1u << (FLAC__BITS_PER_BLURB-dest->bits)) - 1)); - memcpy(dest->buffer+dest->blurbs+1, src->buffer+src->consumed_blurbs+1, sizeof(FLAC__blurb)*(src->blurbs-src->consumed_blurbs-1 + ((src->bits)? 1:0))); - } - else { - dest->buffer[dest->blurbs] <<= bits_to_add; - dest->buffer[dest->blurbs] |= (src->buffer[src->consumed_blurbs] & ((1u << bits_to_add) - 1)); - } - dest->bits = src->bits; - dest->total_bits += bits_to_add; - dest->blurbs = dest->total_bits / FLAC__BITS_PER_BLURB; - - return true; -} - -void FLAC__bitbuffer_free(FLAC__BitBuffer *bb) -{ - FLAC__ASSERT(0 != bb); - - if(0 != bb->buffer) - free(bb->buffer); - bb->buffer = 0; - bb->capacity = 0; - bb->blurbs = bb->bits = bb->total_bits = 0; - bb->consumed_blurbs = bb->consumed_bits = bb->total_consumed_bits = 0; -} - -FLAC__bool FLAC__bitbuffer_clear(FLAC__BitBuffer *bb) -{ - if(bb->buffer == 0) { - bb->capacity = FLAC__BITBUFFER_DEFAULT_CAPACITY; - bb->buffer = (FLAC__blurb*)calloc(bb->capacity, sizeof(FLAC__blurb)); - if(bb->buffer == 0) - return false; - } - else { - memset(bb->buffer, 0, bb->blurbs + (bb->bits?1:0)); - } - bb->blurbs = bb->bits = bb->total_bits = 0; - bb->consumed_blurbs = bb->consumed_bits = bb->total_consumed_bits = 0; - return true; -} - -FLAC__bool FLAC__bitbuffer_clone(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src) -{ - FLAC__ASSERT(0 != dest); - FLAC__ASSERT(0 != dest->buffer); - FLAC__ASSERT(0 != src); - FLAC__ASSERT(0 != src->buffer); - - if(dest->capacity < src->capacity) - if(!bitbuffer_resize_(dest, src->capacity)) - return false; - memcpy(dest->buffer, src->buffer, sizeof(FLAC__blurb)*min(src->capacity, src->blurbs+1)); - dest->blurbs = src->blurbs; - dest->bits = src->bits; - dest->total_bits = src->total_bits; - dest->consumed_blurbs = src->consumed_blurbs; - dest->consumed_bits = src->consumed_bits; - dest->total_consumed_bits = src->total_consumed_bits; - dest->read_crc16 = src->read_crc16; - return true; -} - -void FLAC__bitbuffer_reset_read_crc16(FLAC__BitBuffer *bb, FLAC__uint16 seed) -{ - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT((bb->consumed_bits & 7) == 0); - - bb->read_crc16 = seed; -#if FLAC__BITS_PER_BLURB == 8 - /* no need to do anything */ -#elif FLAC__BITS_PER_BLURB == 32 - bb->crc16_align = bb->consumed_bits; -#else - FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */ -#endif -} - -FLAC__uint16 FLAC__bitbuffer_get_read_crc16(FLAC__BitBuffer *bb) -{ - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT((bb->bits & 7) == 0); - FLAC__ASSERT((bb->consumed_bits & 7) == 0); - -#if FLAC__BITS_PER_BLURB == 8 - /* no need to do anything */ -#elif FLAC__BITS_PER_BLURB == 32 - /*@@@ BUG: even though this probably can't happen with FLAC, need to fix the case where we are called here for the very first blurb and crc16_align is > 0 */ - if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) { - if(bb->consumed_bits == 8) { - const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs]; - FLAC__CRC16_UPDATE(blurb >> 24, bb->read_crc16); - } - else if(bb->consumed_bits == 16) { - const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs]; - FLAC__CRC16_UPDATE(blurb >> 24, bb->read_crc16); - FLAC__CRC16_UPDATE((blurb >> 16) & 0xff, bb->read_crc16); - } - else if(bb->consumed_bits == 24) { - const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs]; - FLAC__CRC16_UPDATE(blurb >> 24, bb->read_crc16); - FLAC__CRC16_UPDATE((blurb >> 16) & 0xff, bb->read_crc16); - FLAC__CRC16_UPDATE((blurb >> 8) & 0xff, bb->read_crc16); - } - } - else { - if(bb->consumed_bits == 8) { - const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs]; - FLAC__CRC16_UPDATE(blurb >> (bb->bits-8), bb->read_crc16); - } - else if(bb->consumed_bits == 16) { - const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs]; - FLAC__CRC16_UPDATE(blurb >> (bb->bits-8), bb->read_crc16); - FLAC__CRC16_UPDATE((blurb >> (bb->bits-16)) & 0xff, bb->read_crc16); - } - else if(bb->consumed_bits == 24) { - const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs]; - FLAC__CRC16_UPDATE(blurb >> (bb->bits-8), bb->read_crc16); - FLAC__CRC16_UPDATE((blurb >> (bb->bits-16)) & 0xff, bb->read_crc16); - FLAC__CRC16_UPDATE((blurb >> (bb->bits-24)) & 0xff, bb->read_crc16); - } - } - bb->crc16_align = bb->consumed_bits; -#else - FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */ -#endif - return bb->read_crc16; -} - -FLAC__uint16 FLAC__bitbuffer_get_write_crc16(const FLAC__BitBuffer *bb) -{ - FLAC__ASSERT((bb->bits & 7) == 0); /* assert that we're byte-aligned */ - -#if FLAC__BITS_PER_BLURB == 8 - return FLAC__crc16(bb->buffer, bb->blurbs); -#elif FLAC__BITS_PER_BLURB == 32 - /* @@@ WATCHOUT: code currently only works for big-endian: */ - return FLAC__crc16((FLAC__byte*)(bb->buffer), (bb->blurbs * FLAC__BYTES_PER_BLURB) + (bb->bits >> 3)); -#else - FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */ -#endif -} - -FLAC__byte FLAC__bitbuffer_get_write_crc8(const FLAC__BitBuffer *bb) -{ - FLAC__ASSERT(0 != bb); - FLAC__ASSERT((bb->bits & 7) == 0); /* assert that we're byte-aligned */ - FLAC__ASSERT(bb->buffer[0] == 0xff); /* MAGIC NUMBER for the first byte of the sync code */ -#if FLAC__BITS_PER_BLURB == 8 - return FLAC__crc8(bb->buffer, bb->blurbs); -#elif FLAC__BITS_PER_BLURB == 32 - /* @@@ WATCHOUT: code currently only works for big-endian: */ - return FLAC__crc8((FLAC__byte*)(bb->buffer), (bb->blurbs * FLAC__BYTES_PER_BLURB) + (bb->bits >> 3)); -#else - FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */ -#endif -} - -FLAC__bool FLAC__bitbuffer_is_byte_aligned(const FLAC__BitBuffer *bb) -{ - return ((bb->bits & 7) == 0); -} - -FLAC__bool FLAC__bitbuffer_is_consumed_byte_aligned(const FLAC__BitBuffer *bb) -{ - return ((bb->consumed_bits & 7) == 0); -} - -unsigned FLAC__bitbuffer_bits_left_for_byte_alignment(const FLAC__BitBuffer *bb) -{ - return 8 - (bb->consumed_bits & 7); -} - -unsigned FLAC__bitbuffer_get_input_bytes_unconsumed(const FLAC__BitBuffer *bb) -{ - FLAC__ASSERT((bb->consumed_bits & 7) == 0 && (bb->bits & 7) == 0); - return (bb->total_bits - bb->total_consumed_bits) >> 3; -} - -void FLAC__bitbuffer_get_buffer(FLAC__BitBuffer *bb, const FLAC__byte **buffer, unsigned *bytes) -{ - FLAC__ASSERT((bb->consumed_bits & 7) == 0 && (bb->bits & 7) == 0); -#if FLAC__BITS_PER_BLURB == 8 - *buffer = bb->buffer + bb->consumed_blurbs; - *bytes = bb->blurbs - bb->consumed_blurbs; -#elif FLAC__BITS_PER_BLURB == 32 - /* @@@ WATCHOUT: code currently only works for big-endian: */ - *buffer = (FLAC__byte*)(bb->buffer + bb->consumed_blurbs) + (bb->consumed_bits >> 3); - *bytes = (bb->total_bits - bb->total_consumed_bits) >> 3; -#else - FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */ -#endif -} - -void FLAC__bitbuffer_release_buffer(FLAC__BitBuffer *bb) -{ -#if FLAC__BITS_PER_BLURB == 8 - (void)bb; -#elif FLAC__BITS_PER_BLURB == 32 - /* @@@ WATCHOUT: code currently only works for big-endian: */ - (void)bb; -#else - FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */ -#endif -} - -FLAC__bool FLAC__bitbuffer_write_zeroes(FLAC__BitBuffer *bb, unsigned bits) -{ - unsigned n; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - if(bits == 0) - return true; - if(!bitbuffer_ensure_size_(bb, bits)) - return false; - bb->total_bits += bits; - while(bits > 0) { - n = min(FLAC__BITS_PER_BLURB - bb->bits, bits); - bb->buffer[bb->blurbs] <<= n; - bits -= n; - bb->bits += n; - if(bb->bits == FLAC__BITS_PER_BLURB) { - bb->blurbs++; - bb->bits = 0; - } - } - return true; -} - -FLaC__INLINE FLAC__bool FLAC__bitbuffer_write_raw_uint32(FLAC__BitBuffer *bb, FLAC__uint32 val, unsigned bits) -{ - unsigned n, k; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(bits <= 32); - if(bits == 0) - return true; - /* inline the size check so we don't incure a function call unnecessarily */ - if(FLAC__BLURBS_TO_BITS(bb->capacity) < bb->total_bits + bits) { - if(!bitbuffer_ensure_size_(bb, bits)) - return false; - } - - /* zero-out unused bits; WATCHOUT: other code relies on this, so this needs to stay */ - if(bits < 32) /* @@@ gcc seems to require this because the following line causes incorrect results when bits==32; investigate */ - val &= (~(0xffffffff << bits)); /* zero-out unused bits */ - - bb->total_bits += bits; - while(bits > 0) { - n = FLAC__BITS_PER_BLURB - bb->bits; - if(n == FLAC__BITS_PER_BLURB) { /* i.e. bb->bits == 0 */ - if(bits < FLAC__BITS_PER_BLURB) { - bb->buffer[bb->blurbs] = (FLAC__blurb)val; - bb->bits = bits; - break; - } - else if(bits == FLAC__BITS_PER_BLURB) { - bb->buffer[bb->blurbs++] = (FLAC__blurb)val; - break; - } - else { - k = bits - FLAC__BITS_PER_BLURB; - bb->buffer[bb->blurbs++] = (FLAC__blurb)(val >> k); - /* we know k < 32 so no need to protect against the gcc bug mentioned above */ - val &= (~(0xffffffff << k)); - bits -= FLAC__BITS_PER_BLURB; - } - } - else if(bits <= n) { - bb->buffer[bb->blurbs] <<= bits; - bb->buffer[bb->blurbs] |= val; - if(bits == n) { - bb->blurbs++; - bb->bits = 0; - } - else - bb->bits += bits; - break; - } - else { - k = bits - n; - bb->buffer[bb->blurbs] <<= n; - bb->buffer[bb->blurbs] |= (val >> k); - /* we know n > 0 so k < 32 so no need to protect against the gcc bug mentioned above */ - val &= (~(0xffffffff << k)); - bits -= n; - bb->blurbs++; - bb->bits = 0; - } - } - - return true; -} - -FLAC__bool FLAC__bitbuffer_write_raw_int32(FLAC__BitBuffer *bb, FLAC__int32 val, unsigned bits) -{ - return FLAC__bitbuffer_write_raw_uint32(bb, (FLAC__uint32)val, bits); -} - -FLAC__bool FLAC__bitbuffer_write_raw_uint64(FLAC__BitBuffer *bb, FLAC__uint64 val, unsigned bits) -{ - static const FLAC__uint64 mask[] = { - 0, - FLAC__U64L(0x0000000000000001), FLAC__U64L(0x0000000000000003), FLAC__U64L(0x0000000000000007), FLAC__U64L(0x000000000000000F), - FLAC__U64L(0x000000000000001F), FLAC__U64L(0x000000000000003F), FLAC__U64L(0x000000000000007F), FLAC__U64L(0x00000000000000FF), - FLAC__U64L(0x00000000000001FF), FLAC__U64L(0x00000000000003FF), FLAC__U64L(0x00000000000007FF), FLAC__U64L(0x0000000000000FFF), - FLAC__U64L(0x0000000000001FFF), FLAC__U64L(0x0000000000003FFF), FLAC__U64L(0x0000000000007FFF), FLAC__U64L(0x000000000000FFFF), - FLAC__U64L(0x000000000001FFFF), FLAC__U64L(0x000000000003FFFF), FLAC__U64L(0x000000000007FFFF), FLAC__U64L(0x00000000000FFFFF), - FLAC__U64L(0x00000000001FFFFF), FLAC__U64L(0x00000000003FFFFF), FLAC__U64L(0x00000000007FFFFF), FLAC__U64L(0x0000000000FFFFFF), - FLAC__U64L(0x0000000001FFFFFF), FLAC__U64L(0x0000000003FFFFFF), FLAC__U64L(0x0000000007FFFFFF), FLAC__U64L(0x000000000FFFFFFF), - FLAC__U64L(0x000000001FFFFFFF), FLAC__U64L(0x000000003FFFFFFF), FLAC__U64L(0x000000007FFFFFFF), FLAC__U64L(0x00000000FFFFFFFF), - FLAC__U64L(0x00000001FFFFFFFF), FLAC__U64L(0x00000003FFFFFFFF), FLAC__U64L(0x00000007FFFFFFFF), FLAC__U64L(0x0000000FFFFFFFFF), - FLAC__U64L(0x0000001FFFFFFFFF), FLAC__U64L(0x0000003FFFFFFFFF), FLAC__U64L(0x0000007FFFFFFFFF), FLAC__U64L(0x000000FFFFFFFFFF), - FLAC__U64L(0x000001FFFFFFFFFF), FLAC__U64L(0x000003FFFFFFFFFF), FLAC__U64L(0x000007FFFFFFFFFF), FLAC__U64L(0x00000FFFFFFFFFFF), - FLAC__U64L(0x00001FFFFFFFFFFF), FLAC__U64L(0x00003FFFFFFFFFFF), FLAC__U64L(0x00007FFFFFFFFFFF), FLAC__U64L(0x0000FFFFFFFFFFFF), - FLAC__U64L(0x0001FFFFFFFFFFFF), FLAC__U64L(0x0003FFFFFFFFFFFF), FLAC__U64L(0x0007FFFFFFFFFFFF), FLAC__U64L(0x000FFFFFFFFFFFFF), - FLAC__U64L(0x001FFFFFFFFFFFFF), FLAC__U64L(0x003FFFFFFFFFFFFF), FLAC__U64L(0x007FFFFFFFFFFFFF), FLAC__U64L(0x00FFFFFFFFFFFFFF), - FLAC__U64L(0x01FFFFFFFFFFFFFF), FLAC__U64L(0x03FFFFFFFFFFFFFF), FLAC__U64L(0x07FFFFFFFFFFFFFF), FLAC__U64L(0x0FFFFFFFFFFFFFFF), - FLAC__U64L(0x1FFFFFFFFFFFFFFF), FLAC__U64L(0x3FFFFFFFFFFFFFFF), FLAC__U64L(0x7FFFFFFFFFFFFFFF), FLAC__U64L(0xFFFFFFFFFFFFFFFF) - }; - unsigned n, k; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(bits <= 64); - if(bits == 0) - return true; - if(!bitbuffer_ensure_size_(bb, bits)) - return false; - val &= mask[bits]; - bb->total_bits += bits; - while(bits > 0) { - if(bb->bits == 0) { - if(bits < FLAC__BITS_PER_BLURB) { - bb->buffer[bb->blurbs] = (FLAC__blurb)val; - bb->bits = bits; - break; - } - else if(bits == FLAC__BITS_PER_BLURB) { - bb->buffer[bb->blurbs++] = (FLAC__blurb)val; - break; - } - else { - k = bits - FLAC__BITS_PER_BLURB; - bb->buffer[bb->blurbs++] = (FLAC__blurb)(val >> k); - /* we know k < 64 so no need to protect against the gcc bug mentioned above */ - val &= (~(FLAC__U64L(0xffffffffffffffff) << k)); - bits -= FLAC__BITS_PER_BLURB; - } - } - else { - n = min(FLAC__BITS_PER_BLURB - bb->bits, bits); - k = bits - n; - bb->buffer[bb->blurbs] <<= n; - bb->buffer[bb->blurbs] |= (val >> k); - /* we know n > 0 so k < 64 so no need to protect against the gcc bug mentioned above */ - val &= (~(FLAC__U64L(0xffffffffffffffff) << k)); - bits -= n; - bb->bits += n; - if(bb->bits == FLAC__BITS_PER_BLURB) { - bb->blurbs++; - bb->bits = 0; - } - } - } - - return true; -} - -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_write_raw_int64(FLAC__BitBuffer *bb, FLAC__int64 val, unsigned bits) -{ - return FLAC__bitbuffer_write_raw_uint64(bb, (FLAC__uint64)val, bits); -} -#endif - -FLaC__INLINE FLAC__bool FLAC__bitbuffer_write_raw_uint32_little_endian(FLAC__BitBuffer *bb, FLAC__uint32 val) -{ - /* this doesn't need to be that fast as currently it is only used for vorbis comments */ - - /* NOTE: we rely on the fact that FLAC__bitbuffer_write_raw_uint32() masks out the unused bits */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, val, 8)) - return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, val>>8, 8)) - return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, val>>16, 8)) - return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, val>>24, 8)) - return false; - - return true; -} - -FLaC__INLINE FLAC__bool FLAC__bitbuffer_write_byte_block(FLAC__BitBuffer *bb, const FLAC__byte vals[], unsigned nvals) -{ - unsigned i; - - /* this could be faster but currently we don't need it to be */ - for(i = 0; i < nvals; i++) { - if(!FLAC__bitbuffer_write_raw_uint32(bb, (FLAC__uint32)(vals[i]), 8)) - return false; - } - - return true; -} - -FLAC__bool FLAC__bitbuffer_write_unary_unsigned(FLAC__BitBuffer *bb, unsigned val) -{ - if(val < 32) - return FLAC__bitbuffer_write_raw_uint32(bb, 1, ++val); - else if(val < 64) - return FLAC__bitbuffer_write_raw_uint64(bb, 1, ++val); - else { - if(!FLAC__bitbuffer_write_zeroes(bb, val)) - return false; - return FLAC__bitbuffer_write_raw_uint32(bb, 1, 1); - } -} - -unsigned FLAC__bitbuffer_rice_bits(int val, unsigned parameter) -{ - unsigned msbs, uval; - - /* fold signed to unsigned */ - if(val < 0) - /* equivalent to - * (unsigned)(((--val) << 1) - 1); - * but without the overflow problem at MININT - */ - uval = (unsigned)(((-(++val)) << 1) + 1); - else - uval = (unsigned)(val << 1); - - msbs = uval >> parameter; - - return 1 + parameter + msbs; -} - -#if 0 /* UNUSED */ -unsigned FLAC__bitbuffer_golomb_bits_signed(int val, unsigned parameter) -{ - unsigned bits, msbs, uval; - unsigned k; - - FLAC__ASSERT(parameter > 0); - - /* fold signed to unsigned */ - if(val < 0) - /* equivalent to - * (unsigned)(((--val) << 1) - 1); - * but without the overflow problem at MININT - */ - uval = (unsigned)(((-(++val)) << 1) + 1); - else - uval = (unsigned)(val << 1); - - k = FLAC__bitmath_ilog2(parameter); - if(parameter == 1u<<k) { - FLAC__ASSERT(k <= 30); - - msbs = uval >> k; - bits = 1 + k + msbs; - } - else { - unsigned q, r, d; - - d = (1 << (k+1)) - parameter; - q = uval / parameter; - r = uval - (q * parameter); - - bits = 1 + q + k; - if(r >= d) - bits++; - } - return bits; -} - -unsigned FLAC__bitbuffer_golomb_bits_unsigned(unsigned uval, unsigned parameter) -{ - unsigned bits, msbs; - unsigned k; - - FLAC__ASSERT(parameter > 0); - - k = FLAC__bitmath_ilog2(parameter); - if(parameter == 1u<<k) { - FLAC__ASSERT(k <= 30); - - msbs = uval >> k; - bits = 1 + k + msbs; - } - else { - unsigned q, r, d; - - d = (1 << (k+1)) - parameter; - q = uval / parameter; - r = uval - (q * parameter); - - bits = 1 + q + k; - if(r >= d) - bits++; - } - return bits; -} -#endif /* UNUSED */ - -#ifdef FLAC__SYMMETRIC_RICE -FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter) -{ - unsigned total_bits, interesting_bits, msbs; - FLAC__uint32 pattern; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(parameter <= 31); - - /* init pattern with the unary end bit and the sign bit */ - if(val < 0) { - pattern = 3; - val = -val; - } - else - pattern = 2; - - msbs = val >> parameter; - interesting_bits = 2 + parameter; - total_bits = interesting_bits + msbs; - pattern <<= parameter; - pattern |= (val & ((1<<parameter)-1)); /* the binary LSBs */ - - if(total_bits <= 32) { - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits)) - return false; - } - else { - /* write the unary MSBs */ - if(!FLAC__bitbuffer_write_zeroes(bb, msbs)) - return false; - /* write the unary end bit, the sign bit, and binary LSBs */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, interesting_bits)) - return false; - } - return true; -} - -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow) -{ - unsigned total_bits, interesting_bits, msbs; - FLAC__uint32 pattern; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(parameter <= 31); - - *overflow = false; - - /* init pattern with the unary end bit and the sign bit */ - if(val < 0) { - pattern = 3; - val = -val; - } - else - pattern = 2; - - msbs = val >> parameter; - interesting_bits = 2 + parameter; - total_bits = interesting_bits + msbs; - pattern <<= parameter; - pattern |= (val & ((1<<parameter)-1)); /* the binary LSBs */ - - if(total_bits <= 32) { - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits)) - return false; - } - else if(total_bits > max_bits) { - *overflow = true; - return true; - } - else { - /* write the unary MSBs */ - if(!FLAC__bitbuffer_write_zeroes(bb, msbs)) - return false; - /* write the unary end bit, the sign bit, and binary LSBs */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, interesting_bits)) - return false; - } - return true; -} -#endif /* UNUSED */ - -FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed_escape(FLAC__BitBuffer *bb, int val, unsigned parameter) -{ - unsigned total_bits, val_bits; - FLAC__uint32 pattern; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(parameter <= 31); - - val_bits = FLAC__bitmath_silog2(val); - total_bits = 2 + parameter + 5 + val_bits; - - if(total_bits <= 32) { - pattern = 3; - pattern <<= (parameter + 5); - pattern |= val_bits; - pattern <<= val_bits; - pattern |= (val & ((1 << val_bits) - 1)); - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits)) - return false; - } - else { - /* write the '-0' escape code first */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, 3u << parameter, 2+parameter)) - return false; - /* write the length */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, val_bits, 5)) - return false; - /* write the value */ - if(!FLAC__bitbuffer_write_raw_int32(bb, val, val_bits)) - return false; - } - return true; -} -#endif /* ifdef FLAC__SYMMETRIC_RICE */ - -FLAC__bool FLAC__bitbuffer_write_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter) -{ - unsigned total_bits, interesting_bits, msbs, uval; - FLAC__uint32 pattern; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(parameter <= 30); - - /* fold signed to unsigned */ - if(val < 0) - /* equivalent to - * (unsigned)(((--val) << 1) - 1); - * but without the overflow problem at MININT - */ - uval = (unsigned)(((-(++val)) << 1) + 1); - else - uval = (unsigned)(val << 1); - - msbs = uval >> parameter; - interesting_bits = 1 + parameter; - total_bits = interesting_bits + msbs; - pattern = 1 << parameter; /* the unary end bit */ - pattern |= (uval & ((1<<parameter)-1)); /* the binary LSBs */ - - if(total_bits <= 32) { - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits)) - return false; - } - else { - /* write the unary MSBs */ - if(!FLAC__bitbuffer_write_zeroes(bb, msbs)) - return false; - /* write the unary end bit and binary LSBs */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, interesting_bits)) - return false; - } - return true; -} - -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_write_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow) -{ - unsigned total_bits, interesting_bits, msbs, uval; - FLAC__uint32 pattern; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(parameter <= 30); - - *overflow = false; - - /* fold signed to unsigned */ - if(val < 0) - /* equivalent to - * (unsigned)(((--val) << 1) - 1); - * but without the overflow problem at MININT - */ - uval = (unsigned)(((-(++val)) << 1) + 1); - else - uval = (unsigned)(val << 1); - - msbs = uval >> parameter; - interesting_bits = 1 + parameter; - total_bits = interesting_bits + msbs; - pattern = 1 << parameter; /* the unary end bit */ - pattern |= (uval & ((1<<parameter)-1)); /* the binary LSBs */ - - if(total_bits <= 32) { - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits)) - return false; - } - else if(total_bits > max_bits) { - *overflow = true; - return true; - } - else { - /* write the unary MSBs */ - if(!FLAC__bitbuffer_write_zeroes(bb, msbs)) - return false; - /* write the unary end bit and binary LSBs */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, interesting_bits)) - return false; - } - return true; -} -#endif /* UNUSED */ - -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_write_golomb_signed(FLAC__BitBuffer *bb, int val, unsigned parameter) -{ - unsigned total_bits, msbs, uval; - unsigned k; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(parameter > 0); - - /* fold signed to unsigned */ - if(val < 0) - /* equivalent to - * (unsigned)(((--val) << 1) - 1); - * but without the overflow problem at MININT - */ - uval = (unsigned)(((-(++val)) << 1) + 1); - else - uval = (unsigned)(val << 1); - - k = FLAC__bitmath_ilog2(parameter); - if(parameter == 1u<<k) { - unsigned pattern; - - FLAC__ASSERT(k <= 30); - - msbs = uval >> k; - total_bits = 1 + k + msbs; - pattern = 1 << k; /* the unary end bit */ - pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */ - - if(total_bits <= 32) { - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits)) - return false; - } - else { - /* write the unary MSBs */ - if(!FLAC__bitbuffer_write_zeroes(bb, msbs)) - return false; - /* write the unary end bit and binary LSBs */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, k+1)) - return false; - } - } - else { - unsigned q, r, d; - - d = (1 << (k+1)) - parameter; - q = uval / parameter; - r = uval - (q * parameter); - /* write the unary MSBs */ - if(!FLAC__bitbuffer_write_zeroes(bb, q)) - return false; - /* write the unary end bit */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, 1, 1)) - return false; - /* write the binary LSBs */ - if(r >= d) { - if(!FLAC__bitbuffer_write_raw_uint32(bb, r+d, k+1)) - return false; - } - else { - if(!FLAC__bitbuffer_write_raw_uint32(bb, r, k)) - return false; - } - } - return true; -} - -FLAC__bool FLAC__bitbuffer_write_golomb_unsigned(FLAC__BitBuffer *bb, unsigned uval, unsigned parameter) -{ - unsigned total_bits, msbs; - unsigned k; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(parameter > 0); - - k = FLAC__bitmath_ilog2(parameter); - if(parameter == 1u<<k) { - unsigned pattern; - - FLAC__ASSERT(k <= 30); - - msbs = uval >> k; - total_bits = 1 + k + msbs; - pattern = 1 << k; /* the unary end bit */ - pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */ - - if(total_bits <= 32) { - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits)) - return false; - } - else { - /* write the unary MSBs */ - if(!FLAC__bitbuffer_write_zeroes(bb, msbs)) - return false; - /* write the unary end bit and binary LSBs */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, k+1)) - return false; - } - } - else { - unsigned q, r, d; - - d = (1 << (k+1)) - parameter; - q = uval / parameter; - r = uval - (q * parameter); - /* write the unary MSBs */ - if(!FLAC__bitbuffer_write_zeroes(bb, q)) - return false; - /* write the unary end bit */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, 1, 1)) - return false; - /* write the binary LSBs */ - if(r >= d) { - if(!FLAC__bitbuffer_write_raw_uint32(bb, r+d, k+1)) - return false; - } - else { - if(!FLAC__bitbuffer_write_raw_uint32(bb, r, k)) - return false; - } - } - return true; -} -#endif /* UNUSED */ - -FLAC__bool FLAC__bitbuffer_write_utf8_uint32(FLAC__BitBuffer *bb, FLAC__uint32 val) -{ - FLAC__bool ok = 1; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(!(val & 0x80000000)); /* this version only handles 31 bits */ - - if(val < 0x80) { - return FLAC__bitbuffer_write_raw_uint32(bb, val, 8); - } - else if(val < 0x800) { - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xC0 | (val>>6), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8); - } - else if(val < 0x10000) { - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xE0 | (val>>12), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8); - } - else if(val < 0x200000) { - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF0 | (val>>18), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>12)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8); - } - else if(val < 0x4000000) { - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF8 | (val>>24), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>18)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>12)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8); - } - else { - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xFC | (val>>30), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>24)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>18)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>12)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8); - } - - return ok; -} - -FLAC__bool FLAC__bitbuffer_write_utf8_uint64(FLAC__BitBuffer *bb, FLAC__uint64 val) -{ - FLAC__bool ok = 1; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(!(val & FLAC__U64L(0xFFFFFFF000000000))); /* this version only handles 36 bits */ - - if(val < 0x80) { - return FLAC__bitbuffer_write_raw_uint32(bb, (FLAC__uint32)val, 8); - } - else if(val < 0x800) { - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xC0 | (FLAC__uint32)(val>>6), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - else if(val < 0x10000) { - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xE0 | (FLAC__uint32)(val>>12), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - else if(val < 0x200000) { - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF0 | (FLAC__uint32)(val>>18), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - else if(val < 0x4000000) { - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF8 | (FLAC__uint32)(val>>24), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - else if(val < 0x80000000) { - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xFC | (FLAC__uint32)(val>>30), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - else { - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xFE, 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); - ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8); - } - - return ok; -} - -FLAC__bool FLAC__bitbuffer_zero_pad_to_byte_boundary(FLAC__BitBuffer *bb) -{ - /* 0-pad to byte boundary */ - if(bb->bits & 7u) - return FLAC__bitbuffer_write_zeroes(bb, 8 - (bb->bits & 7u)); - else - return true; -} - -FLAC__bool FLAC__bitbuffer_peek_bit(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - /* to avoid a drastic speed penalty we don't: - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(bb->bits == 0); - */ - - while(1) { - if(bb->total_consumed_bits < bb->total_bits) { - *val = (bb->buffer[bb->consumed_blurbs] & BLURB_BIT_TO_MASK(bb->consumed_bits))? 1 : 0; - return true; - } - else { - if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) - return false; - } - } -} - -FLAC__bool FLAC__bitbuffer_read_bit(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - /* to avoid a drastic speed penalty we don't: - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(bb->bits == 0); - */ - - while(1) { - if(bb->total_consumed_bits < bb->total_bits) { - *val = (bb->buffer[bb->consumed_blurbs] & BLURB_BIT_TO_MASK(bb->consumed_bits))? 1 : 0; - bb->consumed_bits++; - if(bb->consumed_bits == FLAC__BITS_PER_BLURB) { - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - bb->consumed_bits = 0; - } - bb->total_consumed_bits++; - return true; - } - else { - if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) - return false; - } - } -} - -FLAC__bool FLAC__bitbuffer_read_bit_to_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - /* to avoid a drastic speed penalty we don't: - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(bb->bits == 0); - */ - - while(1) { - if(bb->total_consumed_bits < bb->total_bits) { - *val <<= 1; - *val |= (bb->buffer[bb->consumed_blurbs] & BLURB_BIT_TO_MASK(bb->consumed_bits))? 1 : 0; - bb->consumed_bits++; - if(bb->consumed_bits == FLAC__BITS_PER_BLURB) { - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - bb->consumed_bits = 0; - } - bb->total_consumed_bits++; - return true; - } - else { - if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) - return false; - } - } -} - -FLAC__bool FLAC__bitbuffer_read_bit_to_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - /* to avoid a drastic speed penalty we don't: - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(bb->bits == 0); - */ - - while(1) { - if(bb->total_consumed_bits < bb->total_bits) { - *val <<= 1; - *val |= (bb->buffer[bb->consumed_blurbs] & BLURB_BIT_TO_MASK(bb->consumed_bits))? 1 : 0; - bb->consumed_bits++; - if(bb->consumed_bits == FLAC__BITS_PER_BLURB) { - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - bb->consumed_bits = 0; - } - bb->total_consumed_bits++; - return true; - } - else { - if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) - return false; - } - } -} - -FLaC__INLINE FLAC__bool FLAC__bitbuffer_read_raw_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -#ifdef FLAC__NO_MANUAL_INLINING -{ - unsigned i; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(bits <= 32); - - *val = 0; - for(i = 0; i < bits; i++) { - if(!FLAC__bitbuffer_read_bit_to_uint32(bb, val, read_callback, client_data)) - return false; - } - return true; -} -#else -{ - unsigned i, bits_ = bits; - FLAC__uint32 v = 0; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(bits <= 32); - FLAC__ASSERT((bb->capacity*FLAC__BITS_PER_BLURB) * 2 >= bits); - - if(bits == 0) { - *val = 0; - return true; - } - - while(bb->total_consumed_bits + bits > bb->total_bits) { - if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) - return false; - } -#if FLAC__BITS_PER_BLURB > 8 - if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) { /*@@@ comment on why this is here*/ -#endif - if(bb->consumed_bits) { - i = FLAC__BITS_PER_BLURB - bb->consumed_bits; - if(i <= bits_) { - v = bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits); - bits_ -= i; - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - bb->consumed_bits = 0; - /* we hold off updating bb->total_consumed_bits until the end */ - } - else { - *val = (bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits)) >> (i-bits_); - bb->consumed_bits += bits_; - bb->total_consumed_bits += bits_; - return true; - } - } -#if FLAC__BITS_PER_BLURB == 32 - /* note that we know bits_ cannot be > 32 because of previous assertions */ - if(bits_ == FLAC__BITS_PER_BLURB) { - v = bb->buffer[bb->consumed_blurbs]; - CRC16_UPDATE_BLURB(bb, v, bb->read_crc16); - bb->consumed_blurbs++; - /* bb->consumed_bits is already 0 */ - bb->total_consumed_bits += bits; - *val = v; - return true; - } -#else - while(bits_ >= FLAC__BITS_PER_BLURB) { - v <<= FLAC__BITS_PER_BLURB; - v |= bb->buffer[bb->consumed_blurbs]; - bits_ -= FLAC__BITS_PER_BLURB; - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - /* bb->consumed_bits is already 0 */ - /* we hold off updating bb->total_consumed_bits until the end */ - } -#endif - if(bits_ > 0) { - v <<= bits_; - v |= (bb->buffer[bb->consumed_blurbs] >> (FLAC__BITS_PER_BLURB-bits_)); - bb->consumed_bits = bits_; - /* we hold off updating bb->total_consumed_bits until the end */ - } - bb->total_consumed_bits += bits; - *val = v; -#if FLAC__BITS_PER_BLURB > 8 - } - else { - *val = 0; - for(i = 0; i < bits; i++) { - if(!FLAC__bitbuffer_read_bit_to_uint32(bb, val, read_callback, client_data)) - return false; - } - } -#endif - return true; -} -#endif - -FLAC__bool FLAC__bitbuffer_read_raw_int32(FLAC__BitBuffer *bb, FLAC__int32 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -#ifdef FLAC__NO_MANUAL_INLINING -{ - unsigned i; - FLAC__uint32 v; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(bits <= 32); - - if(bits == 0) { - *val = 0; - return true; - } - - v = 0; - for(i = 0; i < bits; i++) { - if(!FLAC__bitbuffer_read_bit_to_uint32(bb, &v, read_callback, client_data)) - return false; - } - - /* fix the sign */ - i = 32 - bits; - if(i) { - v <<= i; - *val = (FLAC__int32)v; - *val >>= i; - } - else - *val = (FLAC__int32)v; - - return true; -} -#else -{ - unsigned i, bits_ = bits; - FLAC__uint32 v = 0; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(bits <= 32); - FLAC__ASSERT((bb->capacity*FLAC__BITS_PER_BLURB) * 2 >= bits); - - if(bits == 0) { - *val = 0; - return true; - } - - while(bb->total_consumed_bits + bits > bb->total_bits) { - if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) - return false; - } -#if FLAC__BITS_PER_BLURB > 8 - if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) { /*@@@ comment on why this is here*/ -#endif - if(bb->consumed_bits) { - i = FLAC__BITS_PER_BLURB - bb->consumed_bits; - if(i <= bits_) { - v = bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits); - bits_ -= i; - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - bb->consumed_bits = 0; - /* we hold off updating bb->total_consumed_bits until the end */ - } - else { - /* bits_ must be < FLAC__BITS_PER_BLURB-1 if we get to here */ - v = (bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits)); - v <<= (32-i); - *val = (FLAC__int32)v; - *val >>= (32-bits_); - bb->consumed_bits += bits_; - bb->total_consumed_bits += bits_; - return true; - } - } -#if FLAC__BITS_PER_BLURB == 32 - /* note that we know bits_ cannot be > 32 because of previous assertions */ - if(bits_ == FLAC__BITS_PER_BLURB) { - v = bb->buffer[bb->consumed_blurbs]; - bits_ = 0; - CRC16_UPDATE_BLURB(bb, v, bb->read_crc16); - bb->consumed_blurbs++; - /* bb->consumed_bits is already 0 */ - /* we hold off updating bb->total_consumed_bits until the end */ - } -#else - while(bits_ >= FLAC__BITS_PER_BLURB) { - v <<= FLAC__BITS_PER_BLURB; - v |= bb->buffer[bb->consumed_blurbs]; - bits_ -= FLAC__BITS_PER_BLURB; - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - /* bb->consumed_bits is already 0 */ - /* we hold off updating bb->total_consumed_bits until the end */ - } -#endif - if(bits_ > 0) { - v <<= bits_; - v |= (bb->buffer[bb->consumed_blurbs] >> (FLAC__BITS_PER_BLURB-bits_)); - bb->consumed_bits = bits_; - /* we hold off updating bb->total_consumed_bits until the end */ - } - bb->total_consumed_bits += bits; -#if FLAC__BITS_PER_BLURB > 8 - } - else { - for(i = 0; i < bits; i++) { - if(!FLAC__bitbuffer_read_bit_to_uint32(bb, &v, read_callback, client_data)) - return false; - } - } -#endif - - /* fix the sign */ - i = 32 - bits; - if(i) { - v <<= i; - *val = (FLAC__int32)v; - *val >>= i; - } - else - *val = (FLAC__int32)v; - - return true; -} -#endif - -FLAC__bool FLAC__bitbuffer_read_raw_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -#ifdef FLAC__NO_MANUAL_INLINING -{ - unsigned i; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(bits <= 64); - - *val = 0; - for(i = 0; i < bits; i++) { - if(!FLAC__bitbuffer_read_bit_to_uint64(bb, val, read_callback, client_data)) - return false; - } - return true; -} -#else -{ - unsigned i, bits_ = bits; - FLAC__uint64 v = 0; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(bits <= 64); - FLAC__ASSERT((bb->capacity*FLAC__BITS_PER_BLURB) * 2 >= bits); - - if(bits == 0) { - *val = 0; - return true; - } - - while(bb->total_consumed_bits + bits > bb->total_bits) { - if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) - return false; - } -#if FLAC__BITS_PER_BLURB > 8 - if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) { /*@@@ comment on why this is here*/ -#endif - if(bb->consumed_bits) { - i = FLAC__BITS_PER_BLURB - bb->consumed_bits; - if(i <= bits_) { - v = bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits); - bits_ -= i; - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - bb->consumed_bits = 0; - /* we hold off updating bb->total_consumed_bits until the end */ - } - else { - *val = (bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits)) >> (i-bits_); - bb->consumed_bits += bits_; - bb->total_consumed_bits += bits_; - return true; - } - } - while(bits_ >= FLAC__BITS_PER_BLURB) { - v <<= FLAC__BITS_PER_BLURB; - v |= bb->buffer[bb->consumed_blurbs]; - bits_ -= FLAC__BITS_PER_BLURB; - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - /* bb->consumed_bits is already 0 */ - /* we hold off updating bb->total_consumed_bits until the end */ - } - if(bits_ > 0) { - v <<= bits_; - v |= (bb->buffer[bb->consumed_blurbs] >> (FLAC__BITS_PER_BLURB-bits_)); - bb->consumed_bits = bits_; - /* we hold off updating bb->total_consumed_bits until the end */ - } - bb->total_consumed_bits += bits; - *val = v; -#if FLAC__BITS_PER_BLURB > 8 - } - else { - *val = 0; - for(i = 0; i < bits; i++) { - if(!FLAC__bitbuffer_read_bit_to_uint64(bb, val, read_callback, client_data)) - return false; - } - } -#endif - return true; -} -#endif - -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_read_raw_int64(FLAC__BitBuffer *bb, FLAC__int64 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -#ifdef FLAC__NO_MANUAL_INLINING -{ - unsigned i; - FLAC__uint64 v; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(bits <= 64); - - v = 0; - for(i = 0; i < bits; i++) { - if(!FLAC__bitbuffer_read_bit_to_uint64(bb, &v, read_callback, client_data)) - return false; - } - /* fix the sign */ - i = 64 - bits; - if(i) { - v <<= i; - *val = (FLAC__int64)v; - *val >>= i; - } - else - *val = (FLAC__int64)v; - - return true; -} -#else -{ - unsigned i, bits_ = bits; - FLAC__uint64 v = 0; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - FLAC__ASSERT(bits <= 64); - FLAC__ASSERT((bb->capacity*FLAC__BITS_PER_BLURB) * 2 >= bits); - - if(bits == 0) { - *val = 0; - return true; - } - - while(bb->total_consumed_bits + bits > bb->total_bits) { - if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) - return false; - } -#if FLAC__BITS_PER_BLURB > 8 - if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) { /*@@@ comment on why this is here*/ -#endif - if(bb->consumed_bits) { - i = FLAC__BITS_PER_BLURB - bb->consumed_bits; - if(i <= bits_) { - v = bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits); - bits_ -= i; - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - bb->consumed_bits = 0; - /* we hold off updating bb->total_consumed_bits until the end */ - } - else { - /* bits_ must be < FLAC__BITS_PER_BLURB-1 if we get to here */ - v = (bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits)); - v <<= (64-i); - *val = (FLAC__int64)v; - *val >>= (64-bits_); - bb->consumed_bits += bits_; - bb->total_consumed_bits += bits_; - return true; - } - } - while(bits_ >= FLAC__BITS_PER_BLURB) { - v <<= FLAC__BITS_PER_BLURB; - v |= bb->buffer[bb->consumed_blurbs]; - bits_ -= FLAC__BITS_PER_BLURB; - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - /* bb->consumed_bits is already 0 */ - /* we hold off updating bb->total_consumed_bits until the end */ - } - if(bits_ > 0) { - v <<= bits_; - v |= (bb->buffer[bb->consumed_blurbs] >> (FLAC__BITS_PER_BLURB-bits_)); - bb->consumed_bits = bits_; - /* we hold off updating bb->total_consumed_bits until the end */ - } - bb->total_consumed_bits += bits; -#if FLAC__BITS_PER_BLURB > 8 - } - else { - for(i = 0; i < bits; i++) { - if(!FLAC__bitbuffer_read_bit_to_uint64(bb, &v, read_callback, client_data)) - return false; - } - } -#endif - - /* fix the sign */ - i = 64 - bits; - if(i) { - v <<= i; - *val = (FLAC__int64)v; - *val >>= i; - } - else - *val = (FLAC__int64)v; - - return true; -} -#endif -#endif - -FLaC__INLINE FLAC__bool FLAC__bitbuffer_read_raw_uint32_little_endian(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - FLAC__uint32 x8, x32 = 0; - - /* this doesn't need to be that fast as currently it is only used for vorbis comments */ - - if(!FLAC__bitbuffer_read_raw_uint32(bb, &x32, 8, read_callback, client_data)) - return false; - - if(!FLAC__bitbuffer_read_raw_uint32(bb, &x8, 8, read_callback, client_data)) - return false; - x32 |= (x8 << 8); - - if(!FLAC__bitbuffer_read_raw_uint32(bb, &x8, 8, read_callback, client_data)) - return false; - x32 |= (x8 << 16); - - if(!FLAC__bitbuffer_read_raw_uint32(bb, &x8, 8, read_callback, client_data)) - return false; - x32 |= (x8 << 24); - - *val = x32; - return true; -} - -FLAC__bool FLAC__bitbuffer_skip_bits_no_crc(FLAC__BitBuffer *bb, unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - /* - * @@@ a slightly faster implementation is possible but - * probably not that useful since this is only called a - * couple of times in the metadata readers. - */ - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - if(bits > 0) { - const unsigned n = bb->consumed_bits & 7; - unsigned m; - FLAC__uint32 x; - - if(n != 0) { - m = min(8-n, bits); - if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, m, read_callback, client_data)) - return false; - bits -= m; - } - m = bits / 8; - if(m > 0) { - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(bb, 0, m, read_callback, client_data)) - return false; - bits %= 8; - } - if(bits > 0) { - if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, bits, read_callback, client_data)) - return false; - } - } - - return true; -} - -FLAC__bool FLAC__bitbuffer_read_byte_block_aligned_no_crc(FLAC__BitBuffer *bb, FLAC__byte *val, unsigned nvals, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(bb)); - FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(bb)); -#if FLAC__BITS_PER_BLURB == 8 - while(nvals > 0) { - unsigned chunk = min(nvals, bb->blurbs - bb->consumed_blurbs); - if(chunk == 0) { - if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) - return false; - } - else { - if(0 != val) { - memcpy(val, bb->buffer + bb->consumed_blurbs, FLAC__BYTES_PER_BLURB * chunk); - val += FLAC__BYTES_PER_BLURB * chunk; - } - nvals -= chunk; - bb->consumed_blurbs += chunk; - bb->total_consumed_bits = (bb->consumed_blurbs << FLAC__BITS_PER_BLURB_LOG2); - } - } -#else - @@@ need to write this still - FLAC__ASSERT(0); -#endif - - return true; -} - -FLaC__INLINE FLAC__bool FLAC__bitbuffer_read_unary_unsigned(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -#ifdef FLAC__NO_MANUAL_INLINING -{ - unsigned bit, val_ = 0; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - while(1) { - if(!FLAC__bitbuffer_read_bit(bb, &bit, read_callback, client_data)) - return false; - if(bit) - break; - else - val_++; - } - *val = val_; - return true; -} -#else -{ - unsigned i, val_ = 0; - unsigned total_blurbs_ = (bb->total_bits + (FLAC__BITS_PER_BLURB-1)) / FLAC__BITS_PER_BLURB; - FLAC__blurb b; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - -#if FLAC__BITS_PER_BLURB > 8 - if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) { /*@@@ comment on why this is here*/ -#endif - if(bb->consumed_bits) { - b = bb->buffer[bb->consumed_blurbs] << bb->consumed_bits; - if(b) { - for(i = 0; !(b & FLAC__BLURB_TOP_BIT_ONE); i++) - b <<= 1; - *val = i; - i++; - bb->consumed_bits += i; - bb->total_consumed_bits += i; - if(bb->consumed_bits == FLAC__BITS_PER_BLURB) { - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - bb->consumed_bits = 0; - } - return true; - } - else { - val_ = FLAC__BITS_PER_BLURB - bb->consumed_bits; - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - bb->consumed_bits = 0; - bb->total_consumed_bits += val_; - } - } - while(1) { - if(bb->consumed_blurbs >= total_blurbs_) { - if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) - return false; - total_blurbs_ = (bb->total_bits + (FLAC__BITS_PER_BLURB-1)) / FLAC__BITS_PER_BLURB; - } - b = bb->buffer[bb->consumed_blurbs]; - if(b) { - for(i = 0; !(b & FLAC__BLURB_TOP_BIT_ONE); i++) - b <<= 1; - val_ += i; - i++; - bb->consumed_bits = i; - *val = val_; - if(i == FLAC__BITS_PER_BLURB) { - CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16); - bb->consumed_blurbs++; - bb->consumed_bits = 0; - } - bb->total_consumed_bits += i; - return true; - } - else { - val_ += FLAC__BITS_PER_BLURB; - CRC16_UPDATE_BLURB(bb, 0, bb->read_crc16); - bb->consumed_blurbs++; - /* bb->consumed_bits is already 0 */ - bb->total_consumed_bits += FLAC__BITS_PER_BLURB; - } - } -#if FLAC__BITS_PER_BLURB > 8 - } - else { - while(1) { - if(!FLAC__bitbuffer_read_bit(bb, &i, read_callback, client_data)) - return false; - if(i) - break; - else - val_++; - } - *val = val_; - return true; - } -#endif -} -#endif - -#ifdef FLAC__SYMMETRIC_RICE -FLAC__bool FLAC__bitbuffer_read_symmetric_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - FLAC__uint32 sign = 0, lsbs = 0, msbs = 0; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(parameter <= 31); - - /* read the unary MSBs and end bit */ - if(!FLAC__bitbuffer_read_unary_unsigned(bb, &msbs, read_callback, client_data)) - return false; - - /* read the sign bit */ - if(!FLAC__bitbuffer_read_bit_to_uint32(bb, &sign, read_callback, client_data)) - return false; - - /* read the binary LSBs */ - if(!FLAC__bitbuffer_read_raw_uint32(bb, &lsbs, parameter, read_callback, client_data)) - return false; - - /* compose the value */ - *val = (msbs << parameter) | lsbs; - if(sign) - *val = -(*val); - - return true; -} -#endif /* ifdef FLAC__SYMMETRIC_RICE */ - -FLAC__bool FLAC__bitbuffer_read_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - FLAC__uint32 lsbs = 0, msbs = 0; - unsigned uval; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(parameter <= 31); - - /* read the unary MSBs and end bit */ - if(!FLAC__bitbuffer_read_unary_unsigned(bb, &msbs, read_callback, client_data)) - return false; - - /* read the binary LSBs */ - if(!FLAC__bitbuffer_read_raw_uint32(bb, &lsbs, parameter, read_callback, client_data)) - return false; - - /* compose the value */ - uval = (msbs << parameter) | lsbs; - if(uval & 1) - *val = -((int)(uval >> 1)) - 1; - else - *val = (int)(uval >> 1); - - return true; -} - -FLAC__bool FLAC__bitbuffer_read_rice_signed_block(FLAC__BitBuffer *bb, int vals[], unsigned nvals, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - const FLAC__blurb *buffer = bb->buffer; - - unsigned i, j, val_i = 0; - unsigned cbits = 0, uval = 0, msbs = 0, lsbs_left = 0; - FLAC__blurb blurb, save_blurb; - unsigned state = 0; /* 0 = getting unary MSBs, 1 = getting binary LSBs */ - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - FLAC__ASSERT(parameter <= 31); - - if(nvals == 0) - return true; - - i = bb->consumed_blurbs; - /* - * We unroll the main loop to take care of partially consumed blurbs here. - */ - if(bb->consumed_bits > 0) { - save_blurb = blurb = buffer[i]; - cbits = bb->consumed_bits; - blurb <<= cbits; - - while(1) { - if(state == 0) { - if(blurb) { - for(j = 0; !(blurb & FLAC__BLURB_TOP_BIT_ONE); j++) - blurb <<= 1; - msbs += j; - - /* dispose of the unary end bit */ - blurb <<= 1; - j++; - cbits += j; - - uval = 0; - lsbs_left = parameter; - state++; - if(cbits == FLAC__BITS_PER_BLURB) { - cbits = 0; - CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16); - break; - } - } - else { - msbs += FLAC__BITS_PER_BLURB - cbits; - cbits = 0; - CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16); - break; - } - } - else { - const unsigned available_bits = FLAC__BITS_PER_BLURB - cbits; - if(lsbs_left >= available_bits) { - uval <<= available_bits; - uval |= (blurb >> cbits); - cbits = 0; - CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16); - - if(lsbs_left == available_bits) { - /* compose the value */ - uval |= (msbs << parameter); - if(uval & 1) - vals[val_i++] = -((int)(uval >> 1)) - 1; - else - vals[val_i++] = (int)(uval >> 1); - if(val_i == nvals) - break; - - msbs = 0; - state = 0; - } - - lsbs_left -= available_bits; - break; - } - else { - uval <<= lsbs_left; - uval |= (blurb >> (FLAC__BITS_PER_BLURB - lsbs_left)); - blurb <<= lsbs_left; - cbits += lsbs_left; - - /* compose the value */ - uval |= (msbs << parameter); - if(uval & 1) - vals[val_i++] = -((int)(uval >> 1)) - 1; - else - vals[val_i++] = (int)(uval >> 1); - if(val_i == nvals) { - /* back up one if we exited the for loop because we read all nvals but the end came in the middle of a blurb */ - i--; - break; - } - - msbs = 0; - state = 0; - } - } - } - i++; - - bb->consumed_blurbs = i; - bb->consumed_bits = cbits; - bb->total_consumed_bits = (i << FLAC__BITS_PER_BLURB_LOG2) | cbits; - } - - /* - * Now that we are blurb-aligned the logic is slightly simpler - */ - while(val_i < nvals) { - for( ; i < bb->blurbs && val_i < nvals; i++) { - save_blurb = blurb = buffer[i]; - cbits = 0; - while(1) { - if(state == 0) { - if(blurb) { - for(j = 0; !(blurb & FLAC__BLURB_TOP_BIT_ONE); j++) - blurb <<= 1; - msbs += j; - - /* dispose of the unary end bit */ - blurb <<= 1; - j++; - cbits += j; - - uval = 0; - lsbs_left = parameter; - state++; - if(cbits == FLAC__BITS_PER_BLURB) { - cbits = 0; - CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16); - break; - } - } - else { - msbs += FLAC__BITS_PER_BLURB - cbits; - cbits = 0; - CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16); - break; - } - } - else { - const unsigned available_bits = FLAC__BITS_PER_BLURB - cbits; - if(lsbs_left >= available_bits) { - uval <<= available_bits; - uval |= (blurb >> cbits); - cbits = 0; - CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16); - - if(lsbs_left == available_bits) { - /* compose the value */ - uval |= (msbs << parameter); - if(uval & 1) - vals[val_i++] = -((int)(uval >> 1)) - 1; - else - vals[val_i++] = (int)(uval >> 1); - if(val_i == nvals) - break; - - msbs = 0; - state = 0; - } - - lsbs_left -= available_bits; - break; - } - else { - uval <<= lsbs_left; - uval |= (blurb >> (FLAC__BITS_PER_BLURB - lsbs_left)); - blurb <<= lsbs_left; - cbits += lsbs_left; - - /* compose the value */ - uval |= (msbs << parameter); - if(uval & 1) - vals[val_i++] = -((int)(uval >> 1)) - 1; - else - vals[val_i++] = (int)(uval >> 1); - if(val_i == nvals) { - /* back up one if we exited the for loop because we read all nvals but the end came in the middle of a blurb */ - i--; - break; - } - - msbs = 0; - state = 0; - } - } - } - } - bb->consumed_blurbs = i; - bb->consumed_bits = cbits; - bb->total_consumed_bits = (i << FLAC__BITS_PER_BLURB_LOG2) | cbits; - if(val_i < nvals) { - if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) - return false; - /* these must be zero because we can only get here if we got to the end of the buffer */ - FLAC__ASSERT(bb->consumed_blurbs == 0); - FLAC__ASSERT(bb->consumed_bits == 0); - i = 0; - } - } - - return true; -} - -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_read_golomb_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - FLAC__uint32 lsbs = 0, msbs = 0; - unsigned bit, uval, k; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - k = FLAC__bitmath_ilog2(parameter); - - /* read the unary MSBs and end bit */ - if(!FLAC__bitbuffer_read_unary_unsigned(bb, &msbs, read_callback, client_data)) - return false; - - /* read the binary LSBs */ - if(!FLAC__bitbuffer_read_raw_uint32(bb, &lsbs, k, read_callback, client_data)) - return false; - - if(parameter == 1u<<k) { - /* compose the value */ - uval = (msbs << k) | lsbs; - } - else { - unsigned d = (1 << (k+1)) - parameter; - if(lsbs >= d) { - if(!FLAC__bitbuffer_read_bit(bb, &bit, read_callback, client_data)) - return false; - lsbs <<= 1; - lsbs |= bit; - lsbs -= d; - } - /* compose the value */ - uval = msbs * parameter + lsbs; - } - - /* unfold unsigned to signed */ - if(uval & 1) - *val = -((int)(uval >> 1)) - 1; - else - *val = (int)(uval >> 1); - - return true; -} - -FLAC__bool FLAC__bitbuffer_read_golomb_unsigned(FLAC__BitBuffer *bb, unsigned *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data) -{ - FLAC__uint32 lsbs, msbs = 0; - unsigned bit, k; - - FLAC__ASSERT(0 != bb); - FLAC__ASSERT(0 != bb->buffer); - - k = FLAC__bitmath_ilog2(parameter); - - /* read the unary MSBs and end bit */ - if(!FLAC__bitbuffer_read_unary_unsigned(bb, &msbs, read_callback, client_data)) - return false; - - /* read the binary LSBs */ - if(!FLAC__bitbuffer_read_raw_uint32(bb, &lsbs, k, read_callback, client_data)) - return false; - - if(parameter == 1u<<k) { - /* compose the value */ - *val = (msbs << k) | lsbs; - } - else { - unsigned d = (1 << (k+1)) - parameter; - if(lsbs >= d) { - if(!FLAC__bitbuffer_read_bit(bb, &bit, read_callback, client_data)) - return false; - lsbs <<= 1; - lsbs |= bit; - lsbs -= d; - } - /* compose the value */ - *val = msbs * parameter + lsbs; - } - - return true; -} -#endif /* UNUSED */ - -/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */ -FLAC__bool FLAC__bitbuffer_read_utf8_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data, FLAC__byte *raw, unsigned *rawlen) -{ - FLAC__uint32 v = 0; - FLAC__uint32 x; - unsigned i; - - if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80)) { /* 0xxxxxxx */ - v = x; - i = 0; - } - else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */ - v = x & 0x1F; - i = 1; - } - else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */ - v = x & 0x0F; - i = 2; - } - else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */ - v = x & 0x07; - i = 3; - } - else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */ - v = x & 0x03; - i = 4; - } - else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */ - v = x & 0x01; - i = 5; - } - else { - *val = 0xffffffff; - return true; - } - for( ; i; i--) { - if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */ - *val = 0xffffffff; - return true; - } - v <<= 6; - v |= (x & 0x3F); - } - *val = v; - return true; -} - -/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */ -FLAC__bool FLAC__bitbuffer_read_utf8_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data, FLAC__byte *raw, unsigned *rawlen) -{ - FLAC__uint64 v = 0; - FLAC__uint32 x; - unsigned i; - - if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80)) { /* 0xxxxxxx */ - v = x; - i = 0; - } - else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */ - v = x & 0x1F; - i = 1; - } - else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */ - v = x & 0x0F; - i = 2; - } - else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */ - v = x & 0x07; - i = 3; - } - else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */ - v = x & 0x03; - i = 4; - } - else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */ - v = x & 0x01; - i = 5; - } - else if(x & 0xFE && !(x & 0x01)) { /* 11111110 */ - v = 0; - i = 6; - } - else { - *val = FLAC__U64L(0xffffffffffffffff); - return true; - } - for( ; i; i--) { - if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */ - *val = FLAC__U64L(0xffffffffffffffff); - return true; - } - v <<= 6; - v |= (x & 0x3F); - } - *val = v; - return true; -} - -void FLAC__bitbuffer_dump(const FLAC__BitBuffer *bb, FILE *out) -{ - unsigned i, j; - if(bb == 0) { - fprintf(out, "bitbuffer is NULL\n"); - } - else { - fprintf(out, "bitbuffer: capacity=%u blurbs=%u bits=%u total_bits=%u consumed: blurbs=%u, bits=%u, total_bits=%u\n", bb->capacity, bb->blurbs, bb->bits, bb->total_bits, bb->consumed_blurbs, bb->consumed_bits, bb->total_consumed_bits); - - for(i = 0; i < bb->blurbs; i++) { - fprintf(out, "%08X: ", i); - for(j = 0; j < FLAC__BITS_PER_BLURB; j++) - if(i*FLAC__BITS_PER_BLURB+j < bb->total_consumed_bits) - fprintf(out, "."); - else - fprintf(out, "%01u", bb->buffer[i] & (1 << (FLAC__BITS_PER_BLURB-j-1)) ? 1:0); - fprintf(out, "\n"); - } - if(bb->bits > 0) { - fprintf(out, "%08X: ", i); - for(j = 0; j < bb->bits; j++) - if(i*FLAC__BITS_PER_BLURB+j < bb->total_consumed_bits) - fprintf(out, "."); - else - fprintf(out, "%01u", bb->buffer[i] & (1 << (bb->bits-j-1)) ? 1:0); - fprintf(out, "\n"); - } - } -} diff --git a/sys/src/cmd/audio/libFLAC/bitmath.c b/sys/src/cmd/audio/libFLAC/bitmath.c index 5ace20b9f..5b58ca999 100644 --- a/sys/src/cmd/audio/libFLAC/bitmath.c +++ b/sys/src/cmd/audio/libFLAC/bitmath.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,39 +30,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "private/bitmath.h" -#include "FLAC/assert.h" +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif -/* An example of what FLAC__bitmath_ilog2() computes: - * - * ilog2( 0) = assertion failure - * ilog2( 1) = 0 - * ilog2( 2) = 1 - * ilog2( 3) = 1 - * ilog2( 4) = 2 - * ilog2( 5) = 2 - * ilog2( 6) = 2 - * ilog2( 7) = 2 - * ilog2( 8) = 3 - * ilog2( 9) = 3 - * ilog2(10) = 3 - * ilog2(11) = 3 - * ilog2(12) = 3 - * ilog2(13) = 3 - * ilog2(14) = 3 - * ilog2(15) = 3 - * ilog2(16) = 4 - * ilog2(17) = 4 - * ilog2(18) = 4 - */ -unsigned FLAC__bitmath_ilog2(unsigned v) -{ - unsigned l = 0; - FLAC__ASSERT(v > 0); - while(v >>= 1) - l++; - return l; -} +#include "private/bitmath.h" /* An example of what FLAC__bitmath_silog2() computes: * diff --git a/sys/src/cmd/audio/libFLAC/bitreader.c b/sys/src/cmd/audio/libFLAC/bitreader.c new file mode 100644 index 000000000..f61229bd4 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/bitreader.c @@ -0,0 +1,1059 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include "private/bitmath.h" +#include "private/bitreader.h" +#include "private/crc.h" +#include "private/macros.h" +#include "FLAC/assert.h" +#include "share/compat.h" +#include "share/endswap.h" + +/* Things should be fastest when this matches the machine word size */ +/* WATCHOUT: if you change this you must also change the following #defines down to FLAC__clz_uint32 below to match */ +/* WATCHOUT: there are a few places where the code will not work unless uint32_t is >= 32 bits wide */ +/* also, some sections currently only have fast versions for 4 or 8 bytes per word */ +#define FLAC__BYTES_PER_WORD 4 /* sizeof uint32_t */ +#define FLAC__BITS_PER_WORD (8 * FLAC__BYTES_PER_WORD) +#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff) +/* SWAP_BE_WORD_TO_HOST swaps bytes in a uint32_t (which is always big-endian) if necessary to match host byte order */ +#if WORDS_BIGENDIAN +#define SWAP_BE_WORD_TO_HOST(x) (x) +#else +#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x) +#endif + +/* + * This should be at least twice as large as the largest number of words + * required to represent any 'number' (in any encoding) you are going to + * read. With FLAC this is on the order of maybe a few hundred bits. + * If the buffer is smaller than that, the decoder won't be able to read + * in a whole number that is in a variable length encoding (e.g. Rice). + * But to be practical it should be at least 1K bytes. + * + * Increase this number to decrease the number of read callbacks, at the + * expense of using more memory. Or decrease for the reverse effect, + * keeping in mind the limit from the first paragraph. The optimal size + * also depends on the CPU cache size and other factors; some twiddling + * may be necessary to squeeze out the best performance. + */ +static const unsigned FLAC__BITREADER_DEFAULT_CAPACITY = 65536u / FLAC__BITS_PER_WORD; /* in words */ + +struct FLAC__BitReader { + /* any partially-consumed word at the head will stay right-justified as bits are consumed from the left */ + /* any incomplete word at the tail will be left-justified, and bytes from the read callback are added on the right */ + uint32_t *buffer; + unsigned capacity; /* in words */ + unsigned words; /* # of completed words in buffer */ + unsigned bytes; /* # of bytes in incomplete word at buffer[words] */ + unsigned consumed_words; /* #words ... */ + unsigned consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */ + unsigned read_crc16; /* the running frame CRC */ + unsigned crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */ + FLAC__BitReaderReadCallback read_callback; + void *client_data; +}; + +static inline void crc16_update_word_(FLAC__BitReader *br, uint32_t word) +{ + register unsigned crc = br->read_crc16; +#if FLAC__BYTES_PER_WORD == 4 + switch(br->crc16_align) { + case 0: crc = FLAC__CRC16_UPDATE((unsigned)(word >> 24), crc); + case 8: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 16) & 0xff), crc); + case 16: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 8) & 0xff), crc); + case 24: br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)(word & 0xff), crc); + } +#elif FLAC__BYTES_PER_WORD == 8 + switch(br->crc16_align) { + case 0: crc = FLAC__CRC16_UPDATE((unsigned)(word >> 56), crc); + case 8: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 48) & 0xff), crc); + case 16: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 40) & 0xff), crc); + case 24: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 32) & 0xff), crc); + case 32: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 24) & 0xff), crc); + case 40: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 16) & 0xff), crc); + case 48: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 8) & 0xff), crc); + case 56: br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)(word & 0xff), crc); + } +#else + for( ; br->crc16_align < FLAC__BITS_PER_WORD; br->crc16_align += 8) + crc = FLAC__CRC16_UPDATE((unsigned)((word >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), crc); + br->read_crc16 = crc; +#endif + br->crc16_align = 0; +} + +static FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br) +{ + unsigned start, end; + size_t bytes; + FLAC__byte *target; + + /* first shift the unconsumed buffer data toward the front as much as possible */ + if(br->consumed_words > 0) { + start = br->consumed_words; + end = br->words + (br->bytes? 1:0); + memmove(br->buffer, br->buffer+start, FLAC__BYTES_PER_WORD * (end - start)); + + br->words -= start; + br->consumed_words = 0; + } + + /* + * set the target for reading, taking into account word alignment and endianness + */ + bytes = (br->capacity - br->words) * FLAC__BYTES_PER_WORD - br->bytes; + if(bytes == 0) + return false; /* no space left, buffer is too small; see note for FLAC__BITREADER_DEFAULT_CAPACITY */ + target = ((FLAC__byte*)(br->buffer+br->words)) + br->bytes; + + /* before reading, if the existing reader looks like this (say uint32_t is 32 bits wide) + * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1 (partial tail word is left-justified) + * buffer[BE]: 11 22 33 44 55 ?? ?? ?? (shown layed out as bytes sequentially in memory) + * buffer[LE]: 44 33 22 11 ?? ?? ?? 55 (?? being don't-care) + * ^^-------target, bytes=3 + * on LE machines, have to byteswap the odd tail word so nothing is + * overwritten: + */ +#if WORDS_BIGENDIAN +#else + if(br->bytes) + br->buffer[br->words] = SWAP_BE_WORD_TO_HOST(br->buffer[br->words]); +#endif + + /* now it looks like: + * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1 + * buffer[BE]: 11 22 33 44 55 ?? ?? ?? + * buffer[LE]: 44 33 22 11 55 ?? ?? ?? + * ^^-------target, bytes=3 + */ + + /* read in the data; note that the callback may return a smaller number of bytes */ + if(!br->read_callback(target, &bytes, br->client_data)) + return false; + + /* after reading bytes 66 77 88 99 AA BB CC DD EE FF from the client: + * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF + * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ?? + * buffer[LE]: 44 33 22 11 55 66 77 88 99 AA BB CC DD EE FF ?? + * now have to byteswap on LE machines: + */ +#if WORDS_BIGENDIAN +#else + end = (br->words*FLAC__BYTES_PER_WORD + br->bytes + bytes + (FLAC__BYTES_PER_WORD-1)) / FLAC__BYTES_PER_WORD; + for(start = br->words; start < end; start++) + br->buffer[start] = SWAP_BE_WORD_TO_HOST(br->buffer[start]); +#endif + + /* now it looks like: + * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF + * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ?? + * buffer[LE]: 44 33 22 11 88 77 66 55 CC BB AA 99 ?? FF EE DD + * finally we'll update the reader values: + */ + end = br->words*FLAC__BYTES_PER_WORD + br->bytes + bytes; + br->words = end / FLAC__BYTES_PER_WORD; + br->bytes = end % FLAC__BYTES_PER_WORD; + + return true; +} + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +FLAC__BitReader *FLAC__bitreader_new(void) +{ + FLAC__BitReader *br = calloc(1, sizeof(FLAC__BitReader)); + + /* calloc() implies: + memset(br, 0, sizeof(FLAC__BitReader)); + br->buffer = 0; + br->capacity = 0; + br->words = br->bytes = 0; + br->consumed_words = br->consumed_bits = 0; + br->read_callback = 0; + br->client_data = 0; + */ + return br; +} + +void FLAC__bitreader_delete(FLAC__BitReader *br) +{ + FLAC__ASSERT(0 != br); + + FLAC__bitreader_free(br); + free(br); +} + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd) +{ + FLAC__ASSERT(0 != br); + + br->words = br->bytes = 0; + br->consumed_words = br->consumed_bits = 0; + br->capacity = FLAC__BITREADER_DEFAULT_CAPACITY; + br->buffer = malloc(sizeof(uint32_t) * br->capacity); + if(br->buffer == 0) + return false; + br->read_callback = rcb; + br->client_data = cd; + + return true; +} + +void FLAC__bitreader_free(FLAC__BitReader *br) +{ + FLAC__ASSERT(0 != br); + + if(0 != br->buffer) + free(br->buffer); + br->buffer = 0; + br->capacity = 0; + br->words = br->bytes = 0; + br->consumed_words = br->consumed_bits = 0; + br->read_callback = 0; + br->client_data = 0; +} + +FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br) +{ + br->words = br->bytes = 0; + br->consumed_words = br->consumed_bits = 0; + return true; +} + +void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out) +{ + unsigned i, j; + if(br == 0) { + fprintf(out, "bitreader is NULL\n"); + } + else { + fprintf(out, "bitreader: capacity=%u words=%u bytes=%u consumed: words=%u, bits=%u\n", br->capacity, br->words, br->bytes, br->consumed_words, br->consumed_bits); + + for(i = 0; i < br->words; i++) { + fprintf(out, "%08X: ", i); + for(j = 0; j < FLAC__BITS_PER_WORD; j++) + if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits)) + fprintf(out, "."); + else + fprintf(out, "%01u", br->buffer[i] & (1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0); + fprintf(out, "\n"); + } + if(br->bytes > 0) { + fprintf(out, "%08X: ", i); + for(j = 0; j < br->bytes*8; j++) + if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits)) + fprintf(out, "."); + else + fprintf(out, "%01u", br->buffer[i] & (1 << (br->bytes*8-j-1)) ? 1:0); + fprintf(out, "\n"); + } + } +} + +void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed) +{ + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + FLAC__ASSERT((br->consumed_bits & 7) == 0); + + br->read_crc16 = (unsigned)seed; + br->crc16_align = br->consumed_bits; +} + +FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br) +{ + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + FLAC__ASSERT((br->consumed_bits & 7) == 0); + FLAC__ASSERT(br->crc16_align <= br->consumed_bits); + + /* CRC any tail bytes in a partially-consumed word */ + if(br->consumed_bits) { + const uint32_t tail = br->buffer[br->consumed_words]; + for( ; br->crc16_align < br->consumed_bits; br->crc16_align += 8) + br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)((tail >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), br->read_crc16); + } + return br->read_crc16; +} + +inline FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br) +{ + return ((br->consumed_bits & 7) == 0); +} + +inline unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br) +{ + return 8 - (br->consumed_bits & 7); +} + +inline unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br) +{ + return (br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits; +} + +FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, unsigned bits) +{ + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + FLAC__ASSERT(bits <= 32); + FLAC__ASSERT((br->capacity*FLAC__BITS_PER_WORD) * 2 >= bits); + FLAC__ASSERT(br->consumed_words <= br->words); + + /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ + FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); + + if(bits == 0) { /* OPT: investigate if this can ever happen, maybe change to assertion */ + *val = 0; + return true; + } + + while((br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits < bits) { + if(!bitreader_read_from_client_(br)) + return false; + } + if(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */ + /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */ + if(br->consumed_bits) { + /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */ + const unsigned n = FLAC__BITS_PER_WORD - br->consumed_bits; + const uint32_t word = br->buffer[br->consumed_words]; + if(bits < n) { + *val = (word & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (n-bits); + br->consumed_bits += bits; + return true; + } + *val = word & (FLAC__WORD_ALL_ONES >> br->consumed_bits); + bits -= n; + crc16_update_word_(br, word); + br->consumed_words++; + br->consumed_bits = 0; + if(bits) { /* if there are still bits left to read, there have to be less than 32 so they will all be in the next word */ + *val <<= bits; + *val |= (br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits)); + br->consumed_bits = bits; + } + return true; + } + else { + const uint32_t word = br->buffer[br->consumed_words]; + if(bits < FLAC__BITS_PER_WORD) { + *val = word >> (FLAC__BITS_PER_WORD-bits); + br->consumed_bits = bits; + return true; + } + /* at this point 'bits' must be == FLAC__BITS_PER_WORD; because of previous assertions, it can't be larger */ + *val = word; + crc16_update_word_(br, word); + br->consumed_words++; + return true; + } + } + else { + /* in this case we're starting our read at a partial tail word; + * the reader has guaranteed that we have at least 'bits' bits + * available to read, which makes this case simpler. + */ + /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */ + if(br->consumed_bits) { + /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */ + FLAC__ASSERT(br->consumed_bits + bits <= br->bytes*8); + *val = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (FLAC__BITS_PER_WORD-br->consumed_bits-bits); + br->consumed_bits += bits; + return true; + } + else { + *val = br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits); + br->consumed_bits += bits; + return true; + } + } +} + +FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, unsigned bits) +{ + /* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */ + if(!FLAC__bitreader_read_raw_uint32(br, (FLAC__uint32*)val, bits)) + return false; + /* sign-extend: */ + *val <<= (32-bits); + *val >>= (32-bits); + return true; +} + +FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, unsigned bits) +{ + FLAC__uint32 hi, lo; + + if(bits > 32) { + if(!FLAC__bitreader_read_raw_uint32(br, &hi, bits-32)) + return false; + if(!FLAC__bitreader_read_raw_uint32(br, &lo, 32)) + return false; + *val = hi; + *val <<= 32; + *val |= lo; + } + else { + if(!FLAC__bitreader_read_raw_uint32(br, &lo, bits)) + return false; + *val = lo; + } + return true; +} + +inline FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val) +{ + FLAC__uint32 x8, x32 = 0; + + /* this doesn't need to be that fast as currently it is only used for vorbis comments */ + + if(!FLAC__bitreader_read_raw_uint32(br, &x32, 8)) + return false; + + if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) + return false; + x32 |= (x8 << 8); + + if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) + return false; + x32 |= (x8 << 16); + + if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) + return false; + x32 |= (x8 << 24); + + *val = x32; + return true; +} + +FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, unsigned bits) +{ + /* + * OPT: a faster implementation is possible but probably not that useful + * since this is only called a couple of times in the metadata readers. + */ + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + if(bits > 0) { + const unsigned n = br->consumed_bits & 7; + unsigned m; + FLAC__uint32 x; + + if(n != 0) { + m = flac_min(8-n, bits); + if(!FLAC__bitreader_read_raw_uint32(br, &x, m)) + return false; + bits -= m; + } + m = bits / 8; + if(m > 0) { + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(br, m)) + return false; + bits %= 8; + } + if(bits > 0) { + if(!FLAC__bitreader_read_raw_uint32(br, &x, bits)) + return false; + } + } + + return true; +} + +FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, unsigned nvals) +{ + FLAC__uint32 x; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br)); + + /* step 1: skip over partial head word to get word aligned */ + while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */ + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + nvals--; + } + if(0 == nvals) + return true; + /* step 2: skip whole words in chunks */ + while(nvals >= FLAC__BYTES_PER_WORD) { + if(br->consumed_words < br->words) { + br->consumed_words++; + nvals -= FLAC__BYTES_PER_WORD; + } + else if(!bitreader_read_from_client_(br)) + return false; + } + /* step 3: skip any remainder from partial tail bytes */ + while(nvals) { + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + nvals--; + } + + return true; +} + +FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, unsigned nvals) +{ + FLAC__uint32 x; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br)); + + /* step 1: read from partial head word to get word aligned */ + while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */ + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + *val++ = (FLAC__byte)x; + nvals--; + } + if(0 == nvals) + return true; + /* step 2: read whole words in chunks */ + while(nvals >= FLAC__BYTES_PER_WORD) { + if(br->consumed_words < br->words) { + const uint32_t word = br->buffer[br->consumed_words++]; +#if FLAC__BYTES_PER_WORD == 4 + val[0] = (FLAC__byte)(word >> 24); + val[1] = (FLAC__byte)(word >> 16); + val[2] = (FLAC__byte)(word >> 8); + val[3] = (FLAC__byte)word; +#elif FLAC__BYTES_PER_WORD == 8 + val[0] = (FLAC__byte)(word >> 56); + val[1] = (FLAC__byte)(word >> 48); + val[2] = (FLAC__byte)(word >> 40); + val[3] = (FLAC__byte)(word >> 32); + val[4] = (FLAC__byte)(word >> 24); + val[5] = (FLAC__byte)(word >> 16); + val[6] = (FLAC__byte)(word >> 8); + val[7] = (FLAC__byte)word; +#else + for(x = 0; x < FLAC__BYTES_PER_WORD; x++) + val[x] = (FLAC__byte)(word >> (8*(FLAC__BYTES_PER_WORD-x-1))); +#endif + val += FLAC__BYTES_PER_WORD; + nvals -= FLAC__BYTES_PER_WORD; + } + else if(!bitreader_read_from_client_(br)) + return false; + } + /* step 3: read any remainder from partial tail bytes */ + while(nvals) { + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + *val++ = (FLAC__byte)x; + nvals--; + } + + return true; +} + +FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, unsigned *val) +#if 0 /* slow but readable version */ +{ + unsigned bit; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + *val = 0; + while(1) { + if(!FLAC__bitreader_read_bit(br, &bit)) + return false; + if(bit) + break; + else + *val++; + } + return true; +} +#else +{ + unsigned i; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + *val = 0; + while(1) { + while(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */ + uint32_t b = br->buffer[br->consumed_words] << br->consumed_bits; + if(b) { + i = FLAC__clz_uint32(b); + *val += i; + i++; + br->consumed_bits += i; + if(br->consumed_bits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(br->consumed_bits == FLAC__BITS_PER_WORD) */ + crc16_update_word_(br, br->buffer[br->consumed_words]); + br->consumed_words++; + br->consumed_bits = 0; + } + return true; + } + else { + *val += FLAC__BITS_PER_WORD - br->consumed_bits; + crc16_update_word_(br, br->buffer[br->consumed_words]); + br->consumed_words++; + br->consumed_bits = 0; + /* didn't find stop bit yet, have to keep going... */ + } + } + /* at this point we've eaten up all the whole words; have to try + * reading through any tail bytes before calling the read callback. + * this is a repeat of the above logic adjusted for the fact we + * don't have a whole word. note though if the client is feeding + * us data a byte at a time (unlikely), br->consumed_bits may not + * be zero. + */ + if(br->bytes*8 > br->consumed_bits) { + const unsigned end = br->bytes * 8; + uint32_t b = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << br->consumed_bits; + if(b) { + i = FLAC__clz_uint32(b); + *val += i; + i++; + br->consumed_bits += i; + FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD); + return true; + } + else { + *val += end - br->consumed_bits; + br->consumed_bits = end; + FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD); + /* didn't find stop bit yet, have to keep going... */ + } + } + if(!bitreader_read_from_client_(br)) + return false; + } +} +#endif + +FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, unsigned parameter) +{ + FLAC__uint32 lsbs = 0, msbs = 0; + unsigned uval; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + FLAC__ASSERT(parameter <= 31); + + /* read the unary MSBs and end bit */ + if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) + return false; + + /* read the binary LSBs */ + if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter)) + return false; + + /* compose the value */ + uval = (msbs << parameter) | lsbs; + if(uval & 1) + *val = -((int)(uval >> 1)) - 1; + else + *val = (int)(uval >> 1); + + return true; +} + +/* this is by far the most heavily used reader call. it ain't pretty but it's fast */ +FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter) +{ + /* try and get br->consumed_words and br->consumed_bits into register; + * must remember to flush them back to *br before calling other + * bitreader functions that use them, and before returning */ + unsigned cwords, words, lsbs, msbs, x, y; + unsigned ucbits; /* keep track of the number of unconsumed bits in word */ + uint32_t b; + int *val, *end; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ + FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); + FLAC__ASSERT(parameter < 32); + /* the above two asserts also guarantee that the binary part never straddles more than 2 words, so we don't have to loop to read it */ + + val = vals; + end = vals + nvals; + + if(parameter == 0) { + while(val < end) { + /* read the unary MSBs and end bit */ + if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) + return false; + + *val++ = (int)(msbs >> 1) ^ -(int)(msbs & 1); + } + + return true; + } + + FLAC__ASSERT(parameter > 0); + + cwords = br->consumed_words; + words = br->words; + + /* if we've not consumed up to a partial tail word... */ + if(cwords >= words) { + x = 0; + goto process_tail; + } + + ucbits = FLAC__BITS_PER_WORD - br->consumed_bits; + b = br->buffer[cwords] << br->consumed_bits; /* keep unconsumed bits aligned to left */ + + while(val < end) { + /* read the unary MSBs and end bit */ + x = y = FLAC__clz2_uint32(b); + if(x == FLAC__BITS_PER_WORD) { + x = ucbits; + do { + /* didn't find stop bit yet, have to keep going... */ + crc16_update_word_(br, br->buffer[cwords++]); + if (cwords >= words) + goto incomplete_msbs; + b = br->buffer[cwords]; + y = FLAC__clz2_uint32(b); + x += y; + } while(y == FLAC__BITS_PER_WORD); + } + b <<= y; + b <<= 1; /* account for stop bit */ + ucbits = (ucbits - x - 1) % FLAC__BITS_PER_WORD; + msbs = x; + + /* read the binary LSBs */ + x = b >> (FLAC__BITS_PER_WORD - parameter); + if(parameter <= ucbits) { + ucbits -= parameter; + b <<= parameter; + } else { + /* there are still bits left to read, they will all be in the next word */ + crc16_update_word_(br, br->buffer[cwords++]); + if (cwords >= words) + goto incomplete_lsbs; + b = br->buffer[cwords]; + ucbits += FLAC__BITS_PER_WORD - parameter; + x |= b >> ucbits; + b <<= FLAC__BITS_PER_WORD - ucbits; + } + lsbs = x; + + /* compose the value */ + x = (msbs << parameter) | lsbs; + *val++ = (int)(x >> 1) ^ -(int)(x & 1); + + continue; + + /* at this point we've eaten up all the whole words */ +process_tail: + do { + if(0) { +incomplete_msbs: + br->consumed_bits = 0; + br->consumed_words = cwords; + } + + /* read the unary MSBs and end bit */ + if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) + return false; + msbs += x; + x = ucbits = 0; + + if(0) { +incomplete_lsbs: + br->consumed_bits = 0; + br->consumed_words = cwords; + } + + /* read the binary LSBs */ + if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter - ucbits)) + return false; + lsbs = x | lsbs; + + /* compose the value */ + x = (msbs << parameter) | lsbs; + *val++ = (int)(x >> 1) ^ -(int)(x & 1); + x = 0; + + cwords = br->consumed_words; + words = br->words; + ucbits = FLAC__BITS_PER_WORD - br->consumed_bits; + b = br->buffer[cwords] << br->consumed_bits; + } while(cwords >= words && val < end); + } + + if(ucbits == 0 && cwords < words) { + /* don't leave the head word with no unconsumed bits */ + crc16_update_word_(br, br->buffer[cwords++]); + ucbits = FLAC__BITS_PER_WORD; + } + + br->consumed_bits = FLAC__BITS_PER_WORD - ucbits; + br->consumed_words = cwords; + + return true; +} + +#if 0 /* UNUSED */ +FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, unsigned parameter) +{ + FLAC__uint32 lsbs = 0, msbs = 0; + unsigned bit, uval, k; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + k = FLAC__bitmath_ilog2(parameter); + + /* read the unary MSBs and end bit */ + if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) + return false; + + /* read the binary LSBs */ + if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k)) + return false; + + if(parameter == 1u<<k) { + /* compose the value */ + uval = (msbs << k) | lsbs; + } + else { + unsigned d = (1 << (k+1)) - parameter; + if(lsbs >= d) { + if(!FLAC__bitreader_read_bit(br, &bit)) + return false; + lsbs <<= 1; + lsbs |= bit; + lsbs -= d; + } + /* compose the value */ + uval = msbs * parameter + lsbs; + } + + /* unfold unsigned to signed */ + if(uval & 1) + *val = -((int)(uval >> 1)) - 1; + else + *val = (int)(uval >> 1); + + return true; +} + +FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, unsigned *val, unsigned parameter) +{ + FLAC__uint32 lsbs, msbs = 0; + unsigned bit, k; + + FLAC__ASSERT(0 != br); + FLAC__ASSERT(0 != br->buffer); + + k = FLAC__bitmath_ilog2(parameter); + + /* read the unary MSBs and end bit */ + if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) + return false; + + /* read the binary LSBs */ + if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k)) + return false; + + if(parameter == 1u<<k) { + /* compose the value */ + *val = (msbs << k) | lsbs; + } + else { + unsigned d = (1 << (k+1)) - parameter; + if(lsbs >= d) { + if(!FLAC__bitreader_read_bit(br, &bit)) + return false; + lsbs <<= 1; + lsbs |= bit; + lsbs -= d; + } + /* compose the value */ + *val = msbs * parameter + lsbs; + } + + return true; +} +#endif /* UNUSED */ + +/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */ +FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, unsigned *rawlen) +{ + FLAC__uint32 v = 0; + FLAC__uint32 x; + unsigned i; + + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + if(raw) + raw[(*rawlen)++] = (FLAC__byte)x; + if(!(x & 0x80)) { /* 0xxxxxxx */ + v = x; + i = 0; + } + else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */ + v = x & 0x1F; + i = 1; + } + else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */ + v = x & 0x0F; + i = 2; + } + else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */ + v = x & 0x07; + i = 3; + } + else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */ + v = x & 0x03; + i = 4; + } + else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */ + v = x & 0x01; + i = 5; + } + else { + *val = 0xffffffff; + return true; + } + for( ; i; i--) { + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + if(raw) + raw[(*rawlen)++] = (FLAC__byte)x; + if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */ + *val = 0xffffffff; + return true; + } + v <<= 6; + v |= (x & 0x3F); + } + *val = v; + return true; +} + +/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */ +FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, unsigned *rawlen) +{ + FLAC__uint64 v = 0; + FLAC__uint32 x; + unsigned i; + + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + if(raw) + raw[(*rawlen)++] = (FLAC__byte)x; + if(!(x & 0x80)) { /* 0xxxxxxx */ + v = x; + i = 0; + } + else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */ + v = x & 0x1F; + i = 1; + } + else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */ + v = x & 0x0F; + i = 2; + } + else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */ + v = x & 0x07; + i = 3; + } + else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */ + v = x & 0x03; + i = 4; + } + else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */ + v = x & 0x01; + i = 5; + } + else if(x & 0xFE && !(x & 0x01)) { /* 11111110 */ + v = 0; + i = 6; + } + else { + *val = FLAC__U64L(0xffffffffffffffff); + return true; + } + for( ; i; i--) { + if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) + return false; + if(raw) + raw[(*rawlen)++] = (FLAC__byte)x; + if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */ + *val = FLAC__U64L(0xffffffffffffffff); + return true; + } + v <<= 6; + v |= (x & 0x3F); + } + *val = v; + return true; +} + +/* These functions are declared inline in this file but are also callable as + * externs from elsewhere. + * According to the C99 spec, section 6.7.4, simply providing a function + * prototype in a header file without 'inline' and making the function inline + * in this file should be sufficient. + * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To + * fix that we add extern declarations here. + */ +extern FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br); +extern unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br); +extern unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br); +extern FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); diff --git a/sys/src/cmd/audio/libFLAC/bitwriter.c b/sys/src/cmd/audio/libFLAC/bitwriter.c new file mode 100644 index 000000000..76be1bc7b --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/bitwriter.c @@ -0,0 +1,843 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include "private/bitwriter.h" +#include "private/crc.h" +#include "private/macros.h" +#include "FLAC/assert.h" +#include "share/alloc.h" +#include "share/compat.h" +#include "share/endswap.h" + +/* Things should be fastest when this matches the machine word size */ +/* WATCHOUT: if you change this you must also change the following #defines down to SWAP_BE_WORD_TO_HOST below to match */ +/* WATCHOUT: there are a few places where the code will not work unless uint32_t is >= 32 bits wide */ +#define FLAC__BYTES_PER_WORD 4 +#define FLAC__BITS_PER_WORD 32 +#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff) +/* SWAP_BE_WORD_TO_HOST swaps bytes in a uint32_t (which is always big-endian) if necessary to match host byte order */ +#if WORDS_BIGENDIAN +#define SWAP_BE_WORD_TO_HOST(x) (x) +#else +#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x) +#endif + +/* + * The default capacity here doesn't matter too much. The buffer always grows + * to hold whatever is written to it. Usually the encoder will stop adding at + * a frame or metadata block, then write that out and clear the buffer for the + * next one. + */ +static const unsigned FLAC__BITWRITER_DEFAULT_CAPACITY = 32768u / sizeof(uint32_t); /* size in words */ +/* When growing, increment 4K at a time */ +static const unsigned FLAC__BITWRITER_DEFAULT_INCREMENT = 4096u / sizeof(uint32_t); /* size in words */ + +#define FLAC__WORDS_TO_BITS(words) ((words) * FLAC__BITS_PER_WORD) +#define FLAC__TOTAL_BITS(bw) (FLAC__WORDS_TO_BITS((bw)->words) + (bw)->bits) + +struct FLAC__BitWriter { + uint32_t *buffer; + uint32_t accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */ + unsigned capacity; /* capacity of buffer in words */ + unsigned words; /* # of complete words in buffer */ + unsigned bits; /* # of used bits in accum */ +}; + +/* * WATCHOUT: The current implementation only grows the buffer. */ +#ifndef __SUNPRO_C +static +#endif +FLAC__bool bitwriter_grow_(FLAC__BitWriter *bw, unsigned bits_to_add) +{ + unsigned new_capacity; + uint32_t *new_buffer; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + + /* calculate total words needed to store 'bits_to_add' additional bits */ + new_capacity = bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD); + + /* it's possible (due to pessimism in the growth estimation that + * leads to this call) that we don't actually need to grow + */ + if(bw->capacity >= new_capacity) + return true; + + /* round up capacity increase to the nearest FLAC__BITWRITER_DEFAULT_INCREMENT */ + if((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT) + new_capacity += FLAC__BITWRITER_DEFAULT_INCREMENT - ((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT); + /* make sure we got everything right */ + FLAC__ASSERT(0 == (new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT); + FLAC__ASSERT(new_capacity > bw->capacity); + FLAC__ASSERT(new_capacity >= bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD)); + + new_buffer = safe_realloc_mul_2op_(bw->buffer, sizeof(uint32_t), /*times*/new_capacity); + if(new_buffer == 0) + return false; + bw->buffer = new_buffer; + bw->capacity = new_capacity; + return true; +} + + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +FLAC__BitWriter *FLAC__bitwriter_new(void) +{ + FLAC__BitWriter *bw = calloc(1, sizeof(FLAC__BitWriter)); + /* note that calloc() sets all members to 0 for us */ + return bw; +} + +void FLAC__bitwriter_delete(FLAC__BitWriter *bw) +{ + FLAC__ASSERT(0 != bw); + + FLAC__bitwriter_free(bw); + free(bw); +} + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw) +{ + FLAC__ASSERT(0 != bw); + + bw->words = bw->bits = 0; + bw->capacity = FLAC__BITWRITER_DEFAULT_CAPACITY; + bw->buffer = malloc(sizeof(uint32_t) * bw->capacity); + if(bw->buffer == 0) + return false; + + return true; +} + +void FLAC__bitwriter_free(FLAC__BitWriter *bw) +{ + FLAC__ASSERT(0 != bw); + + if(0 != bw->buffer) + free(bw->buffer); + bw->buffer = 0; + bw->capacity = 0; + bw->words = bw->bits = 0; +} + +void FLAC__bitwriter_clear(FLAC__BitWriter *bw) +{ + bw->words = bw->bits = 0; +} + +void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out) +{ + unsigned i, j; + if(bw == 0) { + fprintf(out, "bitwriter is NULL\n"); + } + else { + fprintf(out, "bitwriter: capacity=%u words=%u bits=%u total_bits=%u\n", bw->capacity, bw->words, bw->bits, FLAC__TOTAL_BITS(bw)); + + for(i = 0; i < bw->words; i++) { + fprintf(out, "%08X: ", i); + for(j = 0; j < FLAC__BITS_PER_WORD; j++) + fprintf(out, "%01u", bw->buffer[i] & (1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0); + fprintf(out, "\n"); + } + if(bw->bits > 0) { + fprintf(out, "%08X: ", i); + for(j = 0; j < bw->bits; j++) + fprintf(out, "%01u", bw->accum & (1 << (bw->bits-j-1)) ? 1:0); + fprintf(out, "\n"); + } + } +} + +FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc) +{ + const FLAC__byte *buffer; + size_t bytes; + + FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */ + + if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes)) + return false; + + *crc = (FLAC__uint16)FLAC__crc16(buffer, bytes); + FLAC__bitwriter_release_buffer(bw); + return true; +} + +FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc) +{ + const FLAC__byte *buffer; + size_t bytes; + + FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */ + + if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes)) + return false; + + *crc = FLAC__crc8(buffer, bytes); + FLAC__bitwriter_release_buffer(bw); + return true; +} + +FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw) +{ + return ((bw->bits & 7) == 0); +} + +unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw) +{ + return FLAC__TOTAL_BITS(bw); +} + +FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes) +{ + FLAC__ASSERT((bw->bits & 7) == 0); + /* double protection */ + if(bw->bits & 7) + return false; + /* if we have bits in the accumulator we have to flush those to the buffer first */ + if(bw->bits) { + FLAC__ASSERT(bw->words <= bw->capacity); + if(bw->words == bw->capacity && !bitwriter_grow_(bw, FLAC__BITS_PER_WORD)) + return false; + /* append bits as complete word to buffer, but don't change bw->accum or bw->bits */ + bw->buffer[bw->words] = SWAP_BE_WORD_TO_HOST(bw->accum << (FLAC__BITS_PER_WORD-bw->bits)); + } + /* now we can just return what we have */ + *buffer = (FLAC__byte*)bw->buffer; + *bytes = (FLAC__BYTES_PER_WORD * bw->words) + (bw->bits >> 3); + return true; +} + +void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw) +{ + /* nothing to do. in the future, strict checking of a 'writer-is-in- + * get-mode' flag could be added everywhere and then cleared here + */ + (void)bw; +} + +inline FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits) +{ + unsigned n; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + + if(bits == 0) + return true; + /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ + if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits)) + return false; + /* first part gets to word alignment */ + if(bw->bits) { + n = flac_min(FLAC__BITS_PER_WORD - bw->bits, bits); + bw->accum <<= n; + bits -= n; + bw->bits += n; + if(bw->bits == FLAC__BITS_PER_WORD) { + bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); + bw->bits = 0; + } + else + return true; + } + /* do whole words */ + while(bits >= FLAC__BITS_PER_WORD) { + bw->buffer[bw->words++] = 0; + bits -= FLAC__BITS_PER_WORD; + } + /* do any leftovers */ + if(bits > 0) { + bw->accum = 0; + bw->bits = bits; + } + return true; +} + +inline FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits) +{ + register unsigned left; + + /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ + FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + + FLAC__ASSERT(bits <= 32); + if(bits == 0) + return true; + + /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ + if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits)) + return false; + + left = FLAC__BITS_PER_WORD - bw->bits; + if(bits < left) { + bw->accum <<= bits; + bw->accum |= val; + bw->bits += bits; + } + else if(bw->bits) { /* WATCHOUT: if bw->bits == 0, left==FLAC__BITS_PER_WORD and bw->accum<<=left is a NOP instead of setting to 0 */ + bw->accum <<= left; + bw->accum |= val >> (bw->bits = bits - left); + bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); + bw->accum = val; + } + else { + bw->accum = val; + bw->bits = 0; + bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(val); + } + + return true; +} + +inline FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits) +{ + /* zero-out unused bits */ + if(bits < 32) + val &= (~(0xffffffff << bits)); + + return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits); +} + +inline FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits) +{ + /* this could be a little faster but it's not used for much */ + if(bits > 32) { + return + FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(val>>32), bits-32) && + FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 32); + } + else + return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits); +} + +inline FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val) +{ + /* this doesn't need to be that fast as currently it is only used for vorbis comments */ + + if(!FLAC__bitwriter_write_raw_uint32(bw, val & 0xff, 8)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>8) & 0xff, 8)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>16) & 0xff, 8)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, val>>24, 8)) + return false; + + return true; +} + +inline FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals) +{ + unsigned i; + + /* this could be faster but currently we don't need it to be since it's only used for writing metadata */ + for(i = 0; i < nvals; i++) { + if(!FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(vals[i]), 8)) + return false; + } + + return true; +} + +FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val) +{ + if(val < 32) + return FLAC__bitwriter_write_raw_uint32(bw, 1, ++val); + else + return + FLAC__bitwriter_write_zeroes(bw, val) && + FLAC__bitwriter_write_raw_uint32(bw, 1, 1); +} + +unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter) +{ + FLAC__uint32 uval; + + FLAC__ASSERT(parameter < sizeof(unsigned)*8); + + /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */ + uval = (val<<1) ^ (val>>31); + + return 1 + parameter + (uval >> parameter); +} + +#if 0 /* UNUSED */ +unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter) +{ + unsigned bits, msbs, uval; + unsigned k; + + FLAC__ASSERT(parameter > 0); + + /* fold signed to unsigned */ + if(val < 0) + uval = (unsigned)(((-(++val)) << 1) + 1); + else + uval = (unsigned)(val << 1); + + k = FLAC__bitmath_ilog2(parameter); + if(parameter == 1u<<k) { + FLAC__ASSERT(k <= 30); + + msbs = uval >> k; + bits = 1 + k + msbs; + } + else { + unsigned q, r, d; + + d = (1 << (k+1)) - parameter; + q = uval / parameter; + r = uval - (q * parameter); + + bits = 1 + q + k; + if(r >= d) + bits++; + } + return bits; +} + +unsigned FLAC__bitwriter_golomb_bits_unsigned(unsigned uval, unsigned parameter) +{ + unsigned bits, msbs; + unsigned k; + + FLAC__ASSERT(parameter > 0); + + k = FLAC__bitmath_ilog2(parameter); + if(parameter == 1u<<k) { + FLAC__ASSERT(k <= 30); + + msbs = uval >> k; + bits = 1 + k + msbs; + } + else { + unsigned q, r, d; + + d = (1 << (k+1)) - parameter; + q = uval / parameter; + r = uval - (q * parameter); + + bits = 1 + q + k; + if(r >= d) + bits++; + } + return bits; +} +#endif /* UNUSED */ + +FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter) +{ + unsigned total_bits, interesting_bits, msbs; + FLAC__uint32 uval, pattern; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + FLAC__ASSERT(parameter < 8*sizeof(uval)); + + /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */ + uval = (val<<1) ^ (val>>31); + + msbs = uval >> parameter; + interesting_bits = 1 + parameter; + total_bits = interesting_bits + msbs; + pattern = 1 << parameter; /* the unary end bit */ + pattern |= (uval & ((1<<parameter)-1)); /* the binary LSBs */ + + if(total_bits <= 32) + return FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits); + else + return + FLAC__bitwriter_write_zeroes(bw, msbs) && /* write the unary MSBs */ + FLAC__bitwriter_write_raw_uint32(bw, pattern, interesting_bits); /* write the unary end bit and binary LSBs */ +} + +FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter) +{ + const FLAC__uint32 mask1 = FLAC__WORD_ALL_ONES << parameter; /* we val|=mask1 to set the stop bit above it... */ + const FLAC__uint32 mask2 = FLAC__WORD_ALL_ONES >> (31-parameter); /* ...then mask off the bits above the stop bit with val&=mask2*/ + FLAC__uint32 uval; + unsigned left; + const unsigned lsbits = 1 + parameter; + unsigned msbits; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + FLAC__ASSERT(parameter < 8*sizeof(uint32_t)-1); + /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ + FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); + + while(nvals) { + /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */ + uval = (*vals<<1) ^ (*vals>>31); + + msbits = uval >> parameter; + + if(bw->bits && bw->bits + msbits + lsbits < FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current uint32_t */ + /* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free uint32_t to work in */ + bw->bits = bw->bits + msbits + lsbits; + uval |= mask1; /* set stop bit */ + uval &= mask2; /* mask off unused top bits */ + bw->accum <<= msbits + lsbits; + bw->accum |= uval; + } + else { + /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+msbits+lsbits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ + /* OPT: pessimism may cause flurry of false calls to grow_ which eat up all savings before it */ + if(bw->capacity <= bw->words + bw->bits + msbits + 1/*lsbits always fit in 1 uint32_t*/ && !bitwriter_grow_(bw, msbits+lsbits)) + return false; + + if(msbits) { + /* first part gets to word alignment */ + if(bw->bits) { + left = FLAC__BITS_PER_WORD - bw->bits; + if(msbits < left) { + bw->accum <<= msbits; + bw->bits += msbits; + goto break1; + } + else { + bw->accum <<= left; + msbits -= left; + bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); + bw->bits = 0; + } + } + /* do whole words */ + while(msbits >= FLAC__BITS_PER_WORD) { + bw->buffer[bw->words++] = 0; + msbits -= FLAC__BITS_PER_WORD; + } + /* do any leftovers */ + if(msbits > 0) { + bw->accum = 0; + bw->bits = msbits; + } + } +break1: + uval |= mask1; /* set stop bit */ + uval &= mask2; /* mask off unused top bits */ + + left = FLAC__BITS_PER_WORD - bw->bits; + if(lsbits < left) { + bw->accum <<= lsbits; + bw->accum |= uval; + bw->bits += lsbits; + } + else { + /* if bw->bits == 0, left==FLAC__BITS_PER_WORD which will always + * be > lsbits (because of previous assertions) so it would have + * triggered the (lsbits<left) case above. + */ + FLAC__ASSERT(bw->bits); + FLAC__ASSERT(left < FLAC__BITS_PER_WORD); + bw->accum <<= left; + bw->accum |= uval >> (bw->bits = lsbits - left); + bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); + bw->accum = uval; + } + } + vals++; + nvals--; + } + return true; +} + +#if 0 /* UNUSED */ +FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter) +{ + unsigned total_bits, msbs, uval; + unsigned k; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + FLAC__ASSERT(parameter > 0); + + /* fold signed to unsigned */ + if(val < 0) + uval = (unsigned)(((-(++val)) << 1) + 1); + else + uval = (unsigned)(val << 1); + + k = FLAC__bitmath_ilog2(parameter); + if(parameter == 1u<<k) { + unsigned pattern; + + FLAC__ASSERT(k <= 30); + + msbs = uval >> k; + total_bits = 1 + k + msbs; + pattern = 1 << k; /* the unary end bit */ + pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */ + + if(total_bits <= 32) { + if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits)) + return false; + } + else { + /* write the unary MSBs */ + if(!FLAC__bitwriter_write_zeroes(bw, msbs)) + return false; + /* write the unary end bit and binary LSBs */ + if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, k+1)) + return false; + } + } + else { + unsigned q, r, d; + + d = (1 << (k+1)) - parameter; + q = uval / parameter; + r = uval - (q * parameter); + /* write the unary MSBs */ + if(!FLAC__bitwriter_write_zeroes(bw, q)) + return false; + /* write the unary end bit */ + if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1)) + return false; + /* write the binary LSBs */ + if(r >= d) { + if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1)) + return false; + } + else { + if(!FLAC__bitwriter_write_raw_uint32(bw, r, k)) + return false; + } + } + return true; +} + +FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned uval, unsigned parameter) +{ + unsigned total_bits, msbs; + unsigned k; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + FLAC__ASSERT(parameter > 0); + + k = FLAC__bitmath_ilog2(parameter); + if(parameter == 1u<<k) { + unsigned pattern; + + FLAC__ASSERT(k <= 30); + + msbs = uval >> k; + total_bits = 1 + k + msbs; + pattern = 1 << k; /* the unary end bit */ + pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */ + + if(total_bits <= 32) { + if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits)) + return false; + } + else { + /* write the unary MSBs */ + if(!FLAC__bitwriter_write_zeroes(bw, msbs)) + return false; + /* write the unary end bit and binary LSBs */ + if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, k+1)) + return false; + } + } + else { + unsigned q, r, d; + + d = (1 << (k+1)) - parameter; + q = uval / parameter; + r = uval - (q * parameter); + /* write the unary MSBs */ + if(!FLAC__bitwriter_write_zeroes(bw, q)) + return false; + /* write the unary end bit */ + if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1)) + return false; + /* write the binary LSBs */ + if(r >= d) { + if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1)) + return false; + } + else { + if(!FLAC__bitwriter_write_raw_uint32(bw, r, k)) + return false; + } + } + return true; +} +#endif /* UNUSED */ + +FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val) +{ + FLAC__bool ok = 1; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + + FLAC__ASSERT(!(val & 0x80000000)); /* this version only handles 31 bits */ + + if(val < 0x80) { + return FLAC__bitwriter_write_raw_uint32(bw, val, 8); + } + else if(val < 0x800) { + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (val>>6), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8); + } + else if(val < 0x10000) { + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (val>>12), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8); + } + else if(val < 0x200000) { + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (val>>18), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8); + } + else if(val < 0x4000000) { + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (val>>24), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8); + } + else { + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (val>>30), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>24)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8); + } + + return ok; +} + +FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val) +{ + FLAC__bool ok = 1; + + FLAC__ASSERT(0 != bw); + FLAC__ASSERT(0 != bw->buffer); + + FLAC__ASSERT(!(val & FLAC__U64L(0xFFFFFFF000000000))); /* this version only handles 36 bits */ + + if(val < 0x80) { + return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 8); + } + else if(val < 0x800) { + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (FLAC__uint32)(val>>6), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + else if(val < 0x10000) { + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (FLAC__uint32)(val>>12), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + else if(val < 0x200000) { + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (FLAC__uint32)(val>>18), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + else if(val < 0x4000000) { + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (FLAC__uint32)(val>>24), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + else if(val < 0x80000000) { + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (FLAC__uint32)(val>>30), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + else { + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFE, 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); + } + + return ok; +} + +FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw) +{ + /* 0-pad to byte boundary */ + if(bw->bits & 7u) + return FLAC__bitwriter_write_zeroes(bw, 8 - (bw->bits & 7u)); + else + return true; +} + +/* These functions are declared inline in this file but are also callable as + * externs from elsewhere. + * According to the C99 spec, section 6.7.4, simply providing a function + * prototype in a header file without 'inline' and making the function inline + * in this file should be sufficient. + * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To + * fix that we add extern declarations here. + */ +extern FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits); +extern FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits); +extern FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits); +extern FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val); +extern FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals); diff --git a/sys/src/cmd/audio/libFLAC/cpu.c b/sys/src/cmd/audio/libFLAC/cpu.c index 63ce05e09..6cc1adb38 100644 --- a/sys/src/cmd/audio/libFLAC/cpu.c +++ b/sys/src/cmd/audio/libFLAC/cpu.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,89 +30,458 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include "private/cpu.h" -#include<stdlib.h> -#include<stdio.h> +#include "private/memory.h" +#include <stdlib.h> +#ifdef DEBUG +# include <stdio.h> +#endif -#ifdef HAVE_CONFIG_H -#include <config.h> +#if defined FLAC__CPU_IA32 +# include <signal.h> + +static void disable_sse(FLAC__CPUInfo *info) +{ + info->ia32.sse = false; + info->ia32.sse2 = false; + info->ia32.sse3 = false; + info->ia32.ssse3 = false; + info->ia32.sse41 = false; + info->ia32.sse42 = false; +} + +static void disable_avx(FLAC__CPUInfo *info) +{ + info->ia32.avx = false; + info->ia32.avx2 = false; + info->ia32.fma = false; +} + +#elif defined FLAC__CPU_X86_64 + +static void disable_avx(FLAC__CPUInfo *info) +{ + info->x86.avx = false; + info->x86.avx2 = false; + info->x86.fma = false; +} #endif -#if defined FLAC__CPU_PPC -#if !defined FLAC__NO_ASM -#if defined __APPLE__ && defined __MACH__ +#if defined (__NetBSD__) || defined(__OpenBSD__) +#include <sys/param.h> #include <sys/sysctl.h> -#endif /* __APPLE__ && __MACH__ */ -#endif /* FLAC__NO_ASM */ -#endif /* FLAC__CPU_PPC */ +#include <machine/cpu.h> +#endif -const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000; -const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000; -const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000; -const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000; -const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000; +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) +#include <sys/types.h> +#include <sys/sysctl.h> +#endif + +#if defined(__APPLE__) +/* how to get sysctlbyname()? */ +#endif -const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW = 0x80000000; -const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW = 0x40000000; -const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000; +#ifdef FLAC__CPU_IA32 +/* these are flags in EDX of CPUID AX=00000001 */ +static const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000; +static const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000; +static const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000; +static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000; +static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000; +#endif + +/* these are flags in ECX of CPUID AX=00000001 */ +static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE3 = 0x00000001; +static const unsigned FLAC__CPUINFO_IA32_CPUID_SSSE3 = 0x00000200; +static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE41 = 0x00080000; +static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE42 = 0x00100000; + +#if defined FLAC__AVX_SUPPORTED +/* these are flags in ECX of CPUID AX=00000001 */ +static const unsigned FLAC__CPUINFO_IA32_CPUID_OSXSAVE = 0x08000000; +static const unsigned FLAC__CPUINFO_IA32_CPUID_AVX = 0x10000000; +static const unsigned FLAC__CPUINFO_IA32_CPUID_FMA = 0x00001000; +/* these are flags in EBX of CPUID AX=00000007 */ +static const unsigned FLAC__CPUINFO_IA32_CPUID_AVX2 = 0x00000020; +#endif + +/* + * Extra stuff needed for detection of OS support for SSE on IA-32 + */ +#if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && (defined FLAC__HAS_NASM || defined FLAC__HAS_X86INTRIN) && !defined FLAC__NO_SSE_OS && !defined FLAC__SSE_OS +# if defined(__linux__) +/* + * If the OS doesn't support SSE, we will get here with a SIGILL. We + * modify the return address to jump over the offending SSE instruction + * and also the operation following it that indicates the instruction + * executed successfully. In this way we use no global variables and + * stay thread-safe. + * + * 3 + 3 + 6: + * 3 bytes for "xorps xmm0,xmm0" + * 3 bytes for estimate of how long the follwing "inc var" instruction is + * 6 bytes extra in case our estimate is wrong + * 12 bytes puts us in the NOP "landing zone" + */ +# include <sys/ucontext.h> + static void sigill_handler_sse_os(int signal, siginfo_t *si, void *uc) + { + (void)signal, (void)si; + ((ucontext_t*)uc)->uc_mcontext.gregs[14/*REG_EIP*/] += 3 + 3 + 6; + } +# elif defined(_MSC_VER) +# include <windows.h> +# endif +#endif void FLAC__cpu_info(FLAC__CPUInfo *info) { +/* + * IA32-specific + */ #ifdef FLAC__CPU_IA32 + FLAC__bool ia32_fxsr = false; + FLAC__bool ia32_osxsave = false; + (void) ia32_fxsr; (void) ia32_osxsave; /* to avoid warnings about unused variables */ + memset(info, 0, sizeof(*info)); info->type = FLAC__CPUINFO_TYPE_IA32; -#if !defined FLAC__NO_ASM && defined FLAC__HAS_NASM - info->use_asm = true; +#if !defined FLAC__NO_ASM && (defined FLAC__HAS_NASM || defined FLAC__HAS_X86INTRIN) + info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */ +#ifdef FLAC__HAS_X86INTRIN + if(!FLAC__cpu_have_cpuid_x86()) + return; +#else + if(!FLAC__cpu_have_cpuid_asm_ia32()) + return; +#endif { - unsigned cpuid = FLAC__cpu_info_asm_ia32(); - info->data.ia32.cmov = (cpuid & FLAC__CPUINFO_IA32_CPUID_CMOV)? true : false; - info->data.ia32.mmx = (cpuid & FLAC__CPUINFO_IA32_CPUID_MMX)? true : false; - info->data.ia32.fxsr = (cpuid & FLAC__CPUINFO_IA32_CPUID_FXSR)? true : false; - info->data.ia32.sse = (cpuid & FLAC__CPUINFO_IA32_CPUID_SSE)? true : false; - info->data.ia32.sse2 = (cpuid & FLAC__CPUINFO_IA32_CPUID_SSE2)? true : false; - -#ifndef FLAC__SSE_OS - info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false; -#endif - -#ifdef FLAC__USE_3DNOW - cpuid = FLAC__cpu_info_extended_amd_asm_ia32(); - info->data.ia32._3dnow = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW)? true : false; - info->data.ia32.ext3dnow = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW)? true : false; - info->data.ia32.extmmx = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX)? true : false; + /* http://www.sandpile.org/x86/cpuid.htm */ +#ifdef FLAC__HAS_X86INTRIN + FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx; + FLAC__cpu_info_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); #else - info->data.ia32._3dnow = info->data.ia32.ext3dnow = info->data.ia32.extmmx = false; + FLAC__uint32 flags_ecx, flags_edx; + FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx); +#endif + info->ia32.cmov = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV )? true : false; + info->ia32.mmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX )? true : false; + ia32_fxsr = (flags_edx & FLAC__CPUINFO_IA32_CPUID_FXSR )? true : false; + info->ia32.sse = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE )? true : false; + info->ia32.sse2 = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 )? true : false; + info->ia32.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false; + info->ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false; + info->ia32.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41)? true : false; + info->ia32.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42)? true : false; +#if defined FLAC__HAS_X86INTRIN && defined FLAC__AVX_SUPPORTED + ia32_osxsave = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_OSXSAVE)? true : false; + info->ia32.avx = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_AVX )? true : false; + info->ia32.fma = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_FMA )? true : false; + FLAC__cpu_info_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); + info->ia32.avx2 = (flags_ebx & FLAC__CPUINFO_IA32_CPUID_AVX2 )? true : false; #endif } + +#ifdef DEBUG + fprintf(stderr, "CPU info (IA-32):\n"); + fprintf(stderr, " CMOV ....... %c\n", info->ia32.cmov ? 'Y' : 'n'); + fprintf(stderr, " MMX ........ %c\n", info->ia32.mmx ? 'Y' : 'n'); + fprintf(stderr, " SSE ........ %c\n", info->ia32.sse ? 'Y' : 'n'); + fprintf(stderr, " SSE2 ....... %c\n", info->ia32.sse2 ? 'Y' : 'n'); + fprintf(stderr, " SSE3 ....... %c\n", info->ia32.sse3 ? 'Y' : 'n'); + fprintf(stderr, " SSSE3 ...... %c\n", info->ia32.ssse3 ? 'Y' : 'n'); + fprintf(stderr, " SSE41 ...... %c\n", info->ia32.sse41 ? 'Y' : 'n'); + fprintf(stderr, " SSE42 ...... %c\n", info->ia32.sse42 ? 'Y' : 'n'); +# if defined FLAC__HAS_X86INTRIN && defined FLAC__AVX_SUPPORTED + fprintf(stderr, " AVX ........ %c\n", info->ia32.avx ? 'Y' : 'n'); + fprintf(stderr, " FMA ........ %c\n", info->ia32.fma ? 'Y' : 'n'); + fprintf(stderr, " AVX2 ....... %c\n", info->ia32.avx2 ? 'Y' : 'n'); +# endif +#endif + + /* + * now have to check for OS support of SSE instructions + */ + if(info->ia32.sse) { +#if defined FLAC__NO_SSE_OS + /* assume user knows better than us; turn it off */ + disable_sse(info); +#elif defined FLAC__SSE_OS + /* assume user knows better than us; leave as detected above */ +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__) + int sse = 0; + size_t len; + /* at least one of these must work: */ + len = sizeof(sse); sse = sse || (sysctlbyname("hw.instruction_sse", &sse, &len, NULL, 0) == 0 && sse); + len = sizeof(sse); sse = sse || (sysctlbyname("hw.optional.sse" , &sse, &len, NULL, 0) == 0 && sse); /* __APPLE__ ? */ + if(!sse) + disable_sse(info); +#elif defined(__NetBSD__) || defined (__OpenBSD__) +# if __NetBSD_Version__ >= 105250000 || (defined __OpenBSD__) + int val = 0, mib[2] = { CTL_MACHDEP, CPU_SSE }; + size_t len = sizeof(val); + if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val) + disable_sse(info); + else { /* double-check SSE2 */ + mib[1] = CPU_SSE2; + len = sizeof(val); + if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val) { + disable_sse(info); + info->ia32.sse = true; + } + } +# else + disable_sse(info); +# endif +#elif defined(__linux__) + int sse = 0; + struct sigaction sigill_save; + struct sigaction sigill_sse; + sigill_sse.sa_sigaction = sigill_handler_sse_os; + __sigemptyset(&sigill_sse.sa_mask); + sigill_sse.sa_flags = SA_SIGINFO | SA_RESETHAND; /* SA_RESETHAND just in case our SIGILL return jump breaks, so we don't get stuck in a loop */ + if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save)) + { + /* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */ + /* see sigill_handler_sse_os() for an explanation of the following: */ + asm volatile ( + "xorps %%xmm0,%%xmm0\n\t" /* will cause SIGILL if unsupported by OS */ + "incl %0\n\t" /* SIGILL handler will jump over this */ + /* landing zone */ + "nop\n\t" /* SIGILL jump lands here if "inc" is 9 bytes */ + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" /* SIGILL jump lands here if "inc" is 3 bytes (expected) */ + "nop\n\t" + "nop" /* SIGILL jump lands here if "inc" is 1 byte */ + : "=r"(sse) + : "0"(sse) + ); + + sigaction(SIGILL, &sigill_save, NULL); + } + + if(!sse) + disable_sse(info); +#elif defined(_MSC_VER) + __try { + __asm { + xorps xmm0,xmm0 + } + } + __except(EXCEPTION_EXECUTE_HANDLER) { + if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION) + disable_sse(info); + } +#elif defined(__GNUC__) /* MinGW goes here */ + int sse = 0; + /* Based on the idea described in Agner Fog's manual "Optimizing subroutines in assembly language" */ + /* In theory, not guaranteed to detect lack of OS SSE support on some future Intel CPUs, but in practice works (see the aforementioned manual) */ + if (ia32_fxsr) { + struct { + FLAC__uint32 buff[128]; + } __attribute__((aligned(16))) fxsr; + FLAC__uint32 old_val, new_val; + + asm volatile ("fxsave %0" : "=m" (fxsr) : "m" (fxsr)); + old_val = fxsr.buff[50]; + fxsr.buff[50] ^= 0x0013c0de; /* change value in the buffer */ + asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr)); /* try to change SSE register */ + fxsr.buff[50] = old_val; /* restore old value in the buffer */ + asm volatile ("fxsave %0 " : "=m" (fxsr) : "m" (fxsr)); /* old value will be overwritten if SSE register was changed */ + new_val = fxsr.buff[50]; /* == old_val if FXRSTOR didn't change SSE register and (old_val ^ 0x0013c0de) otherwise */ + fxsr.buff[50] = old_val; /* again restore old value in the buffer */ + asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr)); /* restore old values of registers */ + + if ((old_val^new_val) == 0x0013c0de) + sse = 1; + } + if(!sse) + disable_sse(info); +#else + /* no way to test, disable to be safe */ + disable_sse(info); +#endif +#ifdef DEBUG + fprintf(stderr, " SSE OS sup . %c\n", info->ia32.sse ? 'Y' : 'n'); +#endif + } + else /* info->ia32.sse == false */ + disable_sse(info); + + /* + * now have to check for OS support of AVX instructions + */ + if(info->ia32.avx && ia32_osxsave) { + FLAC__uint32 ecr = FLAC__cpu_xgetbv_x86(); + if ((ecr & 0x6) != 0x6) + disable_avx(info); +#ifdef DEBUG + fprintf(stderr, " AVX OS sup . %c\n", info->ia32.avx ? 'Y' : 'n'); +#endif + } + else /* no OS AVX support*/ + disable_avx(info); #else info->use_asm = false; #endif -#elif defined FLAC__CPU_PPC - info->type = FLAC__CPUINFO_TYPE_PPC; -#if !defined FLAC__NO_ASM + +/* + * x86-64-specific + */ +#elif defined FLAC__CPU_X86_64 + FLAC__bool x86_osxsave = false; + (void) x86_osxsave; /* to avoid warnings about unused variables */ + memset(info, 0, sizeof(*info)); + info->type = FLAC__CPUINFO_TYPE_X86_64; +#if !defined FLAC__NO_ASM && defined FLAC__HAS_X86INTRIN info->use_asm = true; -#ifdef FLAC__USE_ALTIVEC -#if defined __APPLE__ && defined __MACH__ { - int selectors[2] = { CTL_HW, HW_VECTORUNIT }; - int result = 0; - size_t length = sizeof(result); - int error = sysctl(selectors, 2, &result, &length, 0, 0); + /* http://www.sandpile.org/x86/cpuid.htm */ + FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx; + FLAC__cpu_info_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); + info->x86.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false; + info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false; + info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41)? true : false; + info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42)? true : false; +#if defined FLAC__AVX_SUPPORTED + x86_osxsave = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_OSXSAVE)? true : false; + info->x86.avx = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_AVX )? true : false; + info->x86.fma = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_FMA )? true : false; + FLAC__cpu_info_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); + info->x86.avx2 = (flags_ebx & FLAC__CPUINFO_IA32_CPUID_AVX2 )? true : false; +#endif + } +#ifdef DEBUG + fprintf(stderr, "CPU info (x86-64):\n"); + fprintf(stderr, " SSE3 ....... %c\n", info->x86.sse3 ? 'Y' : 'n'); + fprintf(stderr, " SSSE3 ...... %c\n", info->x86.ssse3 ? 'Y' : 'n'); + fprintf(stderr, " SSE41 ...... %c\n", info->x86.sse41 ? 'Y' : 'n'); + fprintf(stderr, " SSE42 ...... %c\n", info->x86.sse42 ? 'Y' : 'n'); +# if defined FLAC__AVX_SUPPORTED + fprintf(stderr, " AVX ........ %c\n", info->x86.avx ? 'Y' : 'n'); + fprintf(stderr, " FMA ........ %c\n", info->x86.fma ? 'Y' : 'n'); + fprintf(stderr, " AVX2 ....... %c\n", info->x86.avx2 ? 'Y' : 'n'); +# endif +#endif - info->data.ppc.altivec = error==0 ? result!=0 : 0; + /* + * now have to check for OS support of AVX instructions + */ + if(info->x86.avx && x86_osxsave) { + FLAC__uint32 ecr = FLAC__cpu_xgetbv_x86(); + if ((ecr & 0x6) != 0x6) + disable_avx(info); +#ifdef DEBUG + fprintf(stderr, " AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n'); +#endif } -#else /* __APPLE__ && __MACH__ */ - /* don't know of any other thread-safe way to check */ - info->data.ppc.altivec = 0; -#endif /* __APPLE__ && __MACH__ */ -#else /* FLAC__USE_ALTIVEC */ - info->data.ppc.altivec = 0; -#endif /* FLAC__USE_ALTIVEC */ -#else /* FLAC__NO_ASM */ + else /* no OS AVX support*/ + disable_avx(info); +#else info->use_asm = false; -#endif /* FLAC__NO_ASM */ +#endif + +/* + * unknown CPU + */ #else info->type = FLAC__CPUINFO_TYPE_UNKNOWN; info->use_asm = false; #endif } + +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN + +#if defined _MSC_VER +#include <intrin.h> /* for __cpuid() and _xgetbv() */ +#elif defined __GNUC__ && defined HAVE_CPUID_H +#include <cpuid.h> /* for __get_cpuid() and __get_cpuid_max() */ +#endif + +FLAC__uint32 FLAC__cpu_have_cpuid_x86(void) +{ +#ifdef FLAC__CPU_X86_64 + return 1; +#else +# if defined _MSC_VER || defined __INTEL_COMPILER /* Do they support CPUs w/o CPUID support (or OSes that work on those CPUs)? */ + FLAC__uint32 flags1, flags2; + __asm { + pushfd + pushfd + pop eax + mov flags1, eax + xor eax, 0x200000 + push eax + popfd + pushfd + pop eax + mov flags2, eax + popfd + } + if (((flags1^flags2) & 0x200000) != 0) + return 1; + else + return 0; +# elif defined __GNUC__ && defined HAVE_CPUID_H + if (__get_cpuid_max(0, 0) != 0) + return 1; + else + return 0; +# else + return 0; +# endif +#endif +} + +void FLAC__cpu_info_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx) +{ +#if defined _MSC_VER || defined __INTEL_COMPILER + int cpuinfo[4]; + int ext = level & 0x80000000; + __cpuid(cpuinfo, ext); + if((unsigned)cpuinfo[0] < level) { + *eax = *ebx = *ecx = *edx = 0; + return; + } +#if defined FLAC__AVX_SUPPORTED + __cpuidex(cpuinfo, level, 0); /* for AVX2 detection */ +#else + __cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */ +#endif + *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3]; +#elif defined __GNUC__ && defined HAVE_CPUID_H + FLAC__uint32 ext = level & 0x80000000; + __cpuid(ext, *eax, *ebx, *ecx, *edx); + if (*eax < level) { + *eax = *ebx = *ecx = *edx = 0; + return; + } + __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx); +#else + *eax = *ebx = *ecx = *edx = 0; +#endif +} + +FLAC__uint32 FLAC__cpu_xgetbv_x86(void) +{ +#if (defined _MSC_VER || defined __INTEL_COMPILER) && defined FLAC__AVX_SUPPORTED + return (FLAC__uint32)_xgetbv(0); +#elif defined __GNUC__ + FLAC__uint32 lo, hi; + asm volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0)); + return lo; +#else + return 0; +#endif +} + +#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */ diff --git a/sys/src/cmd/audio/libFLAC/crc.c b/sys/src/cmd/audio/libFLAC/crc.c index f453f8c7a..de2cb1884 100644 --- a/sys/src/cmd/audio/libFLAC/crc.c +++ b/sys/src/cmd/audio/libFLAC/crc.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,6 +30,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include "private/crc.h" /* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */ @@ -70,7 +75,7 @@ FLAC__byte const FLAC__crc8_table[256] = { /* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */ -FLAC__uint16 FLAC__crc16_table[256] = { +unsigned const FLAC__crc16_table[256] = { 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, @@ -127,23 +132,12 @@ FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len) return crc; } -void FLAC__crc16_update(const FLAC__byte data, FLAC__uint16 *crc) -{ - *crc = (*crc<<8) ^ FLAC__crc16_table[(*crc>>8) ^ data]; -} - -void FLAC__crc16_update_block(const FLAC__byte *data, unsigned len, FLAC__uint16 *crc) -{ - while(len--) - *crc = (*crc<<8) ^ FLAC__crc16_table[(*crc>>8) ^ *data++]; -} - -FLAC__uint16 FLAC__crc16(const FLAC__byte *data, unsigned len) +unsigned FLAC__crc16(const FLAC__byte *data, unsigned len) { - FLAC__uint16 crc = 0; + unsigned crc = 0; while(len--) - crc = (crc<<8) ^ FLAC__crc16_table[(crc>>8) ^ *data++]; + crc = ((crc<<8) ^ FLAC__crc16_table[(crc>>8) ^ *data++]) & 0xffff; return crc; } diff --git a/sys/src/cmd/audio/libFLAC/file_decoder.c b/sys/src/cmd/audio/libFLAC/file_decoder.c deleted file mode 100644 index c5ea3e2bf..000000000 --- a/sys/src/cmd/audio/libFLAC/file_decoder.c +++ /dev/null @@ -1,675 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 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 <stdio.h> -#include <stdlib.h> /* for malloc() */ -#include <string.h> /* for strcmp() */ -#include <sys/stat.h> /* for stat() */ -#if defined _MSC_VER || defined __MINGW32__ -#include <io.h> /* for _setmode() */ -#include <fcntl.h> /* for _O_BINARY */ -#elif defined __CYGWIN__ -#include <io.h> /* for setmode(), O_BINARY */ -#include <fcntl.h> /* for _O_BINARY */ -#endif -#include "FLAC/assert.h" -#include "protected/file_decoder.h" -#include "protected/seekable_stream_decoder.h" - -/*********************************************************************** - * - * Private class method prototypes - * - ***********************************************************************/ - -static void set_defaults_(FLAC__FileDecoder *decoder); -static FILE *get_binary_stdin_(void); -static FLAC__SeekableStreamDecoderReadStatus read_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data); -static FLAC__SeekableStreamDecoderSeekStatus seek_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); -static FLAC__SeekableStreamDecoderTellStatus tell_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); -static FLAC__SeekableStreamDecoderLengthStatus length_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); -static FLAC__bool eof_callback_(const FLAC__SeekableStreamDecoder *decoder, void *client_data); -static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); -static void metadata_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); -static void error_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); - -/*********************************************************************** - * - * Private class data - * - ***********************************************************************/ - -typedef struct FLAC__FileDecoderPrivate { - FLAC__FileDecoderWriteCallback write_callback; - FLAC__FileDecoderMetadataCallback metadata_callback; - FLAC__FileDecoderErrorCallback error_callback; - void *client_data; - FILE *file; - char *filename; /* == NULL if stdin */ - FLAC__SeekableStreamDecoder *seekable_stream_decoder; -} FLAC__FileDecoderPrivate; - -/*********************************************************************** - * - * Public static class data - * - ***********************************************************************/ - -FLAC_API const char * const FLAC__FileDecoderStateString[] = { - "FLAC__FILE_DECODER_OK", - "FLAC__FILE_DECODER_END_OF_FILE", - "FLAC__FILE_DECODER_ERROR_OPENING_FILE", - "FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR", - "FLAC__FILE_DECODER_SEEK_ERROR", - "FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR", - "FLAC__FILE_DECODER_ALREADY_INITIALIZED", - "FLAC__FILE_DECODER_INVALID_CALLBACK", - "FLAC__FILE_DECODER_UNINITIALIZED" -}; - -FLAC_API FLAC__SeekableStreamDecoder *FLAC__seekable_stream_decoder_new(void); - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -FLAC_API FLAC__FileDecoder *FLAC__file_decoder_new(void) -{ - FLAC__FileDecoder *decoder; - - FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ - - decoder = (FLAC__FileDecoder*)calloc(1, sizeof(FLAC__FileDecoder)); - if(decoder == 0) { - return 0; - } - - decoder->protected_ = (FLAC__FileDecoderProtected*)calloc(1, sizeof(FLAC__FileDecoderProtected)); - if(decoder->protected_ == 0) { - free(decoder); - return 0; - } - - decoder->private_ = (FLAC__FileDecoderPrivate*)calloc(1, sizeof(FLAC__FileDecoderPrivate)); - if(decoder->private_ == 0) { - free(decoder->protected_); - free(decoder); - return 0; - } - - decoder->private_->seekable_stream_decoder = FLAC__seekable_stream_decoder_new(); - if(0 == decoder->private_->seekable_stream_decoder) { - free(decoder->private_); - free(decoder->protected_); - free(decoder); - return 0; - } - - decoder->private_->file = 0; - - set_defaults_(decoder); - - decoder->protected_->state = FLAC__FILE_DECODER_UNINITIALIZED; - - return decoder; -} - -FLAC_API void FLAC__file_decoder_delete(FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); - - (void)FLAC__file_decoder_finish(decoder); - - FLAC__seekable_stream_decoder_delete(decoder->private_->seekable_stream_decoder); - - free(decoder->private_); - free(decoder->protected_); - free(decoder); -} - -/*********************************************************************** - * - * Public class methods - * - ***********************************************************************/ - -FLAC_API FLAC__FileDecoderState FLAC__file_decoder_init(FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return decoder->protected_->state = FLAC__FILE_DECODER_ALREADY_INITIALIZED; - - if(0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback) - return decoder->protected_->state = FLAC__FILE_DECODER_INVALID_CALLBACK; - - if(0 == decoder->private_->filename) - decoder->private_->file = get_binary_stdin_(); - else - decoder->private_->file = fopen(decoder->private_->filename, "rb"); - - if(decoder->private_->file == 0) - return decoder->protected_->state = FLAC__FILE_DECODER_ERROR_OPENING_FILE; - - FLAC__seekable_stream_decoder_set_read_callback(decoder->private_->seekable_stream_decoder, read_callback_); - FLAC__seekable_stream_decoder_set_seek_callback(decoder->private_->seekable_stream_decoder, seek_callback_); - FLAC__seekable_stream_decoder_set_tell_callback(decoder->private_->seekable_stream_decoder, tell_callback_); - FLAC__seekable_stream_decoder_set_length_callback(decoder->private_->seekable_stream_decoder, length_callback_); - FLAC__seekable_stream_decoder_set_eof_callback(decoder->private_->seekable_stream_decoder, eof_callback_); - FLAC__seekable_stream_decoder_set_write_callback(decoder->private_->seekable_stream_decoder, write_callback_); - FLAC__seekable_stream_decoder_set_metadata_callback(decoder->private_->seekable_stream_decoder, metadata_callback_); - FLAC__seekable_stream_decoder_set_error_callback(decoder->private_->seekable_stream_decoder, error_callback_); - FLAC__seekable_stream_decoder_set_client_data(decoder->private_->seekable_stream_decoder, decoder); - - if(FLAC__seekable_stream_decoder_init(decoder->private_->seekable_stream_decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) - return decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR; - - return decoder->protected_->state = FLAC__FILE_DECODER_OK; -} - -FLAC_API FLAC__bool FLAC__file_decoder_finish(FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - - if(decoder->protected_->state == FLAC__FILE_DECODER_UNINITIALIZED) - return true; - - FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); - - if(0 != decoder->private_->file && decoder->private_->file != stdin) { - fclose(decoder->private_->file); - decoder->private_->file = 0; - } - - if(0 != decoder->private_->filename) { - free(decoder->private_->filename); - decoder->private_->filename = 0; - } - - set_defaults_(decoder); - - decoder->protected_->state = FLAC__FILE_DECODER_UNINITIALIZED; - - return FLAC__seekable_stream_decoder_finish(decoder->private_->seekable_stream_decoder); -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_md5_checking(FLAC__FileDecoder *decoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_decoder_set_md5_checking(decoder->private_->seekable_stream_decoder, value); -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_filename(FLAC__FileDecoder *decoder, const char *value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != value); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - if(0 != decoder->private_->filename) { - free(decoder->private_->filename); - decoder->private_->filename = 0; - } - if(0 != strcmp(value, "-")) { - if(0 == (decoder->private_->filename = (char*)malloc(strlen(value)+1))) { - decoder->protected_->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - strcpy(decoder->private_->filename, value); - } - return true; -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_write_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderWriteCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - decoder->private_->write_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderMetadataCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - decoder->private_->metadata_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_error_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderErrorCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - decoder->private_->error_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_client_data(FLAC__FileDecoder *decoder, void *value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - decoder->private_->client_data = value; - return true; -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond(FLAC__FileDecoder *decoder, FLAC__MetadataType type) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_decoder_set_metadata_respond(decoder->private_->seekable_stream_decoder, type); -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4]) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_decoder_set_metadata_respond_application(decoder->private_->seekable_stream_decoder, id); -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond_all(FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_decoder_set_metadata_respond_all(decoder->private_->seekable_stream_decoder); -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore(FLAC__FileDecoder *decoder, FLAC__MetadataType type) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_decoder_set_metadata_ignore(decoder->private_->seekable_stream_decoder, type); -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4]) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder->private_->seekable_stream_decoder, id); -} - -FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore_all(FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); - if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder->private_->seekable_stream_decoder); -} - -FLAC_API FLAC__FileDecoderState FLAC__file_decoder_get_state(const FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->state; -} - -FLAC_API FLAC__SeekableStreamDecoderState FLAC__file_decoder_get_seekable_stream_decoder_state(const FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__seekable_stream_decoder_get_state(decoder->private_->seekable_stream_decoder); -} - -FLAC_API FLAC__StreamDecoderState FLAC__file_decoder_get_stream_decoder_state(const FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__seekable_stream_decoder_get_stream_decoder_state(decoder->private_->seekable_stream_decoder); -} - -FLAC_API const char *FLAC__file_decoder_get_resolved_state_string(const FLAC__FileDecoder *decoder) -{ - if(decoder->protected_->state != FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR) - return FLAC__FileDecoderStateString[decoder->protected_->state]; - else - return FLAC__seekable_stream_decoder_get_resolved_state_string(decoder->private_->seekable_stream_decoder); -} - -FLAC_API FLAC__bool FLAC__file_decoder_get_md5_checking(const FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__seekable_stream_decoder_get_md5_checking(decoder->private_->seekable_stream_decoder); -} - -FLAC_API unsigned FLAC__file_decoder_get_channels(const FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__seekable_stream_decoder_get_channels(decoder->private_->seekable_stream_decoder); -} - -FLAC_API FLAC__ChannelAssignment FLAC__file_decoder_get_channel_assignment(const FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__seekable_stream_decoder_get_channel_assignment(decoder->private_->seekable_stream_decoder); -} - -FLAC_API unsigned FLAC__file_decoder_get_bits_per_sample(const FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__seekable_stream_decoder_get_bits_per_sample(decoder->private_->seekable_stream_decoder); -} - -FLAC_API unsigned FLAC__file_decoder_get_sample_rate(const FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__seekable_stream_decoder_get_sample_rate(decoder->private_->seekable_stream_decoder); -} - -FLAC_API unsigned FLAC__file_decoder_get_blocksize(const FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__seekable_stream_decoder_get_blocksize(decoder->private_->seekable_stream_decoder); -} - -FLAC_API FLAC__bool FLAC__file_decoder_get_decode_position(const FLAC__FileDecoder *decoder, FLAC__uint64 *position) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__seekable_stream_decoder_get_decode_position(decoder->private_->seekable_stream_decoder, position); -} - -FLAC_API FLAC__bool FLAC__file_decoder_process_single(FLAC__FileDecoder *decoder) -{ - FLAC__bool ret; - FLAC__ASSERT(0 != decoder); - - if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) - decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE; - - if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE) - return true; - - FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); - - ret = FLAC__seekable_stream_decoder_process_single(decoder->private_->seekable_stream_decoder); - if(!ret) - decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR; - - return ret; -} - -FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_metadata(FLAC__FileDecoder *decoder) -{ - FLAC__bool ret; - FLAC__ASSERT(0 != decoder); - - if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) - decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE; - - if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE) - return true; - - FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); - - ret = FLAC__seekable_stream_decoder_process_until_end_of_metadata(decoder->private_->seekable_stream_decoder); - if(!ret) - decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR; - - return ret; -} - -FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_file(FLAC__FileDecoder *decoder) -{ - FLAC__bool ret; - FLAC__ASSERT(0 != decoder); - - if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) - decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE; - - if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE) - return true; - - FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); - - ret = FLAC__seekable_stream_decoder_process_until_end_of_stream(decoder->private_->seekable_stream_decoder); - if(!ret) - decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR; - - return ret; -} - -FLAC_API FLAC__bool FLAC__file_decoder_skip_single_frame(FLAC__FileDecoder *decoder) -{ - FLAC__bool ret; - FLAC__ASSERT(0 != decoder); - - if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) - decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE; - - if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE) - return true; - - FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); - - ret = FLAC__seekable_stream_decoder_skip_single_frame(decoder->private_->seekable_stream_decoder); - if(!ret) - decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR; - - return ret; -} - -FLAC_API FLAC__bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, FLAC__uint64 sample) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK || decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE); - - if(decoder->private_->filename == 0) { /* means the file is stdin... */ - decoder->protected_->state = FLAC__FILE_DECODER_SEEK_ERROR; - return false; - } - - if(!FLAC__seekable_stream_decoder_seek_absolute(decoder->private_->seekable_stream_decoder, sample)) { - decoder->protected_->state = FLAC__FILE_DECODER_SEEK_ERROR; - return false; - } - else { - decoder->protected_->state = FLAC__FILE_DECODER_OK; - return true; - } -} - - -/*********************************************************************** - * - * Private class methods - * - ***********************************************************************/ - -void set_defaults_(FLAC__FileDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - - decoder->private_->filename = 0; - decoder->private_->write_callback = 0; - decoder->private_->metadata_callback = 0; - decoder->private_->error_callback = 0; - decoder->private_->client_data = 0; -} - -/* - * This will forcibly set stdin to binary mode (for OSes that require it) - */ -FILE *get_binary_stdin_(void) -{ - /* if something breaks here it is probably due to the presence or - * absence of an underscore before the identifiers 'setmode', - * 'fileno', and/or 'O_BINARY'; check your system header files. - */ -#if defined _MSC_VER || defined __MINGW32__ - _setmode(_fileno(stdin), _O_BINARY); -#elif defined __CYGWIN__ - /* almost certainly not needed for any modern Cygwin, but let's be safe... */ - setmode(_fileno(stdin), _O_BINARY); -#endif - - return stdin; -} - -FLAC__SeekableStreamDecoderReadStatus read_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) -{ - FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; - (void)decoder; - - if(*bytes > 0) { - *bytes = (unsigned)fread(buffer, sizeof(FLAC__byte), *bytes, file_decoder->private_->file); - if(ferror(file_decoder->private_->file)) { - return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; - } - else { - return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; - } - } - else - return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; /* abort to avoid a deadlock */ -} - -FLAC__SeekableStreamDecoderSeekStatus seek_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) -{ - FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; - (void)decoder; - - if(fseek(file_decoder->private_->file, (long)absolute_byte_offset, SEEK_SET) < 0) - return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; - else - return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; -} - -FLAC__SeekableStreamDecoderTellStatus tell_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) -{ - FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; - long pos; - (void)decoder; - - if((pos = ftell(file_decoder->private_->file)) < 0) - return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR; - else { - *absolute_byte_offset = (FLAC__uint64)pos; - return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; - } -} - -FLAC__SeekableStreamDecoderLengthStatus length_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) -{ - FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; - struct stat filestats; - (void)decoder; - - if(0 == file_decoder->private_->filename || stat(file_decoder->private_->filename, &filestats) != 0) - return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR; - else { - *stream_length = (FLAC__uint64)filestats.st_size; - return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; - } -} - -FLAC__bool eof_callback_(const FLAC__SeekableStreamDecoder *decoder, void *client_data) -{ - FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; - (void)decoder; - - return feof(file_decoder->private_->file)? true : false; -} - -FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) -{ - FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; - (void)decoder; - - return file_decoder->private_->write_callback(file_decoder, frame, buffer, file_decoder->private_->client_data); -} - -void metadata_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) -{ - FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; - (void)decoder; - - file_decoder->private_->metadata_callback(file_decoder, metadata, file_decoder->private_->client_data); -} - -void error_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) -{ - FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; - (void)decoder; - - file_decoder->private_->error_callback(file_decoder, status, file_decoder->private_->client_data); -} diff --git a/sys/src/cmd/audio/libFLAC/file_encoder.c b/sys/src/cmd/audio/libFLAC/file_encoder.c deleted file mode 100644 index bc899b56a..000000000 --- a/sys/src/cmd/audio/libFLAC/file_encoder.c +++ /dev/null @@ -1,777 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2002,2003,2004 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 <stdio.h> -#include <stdlib.h> /* for malloc() */ -#include <string.h> /* for strlen(), strcpy() */ -#include "FLAC/assert.h" -#include "protected/file_encoder.h" - -#ifdef max -#undef max -#endif -#define max(x,y) ((x)>(y)?(x):(y)) - -/*********************************************************************** - * - * Private class method prototypes - * - ***********************************************************************/ - -/* unpublished debug routines */ -extern FLAC__bool FLAC__seekable_stream_encoder_disable_constant_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value); -extern FLAC__bool FLAC__seekable_stream_encoder_disable_fixed_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value); -extern FLAC__bool FLAC__seekable_stream_encoder_disable_verbatim_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value); - -static void set_defaults_(FLAC__FileEncoder *encoder); -static FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); -static FLAC__SeekableStreamEncoderTellStatus tell_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); -static FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data); - -/*********************************************************************** - * - * Private class data - * - ***********************************************************************/ - -typedef struct FLAC__FileEncoderPrivate { - FLAC__FileEncoderProgressCallback progress_callback; - void *client_data; - char *filename; - FLAC__uint64 bytes_written; - FLAC__uint64 samples_written; - unsigned frames_written; - unsigned total_frames_estimate; - FLAC__SeekableStreamEncoder *seekable_stream_encoder; - FILE *file; -} FLAC__FileEncoderPrivate; - -/*********************************************************************** - * - * Public static class data - * - ***********************************************************************/ - -FLAC_API const char * const FLAC__FileEncoderStateString[] = { - "FLAC__FILE_ENCODER_OK", - "FLAC__FILE_ENCODER_NO_FILENAME", - "FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR", - "FLAC__FILE_ENCODER_FATAL_ERROR_WHILE_WRITING", - "FLAC__FILE_ENCODER_ERROR_OPENING_FILE", - "FLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR", - "FLAC__FILE_ENCODER_ALREADY_INITIALIZED", - "FLAC__FILE_ENCODER_UNINITIALIZED" -}; - -FLAC_API FLAC__SeekableStreamEncoder *FLAC__seekable_stream_encoder_new(void); - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -FLAC_API FLAC__FileEncoder *FLAC__file_encoder_new() -{ - FLAC__FileEncoder *encoder; - - FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ - - encoder = (FLAC__FileEncoder*)calloc(1, sizeof(FLAC__FileEncoder)); - if(encoder == 0) { - return 0; - } - - encoder->protected_ = (FLAC__FileEncoderProtected*)calloc(1, sizeof(FLAC__FileEncoderProtected)); - if(encoder->protected_ == 0) { - free(encoder); - return 0; - } - - encoder->private_ = (FLAC__FileEncoderPrivate*)calloc(1, sizeof(FLAC__FileEncoderPrivate)); - if(encoder->private_ == 0) { - free(encoder->protected_); - free(encoder); - return 0; - } - - encoder->private_->seekable_stream_encoder = FLAC__seekable_stream_encoder_new(); - if(0 == encoder->private_->seekable_stream_encoder) { - free(encoder->private_); - free(encoder->protected_); - free(encoder); - return 0; - } - - encoder->private_->file = 0; - - set_defaults_(encoder); - - encoder->protected_->state = FLAC__FILE_ENCODER_UNINITIALIZED; - - return encoder; -} - -FLAC_API void FLAC__file_encoder_delete(FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - - (void)FLAC__file_encoder_finish(encoder); - - FLAC__seekable_stream_encoder_delete(encoder->private_->seekable_stream_encoder); - - free(encoder->private_); - free(encoder->protected_); - free(encoder); -} - -/*********************************************************************** - * - * Public class methods - * - ***********************************************************************/ - -FLAC_API FLAC__FileEncoderState FLAC__file_encoder_init(FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return encoder->protected_->state = FLAC__FILE_ENCODER_ALREADY_INITIALIZED; - - if(0 == encoder->private_->filename) - return encoder->protected_->state = FLAC__FILE_ENCODER_NO_FILENAME; - - encoder->private_->file = fopen(encoder->private_->filename, "w+b"); - - if(encoder->private_->file == 0) - return encoder->protected_->state = FLAC__FILE_ENCODER_ERROR_OPENING_FILE; - - encoder->private_->bytes_written = 0; - encoder->private_->samples_written = 0; - encoder->private_->frames_written = 0; - - FLAC__seekable_stream_encoder_set_seek_callback(encoder->private_->seekable_stream_encoder, seek_callback_); - FLAC__seekable_stream_encoder_set_tell_callback(encoder->private_->seekable_stream_encoder, tell_callback_); - FLAC__seekable_stream_encoder_set_write_callback(encoder->private_->seekable_stream_encoder, write_callback_); - FLAC__seekable_stream_encoder_set_client_data(encoder->private_->seekable_stream_encoder, encoder); - - if(FLAC__seekable_stream_encoder_init(encoder->private_->seekable_stream_encoder) != FLAC__SEEKABLE_STREAM_ENCODER_OK) - return encoder->protected_->state = FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR; - - { - unsigned blocksize = FLAC__file_encoder_get_blocksize(encoder); - - FLAC__ASSERT(blocksize != 0); - encoder->private_->total_frames_estimate = (unsigned)((FLAC__file_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize); - } - - return encoder->protected_->state = FLAC__FILE_ENCODER_OK; -} - -FLAC_API void FLAC__file_encoder_finish(FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - - if(encoder->protected_->state == FLAC__FILE_ENCODER_UNINITIALIZED) - return; - - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - - /* FLAC__seekable_stream_encoder_finish() might write data so we must close the file after it. */ - - FLAC__seekable_stream_encoder_finish(encoder->private_->seekable_stream_encoder); - - if(0 != encoder->private_->file) { - fclose(encoder->private_->file); - encoder->private_->file = 0; - } - - if(0 != encoder->private_->filename) { - free(encoder->private_->filename); - encoder->private_->filename = 0; - } - - set_defaults_(encoder); - - encoder->protected_->state = FLAC__FILE_ENCODER_UNINITIALIZED; -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_verify(FLAC__FileEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_verify(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_streamable_subset(FLAC__FileEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_streamable_subset(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_do_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_do_mid_side_stereo(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_loose_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_channels(FLAC__FileEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_channels(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_bits_per_sample(FLAC__FileEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_bits_per_sample(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_sample_rate(FLAC__FileEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_sample_rate(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_blocksize(FLAC__FileEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_blocksize(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_max_lpc_order(FLAC__FileEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_max_lpc_order(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_qlp_coeff_precision(FLAC__FileEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_qlp_coeff_precision(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_do_qlp_coeff_prec_search(FLAC__FileEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_do_escape_coding(FLAC__FileEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_do_escape_coding(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_do_exhaustive_model_search(FLAC__FileEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_do_exhaustive_model_search(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_min_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_min_residual_partition_order(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_max_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_max_residual_partition_order(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_rice_parameter_search_dist(FLAC__FileEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_rice_parameter_search_dist(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_total_samples_estimate(FLAC__FileEncoder *encoder, FLAC__uint64 value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_total_samples_estimate(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_metadata(FLAC__FileEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_set_metadata(encoder->private_->seekable_stream_encoder, metadata, num_blocks); -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_filename(FLAC__FileEncoder *encoder, const char *value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != value); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - if(0 != encoder->private_->filename) { - free(encoder->private_->filename); - encoder->private_->filename = 0; - } - if(0 == (encoder->private_->filename = (char*)malloc(strlen(value)+1))) { - encoder->protected_->state = FLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR; - return false; - } - strcpy(encoder->private_->filename, value); - return true; -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_progress_callback(FLAC__FileEncoder *encoder, FLAC__FileEncoderProgressCallback value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - encoder->private_->progress_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__file_encoder_set_client_data(FLAC__FileEncoder *encoder, void *value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - encoder->private_->client_data = value; - return true; -} - -/* - * These three functions are not static, but not publically exposed in - * include/FLAC/ either. They are used by the test suite. - */ -FLAC_API FLAC__bool FLAC__file_encoder_disable_constant_subframes(FLAC__FileEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_disable_constant_subframes(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_disable_fixed_subframes(FLAC__FileEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_disable_fixed_subframes(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__file_encoder_disable_verbatim_subframes(FLAC__FileEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) - return false; - return FLAC__seekable_stream_encoder_disable_verbatim_subframes(encoder->private_->seekable_stream_encoder, value); -} - -FLAC_API FLAC__FileEncoderState FLAC__file_encoder_get_state(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->state; -} - -FLAC_API FLAC__SeekableStreamEncoderState FLAC__file_encoder_get_seekable_stream_encoder_state(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_state(encoder->private_->seekable_stream_encoder); -} - -FLAC_API FLAC__StreamEncoderState FLAC__file_encoder_get_stream_encoder_state(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_stream_encoder_state(encoder->private_->seekable_stream_encoder); -} - -FLAC_API FLAC__StreamDecoderState FLAC__file_encoder_get_verify_decoder_state(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_verify_decoder_state(encoder->private_->seekable_stream_encoder); -} - -FLAC_API const char *FLAC__file_encoder_get_resolved_state_string(const FLAC__FileEncoder *encoder) -{ - if(encoder->protected_->state != FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR) - return FLAC__FileEncoderStateString[encoder->protected_->state]; - else - return FLAC__seekable_stream_encoder_get_resolved_state_string(encoder->private_->seekable_stream_encoder); -} - -FLAC_API void FLAC__file_encoder_get_verify_decoder_error_stats(const FLAC__FileEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__seekable_stream_encoder_get_verify_decoder_error_stats(encoder->private_->seekable_stream_encoder, absolute_sample, frame_number, channel, sample, expected, got); -} - -FLAC_API FLAC__bool FLAC__file_encoder_get_verify(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_verify(encoder->private_->seekable_stream_encoder); -} - -FLAC_API FLAC__bool FLAC__file_encoder_get_streamable_subset(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_streamable_subset(encoder->private_->seekable_stream_encoder); -} - -FLAC_API FLAC__bool FLAC__file_encoder_get_do_mid_side_stereo(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_do_mid_side_stereo(encoder->private_->seekable_stream_encoder); -} - -FLAC_API FLAC__bool FLAC__file_encoder_get_loose_mid_side_stereo(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_loose_mid_side_stereo(encoder->private_->seekable_stream_encoder); -} - -FLAC_API unsigned FLAC__file_encoder_get_channels(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_channels(encoder->private_->seekable_stream_encoder); -} - -FLAC_API unsigned FLAC__file_encoder_get_bits_per_sample(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_bits_per_sample(encoder->private_->seekable_stream_encoder); -} - -FLAC_API unsigned FLAC__file_encoder_get_sample_rate(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_sample_rate(encoder->private_->seekable_stream_encoder); -} - -FLAC_API unsigned FLAC__file_encoder_get_blocksize(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_blocksize(encoder->private_->seekable_stream_encoder); -} - -FLAC_API unsigned FLAC__file_encoder_get_max_lpc_order(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_max_lpc_order(encoder->private_->seekable_stream_encoder); -} - -FLAC_API unsigned FLAC__file_encoder_get_qlp_coeff_precision(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_qlp_coeff_precision(encoder->private_->seekable_stream_encoder); -} - -FLAC_API FLAC__bool FLAC__file_encoder_get_do_qlp_coeff_prec_search(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(encoder->private_->seekable_stream_encoder); -} - -FLAC_API FLAC__bool FLAC__file_encoder_get_do_escape_coding(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_do_escape_coding(encoder->private_->seekable_stream_encoder); -} - -FLAC_API FLAC__bool FLAC__file_encoder_get_do_exhaustive_model_search(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_do_exhaustive_model_search(encoder->private_->seekable_stream_encoder); -} - -FLAC_API unsigned FLAC__file_encoder_get_min_residual_partition_order(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_min_residual_partition_order(encoder->private_->seekable_stream_encoder); -} - -FLAC_API unsigned FLAC__file_encoder_get_max_residual_partition_order(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_max_residual_partition_order(encoder->private_->seekable_stream_encoder); -} - -FLAC_API unsigned FLAC__file_encoder_get_rice_parameter_search_dist(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_rice_parameter_search_dist(encoder->private_->seekable_stream_encoder); -} - -FLAC_API FLAC__uint64 FLAC__file_encoder_get_total_samples_estimate(const FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__seekable_stream_encoder_get_total_samples_estimate(encoder->private_->seekable_stream_encoder); -} - -FLAC_API FLAC__bool FLAC__file_encoder_process(FLAC__FileEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - if(!FLAC__seekable_stream_encoder_process(encoder->private_->seekable_stream_encoder, buffer, samples)) { - encoder->protected_->state = FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR; - return false; - } - else - return true; -} - -/* 'samples' is channel-wide samples, e.g. for 1 second at 44100Hz, 'samples' = 44100 regardless of the number of channels */ -FLAC_API FLAC__bool FLAC__file_encoder_process_interleaved(FLAC__FileEncoder *encoder, const FLAC__int32 buffer[], unsigned samples) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - if(!FLAC__seekable_stream_encoder_process_interleaved(encoder->private_->seekable_stream_encoder, buffer, samples)) { - encoder->protected_->state = FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR; - return false; - } - else - return true; -} - - -/*********************************************************************** - * - * Private class methods - * - ***********************************************************************/ - -void set_defaults_(FLAC__FileEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - - encoder->private_->progress_callback = 0; - encoder->private_->client_data = 0; - encoder->private_->total_frames_estimate = 0; - encoder->private_->filename = 0; -} - -FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) -{ - FLAC__FileEncoder *file_encoder = (FLAC__FileEncoder*)client_data; - - (void)encoder; - - FLAC__ASSERT(0 != file_encoder); - - if(fseek(file_encoder->private_->file, (long)absolute_byte_offset, SEEK_SET) < 0) - return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR; - else - return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK; -} - -FLAC__SeekableStreamEncoderTellStatus tell_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) -{ - FLAC__FileEncoder *file_encoder = (FLAC__FileEncoder*)client_data; - long offset; - - (void)encoder; - - FLAC__ASSERT(0 != file_encoder); - - offset = ftell(file_encoder->private_->file); - - if(offset < 0) { - return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR; - } - else { - *absolute_byte_offset = (FLAC__uint64)offset; - return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK; - } -} - -#ifdef FLAC__VALGRIND_TESTING -static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - size_t ret = fwrite(ptr, size, nmemb, stream); - if(!ferror(stream)) - fflush(stream); - return ret; -} -#else -#define local__fwrite fwrite -#endif - -FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data) -{ - FLAC__FileEncoder *file_encoder = (FLAC__FileEncoder*)client_data; - - (void)encoder, (void)samples, (void)current_frame; - - FLAC__ASSERT(0 != file_encoder); - - if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, file_encoder->private_->file) == bytes) { - file_encoder->private_->bytes_written += bytes; - file_encoder->private_->samples_written += samples; - /* we keep a high watermark on the number of frames written because - * when the encoder goes back to write metadata, 'current_frame' - * will drop back to 0. - */ - file_encoder->private_->frames_written = max(file_encoder->private_->frames_written, current_frame+1); - if(0 != file_encoder->private_->progress_callback && samples > 0) - file_encoder->private_->progress_callback(file_encoder, file_encoder->private_->bytes_written, file_encoder->private_->samples_written, file_encoder->private_->frames_written, file_encoder->private_->total_frames_estimate, file_encoder->private_->client_data); - return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; - } - else - return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; -} diff --git a/sys/src/cmd/audio/libFLAC/fixed.c b/sys/src/cmd/audio/libFLAC/fixed.c index bf88461a6..74b31b328 100644 --- a/sys/src/cmd/audio/libFLAC/fixed.c +++ b/sys/src/cmd/audio/libFLAC/fixed.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,26 +30,194 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include <math.h> +#include <string.h> +#include "share/compat.h" +#include "private/bitmath.h" #include "private/fixed.h" +#include "private/macros.h" #include "FLAC/assert.h" -#ifndef M_LN2 -/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */ -#define M_LN2 0.69314718055994530942 -#endif - -#ifdef min -#undef min -#endif -#define min(x,y) ((x) < (y)? (x) : (y)) - #ifdef local_abs #undef local_abs #endif #define local_abs(x) ((unsigned)((x)<0? -(x) : (x))) -unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#ifdef FLAC__INTEGER_ONLY_LIBRARY +/* rbps stands for residual bits per sample + * + * (ln(2) * err) + * rbps = log (-----------) + * 2 ( n ) + */ +static FLAC__fixedpoint local__compute_rbps_integerized(FLAC__uint32 err, FLAC__uint32 n) +{ + FLAC__uint32 rbps; + unsigned bits; /* the number of bits required to represent a number */ + int fracbits; /* the number of bits of rbps that comprise the fractional part */ + + FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint)); + FLAC__ASSERT(err > 0); + FLAC__ASSERT(n > 0); + + FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE); + if(err <= n) + return 0; + /* + * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1. + * These allow us later to know we won't lose too much precision in the + * fixed-point division (err<<fracbits)/n. + */ + + fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2(err)+1); + + err <<= fracbits; + err /= n; + /* err now holds err/n with fracbits fractional bits */ + + /* + * Whittle err down to 16 bits max. 16 significant bits is enough for + * our purposes. + */ + FLAC__ASSERT(err > 0); + bits = FLAC__bitmath_ilog2(err)+1; + if(bits > 16) { + err >>= (bits-16); + fracbits -= (bits-16); + } + rbps = (FLAC__uint32)err; + + /* Multiply by fixed-point version of ln(2), with 16 fractional bits */ + rbps *= FLAC__FP_LN2; + fracbits += 16; + FLAC__ASSERT(fracbits >= 0); + + /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */ + { + const int f = fracbits & 3; + if(f) { + rbps >>= f; + fracbits -= f; + } + } + + rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1)); + + if(rbps == 0) + return 0; + + /* + * The return value must have 16 fractional bits. Since the whole part + * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits + * must be >= -3, these assertion allows us to be able to shift rbps + * left if necessary to get 16 fracbits without losing any bits of the + * whole part of rbps. + * + * There is a slight chance due to accumulated error that the whole part + * will require 6 bits, so we use 6 in the assertion. Really though as + * long as it fits in 13 bits (32 - (16 - (-3))) we are fine. + */ + FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6); + FLAC__ASSERT(fracbits >= -3); + + /* now shift the decimal point into place */ + if(fracbits < 16) + return rbps << (16-fracbits); + else if(fracbits > 16) + return rbps >> (fracbits-16); + else + return rbps; +} + +static FLAC__fixedpoint local__compute_rbps_wide_integerized(FLAC__uint64 err, FLAC__uint32 n) +{ + FLAC__uint32 rbps; + unsigned bits; /* the number of bits required to represent a number */ + int fracbits; /* the number of bits of rbps that comprise the fractional part */ + + FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint)); + FLAC__ASSERT(err > 0); + FLAC__ASSERT(n > 0); + + FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE); + if(err <= n) + return 0; + /* + * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1. + * These allow us later to know we won't lose too much precision in the + * fixed-point division (err<<fracbits)/n. + */ + + fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2_wide(err)+1); + + err <<= fracbits; + err /= n; + /* err now holds err/n with fracbits fractional bits */ + + /* + * Whittle err down to 16 bits max. 16 significant bits is enough for + * our purposes. + */ + FLAC__ASSERT(err > 0); + bits = FLAC__bitmath_ilog2_wide(err)+1; + if(bits > 16) { + err >>= (bits-16); + fracbits -= (bits-16); + } + rbps = (FLAC__uint32)err; + + /* Multiply by fixed-point version of ln(2), with 16 fractional bits */ + rbps *= FLAC__FP_LN2; + fracbits += 16; + FLAC__ASSERT(fracbits >= 0); + + /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */ + { + const int f = fracbits & 3; + if(f) { + rbps >>= f; + fracbits -= f; + } + } + + rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1)); + + if(rbps == 0) + return 0; + + /* + * The return value must have 16 fractional bits. Since the whole part + * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits + * must be >= -3, these assertion allows us to be able to shift rbps + * left if necessary to get 16 fracbits without losing any bits of the + * whole part of rbps. + * + * There is a slight chance due to accumulated error that the whole part + * will require 6 bits, so we use 6 in the assertion. Really though as + * long as it fits in 13 bits (32 - (16 - (-3))) we are fine. + */ + FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6); + FLAC__ASSERT(fracbits >= -3); + + /* now shift the decimal point into place */ + if(fracbits < 16) + return rbps << (16-fracbits); + else if(fracbits > 16) + return rbps >> (fracbits-16); + else + return rbps; +} +#endif + +#ifndef FLAC__INTEGER_ONLY_LIBRARY +unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#else +unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#endif { FLAC__int32 last_error_0 = data[-1]; FLAC__int32 last_error_1 = data[-1] - data[-2]; @@ -66,11 +235,11 @@ unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned d error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save; } - if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4)) + if(total_error_0 < flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4)) order = 0; - else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4)) + else if(total_error_1 < flac_min(flac_min(total_error_2, total_error_3), total_error_4)) order = 1; - else if(total_error_2 < min(total_error_3, total_error_4)) + else if(total_error_2 < flac_min(total_error_3, total_error_4)) order = 2; else if(total_error_3 < total_error_4) order = 3; @@ -85,16 +254,28 @@ unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned d FLAC__ASSERT(data_len > 0 || total_error_2 == 0); FLAC__ASSERT(data_len > 0 || total_error_3 == 0); FLAC__ASSERT(data_len > 0 || total_error_4 == 0); - residual_bits_per_sample[0] = (FLAC__real)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[1] = (FLAC__real)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[2] = (FLAC__real)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[3] = (FLAC__real)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[4] = (FLAC__real)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0); +#ifndef FLAC__INTEGER_ONLY_LIBRARY + residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0); +#else + residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_integerized(total_error_0, data_len) : 0; + residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_integerized(total_error_1, data_len) : 0; + residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_integerized(total_error_2, data_len) : 0; + residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_integerized(total_error_3, data_len) : 0; + residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_integerized(total_error_4, data_len) : 0; +#endif return order; } -unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#ifndef FLAC__INTEGER_ONLY_LIBRARY +unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#else +unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +#endif { FLAC__int32 last_error_0 = data[-1]; FLAC__int32 last_error_1 = data[-1] - data[-2]; @@ -116,11 +297,11 @@ unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsig error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save; } - if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4)) + if(total_error_0 < flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4)) order = 0; - else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4)) + else if(total_error_1 < flac_min(flac_min(total_error_2, total_error_3), total_error_4)) order = 1; - else if(total_error_2 < min(total_error_3, total_error_4)) + else if(total_error_2 < flac_min(total_error_3, total_error_4)) order = 2; else if(total_error_3 < total_error_4) order = 3; @@ -135,19 +316,18 @@ unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsig FLAC__ASSERT(data_len > 0 || total_error_2 == 0); FLAC__ASSERT(data_len > 0 || total_error_3 == 0); FLAC__ASSERT(data_len > 0 || total_error_4 == 0); -#if defined _MSC_VER || defined __MINGW32__ - /* with VC++ you have to spoon feed it the casting */ - residual_bits_per_sample[0] = (FLAC__real)((total_error_0 > 0) ? log(M_LN2 * (double)(FLAC__int64)total_error_0 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[1] = (FLAC__real)((total_error_1 > 0) ? log(M_LN2 * (double)(FLAC__int64)total_error_1 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[2] = (FLAC__real)((total_error_2 > 0) ? log(M_LN2 * (double)(FLAC__int64)total_error_2 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[3] = (FLAC__real)((total_error_3 > 0) ? log(M_LN2 * (double)(FLAC__int64)total_error_3 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[4] = (FLAC__real)((total_error_4 > 0) ? log(M_LN2 * (double)(FLAC__int64)total_error_4 / (double)data_len) / M_LN2 : 0.0); +#ifndef FLAC__INTEGER_ONLY_LIBRARY + residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0); #else - residual_bits_per_sample[0] = (FLAC__real)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[1] = (FLAC__real)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[2] = (FLAC__real)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[3] = (FLAC__real)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[4] = (FLAC__real)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0); + residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_wide_integerized(total_error_0, data_len) : 0; + residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_wide_integerized(total_error_1, data_len) : 0; + residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_wide_integerized(total_error_2, data_len) : 0; + residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_wide_integerized(total_error_3, data_len) : 0; + residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_wide_integerized(total_error_4, data_len) : 0; #endif return order; @@ -160,32 +340,36 @@ void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, u switch(order) { case 0: - for(i = 0; i < idata_len; i++) { - residual[i] = data[i]; - } + FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); + memcpy(residual, data, sizeof(residual[0])*data_len); break; case 1: - for(i = 0; i < idata_len; i++) { + for(i = 0; i < idata_len; i++) residual[i] = data[i] - data[i-1]; - } break; case 2: - for(i = 0; i < idata_len; i++) { - /* == data[i] - 2*data[i-1] + data[i-2] */ + for(i = 0; i < idata_len; i++) +#if 1 /* OPT: may be faster with some compilers on some systems */ residual[i] = data[i] - (data[i-1] << 1) + data[i-2]; - } +#else + residual[i] = data[i] - 2*data[i-1] + data[i-2]; +#endif break; case 3: - for(i = 0; i < idata_len; i++) { - /* == data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3] */ + for(i = 0; i < idata_len; i++) +#if 1 /* OPT: may be faster with some compilers on some systems */ residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3]; - } +#else + residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3]; +#endif break; case 4: - for(i = 0; i < idata_len; i++) { - /* == data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4] */ + for(i = 0; i < idata_len; i++) +#if 1 /* OPT: may be faster with some compilers on some systems */ residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4]; - } +#else + residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4]; +#endif break; default: FLAC__ASSERT(0); @@ -198,32 +382,36 @@ void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, switch(order) { case 0: - for(i = 0; i < idata_len; i++) { - data[i] = residual[i]; - } + FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); + memcpy(data, residual, sizeof(residual[0])*data_len); break; case 1: - for(i = 0; i < idata_len; i++) { + for(i = 0; i < idata_len; i++) data[i] = residual[i] + data[i-1]; - } break; case 2: - for(i = 0; i < idata_len; i++) { - /* == residual[i] + 2*data[i-1] - data[i-2] */ + for(i = 0; i < idata_len; i++) +#if 1 /* OPT: may be faster with some compilers on some systems */ data[i] = residual[i] + (data[i-1]<<1) - data[i-2]; - } +#else + data[i] = residual[i] + 2*data[i-1] - data[i-2]; +#endif break; case 3: - for(i = 0; i < idata_len; i++) { - /* residual[i] + 3*data[i-1] - 3*data[i-2]) + data[i-3] */ + for(i = 0; i < idata_len; i++) +#if 1 /* OPT: may be faster with some compilers on some systems */ data[i] = residual[i] + (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) + data[i-3]; - } +#else + data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3]; +#endif break; case 4: - for(i = 0; i < idata_len; i++) { - /* == residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4] */ + for(i = 0; i < idata_len; i++) +#if 1 /* OPT: may be faster with some compilers on some systems */ data[i] = residual[i] + ((data[i-1]+data[i-3])<<2) - ((data[i-2]<<2) + (data[i-2]<<1)) - data[i-4]; - } +#else + data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4]; +#endif break; default: FLAC__ASSERT(0); diff --git a/sys/src/cmd/audio/libFLAC/float.c b/sys/src/cmd/audio/libFLAC/float.c new file mode 100644 index 000000000..068069f36 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/float.c @@ -0,0 +1,302 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "FLAC/assert.h" +#include "share/compat.h" +#include "private/float.h" + +#ifdef FLAC__INTEGER_ONLY_LIBRARY + +const FLAC__fixedpoint FLAC__FP_ZERO = 0; +const FLAC__fixedpoint FLAC__FP_ONE_HALF = 0x00008000; +const FLAC__fixedpoint FLAC__FP_ONE = 0x00010000; +const FLAC__fixedpoint FLAC__FP_LN2 = 45426; +const FLAC__fixedpoint FLAC__FP_E = 178145; + +/* Lookup tables for Knuth's logarithm algorithm */ +#define LOG2_LOOKUP_PRECISION 16 +static const FLAC__uint32 log2_lookup[][LOG2_LOOKUP_PRECISION] = { + { + /* + * 0 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00000001, + /* lg(4/3) = */ 0x00000000, + /* lg(8/7) = */ 0x00000000, + /* lg(16/15) = */ 0x00000000, + /* lg(32/31) = */ 0x00000000, + /* lg(64/63) = */ 0x00000000, + /* lg(128/127) = */ 0x00000000, + /* lg(256/255) = */ 0x00000000, + /* lg(512/511) = */ 0x00000000, + /* lg(1024/1023) = */ 0x00000000, + /* lg(2048/2047) = */ 0x00000000, + /* lg(4096/4095) = */ 0x00000000, + /* lg(8192/8191) = */ 0x00000000, + /* lg(16384/16383) = */ 0x00000000, + /* lg(32768/32767) = */ 0x00000000 + }, + { + /* + * 4 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00000010, + /* lg(4/3) = */ 0x00000007, + /* lg(8/7) = */ 0x00000003, + /* lg(16/15) = */ 0x00000001, + /* lg(32/31) = */ 0x00000001, + /* lg(64/63) = */ 0x00000000, + /* lg(128/127) = */ 0x00000000, + /* lg(256/255) = */ 0x00000000, + /* lg(512/511) = */ 0x00000000, + /* lg(1024/1023) = */ 0x00000000, + /* lg(2048/2047) = */ 0x00000000, + /* lg(4096/4095) = */ 0x00000000, + /* lg(8192/8191) = */ 0x00000000, + /* lg(16384/16383) = */ 0x00000000, + /* lg(32768/32767) = */ 0x00000000 + }, + { + /* + * 8 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00000100, + /* lg(4/3) = */ 0x0000006a, + /* lg(8/7) = */ 0x00000031, + /* lg(16/15) = */ 0x00000018, + /* lg(32/31) = */ 0x0000000c, + /* lg(64/63) = */ 0x00000006, + /* lg(128/127) = */ 0x00000003, + /* lg(256/255) = */ 0x00000001, + /* lg(512/511) = */ 0x00000001, + /* lg(1024/1023) = */ 0x00000000, + /* lg(2048/2047) = */ 0x00000000, + /* lg(4096/4095) = */ 0x00000000, + /* lg(8192/8191) = */ 0x00000000, + /* lg(16384/16383) = */ 0x00000000, + /* lg(32768/32767) = */ 0x00000000 + }, + { + /* + * 12 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00001000, + /* lg(4/3) = */ 0x000006a4, + /* lg(8/7) = */ 0x00000315, + /* lg(16/15) = */ 0x0000017d, + /* lg(32/31) = */ 0x000000bc, + /* lg(64/63) = */ 0x0000005d, + /* lg(128/127) = */ 0x0000002e, + /* lg(256/255) = */ 0x00000017, + /* lg(512/511) = */ 0x0000000c, + /* lg(1024/1023) = */ 0x00000006, + /* lg(2048/2047) = */ 0x00000003, + /* lg(4096/4095) = */ 0x00000001, + /* lg(8192/8191) = */ 0x00000001, + /* lg(16384/16383) = */ 0x00000000, + /* lg(32768/32767) = */ 0x00000000 + }, + { + /* + * 16 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00010000, + /* lg(4/3) = */ 0x00006a40, + /* lg(8/7) = */ 0x00003151, + /* lg(16/15) = */ 0x000017d6, + /* lg(32/31) = */ 0x00000bba, + /* lg(64/63) = */ 0x000005d1, + /* lg(128/127) = */ 0x000002e6, + /* lg(256/255) = */ 0x00000172, + /* lg(512/511) = */ 0x000000b9, + /* lg(1024/1023) = */ 0x0000005c, + /* lg(2048/2047) = */ 0x0000002e, + /* lg(4096/4095) = */ 0x00000017, + /* lg(8192/8191) = */ 0x0000000c, + /* lg(16384/16383) = */ 0x00000006, + /* lg(32768/32767) = */ 0x00000003 + }, + { + /* + * 20 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x00100000, + /* lg(4/3) = */ 0x0006a3fe, + /* lg(8/7) = */ 0x00031513, + /* lg(16/15) = */ 0x00017d60, + /* lg(32/31) = */ 0x0000bb9d, + /* lg(64/63) = */ 0x00005d10, + /* lg(128/127) = */ 0x00002e59, + /* lg(256/255) = */ 0x00001721, + /* lg(512/511) = */ 0x00000b8e, + /* lg(1024/1023) = */ 0x000005c6, + /* lg(2048/2047) = */ 0x000002e3, + /* lg(4096/4095) = */ 0x00000171, + /* lg(8192/8191) = */ 0x000000b9, + /* lg(16384/16383) = */ 0x0000005c, + /* lg(32768/32767) = */ 0x0000002e + }, + { + /* + * 24 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x01000000, + /* lg(4/3) = */ 0x006a3fe6, + /* lg(8/7) = */ 0x00315130, + /* lg(16/15) = */ 0x0017d605, + /* lg(32/31) = */ 0x000bb9ca, + /* lg(64/63) = */ 0x0005d0fc, + /* lg(128/127) = */ 0x0002e58f, + /* lg(256/255) = */ 0x0001720e, + /* lg(512/511) = */ 0x0000b8d8, + /* lg(1024/1023) = */ 0x00005c61, + /* lg(2048/2047) = */ 0x00002e2d, + /* lg(4096/4095) = */ 0x00001716, + /* lg(8192/8191) = */ 0x00000b8b, + /* lg(16384/16383) = */ 0x000005c5, + /* lg(32768/32767) = */ 0x000002e3 + }, + { + /* + * 28 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ 0x10000000, + /* lg(4/3) = */ 0x06a3fe5c, + /* lg(8/7) = */ 0x03151301, + /* lg(16/15) = */ 0x017d6049, + /* lg(32/31) = */ 0x00bb9ca6, + /* lg(64/63) = */ 0x005d0fba, + /* lg(128/127) = */ 0x002e58f7, + /* lg(256/255) = */ 0x001720da, + /* lg(512/511) = */ 0x000b8d87, + /* lg(1024/1023) = */ 0x0005c60b, + /* lg(2048/2047) = */ 0x0002e2d7, + /* lg(4096/4095) = */ 0x00017160, + /* lg(8192/8191) = */ 0x0000b8ad, + /* lg(16384/16383) = */ 0x00005c56, + /* lg(32768/32767) = */ 0x00002e2b + } +}; + +#if 0 +static const FLAC__uint64 log2_lookup_wide[] = { + { + /* + * 32 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ FLAC__U64L(0x100000000), + /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c6), + /* lg(8/7) = */ FLAC__U64L(0x31513015), + /* lg(16/15) = */ FLAC__U64L(0x17d60497), + /* lg(32/31) = */ FLAC__U64L(0x0bb9ca65), + /* lg(64/63) = */ FLAC__U64L(0x05d0fba2), + /* lg(128/127) = */ FLAC__U64L(0x02e58f74), + /* lg(256/255) = */ FLAC__U64L(0x01720d9c), + /* lg(512/511) = */ FLAC__U64L(0x00b8d875), + /* lg(1024/1023) = */ FLAC__U64L(0x005c60aa), + /* lg(2048/2047) = */ FLAC__U64L(0x002e2d72), + /* lg(4096/4095) = */ FLAC__U64L(0x00171600), + /* lg(8192/8191) = */ FLAC__U64L(0x000b8ad2), + /* lg(16384/16383) = */ FLAC__U64L(0x0005c55d), + /* lg(32768/32767) = */ FLAC__U64L(0x0002e2ac) + }, + { + /* + * 48 fraction bits + */ + /* undefined */ 0x00000000, + /* lg(2/1) = */ FLAC__U64L(0x1000000000000), + /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c60429), + /* lg(8/7) = */ FLAC__U64L(0x315130157f7a), + /* lg(16/15) = */ FLAC__U64L(0x17d60496cfbb), + /* lg(32/31) = */ FLAC__U64L(0xbb9ca64ecac), + /* lg(64/63) = */ FLAC__U64L(0x5d0fba187cd), + /* lg(128/127) = */ FLAC__U64L(0x2e58f7441ee), + /* lg(256/255) = */ FLAC__U64L(0x1720d9c06a8), + /* lg(512/511) = */ FLAC__U64L(0xb8d8752173), + /* lg(1024/1023) = */ FLAC__U64L(0x5c60aa252e), + /* lg(2048/2047) = */ FLAC__U64L(0x2e2d71b0d8), + /* lg(4096/4095) = */ FLAC__U64L(0x1716001719), + /* lg(8192/8191) = */ FLAC__U64L(0xb8ad1de1b), + /* lg(16384/16383) = */ FLAC__U64L(0x5c55d640d), + /* lg(32768/32767) = */ FLAC__U64L(0x2e2abcf52) + } +}; +#endif + +FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision) +{ + const FLAC__uint32 ONE = (1u << fracbits); + const FLAC__uint32 *table = log2_lookup[fracbits >> 2]; + + FLAC__ASSERT(fracbits < 32); + FLAC__ASSERT((fracbits & 0x3) == 0); + + if(x < ONE) + return 0; + + if(precision > LOG2_LOOKUP_PRECISION) + precision = LOG2_LOOKUP_PRECISION; + + /* Knuth's algorithm for computing logarithms, optimized for base-2 with lookup tables */ + { + FLAC__uint32 y = 0; + FLAC__uint32 z = x >> 1, k = 1; + while (x > ONE && k < precision) { + if (x - z >= ONE) { + x -= z; + z = x >> k; + y += table[k]; + } + else { + z >>= 1; + k++; + } + } + return y; + } +} + +#endif /* defined FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/sys/src/cmd/audio/libFLAC/format.c b/sys/src/cmd/audio/libFLAC/format.c index d4ac5acb9..4d0d8329b 100644 --- a/sys/src/cmd/audio/libFLAC/format.c +++ b/sys/src/cmd/audio/libFLAC/format.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,41 +30,27 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include <stdio.h> #include <stdlib.h> /* for qsort() */ +#include <string.h> /* for memset() */ #include "FLAC/assert.h" #include "FLAC/format.h" +#include "share/compat.h" #include "private/format.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef min -#undef min -#endif -#define min(a,b) ((a)<(b)?(a):(b)) - -/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */ -#ifdef _MSC_VER -#define FLAC__U64L(x) x -#else -#define FLAC__U64L(x) x##LLU -#endif +#include "private/macros.h" /* VERSION should come from configure */ FLAC_API const char *FLAC__VERSION_STRING = VERSION; -#if defined _MSC_VER || defined __MINW32__ -/* yet one more hack because of MSVC6: */ -FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.1.1 20041001"; -#else -FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20041001"; -#endif +FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20141125"; FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' }; FLAC_API const unsigned FLAC__STREAM_SYNC = 0x664C6143; -FLAC_API const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */; +FLAC_API const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */ FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */ FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */ @@ -104,13 +91,23 @@ FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */ FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */ FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */ + FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */ FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */ FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */ FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC = 0x3ffe; FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */ -FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN = 2; /* bits */ +FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */ +FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */ FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */ FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */ FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */ @@ -123,12 +120,15 @@ FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */ FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */ FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */ FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */ +FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */ FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */ FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */ +FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER = 31; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */ FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = { - "PARTITIONED_RICE" + "PARTITIONED_RICE", + "PARTITIONED_RICE2" }; FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */ @@ -168,14 +168,57 @@ FLAC_API const char * const FLAC__MetadataTypeString[] = { "APPLICATION", "SEEKTABLE", "VORBIS_COMMENT", - "CUESHEET" + "CUESHEET", + "PICTURE" +}; + +FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = { + "Other", + "32x32 pixels 'file icon' (PNG only)", + "Other file icon", + "Cover (front)", + "Cover (back)", + "Leaflet page", + "Media (e.g. label side of CD)", + "Lead artist/lead performer/soloist", + "Artist/performer", + "Conductor", + "Band/Orchestra", + "Composer", + "Lyricist/text writer", + "Recording Location", + "During recording", + "During performance", + "Movie/video screen capture", + "A bright coloured fish", + "Illustration", + "Band/artist logotype", + "Publisher/Studio logotype" }; FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate) { + if(sample_rate == 0 || sample_rate > FLAC__MAX_SAMPLE_RATE) { + return false; + } + else + return true; +} + +FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(unsigned blocksize, unsigned sample_rate) +{ + if(blocksize > 16384) + return false; + else if(sample_rate <= 48000 && blocksize > 4608) + return false; + else + return true; +} + +FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate) +{ if( - sample_rate == 0 || - sample_rate > FLAC__MAX_SAMPLE_RATE || + !FLAC__format_sample_rate_is_valid(sample_rate) || ( sample_rate >= (1u << 16) && !(sample_rate % 1000 == 0 || sample_rate % 10 == 0) @@ -187,6 +230,7 @@ FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate) return true; } +/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table) { unsigned i; @@ -222,6 +266,7 @@ static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLA return 1; } +/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table) { unsigned i, j; @@ -254,6 +299,112 @@ FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *se return j; } +/* + * also disallows non-shortest-form encodings, c.f. + * http://www.unicode.org/versions/corrigendum1.html + * and a more clear explanation at the end of this section: + * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + */ +static unsigned utf8len_(const FLAC__byte *utf8) +{ + FLAC__ASSERT(0 != utf8); + if ((utf8[0] & 0x80) == 0) { + return 1; + } + else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) { + if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */ + return 0; + return 2; + } + else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) { + if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */ + return 0; + /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */ + if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */ + return 0; + if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */ + return 0; + return 3; + } + else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) { + if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */ + return 0; + return 4; + } + else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) { + if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */ + return 0; + return 5; + } + else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) { + if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */ + return 0; + return 6; + } + else { + return 0; + } +} + +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name) +{ + char c; + for(c = *name; c; c = *(++name)) + if(c < 0x20 || c == 0x3d || c > 0x7d) + return false; + return true; +} + +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length) +{ + if(length == (unsigned)(-1)) { + while(*value) { + unsigned n = utf8len_(value); + if(n == 0) + return false; + value += n; + } + } + else { + const FLAC__byte *end = value + length; + while(value < end) { + unsigned n = utf8len_(value); + if(n == 0) + return false; + value += n; + } + if(value != end) + return false; + } + return true; +} + +FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length) +{ + const FLAC__byte *s, *end; + + for(s = entry, end = s + length; s < end && *s != '='; s++) { + if(*s < 0x20 || *s > 0x7D) + return false; + } + if(s == end) + return false; + + s++; /* skip '=' */ + + while(s < end) { + unsigned n = utf8len_(s); + if(n == 0) + return false; + s += n; + } + if(s != end) + return false; + + return true; +} + +/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation) { unsigned i, j; @@ -293,7 +444,12 @@ FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_Cu } if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) { - if(violation) *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples"; + if(violation) { + if(i == cue_sheet->num_tracks-1) /* the lead-out track... */ + *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples"; + else + *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples"; + } return false; } @@ -327,6 +483,31 @@ FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_Cu return true; } +/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ +FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation) +{ + char *p; + FLAC__byte *b; + + for(p = picture->mime_type; *p; p++) { + if(*p < 0x20 || *p > 0x7e) { + if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)"; + return false; + } + } + + for(b = picture->description; *b; ) { + unsigned n = utf8len_(b); + if(n == 0) { + if(violation) *violation = "description string must be valid UTF-8"; + return false; + } + b += n; + } + + return true; +} + /* * These routines are private to libFLAC */ @@ -347,7 +528,7 @@ unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned block max_rice_partition_order++; blocksize >>= 1; } - return min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order); + return flac_min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order); } unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order) @@ -392,10 +573,11 @@ FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_s FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits)); if(object->capacity_by_order < max_partition_order) { - if(0 == (object->parameters = (unsigned*)realloc(object->parameters, sizeof(unsigned)*(1 << max_partition_order)))) + if(0 == (object->parameters = realloc(object->parameters, sizeof(unsigned)*(1 << max_partition_order)))) return false; - if(0 == (object->raw_bits = (unsigned*)realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order)))) + if(0 == (object->raw_bits = realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order)))) return false; + memset(object->raw_bits, 0, sizeof(unsigned)*(1 << max_partition_order)); object->capacity_by_order = max_partition_order; } diff --git a/sys/src/cmd/audio/libFLAC/lpc.c b/sys/src/cmd/audio/libFLAC/lpc.c index 275b707a3..7eff63e6d 100644 --- a/sys/src/cmd/audio/libFLAC/lpc.c +++ b/sys/src/cmd/audio/libFLAC/lpc.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,19 +30,48 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include <math.h> + #include "FLAC/assert.h" #include "FLAC/format.h" +#include "share/compat.h" #include "private/bitmath.h" #include "private/lpc.h" +#include "private/macros.h" #if defined DEBUG || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE #include <stdio.h> #endif -#ifndef M_LN2 -/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */ -#define M_LN2 0.69314718055994530942 +/* OPT: #undef'ing this may improve the speed on some architectures */ +#define FLAC__LPC_UNROLLED_FILTER_LOOPS + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +#if !defined(HAVE_LROUND) +#if defined(_MSC_VER) +#include <float.h> +#define copysign _copysign +#elif defined(__GNUC__) +#define copysign __builtin_copysign +#elif defined(Plan9) +#define copysign(x,y) ((x > 0.0 && y < 0.0) || (x < 0.0 && y > 0.0)) ? -x : x #endif +static inline long int lround(double x) { + return (long)(x + copysign (0.5, x)); +} +/* If this fails, we are in the presence of a mid 90's compiler, move along... */ +#endif + +void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], unsigned data_len) +{ + unsigned i; + for(i = 0; i < data_len; i++) + out[i] = in[i] * window[i]; +} void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]) { @@ -53,6 +83,13 @@ void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_le FLAC__ASSERT(lag > 0); FLAC__ASSERT(lag <= data_len); + /* + * Technically we should subtract the mean first like so: + * for(i = 0; i < data_len; i++) + * data[i] -= mean; + * but it appears not to make enough of a difference to matter, and + * most signals are already closely centered around zero + */ while(lag--) { for(i = lag, d = 0.0; i < data_len; i++) d += data[i] * data[i - lag]; @@ -85,28 +122,29 @@ void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_le } } -void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__real error[]) +void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[]) { unsigned i, j; - double r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_ORDER]; + FLAC__double r, err, lpc[FLAC__MAX_LPC_ORDER]; - FLAC__ASSERT(0 < max_order); - FLAC__ASSERT(max_order <= FLAC__MAX_LPC_ORDER); + FLAC__ASSERT(0 != max_order); + FLAC__ASSERT(0 < *max_order); + FLAC__ASSERT(*max_order <= FLAC__MAX_LPC_ORDER); FLAC__ASSERT(autoc[0] != 0.0); err = autoc[0]; - for(i = 0; i < max_order; i++) { + for(i = 0; i < *max_order; i++) { /* Sum up this iteration's reflection coefficient. */ r = -autoc[i+1]; for(j = 0; j < i; j++) r -= lpc[j] * autoc[i-j]; - ref[i] = (r/=err); + r /= err; /* Update LPC coefficients and total error. */ lpc[i]=r; for(j = 0; j < (i>>1); j++) { - double tmp = lpc[j]; + FLAC__double tmp = lpc[j]; lpc[j] += r * lpc[i-1-j]; lpc[i-1-j] += r * tmp; } @@ -118,17 +156,21 @@ void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned max_or /* save this order */ for(j = 0; j <= i; j++) lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */ - error[i] = (FLAC__real)err; + error[i] = err; + + /* see SF bug https://sourceforge.net/p/flac/bugs/234/ */ + if(err == 0.0) { + *max_order = i+1; + return; + } } } int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift) { unsigned i; - double d, cmax = -1e32; + FLAC__double cmax; FLAC__int32 qmax, qmin; - const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1; - const int min_shiftlimit = -max_shiftlimit - 1; FLAC__ASSERT(precision > 0); FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION); @@ -139,77 +181,96 @@ int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, qmin = -qmax; qmax--; + /* calc cmax = max( |lp_coeff[i]| ) */ + cmax = 0.0; for(i = 0; i < order; i++) { - if(lp_coeff[i] == 0.0) - continue; - d = fabs(lp_coeff[i]); + const FLAC__double d = fabs(lp_coeff[i]); if(d > cmax) cmax = d; } -redo_it: + if(cmax <= 0.0) { /* => coefficients are all 0, which means our constant-detect didn't work */ return 2; } else { + const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1; + const int min_shiftlimit = -max_shiftlimit - 1; int log2cmax; (void)frexp(cmax, &log2cmax); log2cmax--; *shift = (int)precision - log2cmax - 1; - if(*shift < min_shiftlimit || *shift > max_shiftlimit) { -#if 0 - /*@@@ this does not seem to help at all, but was not extensively tested either: */ - if(*shift > max_shiftlimit) - *shift = max_shiftlimit; - else -#endif - return 1; - } + if(*shift > max_shiftlimit) + *shift = max_shiftlimit; + else if(*shift < min_shiftlimit) + return 1; } if(*shift >= 0) { + FLAC__double error = 0.0; + FLAC__int32 q; for(i = 0; i < order; i++) { - qlp_coeff[i] = (FLAC__int32)floor((double)lp_coeff[i] * (double)(1 << *shift)); + error += lp_coeff[i] * (1 << *shift); + q = lround(error); - /* double-check the result */ - if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) { #ifdef FLAC__OVERFLOW_DETECT - fprintf(stderr,"FLAC__lpc_quantize_coefficients: compensating for overflow, qlp_coeff[%u]=%d, lp_coeff[%u]=%f, cmax=%f, precision=%u, shift=%d, q=%f, f(q)=%f\n", i, qlp_coeff[i], i, lp_coeff[i], cmax, precision, *shift, (double)lp_coeff[i] * (double)(1 << *shift), floor((double)lp_coeff[i] * (double)(1 << *shift))); + if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */ + fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]); + else if(q < qmin) + fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]); #endif - cmax *= 2.0; - goto redo_it; - } + if(q > qmax) + q = qmax; + else if(q < qmin) + q = qmin; + error -= q; + qlp_coeff[i] = q; } } - else { /* (*shift < 0) */ + /* negative shift is very rare but due to design flaw, negative shift is + * a NOP in the decoder, so it must be handled specially by scaling down + * coeffs + */ + else { const int nshift = -(*shift); + FLAC__double error = 0.0; + FLAC__int32 q; #ifdef DEBUG - fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift = %d\n", *shift); + fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift=%d order=%u cmax=%f\n", *shift, order, cmax); #endif for(i = 0; i < order; i++) { - qlp_coeff[i] = (FLAC__int32)floor((double)lp_coeff[i] / (double)(1 << nshift)); - - /* double-check the result */ - if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) { + error += lp_coeff[i] / (1 << nshift); + q = lround(error); #ifdef FLAC__OVERFLOW_DETECT - fprintf(stderr,"FLAC__lpc_quantize_coefficients: compensating for overflow, qlp_coeff[%u]=%d, lp_coeff[%u]=%f, cmax=%f, precision=%u, shift=%d, q=%f, f(q)=%f\n", i, qlp_coeff[i], i, lp_coeff[i], cmax, precision, *shift, (double)lp_coeff[i] / (double)(1 << nshift), floor((double)lp_coeff[i] / (double)(1 << nshift))); + if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */ + fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]); + else if(q < qmin) + fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]); #endif - cmax *= 2.0; - goto redo_it; - } + if(q > qmax) + q = qmax; + else if(q < qmin) + q = qmin; + error -= q; + qlp_coeff[i] = q; } + *shift = 0; } return 0; } -void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]) +#if defined(_MSC_VER) +// silence MSVC warnings about __restrict modifier +#pragma warning ( disable : 4028 ) +#endif + +void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 * flac_restrict data, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict residual) +#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) { -#ifdef FLAC__OVERFLOW_DETECT FLAC__int64 sumo; -#endif unsigned i, j; FLAC__int32 sum; const FLAC__int32 *history; @@ -223,23 +284,13 @@ void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 data[], FLAC__ASSERT(order > 0); for(i = 0; i < data_len; i++) { -#ifdef FLAC__OVERFLOW_DETECT sumo = 0; -#endif sum = 0; history = data; for(j = 0; j < order; j++) { sum += qlp_coeff[j] * (*(--history)); -#ifdef FLAC__OVERFLOW_DETECT sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history); -#if defined _MSC_VER - if(sumo > 2147483647I64 || sumo < -2147483648I64) - fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%I64d\n",i,j,qlp_coeff[j],*history,sumo); -#else - if(sumo > 2147483647ll || sumo < -2147483648ll) - fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld\n",i,j,qlp_coeff[j],*history,sumo); -#endif -#endif + fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo); } *(residual++) = *(data++) - (sum >> lp_quantization); } @@ -253,8 +304,231 @@ void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 data[], } */ } +#else /* fully unrolled version for normal use */ +{ + int i; + FLAC__int32 sum; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + /* + * We do unique versions up to 12th order since that's the subset limit. + * Also they are roughly ordered to match frequency of occurrence to + * minimize branching. + */ + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 11 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + else { + if(order == 10) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 9 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 7 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + else { + if(order == 6) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 5 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 3 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + } + else { + if(order == 2) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + } + else { /* order == 1 */ + for(i = 0; i < (int)data_len; i++) + residual[i] = data[i] - ((qlp_coeff[0] * data[i-1]) >> lp_quantization); + } + } + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; + case 31: sum += qlp_coeff[30] * data[i-31]; + case 30: sum += qlp_coeff[29] * data[i-30]; + case 29: sum += qlp_coeff[28] * data[i-29]; + case 28: sum += qlp_coeff[27] * data[i-28]; + case 27: sum += qlp_coeff[26] * data[i-27]; + case 26: sum += qlp_coeff[25] * data[i-26]; + case 25: sum += qlp_coeff[24] * data[i-25]; + case 24: sum += qlp_coeff[23] * data[i-24]; + case 23: sum += qlp_coeff[22] * data[i-23]; + case 22: sum += qlp_coeff[21] * data[i-22]; + case 21: sum += qlp_coeff[20] * data[i-21]; + case 20: sum += qlp_coeff[19] * data[i-20]; + case 19: sum += qlp_coeff[18] * data[i-19]; + case 18: sum += qlp_coeff[17] * data[i-18]; + case 17: sum += qlp_coeff[16] * data[i-17]; + case 16: sum += qlp_coeff[15] * data[i-16]; + case 15: sum += qlp_coeff[14] * data[i-15]; + case 14: sum += qlp_coeff[13] * data[i-14]; + case 13: sum += qlp_coeff[12] * data[i-13]; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[ 9] * data[i-10]; + sum += qlp_coeff[ 8] * data[i- 9]; + sum += qlp_coeff[ 7] * data[i- 8]; + sum += qlp_coeff[ 6] * data[i- 7]; + sum += qlp_coeff[ 5] * data[i- 6]; + sum += qlp_coeff[ 4] * data[i- 5]; + sum += qlp_coeff[ 3] * data[i- 4]; + sum += qlp_coeff[ 2] * data[i- 3]; + sum += qlp_coeff[ 1] * data[i- 2]; + sum += qlp_coeff[ 0] * data[i- 1]; + } + residual[i] = data[i] - (sum >> lp_quantization); + } + } +} +#endif -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]) +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 * flac_restrict data, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict residual) +#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) { unsigned i, j; FLAC__int64 sum; @@ -273,28 +547,249 @@ void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 dat history = data; for(j = 0; j < order; j++) sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history)); -#ifdef FLAC__OVERFLOW_DETECT if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) { - fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%lld\n", i, sum >> lp_quantization); + fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%" PRId64 "\n", i, (sum >> lp_quantization)); break; } if(FLAC__bitmath_silog2_wide((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) { - fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%lld, residual=%lld\n", i, *data, sum >> lp_quantization, (FLAC__int64)(*data) - (sum >> lp_quantization)); + fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%" PRId64 ", residual=%" PRId64 "\n", i, *data, (int64_t)(sum >> lp_quantization), ((FLAC__int64)(*data) - (sum >> lp_quantization))); break; } -#endif *(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization); } } +#else /* fully unrolled version for normal use */ +{ + int i; + FLAC__int64 sum; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + /* + * We do unique versions up to 12th order since that's the subset limit. + * Also they are roughly ordered to match frequency of occurrence to + * minimize branching. + */ + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 11 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + } + else { + if(order == 10) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 9 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 7 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + } + else { + if(order == 6) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 5 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 3 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + } + else { + if(order == 2) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 1 */ + for(i = 0; i < (int)data_len; i++) + residual[i] = data[i] - (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization); + } + } + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; + case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; + case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; + case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; + case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; + case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; + case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; + case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; + case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; + case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; + case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; + case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; + case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; + case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; + case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; + case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; + case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; + case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; + case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; + case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; + sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; + sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; + sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; + sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; + sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; + sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; + sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; + sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; + sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; + } + residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization); + } + } +} +#endif + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ -void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]) +void FLAC__lpc_restore_signal(const FLAC__int32 * flac_restrict residual, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict data) +#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) { -#ifdef FLAC__OVERFLOW_DETECT FLAC__int64 sumo; -#endif unsigned i, j; FLAC__int32 sum; - const FLAC__int32 *history; + const FLAC__int32 *r = residual, *history; #ifdef FLAC__OVERFLOW_DETECT_VERBOSE fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); @@ -305,25 +800,16 @@ void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, c FLAC__ASSERT(order > 0); for(i = 0; i < data_len; i++) { -#ifdef FLAC__OVERFLOW_DETECT sumo = 0; -#endif sum = 0; history = data; for(j = 0; j < order; j++) { sum += qlp_coeff[j] * (*(--history)); -#ifdef FLAC__OVERFLOW_DETECT sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history); -#if defined _MSC_VER - if(sumo > 2147483647I64 || sumo < -2147483648I64) - fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%I64d\n",i,j,qlp_coeff[j],*history,sumo); -#else if(sumo > 2147483647ll || sumo < -2147483648ll) - fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld\n",i,j,qlp_coeff[j],*history,sumo); -#endif -#endif + fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo); } - *(data++) = *(residual++) + (sum >> lp_quantization); + *(data++) = *(r++) + (sum >> lp_quantization); } /* Here's a slower but clearer version: @@ -335,12 +821,235 @@ void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, c } */ } +#else /* fully unrolled version for normal use */ +{ + int i; + FLAC__int32 sum; + + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + /* + * We do unique versions up to 12th order since that's the subset limit. + * Also they are roughly ordered to match frequency of occurrence to + * minimize branching. + */ + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 11 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + } + else { + if(order == 10) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[9] * data[i-10]; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 9 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[8] * data[i-9]; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[7] * data[i-8]; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 7 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[6] * data[i-7]; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + } + else { + if(order == 6) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[5] * data[i-6]; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 5 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[4] * data[i-5]; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[3] * data[i-4]; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 3 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[2] * data[i-3]; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + } + else { + if(order == 2) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[1] * data[i-2]; + sum += qlp_coeff[0] * data[i-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + } + else { /* order == 1 */ + for(i = 0; i < (int)data_len; i++) + data[i] = residual[i] + ((qlp_coeff[0] * data[i-1]) >> lp_quantization); + } + } + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * data[i-32]; + case 31: sum += qlp_coeff[30] * data[i-31]; + case 30: sum += qlp_coeff[29] * data[i-30]; + case 29: sum += qlp_coeff[28] * data[i-29]; + case 28: sum += qlp_coeff[27] * data[i-28]; + case 27: sum += qlp_coeff[26] * data[i-27]; + case 26: sum += qlp_coeff[25] * data[i-26]; + case 25: sum += qlp_coeff[24] * data[i-25]; + case 24: sum += qlp_coeff[23] * data[i-24]; + case 23: sum += qlp_coeff[22] * data[i-23]; + case 22: sum += qlp_coeff[21] * data[i-22]; + case 21: sum += qlp_coeff[20] * data[i-21]; + case 20: sum += qlp_coeff[19] * data[i-20]; + case 19: sum += qlp_coeff[18] * data[i-19]; + case 18: sum += qlp_coeff[17] * data[i-18]; + case 17: sum += qlp_coeff[16] * data[i-17]; + case 16: sum += qlp_coeff[15] * data[i-16]; + case 15: sum += qlp_coeff[14] * data[i-15]; + case 14: sum += qlp_coeff[13] * data[i-14]; + case 13: sum += qlp_coeff[12] * data[i-13]; + sum += qlp_coeff[11] * data[i-12]; + sum += qlp_coeff[10] * data[i-11]; + sum += qlp_coeff[ 9] * data[i-10]; + sum += qlp_coeff[ 8] * data[i- 9]; + sum += qlp_coeff[ 7] * data[i- 8]; + sum += qlp_coeff[ 6] * data[i- 7]; + sum += qlp_coeff[ 5] * data[i- 6]; + sum += qlp_coeff[ 4] * data[i- 5]; + sum += qlp_coeff[ 3] * data[i- 4]; + sum += qlp_coeff[ 2] * data[i- 3]; + sum += qlp_coeff[ 1] * data[i- 2]; + sum += qlp_coeff[ 0] * data[i- 1]; + } + data[i] = residual[i] + (sum >> lp_quantization); + } + } +} +#endif -void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]) +void FLAC__lpc_restore_signal_wide(const FLAC__int32 * flac_restrict residual, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict data) +#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) { unsigned i, j; FLAC__int64 sum; - const FLAC__int32 *history; + const FLAC__int32 *r = residual, *history; #ifdef FLAC__OVERFLOW_DETECT_VERBOSE fprintf(stderr,"FLAC__lpc_restore_signal_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); @@ -355,69 +1064,296 @@ void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_l history = data; for(j = 0; j < order; j++) sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history)); -#ifdef FLAC__OVERFLOW_DETECT if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) { - fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%lld\n", i, sum >> lp_quantization); + fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%" PRId64 "\n", i, (sum >> lp_quantization)); break; } - if(FLAC__bitmath_silog2_wide((FLAC__int64)(*residual) + (sum >> lp_quantization)) > 32) { - fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%lld, data=%lld\n", i, *residual, sum >> lp_quantization, (FLAC__int64)(*residual) + (sum >> lp_quantization)); + if(FLAC__bitmath_silog2_wide((FLAC__int64)(*r) + (sum >> lp_quantization)) > 32) { + fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%" PRId64 ", data=%" PRId64 "\n", i, *r, (sum >> lp_quantization), ((FLAC__int64)(*r) + (sum >> lp_quantization))); break; } -#endif - *(data++) = *(residual++) + (FLAC__int32)(sum >> lp_quantization); + *(data++) = *(r++) + (FLAC__int32)(sum >> lp_quantization); } } +#else /* fully unrolled version for normal use */ +{ + int i; + FLAC__int64 sum; -FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__real lpc_error, unsigned total_samples) + FLAC__ASSERT(order > 0); + FLAC__ASSERT(order <= 32); + + /* + * We do unique versions up to 12th order since that's the subset limit. + * Also they are roughly ordered to match frequency of occurrence to + * minimize branching. + */ + if(order <= 12) { + if(order > 8) { + if(order > 10) { + if(order == 12) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 11 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } + } + else { + if(order == 10) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 9 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } + } + } + else if(order > 4) { + if(order > 6) { + if(order == 8) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 7 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } + } + else { + if(order == 6) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 5 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } + } + } + else { + if(order > 2) { + if(order == 4) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 3 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } + } + else { + if(order == 2) { + for(i = 0; i < (int)data_len; i++) { + sum = 0; + sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; + sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } + else { /* order == 1 */ + for(i = 0; i < (int)data_len; i++) + data[i] = residual[i] + (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization); + } + } + } + } + else { /* order > 12 */ + for(i = 0; i < (int)data_len; i++) { + sum = 0; + switch(order) { + case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; + case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; + case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; + case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; + case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; + case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; + case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; + case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; + case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; + case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; + case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; + case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; + case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; + case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; + case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; + case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; + case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; + case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; + case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; + case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; + sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; + sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; + sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; + sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; + sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; + sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; + sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; + sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; + sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; + sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; + sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; + sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; + } + data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization); + } + } +} +#endif + +#if defined(_MSC_VER) +#pragma warning ( default : 4028 ) +#endif + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples) { - double error_scale; + FLAC__double error_scale; FLAC__ASSERT(total_samples > 0); - error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__real)total_samples; + error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples; return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale); } -FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__real lpc_error, double error_scale) +FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale) { if(lpc_error > 0.0) { - FLAC__real bps = (FLAC__real)((double)0.5 * log(error_scale * lpc_error) / M_LN2); + FLAC__double bps = (FLAC__double)0.5 * log(error_scale * lpc_error) / M_LN2; if(bps >= 0.0) return bps; else return 0.0; } - else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate float resolution */ - return (FLAC__real)1e32; + else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */ + return 1e32; } else { return 0.0; } } -unsigned FLAC__lpc_compute_best_order(const FLAC__real lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample) +unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order) { - unsigned order, best_order; - FLAC__real best_bits, tmp_bits; - double error_scale; + unsigned order, indx, best_index; /* 'index' the index into lpc_error; index==order-1 since lpc_error[0] is for order==1, lpc_error[1] is for order==2, etc */ + FLAC__double bits, best_bits, error_scale; FLAC__ASSERT(max_order > 0); FLAC__ASSERT(total_samples > 0); - error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__real)total_samples; + error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples; - best_order = 0; - best_bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[0], error_scale) * (FLAC__real)total_samples; + best_index = 0; + best_bits = (unsigned)(-1); - for(order = 1; order < max_order; order++) { - tmp_bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[order], error_scale) * (FLAC__real)(total_samples - order) + (FLAC__real)(order * bits_per_signal_sample); - if(tmp_bits < best_bits) { - best_order = order; - best_bits = tmp_bits; + for(indx = 0, order = 1; indx < max_order; indx++, order++) { + bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[indx], error_scale) * (FLAC__double)(total_samples - order) + (FLAC__double)(order * overhead_bits_per_order); + if(bits < best_bits) { + best_index = indx; + best_bits = bits; } } - return best_order+1; /* +1 since index of lpc_error[] is order-1 */ + return best_index+1; /* +1 since indx of lpc_error[] is order-1 */ } + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/sys/src/cmd/audio/libFLAC/md5.c b/sys/src/cmd/audio/libFLAC/md5.c index 9679387db..e5adc3e35 100644 --- a/sys/src/cmd/audio/libFLAC/md5.c +++ b/sys/src/cmd/audio/libFLAC/md5.c @@ -1,3 +1,14 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> /* for malloc() */ +#include <string.h> /* for memcpy() */ + +#include "private/md5.h" +#include "share/alloc.h" +#include "share/endswap.h" + /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was @@ -23,23 +34,6 @@ * Still in the public domain. */ -#include <stdlib.h> /* for malloc() */ -#include <string.h> /* for memcpy() */ - -#include "private/md5.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifndef FLaC__INLINE -#define FLaC__INLINE -#endif - -static FLAC__bool is_big_endian_host_; - -#ifndef ASM_MD5 - /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ @@ -57,9 +51,7 @@ static FLAC__bool is_big_endian_host_; * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ -FLaC__INLINE -void -FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16]) +static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16]) { register FLAC__uint32 a, b, c, d; @@ -142,51 +134,48 @@ FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16]) buf[3] += d; } -#endif - -FLaC__INLINE -void -byteSwap(FLAC__uint32 *buf, unsigned words) +#if WORDS_BIGENDIAN +//@@@@@@ OPT: use bswap/intrinsics +static void byteSwap(FLAC__uint32 *buf, unsigned words) { - md5byte *p = (md5byte *)buf; - - if(!is_big_endian_host_) - return; + register FLAC__uint32 x; do { - *buf++ = (FLAC__uint32)((unsigned)p[3] << 8 | p[2]) << 16 | ((unsigned)p[1] << 8 | p[0]); - p += 4; + x = *buf; + x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); + *buf++ = (x >> 16) | (x << 16); } while (--words); } - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void -FLAC__MD5Init(struct FLAC__MD5Context *ctx) +static void byteSwapX16(FLAC__uint32 *buf) { - FLAC__uint32 test = 1; - - is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true; - - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bytes[0] = 0; - ctx->bytes[1] = 0; - - ctx->internal_buf = 0; - ctx->capacity = 0; + register FLAC__uint32 x; + + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); + x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf = (x >> 16) | (x << 16); } +#else +#define byteSwap(buf, words) +#define byteSwapX16(buf) +#endif /* * Update context to reflect the concatenation of another buffer full * of bytes. */ -void -FLAC__MD5Update(struct FLAC__MD5Context *ctx, md5byte const *buf, unsigned len) +static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, unsigned len) { FLAC__uint32 t; @@ -198,12 +187,12 @@ FLAC__MD5Update(struct FLAC__MD5Context *ctx, md5byte const *buf, unsigned len) t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ if (t > len) { - memcpy((md5byte *)ctx->in + 64 - t, buf, len); + memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len); return; } /* First chunk is an odd size */ - memcpy((md5byte *)ctx->in + 64 - t, buf, t); - byteSwap(ctx->in, 16); + memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t); + byteSwapX16(ctx->in); FLAC__MD5Transform(ctx->buf, ctx->in); buf += t; len -= t; @@ -211,7 +200,7 @@ FLAC__MD5Update(struct FLAC__MD5Context *ctx, md5byte const *buf, unsigned len) /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); - byteSwap(ctx->in, 16); + byteSwapX16(ctx->in); FLAC__MD5Transform(ctx->buf, ctx->in); buf += 64; len -= 64; @@ -222,66 +211,31 @@ FLAC__MD5Update(struct FLAC__MD5Context *ctx, md5byte const *buf, unsigned len) } /* - * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it. + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. */ -FLAC__bool -FLAC__MD5Accumulate(struct FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample) +void FLAC__MD5Init(FLAC__MD5Context *ctx) { - unsigned channel, sample, a_byte; - FLAC__int32 a_word; - FLAC__byte *buf_; - const unsigned bytes_needed = channels * samples * bytes_per_sample; - - if(ctx->capacity < bytes_needed) { - FLAC__byte *tmp = (FLAC__byte*)realloc(ctx->internal_buf, bytes_needed); - if(0 == tmp) { - free(ctx->internal_buf); - if(0 == (ctx->internal_buf = (FLAC__byte*)malloc(bytes_needed))) - return false; - } - ctx->internal_buf = tmp; - ctx->capacity = bytes_needed; - } - - buf_ = ctx->internal_buf; - -#ifdef FLAC__CPU_IA32 - if(channels == 2 && bytes_per_sample == 2) { - memcpy(buf_, signal[0], sizeof(FLAC__int32) * samples); - buf_ += sizeof(FLAC__int16); - for(sample = 0; sample < samples; sample++) - ((FLAC__int16 *)buf_)[2 * sample] = (FLAC__int16)signal[1][sample]; - } - else if(channels == 1 && bytes_per_sample == 2) { - for(sample = 0; sample < samples; sample++) - ((FLAC__int16 *)buf_)[sample] = (FLAC__int16)signal[0][sample]; - } - else -#endif - for(sample = 0; sample < samples; sample++) { - for(channel = 0; channel < channels; channel++) { - a_word = signal[channel][sample]; - for(a_byte = 0; a_byte < bytes_per_sample; a_byte++) { - *buf_++ = (FLAC__byte)(a_word & 0xff); - a_word >>= 8; - } - } - } + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; - FLAC__MD5Update(ctx, ctx->internal_buf, bytes_needed); + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; - return true; + ctx->internal_buf.p8= 0; + ctx->capacity = 0; } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ -void -FLAC__MD5Final(md5byte digest[16], struct FLAC__MD5Context *ctx) +void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx) { int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ - md5byte *p = (md5byte *)ctx->in + count; + FLAC__byte *p = (FLAC__byte *)ctx->in + count; /* Set the first char of padding to 0x80. There is always room. */ *p++ = 0x80; @@ -291,9 +245,9 @@ FLAC__MD5Final(md5byte digest[16], struct FLAC__MD5Context *ctx) if (count < 0) { /* Padding forces an extra block */ memset(p, 0, count + 8); - byteSwap(ctx->in, 16); + byteSwapX16(ctx->in); FLAC__MD5Transform(ctx->buf, ctx->in); - p = (md5byte *)ctx->in; + p = (FLAC__byte *)ctx->in; count = 56; } memset(p, 0, count); @@ -306,10 +260,259 @@ FLAC__MD5Final(md5byte digest[16], struct FLAC__MD5Context *ctx) byteSwap(ctx->buf, 4); memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ - if(0 != ctx->internal_buf) { - free(ctx->internal_buf); - ctx->internal_buf = 0; + if (0 != ctx->internal_buf.p8) { + free(ctx->internal_buf.p8); + ctx->internal_buf.p8= 0; ctx->capacity = 0; } + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +/* + * Convert the incoming audio signal to a byte stream + */ +static void format_input_(FLAC__multibyte *mbuf, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample) +{ + FLAC__byte *buf_ = mbuf->p8; + FLAC__int16 *buf16 = mbuf->p16; + FLAC__int32 *buf32 = mbuf->p32; + FLAC__int32 a_word; + unsigned channel, sample; + + /* Storage in the output buffer, buf, is little endian. */ + +#define BYTES_CHANNEL_SELECTOR(bytes, channels) (bytes * 100 + channels) + + /* First do the most commonly used combinations. */ + switch (BYTES_CHANNEL_SELECTOR (bytes_per_sample, channels)) { + /* One byte per sample. */ + case (BYTES_CHANNEL_SELECTOR (1, 1)): + for (sample = 0; sample < samples; sample++) + *buf_++ = signal[0][sample]; + return; + + case (BYTES_CHANNEL_SELECTOR (1, 2)): + for (sample = 0; sample < samples; sample++) { + *buf_++ = signal[0][sample]; + *buf_++ = signal[1][sample]; + } + return; + + case (BYTES_CHANNEL_SELECTOR (1, 4)): + for (sample = 0; sample < samples; sample++) { + *buf_++ = signal[0][sample]; + *buf_++ = signal[1][sample]; + *buf_++ = signal[2][sample]; + *buf_++ = signal[3][sample]; + } + return; + + case (BYTES_CHANNEL_SELECTOR (1, 6)): + for (sample = 0; sample < samples; sample++) { + *buf_++ = signal[0][sample]; + *buf_++ = signal[1][sample]; + *buf_++ = signal[2][sample]; + *buf_++ = signal[3][sample]; + *buf_++ = signal[4][sample]; + *buf_++ = signal[5][sample]; + } + return; + + case (BYTES_CHANNEL_SELECTOR (1, 8)): + for (sample = 0; sample < samples; sample++) { + *buf_++ = signal[0][sample]; + *buf_++ = signal[1][sample]; + *buf_++ = signal[2][sample]; + *buf_++ = signal[3][sample]; + *buf_++ = signal[4][sample]; + *buf_++ = signal[5][sample]; + *buf_++ = signal[6][sample]; + *buf_++ = signal[7][sample]; + } + return; + + /* Two bytes per sample. */ + case (BYTES_CHANNEL_SELECTOR (2, 1)): + for (sample = 0; sample < samples; sample++) + *buf16++ = H2LE_16(signal[0][sample]); + return; + + case (BYTES_CHANNEL_SELECTOR (2, 2)): + for (sample = 0; sample < samples; sample++) { + *buf16++ = H2LE_16(signal[0][sample]); + *buf16++ = H2LE_16(signal[1][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (2, 4)): + for (sample = 0; sample < samples; sample++) { + *buf16++ = H2LE_16(signal[0][sample]); + *buf16++ = H2LE_16(signal[1][sample]); + *buf16++ = H2LE_16(signal[2][sample]); + *buf16++ = H2LE_16(signal[3][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (2, 6)): + for (sample = 0; sample < samples; sample++) { + *buf16++ = H2LE_16(signal[0][sample]); + *buf16++ = H2LE_16(signal[1][sample]); + *buf16++ = H2LE_16(signal[2][sample]); + *buf16++ = H2LE_16(signal[3][sample]); + *buf16++ = H2LE_16(signal[4][sample]); + *buf16++ = H2LE_16(signal[5][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (2, 8)): + for (sample = 0; sample < samples; sample++) { + *buf16++ = H2LE_16(signal[0][sample]); + *buf16++ = H2LE_16(signal[1][sample]); + *buf16++ = H2LE_16(signal[2][sample]); + *buf16++ = H2LE_16(signal[3][sample]); + *buf16++ = H2LE_16(signal[4][sample]); + *buf16++ = H2LE_16(signal[5][sample]); + *buf16++ = H2LE_16(signal[6][sample]); + *buf16++ = H2LE_16(signal[7][sample]); + } + return; + + /* Three bytes per sample. */ + case (BYTES_CHANNEL_SELECTOR (3, 1)): + for (sample = 0; sample < samples; sample++) { + a_word = signal[0][sample]; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; + } + return; + + case (BYTES_CHANNEL_SELECTOR (3, 2)): + for (sample = 0; sample < samples; sample++) { + a_word = signal[0][sample]; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; + a_word = signal[1][sample]; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; + } + return; + + /* Four bytes per sample. */ + case (BYTES_CHANNEL_SELECTOR (4, 1)): + for (sample = 0; sample < samples; sample++) + *buf32++ = H2LE_32(signal[0][sample]); + return; + + case (BYTES_CHANNEL_SELECTOR (4, 2)): + for (sample = 0; sample < samples; sample++) { + *buf32++ = H2LE_32(signal[0][sample]); + *buf32++ = H2LE_32(signal[1][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (4, 4)): + for (sample = 0; sample < samples; sample++) { + *buf32++ = H2LE_32(signal[0][sample]); + *buf32++ = H2LE_32(signal[1][sample]); + *buf32++ = H2LE_32(signal[2][sample]); + *buf32++ = H2LE_32(signal[3][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (4, 6)): + for (sample = 0; sample < samples; sample++) { + *buf32++ = H2LE_32(signal[0][sample]); + *buf32++ = H2LE_32(signal[1][sample]); + *buf32++ = H2LE_32(signal[2][sample]); + *buf32++ = H2LE_32(signal[3][sample]); + *buf32++ = H2LE_32(signal[4][sample]); + *buf32++ = H2LE_32(signal[5][sample]); + } + return; + + case (BYTES_CHANNEL_SELECTOR (4, 8)): + for (sample = 0; sample < samples; sample++) { + *buf32++ = H2LE_32(signal[0][sample]); + *buf32++ = H2LE_32(signal[1][sample]); + *buf32++ = H2LE_32(signal[2][sample]); + *buf32++ = H2LE_32(signal[3][sample]); + *buf32++ = H2LE_32(signal[4][sample]); + *buf32++ = H2LE_32(signal[5][sample]); + *buf32++ = H2LE_32(signal[6][sample]); + *buf32++ = H2LE_32(signal[7][sample]); + } + return; + + default: + break; + } + + /* General version. */ + switch (bytes_per_sample) { + case 1: + for (sample = 0; sample < samples; sample++) + for (channel = 0; channel < channels; channel++) + *buf_++ = signal[channel][sample]; + return; + + case 2: + for (sample = 0; sample < samples; sample++) + for (channel = 0; channel < channels; channel++) + *buf16++ = H2LE_16(signal[channel][sample]); + return; + + case 3: + for (sample = 0; sample < samples; sample++) + for (channel = 0; channel < channels; channel++) { + a_word = signal[channel][sample]; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; a_word >>= 8; + *buf_++ = (FLAC__byte)a_word; + } + return; + + case 4: + for (sample = 0; sample < samples; sample++) + for (channel = 0; channel < channels; channel++) + *buf32++ = H2LE_32(signal[channel][sample]); + return; + + default: + break; + } +} + +/* + * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it. + */ +FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample) +{ + const size_t bytes_needed = (size_t)channels * (size_t)samples * (size_t)bytes_per_sample; + + /* overflow check */ + if ((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample) + return false; + if ((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples) + return false; + + if (ctx->capacity < bytes_needed) { + FLAC__byte *tmp = realloc(ctx->internal_buf.p8, bytes_needed); + if (0 == tmp) { + free(ctx->internal_buf.p8); + if (0 == (ctx->internal_buf.p8= safe_malloc_(bytes_needed))) + return false; + } + else + ctx->internal_buf.p8= tmp; + ctx->capacity = bytes_needed; + } + + format_input_(&ctx->internal_buf, signal, channels, samples, bytes_per_sample); + + FLAC__MD5Update(ctx, ctx->internal_buf.p8, bytes_needed); + + return true; } diff --git a/sys/src/cmd/audio/libFLAC/memory.c b/sys/src/cmd/audio/libFLAC/memory.c index 9b3dc6a67..d22df70eb 100644 --- a/sys/src/cmd/audio/libFLAC/memory.c +++ b/sys/src/cmd/audio/libFLAC/memory.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,13 +30,18 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "private/memory.h" -#include "FLAC/assert.h" - #ifdef HAVE_CONFIG_H -#include <config.h> +# include <config.h> #endif +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#include "private/memory.h" +#include "FLAC/assert.h" +#include "share/alloc.h" + void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address) { void *x; @@ -44,25 +50,32 @@ void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address) #ifdef FLAC__ALIGN_MALLOC_DATA /* align on 32-byte (256-bit) boundary */ - x = malloc(bytes+31); - *aligned_address = (void*)(((unsigned)x + 31) & -32); + x = safe_malloc_add_2op_(bytes, /*+*/31L); + *aligned_address = (void*)(((uintptr_t)x + 31L) & -32L); #else - x = malloc(bytes); + x = safe_malloc_(bytes); *aligned_address = x; #endif return x; } -FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer) +FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer) { - FLAC__int32 *pa, *pu; /* aligned pointer, unaligned pointer */ + FLAC__int32 *pu; /* unaligned pointer */ + union { /* union needed to comply with C99 pointer aliasing rules */ + FLAC__int32 *pa; /* aligned pointer */ + void *pv; /* aligned pointer alias */ + } u; FLAC__ASSERT(elements > 0); FLAC__ASSERT(0 != unaligned_pointer); FLAC__ASSERT(0 != aligned_pointer); FLAC__ASSERT(unaligned_pointer != aligned_pointer); - pu = (FLAC__int32*)FLAC__memory_alloc_aligned(sizeof(FLAC__int32) * elements, (void**)&pa); + if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ + return false; + + pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); if(0 == pu) { return false; } @@ -70,21 +83,28 @@ FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 if(*unaligned_pointer != 0) free(*unaligned_pointer); *unaligned_pointer = pu; - *aligned_pointer = pa; + *aligned_pointer = u.pa; return true; } } -FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer) +FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer) { - FLAC__uint32 *pa, *pu; /* aligned pointer, unaligned pointer */ + FLAC__uint32 *pu; /* unaligned pointer */ + union { /* union needed to comply with C99 pointer aliasing rules */ + FLAC__uint32 *pa; /* aligned pointer */ + void *pv; /* aligned pointer alias */ + } u; FLAC__ASSERT(elements > 0); FLAC__ASSERT(0 != unaligned_pointer); FLAC__ASSERT(0 != aligned_pointer); FLAC__ASSERT(unaligned_pointer != aligned_pointer); - pu = (FLAC__uint32*)FLAC__memory_alloc_aligned(sizeof(FLAC__uint32) * elements, (void**)&pa); + if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ + return false; + + pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); if(0 == pu) { return false; } @@ -92,21 +112,28 @@ FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint if(*unaligned_pointer != 0) free(*unaligned_pointer); *unaligned_pointer = pu; - *aligned_pointer = pa; + *aligned_pointer = u.pa; return true; } } -FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer) +FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer) { - FLAC__uint64 *pa, *pu; /* aligned pointer, unaligned pointer */ + FLAC__uint64 *pu; /* unaligned pointer */ + union { /* union needed to comply with C99 pointer aliasing rules */ + FLAC__uint64 *pa; /* aligned pointer */ + void *pv; /* aligned pointer alias */ + } u; FLAC__ASSERT(elements > 0); FLAC__ASSERT(0 != unaligned_pointer); FLAC__ASSERT(0 != aligned_pointer); FLAC__ASSERT(unaligned_pointer != aligned_pointer); - pu = (FLAC__uint64*)FLAC__memory_alloc_aligned(sizeof(FLAC__uint64) * elements, (void**)&pa); + if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ + return false; + + pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); if(0 == pu) { return false; } @@ -114,21 +141,28 @@ FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint if(*unaligned_pointer != 0) free(*unaligned_pointer); *unaligned_pointer = pu; - *aligned_pointer = pa; + *aligned_pointer = u.pa; return true; } } -FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer) +FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, unsigned **unaligned_pointer, unsigned **aligned_pointer) { - unsigned *pa, *pu; /* aligned pointer, unaligned pointer */ + unsigned *pu; /* unaligned pointer */ + union { /* union needed to comply with C99 pointer aliasing rules */ + unsigned *pa; /* aligned pointer */ + void *pv; /* aligned pointer alias */ + } u; FLAC__ASSERT(elements > 0); FLAC__ASSERT(0 != unaligned_pointer); FLAC__ASSERT(0 != aligned_pointer); FLAC__ASSERT(unaligned_pointer != aligned_pointer); - pu = (unsigned*)FLAC__memory_alloc_aligned(sizeof(unsigned) * elements, (void**)&pa); + if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ + return false; + + pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); if(0 == pu) { return false; } @@ -136,21 +170,30 @@ FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned if(*unaligned_pointer != 0) free(*unaligned_pointer); *unaligned_pointer = pu; - *aligned_pointer = pa; + *aligned_pointer = u.pa; return true; } } -FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer) +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer) { - FLAC__real *pa, *pu; /* aligned pointer, unaligned pointer */ + FLAC__real *pu; /* unaligned pointer */ + union { /* union needed to comply with C99 pointer aliasing rules */ + FLAC__real *pa; /* aligned pointer */ + void *pv; /* aligned pointer alias */ + } u; FLAC__ASSERT(elements > 0); FLAC__ASSERT(0 != unaligned_pointer); FLAC__ASSERT(0 != aligned_pointer); FLAC__ASSERT(unaligned_pointer != aligned_pointer); - pu = (FLAC__real*)FLAC__memory_alloc_aligned(sizeof(FLAC__real) * elements, (void**)&pa); + if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ + return false; + + pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); if(0 == pu) { return false; } @@ -158,7 +201,18 @@ FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real * if(*unaligned_pointer != 0) free(*unaligned_pointer); *unaligned_pointer = pu; - *aligned_pointer = pa; + *aligned_pointer = u.pa; return true; } } + +#endif + +void *safe_malloc_mul_2op_p(size_t size1, size_t size2) +{ + if(!size1 || !size2) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + if(size1 > SIZE_MAX / size2) + return 0; + return malloc(size1*size2); +} diff --git a/sys/src/cmd/audio/libFLAC/metadata_iterators.c b/sys/src/cmd/audio/libFLAC/metadata_iterators.c index 99029b3ab..1e2892560 100644 --- a/sys/src/cmd/audio/libFLAC/metadata_iterators.c +++ b/sys/src/cmd/audio/libFLAC/metadata_iterators.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,35 +30,31 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <stdarg.h> -#if defined _MSC_VER || defined __MINGW32__ -#include <sys/utime.h> /* for utime() */ -#include <io.h> /* for chmod() */ -#else -#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */ -#include <utime.h> /* for utime() */ -#include <unistd.h> /* for chown(), unlink() */ -#endif #include <sys/stat.h> /* for stat(), maybe chmod() */ #include "private/metadata.h" #include "FLAC/assert.h" -#include "FLAC/file_decoder.h" - -#ifdef max -#undef max -#endif -#define max(a,b) ((a)>(b)?(a):(b)) -#ifdef min -#undef min -#endif -#define min(a,b) ((a)<(b)?(a):(b)) +#include "FLAC/stream_decoder.h" +#include "share/alloc.h" +#include "share/compat.h" +#include "share/macros.h" +#include "share/safe_str.h" +#include "private/macros.h" +#include "private/memory.h" +/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */ +#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p /**************************************************************************** * @@ -80,10 +77,11 @@ static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_c static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length); static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length); static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry); -static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, unsigned max_length); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, unsigned block_length); static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track); static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block); static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length); static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block); @@ -96,6 +94,7 @@ static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handl static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block); static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block); static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block); +static FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block); static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length); static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block); @@ -109,10 +108,10 @@ static unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IO static unsigned seek_to_first_metadata_block_(FILE *f); static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append); -static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, long fixup_is_last_flag_offset, FLAC__bool backup); +static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup); -static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status); -static FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status); +static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status); +static FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status); static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status); static FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status); @@ -120,8 +119,8 @@ static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status); static void cleanup_tempfile_(FILE **tempfile, char **tempfilename); -static FLAC__bool get_file_stats_(const char *filename, struct stat *stats); -static void set_file_stats_(const char *filename, struct stat *stats); +static FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats); +static void set_file_stats_(const char *filename, struct flac_stat_s *stats); static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence); static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle); @@ -147,131 +146,102 @@ static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *st * ***************************************************************************/ -static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); -static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); -static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); +static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); typedef struct { FLAC__bool got_error; - FLAC__bool got_object; FLAC__StreamMetadata *object; } level0_client_data; -FLAC_API FLAC__FileDecoder *FLAC__file_decoder_new(void); - -FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo) +static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type) { level0_client_data cd; - FLAC__FileDecoder *decoder; + FLAC__StreamDecoder *decoder; FLAC__ASSERT(0 != filename); - FLAC__ASSERT(0 != streaminfo); - - decoder = FLAC__file_decoder_new(); - - if(0 == decoder) - return false; cd.got_error = false; - cd.got_object = false; cd.object = 0; - FLAC__file_decoder_set_md5_checking(decoder, false); - FLAC__file_decoder_set_filename(decoder, filename); - FLAC__file_decoder_set_metadata_ignore_all(decoder); - FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO); - FLAC__file_decoder_set_write_callback(decoder, write_callback_); - FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_); - FLAC__file_decoder_set_error_callback(decoder, error_callback_); - FLAC__file_decoder_set_client_data(decoder, &cd); + decoder = FLAC__stream_decoder_new(); - if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK || cd.got_error) { - FLAC__file_decoder_finish(decoder); - FLAC__file_decoder_delete(decoder); - return false; + if(0 == decoder) + return 0; + + FLAC__stream_decoder_set_md5_checking(decoder, false); + FLAC__stream_decoder_set_metadata_ignore_all(decoder); + FLAC__stream_decoder_set_metadata_respond(decoder, type); + + if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) { + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); + return 0; } - if(!FLAC__file_decoder_process_until_end_of_metadata(decoder) || cd.got_error) { - FLAC__file_decoder_finish(decoder); - FLAC__file_decoder_delete(decoder); + if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || cd.got_error) { + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); if(0 != cd.object) FLAC__metadata_object_delete(cd.object); - return false; - } - - FLAC__file_decoder_finish(decoder); - FLAC__file_decoder_delete(decoder); - - if(cd.got_object) { - /* can just copy the contents since STREAMINFO has no internal structure */ - *streaminfo = *(cd.object); + return 0; } - if(0 != cd.object) - FLAC__metadata_object_delete(cd.object); + (void)FLAC__stream_decoder_finish(decoder); + FLAC__stream_decoder_delete(decoder); - return cd.got_object; + return cd.object; } -FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags) +FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo) { - level0_client_data cd; - FLAC__FileDecoder *decoder; + FLAC__StreamMetadata *object; FLAC__ASSERT(0 != filename); - FLAC__ASSERT(0 != tags); + FLAC__ASSERT(0 != streaminfo); - decoder = FLAC__file_decoder_new(); + object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO); - if(0 == decoder) + if (object) { + /* can just copy the contents since STREAMINFO has no internal structure */ + *streaminfo = *object; + FLAC__metadata_object_delete(object); + return true; + } + else { return false; + } +} - *tags = 0; - - cd.got_error = false; - cd.got_object = false; - cd.object = 0; +FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != tags); - FLAC__file_decoder_set_md5_checking(decoder, false); - FLAC__file_decoder_set_filename(decoder, filename); - FLAC__file_decoder_set_metadata_ignore_all(decoder); - FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); - FLAC__file_decoder_set_write_callback(decoder, write_callback_); - FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_); - FLAC__file_decoder_set_error_callback(decoder, error_callback_); - FLAC__file_decoder_set_client_data(decoder, &cd); + *tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT); - if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK || cd.got_error) { - FLAC__file_decoder_finish(decoder); - FLAC__file_decoder_delete(decoder); - return false; - } - - if(!FLAC__file_decoder_process_until_end_of_metadata(decoder) || cd.got_error) { - FLAC__file_decoder_finish(decoder); - FLAC__file_decoder_delete(decoder); - if(0 != cd.object) - FLAC__metadata_object_delete(cd.object); - return false; - } + return 0 != *tags; +} - FLAC__file_decoder_finish(decoder); - FLAC__file_decoder_delete(decoder); +FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != cuesheet); - if(cd.got_object) - *tags = cd.object; + *cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET); - return cd.got_object; + return 0 != *cuesheet; } -FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) { (void)decoder, (void)frame, (void)buffer, (void)client_data; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } -void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) { level0_client_data *cd = (level0_client_data *)client_data; (void)decoder; @@ -280,15 +250,13 @@ void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMeta * we assume we only get here when the one metadata block we were * looking for was passed to us */ - if(!cd->got_object) { + if(!cd->got_error && 0 == cd->object) { if(0 == (cd->object = FLAC__metadata_object_clone(metadata))) cd->got_error = true; - else - cd->got_object = true; } } -void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) { level0_client_data *cd = (level0_client_data *)client_data; (void)decoder; @@ -297,6 +265,56 @@ void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorS cd->got_error = true; } +FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors) +{ + FLAC__Metadata_SimpleIterator *it; + FLAC__uint64 max_area_seen = 0; + FLAC__uint64 max_depth_seen = 0; + + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != picture); + + *picture = 0; + + it = FLAC__metadata_simple_iterator_new(); + if(0 == it) + return false; + if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) { + FLAC__metadata_simple_iterator_delete(it); + return false; + } + do { + if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) { + FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it); + FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height; + /* check constraints */ + if( + (type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) && + (mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) && + (description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) && + obj->data.picture.width <= max_width && + obj->data.picture.height <= max_height && + obj->data.picture.depth <= max_depth && + obj->data.picture.colors <= max_colors && + (area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen)) + ) { + if(*picture) + FLAC__metadata_object_delete(*picture); + *picture = obj; + max_area_seen = area; + max_depth_seen = obj->data.picture.depth; + } + else { + FLAC__metadata_object_delete(obj); + } + } + } while(FLAC__metadata_simple_iterator_next(it)); + + FLAC__metadata_simple_iterator_delete(it); + + return (0 != *picture); +} + /**************************************************************************** * @@ -310,13 +328,12 @@ void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorS struct FLAC__Metadata_SimpleIterator { FILE *file; char *filename, *tempfile_path_prefix; - struct stat stats; + struct flac_stat_s stats; FLAC__bool has_stats; FLAC__bool is_writable; FLAC__Metadata_SimpleIteratorStatus status; - /*@@@ 2G limits here because of the offset type: */ - long offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH]; - long first_offset; /* this is the offset to the STREAMINFO block */ + FLAC__off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH]; + FLAC__off_t first_offset; /* this is the offset to the STREAMINFO block */ unsigned depth; /* this is the metadata block header of the current block we are pointing to: */ FLAC__bool is_last; @@ -343,7 +360,7 @@ FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = { FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void) { - FLAC__Metadata_SimpleIterator *iterator = (FLAC__Metadata_SimpleIterator*)calloc(1, sizeof(FLAC__Metadata_SimpleIterator)); + FLAC__Metadata_SimpleIterator *iterator = calloc(1, sizeof(FLAC__Metadata_SimpleIterator)); if(0 != iterator) { iterator->file = 0; @@ -404,10 +421,10 @@ static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *it FLAC__ASSERT(0 != iterator); - if(read_only || 0 == (iterator->file = fopen(iterator->filename, "r+b"))) { + if(read_only || 0 == (iterator->file = flac_fopen(iterator->filename, "r+b"))) { iterator->is_writable = false; if(read_only || errno == EACCES) { - if(0 == (iterator->file = fopen(iterator->filename, "rb"))) { + if(0 == (iterator->file = flac_fopen(iterator->filename, "rb"))) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; return false; } @@ -425,7 +442,7 @@ static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *it switch(ret) { case 0: iterator->depth = 0; - iterator->first_offset = iterator->offset[iterator->depth] = ftell(iterator->file); + iterator->first_offset = iterator->offset[iterator->depth] = ftello(iterator->file); return read_metadata_block_header_(iterator); case 1: iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; @@ -462,7 +479,7 @@ FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *it FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats) { - const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'rename(...)' for what it will take to finish implementing this */ + const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'flac_rename(...)' for what it will take to finish implementing this */ FLAC__ASSERT(0 != iterator); FLAC__ASSERT(0 != filename); @@ -500,19 +517,19 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIte if(iterator->is_last) return false; - if(0 != fseek(iterator->file, iterator->length, SEEK_CUR)) { + if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } - iterator->offset[iterator->depth] = ftell(iterator->file); + iterator->offset[iterator->depth] = ftello(iterator->file); return read_metadata_block_header_(iterator); } FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator) { - long this_offset; + FLAC__off_t this_offset; FLAC__ASSERT(0 != iterator); FLAC__ASSERT(0 != iterator->file); @@ -520,7 +537,7 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIte if(iterator->offset[iterator->depth] == iterator->first_offset) return false; - if(0 != fseek(iterator->file, iterator->first_offset, SEEK_SET)) { + if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } @@ -528,13 +545,13 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIte if(!read_metadata_block_header_(iterator)) return false; - /* we ignore any error from ftell() and catch it in fseek() */ - while(ftell(iterator->file) + (long)iterator->length < iterator->offset[iterator->depth]) { - if(0 != fseek(iterator->file, iterator->length, SEEK_CUR)) { + /* we ignore any error from ftello() and catch it in fseeko() */ + while(ftello(iterator->file) + (FLAC__off_t)iterator->length < iterator->offset[iterator->depth]) { + if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } - this_offset = ftell(iterator->file); + this_offset = ftello(iterator->file); if(!read_metadata_block_header_(iterator)) return false; } @@ -544,6 +561,24 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIte return true; } +/*@@@@add to tests*/ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + return iterator->is_last; +} + +/*@@@@add to tests*/ +FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + return iterator->offset[iterator->depth]; +} + FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator) { FLAC__ASSERT(0 != iterator); @@ -552,6 +587,43 @@ FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const return iterator->type; } +/*@@@@add to tests*/ +FLAC_API unsigned FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + return iterator->length; +} + +/*@@@@add to tests*/ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id) +{ + const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(0 != id); + + if(iterator->type != FLAC__METADATA_TYPE_APPLICATION) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; + return false; + } + + if(fread(id, 1, id_bytes, iterator->file) != id_bytes) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + + /* back up */ + if(0 != fseeko(iterator->file, -((int)id_bytes), SEEK_CUR)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + return true; +} + FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator) { FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type); @@ -569,7 +641,7 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Me } /* back up to the beginning of the block data to stay consistent */ - if(0 != fseek(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) { + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; FLAC__metadata_object_delete(block); return 0; @@ -583,7 +655,7 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Me FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding) { - FLAC__ASSERT_DECLARATION(long debug_target_offset = iterator->offset[iterator->depth];) + FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];) FLAC__bool ret; FLAC__ASSERT(0 != iterator); @@ -610,13 +682,13 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_Simp if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) { ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last); FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH); + FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); return ret; } else { ret = rewrite_whole_file_(iterator, block, /*append=*/false); FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH); + FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); return ret; } } @@ -659,21 +731,21 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_Simp if(padding_leftover == 0) { ret = write_metadata_block_stationary_(iterator, block); FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH); + FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); return ret; } else { FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH); ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last); FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH); + FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); return ret; } } else { ret = rewrite_whole_file_(iterator, block, /*append=*/false); FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH); + FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); return ret; } } @@ -684,15 +756,17 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Meta unsigned padding_leftover = 0; FLAC__bool padding_is_last = false; - FLAC__ASSERT_DECLARATION(long debug_target_offset = iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;) + FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;) FLAC__bool ret; FLAC__ASSERT(0 != iterator); FLAC__ASSERT(0 != iterator->file); FLAC__ASSERT(0 != block); - if(!iterator->is_writable) + if(!iterator->is_writable) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE; return false; + } if(block->type == FLAC__METADATA_TYPE_STREAMINFO) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; @@ -739,28 +813,28 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Meta if(padding_leftover == 0) { ret = write_metadata_block_stationary_(iterator, block); FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH); + FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); return ret; } else { FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH); ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last); FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH); + FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); return ret; } } else { ret = rewrite_whole_file_(iterator, block, /*append=*/true); FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset); - FLAC__ASSERT(ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH); + FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH); return ret; } } FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding) { - FLAC__ASSERT_DECLARATION(long debug_target_offset = iterator->offset[iterator->depth];) + FLAC__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];) FLAC__bool ret; if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) { @@ -782,14 +856,14 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_S FLAC__metadata_object_delete(padding); if(!FLAC__metadata_simple_iterator_prev(iterator)) return false; - FLAC__ASSERT(iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length == debug_target_offset); - FLAC__ASSERT(ftell(iterator->file) + (long)iterator->length == debug_target_offset); + FLAC__ASSERT(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_target_offset); + FLAC__ASSERT(ftello(iterator->file) + (FLAC__off_t)iterator->length == debug_target_offset); return true; } else { ret = rewrite_whole_file_(iterator, 0, /*append=*/false); - FLAC__ASSERT(iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length == debug_target_offset); - FLAC__ASSERT(ftell(iterator->file) + (long)iterator->length == debug_target_offset); + FLAC__ASSERT(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_target_offset); + FLAC__ASSERT(ftello(iterator->file) + (FLAC__off_t)iterator->length == debug_target_offset); return ret; } } @@ -810,17 +884,21 @@ typedef struct FLAC__Metadata_Node { struct FLAC__Metadata_Chain { char *filename; /* will be NULL if using callbacks */ + FLAC__bool is_ogg; FLAC__Metadata_Node *head; FLAC__Metadata_Node *tail; unsigned nodes; FLAC__Metadata_ChainStatus status; - long first_offset, last_offset; /*@@@ 2G limit */ + FLAC__off_t first_offset, last_offset; /* * This is the length of the chain initially read from the FLAC file. * it is used to compare against the current length to decide whether * or not the whole file has to be rewritten. */ - unsigned initial_length; /*@@@ 4G limit */ + FLAC__off_t initial_length; + /* @@@ hacky, these are currently only needed by ogg reader */ + FLAC__IOHandle handle; + FLAC__IOCallback_Read read_cb; }; struct FLAC__Metadata_Iterator { @@ -850,7 +928,7 @@ FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = { static FLAC__Metadata_Node *node_new_(void) { - return (FLAC__Metadata_Node*)calloc(1, sizeof(FLAC__Metadata_Node)); + return calloc(1, sizeof(FLAC__Metadata_Node)); } static void node_delete_(FLAC__Metadata_Node *node) @@ -866,10 +944,12 @@ static void chain_init_(FLAC__Metadata_Chain *chain) FLAC__ASSERT(0 != chain); chain->filename = 0; + chain->is_ogg = false; chain->head = chain->tail = 0; chain->nodes = 0; chain->status = FLAC__METADATA_CHAIN_STATUS_OK; chain->initial_length = 0; + chain->read_cb = 0; } static void chain_clear_(FLAC__Metadata_Chain *chain) @@ -939,10 +1019,10 @@ static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node node_delete_(node); } -static unsigned chain_calculate_length_(FLAC__Metadata_Chain *chain) +static FLAC__off_t chain_calculate_length_(FLAC__Metadata_Chain *chain) { const FLAC__Metadata_Node *node; - unsigned length = 0; + FLAC__off_t length = 0; for(node = chain->head; node; node = node->next) length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length); return length; @@ -1021,20 +1101,20 @@ static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLA /* WATCHOUT: Make sure to also update the logic in * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes. */ -static unsigned chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding) +static FLAC__off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding) { - unsigned current_length = chain_calculate_length_(chain); + FLAC__off_t current_length = chain_calculate_length_(chain); if(use_padding) { /* if the metadata shrank and the last block is padding, we just extend the last padding block */ if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) { - const unsigned delta = chain->initial_length - current_length; + const FLAC__off_t delta = chain->initial_length - current_length; chain->tail->data->length += delta; current_length += delta; FLAC__ASSERT(current_length == chain->initial_length); } /* if the metadata shrank more than 4 bytes then there's room to add another padding block */ - else if(current_length + FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) { + else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) { FLAC__StreamMetadata *padding; FLAC__Metadata_Node *node; if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) { @@ -1054,16 +1134,16 @@ static unsigned chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool } /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */ else if(current_length > chain->initial_length) { - const unsigned delta = current_length - chain->initial_length; + const FLAC__off_t delta = current_length - chain->initial_length; if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) { /* if the delta is exactly the size of the last padding block, remove the padding block */ - if(chain->tail->data->length + FLAC__STREAM_METADATA_HEADER_LENGTH == delta) { + if((FLAC__off_t)chain->tail->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) { chain_delete_node_(chain, chain->tail); current_length = chain_calculate_length_(chain); FLAC__ASSERT(current_length == chain->initial_length); } /* if there is at least 'delta' bytes of padding, trim the padding down */ - else if(chain->tail->data->length >= delta) { + else if((FLAC__off_t)chain->tail->data->length >= delta) { chain->tail->data->length -= delta; current_length -= delta; FLAC__ASSERT(current_length == chain->initial_length); @@ -1106,7 +1186,7 @@ static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle han chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; return false; } - chain->first_offset = (long)pos; + chain->first_offset = (FLAC__off_t)pos; } { @@ -1122,6 +1202,7 @@ static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle han } if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) { + node_delete_(node); chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; return false; } @@ -1151,7 +1232,7 @@ static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle han chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; return false; } - chain->last_offset = (long)pos; + chain->last_offset = (FLAC__off_t)pos; } chain->initial_length = chain_calculate_length_(chain); @@ -1159,6 +1240,96 @@ static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle han return true; } +static FLAC__StreamDecoderReadStatus chain_read_ogg_read_cb_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data; + (void)decoder; + if(*bytes > 0 && chain->status == FLAC__METADATA_CHAIN_STATUS_OK) { + *bytes = chain->read_cb(buffer, sizeof(FLAC__byte), *bytes, chain->handle); + if(*bytes == 0) + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; +} + +static FLAC__StreamDecoderWriteStatus chain_read_ogg_write_cb_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + (void)decoder, (void)frame, (void)buffer, (void)client_data; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; +} + +static void chain_read_ogg_metadata_cb_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data; + FLAC__Metadata_Node *node; + + (void)decoder; + + node = node_new_(); + if(0 == node) { + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return; + } + + node->data = FLAC__metadata_object_clone(metadata); + if(0 == node->data) { + node_delete_(node); + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return; + } + + chain_append_node_(chain, node); +} + +static void chain_read_ogg_error_cb_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data; + (void)decoder, (void)status; + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */ +} + +static FLAC__bool chain_read_ogg_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb) +{ + FLAC__StreamDecoder *decoder; + + FLAC__ASSERT(0 != chain); + + /* we assume we're already at the beginning of the file */ + + chain->handle = handle; + chain->read_cb = read_cb; + if(0 == (decoder = FLAC__stream_decoder_new())) { + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + FLAC__stream_decoder_set_metadata_respond_all(decoder); + if(FLAC__stream_decoder_init_ogg_stream(decoder, chain_read_ogg_read_cb_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, chain_read_ogg_write_cb_, chain_read_ogg_metadata_cb_, chain_read_ogg_error_cb_, chain) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + FLAC__stream_decoder_delete(decoder); + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */ + return false; + } + + chain->first_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */ + + if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */ + if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) { + FLAC__stream_decoder_delete(decoder); + return false; + } + + FLAC__stream_decoder_delete(decoder); + + chain->last_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */ + + chain->initial_length = chain_calculate_length_(chain); + + return true; +} + static FLAC__bool chain_rewrite_metadata_in_place_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, FLAC__IOCallback_Seek seek_cb) { FLAC__Metadata_Node *node; @@ -1182,7 +1353,7 @@ static FLAC__bool chain_rewrite_metadata_in_place_cb_(FLAC__Metadata_Chain *chai } } - /*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/ + /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/ chain->status = FLAC__METADATA_CHAIN_STATUS_OK; return true; @@ -1195,7 +1366,7 @@ static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain) FLAC__ASSERT(0 != chain->filename); - if(0 == (file = fopen(chain->filename, "r+b"))) { + if(0 == (file = flac_fopen(chain->filename, "r+b"))) { chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; return false; } @@ -1210,7 +1381,7 @@ static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain) static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix) { - FILE *f, *tempfile; + FILE *f, *tempfile = NULL; char *tempfilename; FLAC__Metadata_SimpleIteratorStatus status; const FLAC__Metadata_Node *node; @@ -1220,44 +1391,40 @@ static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *t FLAC__ASSERT(0 != chain->head); /* copy the file prefix (data up to first metadata block */ - if(0 == (f = fopen(chain->filename, "rb"))) { + if(0 == (f = flac_fopen(chain->filename, "rb"))) { chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; return false; } if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &tempfilename, &status)) { chain->status = get_equivalent_status_(status); - cleanup_tempfile_(&tempfile, &tempfilename); - return false; + goto err; } if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) { chain->status = get_equivalent_status_(status); - cleanup_tempfile_(&tempfile, &tempfilename); - return false; + goto err; } /* write the metadata */ for(node = chain->head; node; node = node->next) { if(!write_metadata_block_header_(tempfile, &status, node->data)) { chain->status = get_equivalent_status_(status); - return false; + goto err; } if(!write_metadata_block_data_(tempfile, &status, node->data)) { chain->status = get_equivalent_status_(status); - return false; + goto err; } } - /*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/ + /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/ /* copy the file postfix (everything after the metadata) */ - if(0 != fseek(f, chain->last_offset, SEEK_SET)) { - cleanup_tempfile_(&tempfile, &tempfilename); + if(0 != fseeko(f, chain->last_offset, SEEK_SET)) { chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; - return false; + goto err; } if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) { - cleanup_tempfile_(&tempfile, &tempfilename); chain->status = get_equivalent_status_(status); - return false; + goto err; } /* move the tempfile on top of the original */ @@ -1266,6 +1433,11 @@ static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *t return false; return true; + +err: + (void)fclose(f); + cleanup_tempfile_(&tempfile, &tempfilename); + return false; } /* assumes 'handle' is already at beginning of file */ @@ -1295,7 +1467,7 @@ static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHa return false; } } - /*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/ + /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/ /* copy the file postfix (everything after the metadata) */ if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) { @@ -1310,9 +1482,9 @@ static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHa return true; } -FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new() +FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void) { - FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)calloc(1, sizeof(FLAC__Metadata_Chain)); + FLAC__Metadata_Chain *chain = calloc(1, sizeof(FLAC__Metadata_Chain)); if(0 != chain) chain_init_(chain); @@ -1340,7 +1512,7 @@ FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_C return status; } -FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename) +static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg) { FILE *file; FLAC__bool ret; @@ -1355,21 +1527,39 @@ FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const return false; } - if(0 == (file = fopen(filename, "rb"))) { + chain->is_ogg = is_ogg; + + if(0 == (file = flac_fopen(filename, "rb"))) { chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; return false; } - /* chain_read_cb_() sets chain->status for us */ - ret = chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_); + /* the function also sets chain->status for us */ + ret = is_ogg? + chain_read_ogg_cb_(chain, file, (FLAC__IOCallback_Read)fread) : + chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_) + ; fclose(file); return ret; } -FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) +FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename) +{ + return chain_read_(chain, filename, /*is_ogg=*/false); +} + +/*@@@@add to tests*/ +FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename) +{ + return chain_read_(chain, filename, /*is_ogg=*/true); +} + +static FLAC__bool chain_read_with_callbacks_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__bool is_ogg) { + FLAC__bool ret; + FLAC__ASSERT(0 != chain); chain_clear_(chain); @@ -1379,16 +1569,32 @@ FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chai return false; } + chain->is_ogg = is_ogg; + /* rewind */ if(0 != callbacks.seek(handle, 0, SEEK_SET)) { chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; return false; } - if(!chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell)) - return false; /* chain->status is already set by chain_read_cb_ */ + /* the function also sets chain->status for us */ + ret = is_ogg? + chain_read_ogg_cb_(chain, handle, callbacks.read) : + chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell) + ; - return true; + return ret; +} + +FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) +{ + return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/false); +} + +/*@@@@add to tests*/ +FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) +{ + return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/true); } FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding) @@ -1397,7 +1603,7 @@ FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata * but doesn't actually alter the chain. Make sure to update the logic * here if chain_prepare_for_write_() changes. */ - const unsigned current_length = chain_calculate_length_(chain); + const FLAC__off_t current_length = chain_calculate_length_(chain); FLAC__ASSERT(0 != chain); @@ -1406,17 +1612,17 @@ FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) return false; /* if the metadata shrank more than 4 bytes then there's room to add another padding block */ - else if(current_length + FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) + else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) return false; /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */ else if(current_length > chain->initial_length) { - const unsigned delta = current_length - chain->initial_length; + const FLAC__off_t delta = current_length - chain->initial_length; if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) { /* if the delta is exactly the size of the last padding block, remove the padding block */ - if(chain->tail->data->length + FLAC__STREAM_METADATA_HEADER_LENGTH == delta) + if((FLAC__off_t)chain->tail->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) return false; /* if there is at least 'delta' bytes of padding, trim the padding down */ - else if(chain->tail->data->length >= delta) + else if((FLAC__off_t)chain->tail->data->length >= delta) return false; } } @@ -1427,12 +1633,17 @@ FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats) { - struct stat stats; + struct flac_stat_s stats; const char *tempfile_path_prefix = 0; - unsigned current_length; + FLAC__off_t current_length; FLAC__ASSERT(0 != chain); + if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */ + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; + return false; + } + if (0 == chain->filename) { chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; return false; @@ -1473,10 +1684,15 @@ FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks) { - unsigned current_length; + FLAC__off_t current_length; FLAC__ASSERT(0 != chain); + if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */ + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; + return false; + } + if (0 != chain->filename) { chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; return false; @@ -1505,10 +1721,15 @@ FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Cha FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks) { - unsigned current_length; + FLAC__off_t current_length; FLAC__ASSERT(0 != chain); + if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */ + chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; + return false; + } + if (0 != chain->filename) { chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; return false; @@ -1596,9 +1817,9 @@ FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain) } -FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new() +FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void) { - FLAC__Metadata_Iterator *iterator = (FLAC__Metadata_Iterator*)calloc(1, sizeof(FLAC__Metadata_Iterator)); + FLAC__Metadata_Iterator *iterator = calloc(1, sizeof(FLAC__Metadata_Iterator)); /* calloc() implies: iterator->current = 0; @@ -1872,9 +2093,11 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle case FLAC__METADATA_TYPE_SEEKTABLE: return read_metadata_block_data_seektable_cb_(handle, read_cb, &block->data.seek_table, block->length); case FLAC__METADATA_TYPE_VORBIS_COMMENT: - return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, &block->data.vorbis_comment); + return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, seek_cb, &block->data.vorbis_comment, block->length); case FLAC__METADATA_TYPE_CUESHEET: return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet); + case FLAC__METADATA_TYPE_PICTURE: + return read_metadata_block_data_picture_cb_(handle, read_cb, &block->data.picture); default: return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length); } @@ -1906,7 +2129,6 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; } - FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length) { (void)block; /* nothing to do; we don't care about reading the padding bytes */ @@ -1924,13 +2146,16 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLA if(read_cb(block->id, 1, id_bytes, handle) != id_bytes) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + if(block_length < id_bytes) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block_length -= id_bytes; if(block_length == 0) { block->data = 0; } else { - if(0 == (block->data = (FLAC__byte*)malloc(block_length))) + if(0 == (block->data = malloc(block_length))) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; if(read_cb(block->data, 1, block_length, handle) != block_length) @@ -1951,7 +2176,7 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC_ if(block->num_points == 0) block->points = 0; - else if(0 == (block->points = (FLAC__StreamMetadata_SeekPoint*)malloc(block->num_points * sizeof(FLAC__StreamMetadata_SeekPoint)))) + else if(0 == (block->points = safe_malloc_mul_2op_p(block->num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)))) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; for(i = 0; i < block->num_points; i++) { @@ -1966,16 +2191,24 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC_ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; } -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry) +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, unsigned max_length) { const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8; FLAC__byte buffer[4]; /* magic number is asserted below */ - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == 4); + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == sizeof(buffer)); + if(max_length < entry_length_len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA; + + max_length -= entry_length_len; if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; entry->length = unpack_uint32_little_endian_(buffer, entry_length_len); + if(max_length < entry->length) { + entry->length = 0; + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA; + } else max_length -= entry->length; if(0 != entry->entry) free(entry->entry); @@ -1984,28 +2217,37 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entr entry->entry = 0; } else { - if(0 == (entry->entry = (FLAC__byte*)malloc(entry->length))) + if(0 == (entry->entry = safe_malloc_add_2op_(entry->length, /*+*/1))) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; if(read_cb(entry->entry, 1, entry->length, handle) != entry->length) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + + entry->entry[entry->length] = '\0'; } return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; } -FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block) +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, unsigned block_length) { unsigned i; FLAC__Metadata_SimpleIteratorStatus status; const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8; FLAC__byte buffer[4]; /* magic number is asserted below */ - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == 4); + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == sizeof(buffer)); - if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string)))) + status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string), block_length); + if(block_length >= 4) + block_length -= 4; + if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA) + goto skip; + else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) return status; + block_length -= block->vendor_string.length; + if(block_length < num_comments_len) goto skip; else block_length -= num_comments_len; if(read_cb(buffer, 1, num_comments_len, handle) != num_comments_len) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; block->num_comments = unpack_uint32_little_endian_(buffer, num_comments_len); @@ -2013,12 +2255,25 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_( if(block->num_comments == 0) { block->comments = 0; } - else if(0 == (block->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) + else if(0 == (block->comments = calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; for(i = 0; i < block->num_comments; i++) { - if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i))) - return status; + status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i, block_length); + if(block_length >= 4) block_length -= 4; + if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA) { + block->num_comments = i; + goto skip; + } + else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) return status; + block_length -= block->comments[i].length; + } + + skip: + if(block_length > 0) { + /* bad metadata */ + if(0 != seek_cb(handle, block_length, SEEK_CUR)) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; } return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; @@ -2068,7 +2323,7 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_( if(track->num_indices == 0) { track->indices = 0; } - else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) + else if(0 == (track->indices = calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; for(i = 0; i < track->num_indices; i++) { @@ -2128,7 +2383,7 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__ if(block->num_tracks == 0) { block->tracks = 0; } - else if(0 == (block->tracks = (FLAC__StreamMetadata_CueSheet_Track*)calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) + else if(0 == (block->tracks = calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; for(i = 0; i < block->num_tracks; i++) { @@ -2139,13 +2394,99 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; } +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstring_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len) +{ + FLAC__byte buffer[sizeof(FLAC__uint32)]; + + FLAC__ASSERT(0 != data); + FLAC__ASSERT(length_len%8 == 0); + + length_len /= 8; /* convert to bytes */ + + FLAC__ASSERT(sizeof(buffer) >= length_len); + + if(read_cb(buffer, 1, length_len, handle) != length_len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + *length = unpack_uint32_(buffer, length_len); + + if(0 != *data) + free(*data); + + if(0 == (*data = safe_malloc_add_2op_(*length, /*+*/1))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + if(*length > 0) { + if(read_cb(*data, 1, *length, handle) != *length) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + } + + (*data)[*length] = '\0'; + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block) +{ + FLAC__Metadata_SimpleIteratorStatus status; + FLAC__byte buffer[4]; /* asserted below that this is big enough */ + FLAC__uint32 len; + + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8); + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_TYPE_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->type = (FLAC__StreamMetadata_Picture_Type)unpack_uint32_(buffer, len); + + if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) + return status; + + if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) + return status; + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->width = unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->height = unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->depth = unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_COLORS_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->colors = unpack_uint32_(buffer, len); + + /* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */ + if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) + return status; + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length) { if(block_length == 0) { block->data = 0; } else { - if(0 == (block->data = (FLAC__byte*)malloc(block_length))) + if(0 == (block->data = malloc(block_length))) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; if(read_cb(block->data, 1, block_length, handle) != block_length) @@ -2215,6 +2556,8 @@ FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment); case FLAC__METADATA_TYPE_CUESHEET: return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet); + case FLAC__METADATA_TYPE_PICTURE: + return write_metadata_block_data_picture_cb_(handle, write_cb, &block->data.picture); default: return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length); } @@ -2307,7 +2650,7 @@ FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, F const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8; FLAC__byte buffer[4]; /* magic number is asserted below */ - FLAC__ASSERT(max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == 4); + FLAC__ASSERT(flac_max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == sizeof(buffer)); pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len); if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len) @@ -2399,17 +2742,17 @@ FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__I return false; for(j = 0; j < track->num_indices; j++) { - FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j; + FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + j; FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0); len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8; - pack_uint64_(index->offset, buffer, len); + pack_uint64_(indx->offset, buffer, len); if(write_cb(buffer, 1, len, handle) != len) return false; FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0); len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8; - pack_uint32_(index->number, buffer, len); + pack_uint32_(indx->number, buffer, len); if(write_cb(buffer, 1, len, handle) != len) return false; @@ -2424,6 +2767,80 @@ FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__I return true; } +FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block) +{ + unsigned len; + size_t slen; + FLAC__byte buffer[4]; /* magic number is asserted below */ + + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_TYPE_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_COLORS_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN%8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8); + + len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8; + pack_uint32_(block->type, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8; + slen = strlen(block->mime_type); + pack_uint32_(slen, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + if(write_cb(block->mime_type, 1, slen, handle) != slen) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8; + slen = strlen((const char *)block->description); + pack_uint32_(slen, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + if(write_cb(block->description, 1, slen, handle) != slen) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8; + pack_uint32_(block->width, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8; + pack_uint32_(block->height, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8; + pack_uint32_(block->depth, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8; + pack_uint32_(block->colors, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8; + pack_uint32_(block->data_length, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + if(write_cb(block->data, 1, block->data_length, handle) != block->data_length) + return false; + + return true; +} + FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length) { if(write_cb(block->data, 1, block_length, handle) != block_length) @@ -2434,7 +2851,7 @@ FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IO FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block) { - if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } @@ -2445,7 +2862,7 @@ FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *itera if(!write_metadata_block_data_(iterator->file, &iterator->status, block)) return false; - if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } @@ -2457,7 +2874,7 @@ FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIt { FLAC__StreamMetadata *padding; - if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } @@ -2488,7 +2905,7 @@ FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIt FLAC__metadata_object_delete(padding); - if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } @@ -2498,10 +2915,10 @@ FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIt FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append) { - FILE *tempfile; - char *tempfilename; + FILE *tempfile = NULL; + char *tempfilename = NULL; int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */ - long fixup_is_last_flag_offset = -1; + FLAC__off_t fixup_is_last_flag_offset = -1; FLAC__ASSERT(0 != block || append == false); @@ -2558,7 +2975,7 @@ FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator) { FLAC__ASSERT(iterator->depth > 0); iterator->depth--; - if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } @@ -2578,7 +2995,7 @@ unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallbac size_t n; unsigned i; - FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == 4); + FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer)); /* skip any id3v2 tag */ errno = 0; @@ -2629,9 +3046,9 @@ unsigned seek_to_first_metadata_block_(FILE *f) FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append) { - const long offset_end = append? iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length : iterator->offset[iterator->depth]; + const FLAC__off_t offset_end = append? iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length : iterator->offset[iterator->depth]; - if(0 != fseek(iterator->file, 0, SEEK_SET)) { + if(0 != fseeko(iterator->file, 0, SEEK_SET)) { iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; } @@ -2647,12 +3064,12 @@ FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iter return true; } -FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, long fixup_is_last_flag_offset, FLAC__bool backup) +FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup) { - long save_offset = iterator->offset[iterator->depth]; /*@@@ 2G limit */ + FLAC__off_t save_offset = iterator->offset[iterator->depth]; FLAC__ASSERT(0 != *tempfile); - if(0 != fseek(iterator->file, save_offset + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length, SEEK_SET)) { + if(0 != fseeko(iterator->file, save_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length, SEEK_SET)) { cleanup_tempfile_(tempfile, tempfilename); iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; @@ -2671,7 +3088,7 @@ FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *ite */ /* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */ FLAC__byte x; - if(0 != fseek(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) { + if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) { cleanup_tempfile_(tempfile, tempfilename); iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; @@ -2689,7 +3106,7 @@ FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *ite FLAC__ASSERT(!(x & 0x80)); x |= 0x80; } - if(0 != fseek(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) { + if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) { cleanup_tempfile_(tempfile, tempfilename); iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; return false; @@ -2712,7 +3129,7 @@ FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *ite if(!simple_iterator_prime_input_(iterator, !iterator->is_writable)) return false; if(backup) { - while(iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length < save_offset) + while(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length < save_offset) if(!FLAC__metadata_simple_iterator_next(iterator)) return false; return true; @@ -2726,13 +3143,14 @@ FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *ite } } -FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status) +FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status) { FLAC__byte buffer[8192]; - unsigned n; + size_t n; + FLAC__ASSERT(bytes >= 0); while(bytes > 0) { - n = min(sizeof(buffer), bytes); + n = flac_min(sizeof(buffer), (size_t)bytes); if(fread(buffer, 1, n, file) != n) { *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; return false; @@ -2747,13 +3165,14 @@ FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, unsigned bytes/*@ return true; } -FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status) +FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status) { FLAC__byte buffer[8192]; - unsigned n; + size_t n; + FLAC__ASSERT(bytes >= 0); while(bytes > 0) { - n = min(sizeof(buffer), bytes); + n = flac_min(sizeof(buffer), (size_t)bytes); if(read_cb(buffer, 1, n, handle) != n) { *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; return false; @@ -2808,35 +3227,59 @@ FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCal return true; } +static int +local_snprintf(char *str, size_t size, const char *fmt, ...) +{ + va_list va; + int rc; + + va_start (va, fmt); + +#if defined _MSC_VER + if (size == 0) + return 1024; + rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va); + if (rc < 0) + rc = size - 1; +#elif defined __MINGW32__ + rc = __mingw_vsnprintf (str, size, fmt, va); +#else + rc = vsnprintf (str, size, fmt, va); +#endif + va_end (va); + + return rc; +} + FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status) { static const char *tempfile_suffix = ".metadata_edit"; if(0 == tempfile_path_prefix) { - if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1))) { + size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1; + if(0 == (*tempfilename = safe_malloc_(dest_len))) { *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; return false; } - strcpy(*tempfilename, filename); - strcat(*tempfilename, tempfile_suffix); + local_snprintf(*tempfilename, dest_len, "%s%s", filename, tempfile_suffix); } else { const char *p = strrchr(filename, '/'); + size_t dest_len; if(0 == p) p = filename; else p++; - if(0 == (*tempfilename = (char*)malloc(strlen(tempfile_path_prefix) + 1 + strlen(p) + strlen(tempfile_suffix) + 1))) { + dest_len = strlen(tempfile_path_prefix) + strlen(p) + strlen(tempfile_suffix) + 2; + + if(0 == (*tempfilename = safe_malloc_(dest_len))) { *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; return false; } - strcpy(*tempfilename, tempfile_path_prefix); - strcat(*tempfilename, "/"); - strcat(*tempfilename, p); - strcat(*tempfilename, tempfile_suffix); + local_snprintf(*tempfilename, dest_len, "%s/%s%s", tempfile_path_prefix, p, tempfile_suffix); } - if(0 == (*tempfile = fopen(*tempfilename, "w+b"))) { + if(0 == (*tempfile = flac_fopen(*tempfilename, "w+b"))) { *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; return false; } @@ -2856,16 +3299,17 @@ FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tem (void)fclose(*tempfile); *tempfile = 0; -#if defined _MSC_VER || defined __MINGW32__ - if(unlink(filename) < 0) { +#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined __EMX__ + /* on some flavors of windows, flac_rename() will fail if the destination already exists */ + if(flac_unlink(filename) < 0) { cleanup_tempfile_(tempfile, tempfilename); *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR; return false; } #endif - /*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just rename(): */ - if(0 != rename(*tempfilename, filename)) { + /*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just flac_rename(): */ + if(0 != flac_rename(*tempfilename, filename)) { cleanup_tempfile_(tempfile, tempfilename); *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR; return false; @@ -2884,20 +3328,20 @@ void cleanup_tempfile_(FILE **tempfile, char **tempfilename) } if(0 != *tempfilename) { - (void)unlink(*tempfilename); + (void)flac_unlink(*tempfilename); free(*tempfilename); *tempfilename = 0; } } -FLAC__bool get_file_stats_(const char *filename, struct stat *stats) +FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats) { FLAC__ASSERT(0 != filename); FLAC__ASSERT(0 != stats); - return (0 == stat(filename, stats)); + return (0 == flac_stat(filename, stats)); } -void set_file_stats_(const char *filename, struct stat *stats) +void set_file_stats_(const char *filename, struct flac_stat_s *stats) { struct utimbuf srctime; @@ -2906,28 +3350,22 @@ void set_file_stats_(const char *filename, struct stat *stats) srctime.actime = stats->st_atime; srctime.modtime = stats->st_mtime; - (void)chmod(filename, stats->st_mode); - (void)utime(filename, &srctime); -#if !defined _MSC_VER && !defined __MINGW32__ - (void)chown(filename, stats->st_uid, -1); - (void)chown(filename, -1, stats->st_gid); + (void)flac_chmod(filename, stats->st_mode); + (void)flac_utime(filename, &srctime); +#if !defined _MSC_VER && !defined __BORLANDC__ && !defined __MINGW32__ + FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1)); + FLAC_CHECK_RETURN(chown(filename, -1, stats->st_gid)); #endif } -/* @@@ WATCHOUT @@@ - * We cast FLAC__int64 to long and use fseek()/ftell() because - * none of our operations on metadata is ever likely to go past - * 2 gigabytes. - */ int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence) { - FLAC__ASSERT(offset <= 0x7fffffff); - return fseek((FILE*)handle, (long)offset, whence); + return fseeko((FILE*)handle, (FLAC__off_t)offset, whence); } FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle) { - return (long)ftell((FILE*)handle); + return ftello((FILE*)handle); } FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status) diff --git a/sys/src/cmd/audio/libFLAC/metadata_object.c b/sys/src/cmd/audio/libFLAC/metadata_object.c index 886a17c77..0456297a3 100644 --- a/sys/src/cmd/audio/libFLAC/metadata_object.c +++ b/sys/src/cmd/audio/libFLAC/metadata_object.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,12 +30,22 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include <stdlib.h> #include <string.h> #include "private/metadata.h" +#include "private/memory.h" #include "FLAC/assert.h" +#include "share/alloc.h" +#include "share/compat.h" + +/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */ +#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p /**************************************************************************** @@ -43,11 +54,20 @@ * ***************************************************************************/ +/* copy bytes: + * from = NULL && bytes = 0 + * to <- NULL + * from != NULL && bytes > 0 + * to <- copy of from + * else ASSERT + * malloc error leaves 'to' unchanged + */ static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes) { + FLAC__ASSERT(0 != to); if(bytes > 0 && 0 != from) { FLAC__byte *x; - if(0 == (x = (FLAC__byte*)malloc(bytes))) + if(0 == (x = safe_malloc_(bytes))) return false; memcpy(x, from, bytes); *to = x; @@ -60,6 +80,55 @@ static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned return true; } +#if 0 /* UNUSED */ +/* like copy_bytes_(), but free()s the original '*to' if the copy succeeds and the original '*to' is non-NULL */ +static FLAC__bool free_copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes) +{ + FLAC__byte *copy; + FLAC__ASSERT(0 != to); + if(copy_bytes_(©, from, bytes)) { + if(*to) + free(*to); + *to = copy; + return true; + } + else + return false; +} +#endif + +/* reallocate entry to 1 byte larger and add a terminating NUL */ +/* realloc() failure leaves entry unchanged */ +static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length) +{ + FLAC__byte *x = safe_realloc_add_2op_(*entry, length, /*+*/1); + if(0 != x) { + x[length] = '\0'; + *entry = x; + return true; + } + else + return false; +} + +/* copies the NUL-terminated C-string 'from' to '*to', leaving '*to' + * unchanged if malloc fails, free()ing the original '*to' if it + * succeeds and the original '*to' was not NULL + */ +static FLAC__bool copy_cstring_(char **to, const char *from) +{ + char *copy = strdup(from); + FLAC__ASSERT(to); + if(copy) { + if(*to) + free(*to); + *to = copy; + return true; + } + else + return false; +} + static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from) { to->length = from->length; @@ -70,9 +139,10 @@ static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, co else { FLAC__byte *x; FLAC__ASSERT(from->length > 0); - if(0 == (x = (FLAC__byte*)malloc(from->length))) + if(0 == (x = safe_malloc_add_2op_(from->length, /*+*/1))) return false; memcpy(x, from->entry, from->length); + x[from->length] = '\0'; to->entry = x; } return true; @@ -87,7 +157,7 @@ static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLA else { FLAC__StreamMetadata_CueSheet_Index *x; FLAC__ASSERT(from->num_indices > 0); - if(0 == (x = (FLAC__StreamMetadata_CueSheet_Index*)malloc(from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)))) + if(0 == (x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index)))) return false; memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); to->indices = x; @@ -109,7 +179,7 @@ static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(unsigned num_points) FLAC__ASSERT(num_points > 0); - object_array = (FLAC__StreamMetadata_SeekPoint*)malloc(num_points * sizeof(FLAC__StreamMetadata_SeekPoint)); + object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)); if(0 != object_array) { unsigned i; @@ -142,7 +212,7 @@ static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_( { FLAC__ASSERT(num_comments > 0); - return (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)); + return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)); } static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments) @@ -194,13 +264,30 @@ static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__S save = dest->entry; - /* do the copy first so that if we fail we leave the object untouched */ - if(copy && (0 != src->entry && src->length > 0)) { - if(!copy_vcentry_(dest, src)) - return false; + if(0 != src->entry) { + if(copy) { + /* do the copy first so that if we fail we leave the dest object untouched */ + if(!copy_vcentry_(dest, src)) + return false; + } + else { + /* we have to make sure that the string we're taking over is null-terminated */ + + /* + * Stripping the const from src->entry is OK since we're taking + * ownership of the pointer. This is a hack around a deficiency + * in the API where the same function is used for 'copy' and + * 'own', but the source entry is a const pointer. If we were + * precise, the 'own' flavor would be a separate function with a + * non-const source pointer. But it's not, so we hack away. + */ + if(!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length)) + return false; + *dest = *src; + } } else { - /* either we're not copying or the src is null */ + /* the src is null */ *dest = *src; } @@ -211,6 +298,22 @@ static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__S return true; } +static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name, unsigned field_name_length) +{ + unsigned i; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(0 != field_name); + + for(i = offset; i < object->data.vorbis_comment.num_comments; i++) { + if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) + return (int)i; + } + + return -1; +} + static void cuesheet_calculate_length_(FLAC__StreamMetadata *object) { unsigned i; @@ -248,14 +351,14 @@ static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(unsi { FLAC__ASSERT(num_indices > 0); - return (FLAC__StreamMetadata_CueSheet_Index*)calloc(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)); + return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)); } static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(unsigned num_tracks) { FLAC__ASSERT(num_tracks > 0); - return (FLAC__StreamMetadata_CueSheet_Track*)calloc(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)); + return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)); } static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks) @@ -337,10 +440,10 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type { FLAC__StreamMetadata *object; - if(type > FLAC__MAX_METADATA_TYPE_CODE) + if(type > FLAC__MAX_METADATA_TYPE) return 0; - object = (FLAC__StreamMetadata*)calloc(1, sizeof(FLAC__StreamMetadata)); + object = calloc(1, sizeof(FLAC__StreamMetadata)); if(0 != object) { object->is_last = false; object->type = type; @@ -367,18 +470,51 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type */ break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: - { - object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING); - if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length)) { - free(object); - return 0; - } - vorbiscomment_calculate_length_(object); + object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING); + if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) { + free(object); + return 0; } + vorbiscomment_calculate_length_(object); break; case FLAC__METADATA_TYPE_CUESHEET: cuesheet_calculate_length_(object); break; + case FLAC__METADATA_TYPE_PICTURE: + object->length = ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */ + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */ + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_COLORS_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + + 0 /* no data */ + ) / 8; + object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER; + object->data.picture.mime_type = 0; + object->data.picture.description = 0; + /* calloc() took care of this for us: + object->data.picture.width = 0; + object->data.picture.height = 0; + object->data.picture.depth = 0; + object->data.picture.colors = 0; + object->data.picture.data_length = 0; + object->data.picture.data = 0; + */ + /* now initialize mime_type and description with empty strings to make things easier on the client */ + if(!copy_cstring_(&object->data.picture.mime_type, "")) { + free(object); + return 0; + } + if(!copy_cstring_((char**)(&object->data.picture.description), "")) { + if(object->data.picture.mime_type) + free(object->data.picture.mime_type); + free(object); + return 0; + } + break; default: /* calloc() took care of this for us: object->length = 0; @@ -408,6 +544,10 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMet case FLAC__METADATA_TYPE_PADDING: break; case FLAC__METADATA_TYPE_APPLICATION: + if(to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */ + FLAC__metadata_object_delete(to); + return 0; + } memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8); if(!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) { FLAC__metadata_object_delete(to); @@ -416,6 +556,10 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMet break; case FLAC__METADATA_TYPE_SEEKTABLE: to->data.seek_table.num_points = object->data.seek_table.num_points; + if(to->data.seek_table.num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */ + FLAC__metadata_object_delete(to); + return 0; + } if(!copy_bytes_((FLAC__byte**)&to->data.seek_table.points, (FLAC__byte*)object->data.seek_table.points, object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint))) { FLAC__metadata_object_delete(to); return 0; @@ -458,6 +602,26 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMet } } break; + case FLAC__METADATA_TYPE_PICTURE: + to->data.picture.type = object->data.picture.type; + if(!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) { + FLAC__metadata_object_delete(to); + return 0; + } + if(!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) { + FLAC__metadata_object_delete(to); + return 0; + } + to->data.picture.width = object->data.picture.width; + to->data.picture.height = object->data.picture.height; + to->data.picture.depth = object->data.picture.depth; + to->data.picture.colors = object->data.picture.colors; + to->data.picture.data_length = object->data.picture.data_length; + if(!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) { + FLAC__metadata_object_delete(to); + return 0; + } + break; default: if(!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) { FLAC__metadata_object_delete(to); @@ -506,6 +670,20 @@ void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object) cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); } break; + case FLAC__METADATA_TYPE_PICTURE: + if(0 != object->data.picture.mime_type) { + free(object->data.picture.mime_type); + object->data.picture.mime_type = 0; + } + if(0 != object->data.picture.description) { + free(object->data.picture.description); + object->data.picture.description = 0; + } + if(0 != object->data.picture.data) { + free(object->data.picture.data); + object->data.picture.data = 0; + } + break; default: if(0 != object->data.unknown.data) { free(object->data.unknown.data); @@ -660,6 +838,29 @@ static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueShe return true; } +static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2) +{ + if(block1->type != block2->type) + return false; + if(block1->mime_type != block2->mime_type && (0 == block1->mime_type || 0 == block2->mime_type || strcmp(block1->mime_type, block2->mime_type))) + return false; + if(block1->description != block2->description && (0 == block1->description || 0 == block2->description || strcmp((const char *)block1->description, (const char *)block2->description))) + return false; + if(block1->width != block2->width) + return false; + if(block1->height != block2->height) + return false; + if(block1->depth != block2->depth) + return false; + if(block1->colors != block2->colors) + return false; + if(block1->data_length != block2->data_length) + return false; + if(block1->data != block2->data && (0 == block1->data || 0 == block2->data || memcmp(block1->data, block2->data, block1->data_length))) + return false; + return true; +} + static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, unsigned block_length) { FLAC__ASSERT(0 != block1); @@ -698,6 +899,8 @@ FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *b return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment); case FLAC__METADATA_TYPE_CUESHEET: return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet); + case FLAC__METADATA_TYPE_PICTURE: + return compare_block_data_picture_(&block1->data.picture, &block2->data.picture); default: return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length); } @@ -742,8 +945,12 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMe return false; } else { - const unsigned old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint); - const unsigned new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint); + const size_t old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint); + const size_t new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint); + + /* overflow check */ + if(new_num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) + return false; FLAC__ASSERT(object->data.seek_table.num_points > 0); @@ -751,7 +958,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMe free(object->data.seek_table.points); object->data.seek_table.points = 0; } - else if(0 == (object->data.seek_table.points = (FLAC__StreamMetadata_SeekPoint*)realloc(object->data.seek_table.points, new_size))) + else if(0 == (object->data.seek_table.points = realloc(object->data.seek_table.points, new_size))) return false; /* if growing, set new elements to placeholders */ @@ -885,7 +1092,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_point FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); FLAC__ASSERT(total_samples > 0); - if(num > 0) { + if(num > 0 && total_samples > 0) { FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; unsigned i, j; @@ -904,6 +1111,39 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_point return true; } +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + FLAC__ASSERT(samples > 0); + FLAC__ASSERT(total_samples > 0); + + if(samples > 0 && total_samples > 0) { + FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; + unsigned i, j; + FLAC__uint64 num, sample; + + num = 1 + total_samples / samples; /* 1+ for the first sample at 0 */ + /* now account for the fact that we don't place a seekpoint at "total_samples" since samples are number from 0: */ + if(total_samples % samples == 0) + num--; + + i = seek_table->num_points; + + if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (unsigned)num)) + return false; + + sample = 0; + for(j = 0; j < num; i++, j++, sample += samples) { + seek_table->points[i].sample_number = sample; + seek_table->points[i].stream_offset = 0; + seek_table->points[i].frame_samples = 0; + } + } + + return true; +} + FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact) { unsigned unique; @@ -918,6 +1158,8 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMe FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) { + if(!FLAC__format_vorbiscomment_entry_value_is_legal(entry.entry, entry.length)) + return false; return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy); } @@ -934,8 +1176,12 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__St return false; } else { - const unsigned old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); - const unsigned new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); + const size_t old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); + const size_t new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry); + + /* overflow check */ + if(new_num_comments > UINT32_MAX / sizeof(FLAC__StreamMetadata_VorbisComment_Entry)) + return false; FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0); @@ -951,7 +1197,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__St free(object->data.vorbis_comment.comments); object->data.vorbis_comment.comments = 0; } - else if(0 == (object->data.vorbis_comment.comments = (FLAC__StreamMetadata_VorbisComment_Entry*)realloc(object->data.vorbis_comment.comments, new_size))) + else if(0 == (object->data.vorbis_comment.comments = realloc(object->data.vorbis_comment.comments, new_size))) return false; /* if growing, zero all the length/pointers of new elements */ @@ -970,6 +1216,8 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__Stream FLAC__ASSERT(0 != object); FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments); + if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) + return false; return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy); } @@ -981,6 +1229,9 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__Str FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments); + if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) + return false; + vc = &object->data.vorbis_comment; if(!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1)) @@ -994,6 +1245,58 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__Str return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy); } +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy); +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy) +{ + FLAC__ASSERT(0 != entry.entry && entry.length > 0); + + if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) + return false; + + { + int i; + size_t field_name_length; + const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); + + FLAC__ASSERT(0 != eq); + + if(0 == eq) + return false; /* double protection */ + + field_name_length = eq-entry.entry; + + i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length); + if(i >= 0) { + unsigned indx = (unsigned)i; + if(!FLAC__metadata_object_vorbiscomment_set_comment(object, indx, entry, copy)) + return false; + entry = object->data.vorbis_comment.comments[indx]; + indx++; /* skip over replaced comment */ + if(all && indx < object->data.vorbis_comment.num_comments) { + i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length); + while(i >= 0) { + indx = (unsigned)i; + if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, indx)) + return false; + if(indx < object->data.vorbis_comment.num_comments) + i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length); + else + i = -1; + } + } + return true; + } + else + return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy); + } +} + FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num) { FLAC__StreamMetadata_VorbisComment *vc; @@ -1016,32 +1319,77 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__Str return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1); } -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, unsigned field_name_length) +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value) { - const FLAC__byte *eq = (FLAC__byte*)memchr(entry->entry, '=', entry->length); -#if defined _MSC_VER || defined __MINGW32__ -#define FLAC__STRNCASECMP strnicmp -#else -#define FLAC__STRNCASECMP strncasecmp -#endif - return (0 != eq && (unsigned)(eq-entry->entry) == field_name_length && 0 == FLAC__STRNCASECMP(field_name, (const char *)entry->entry, field_name_length)); -#undef FLAC__STRNCASECMP + FLAC__ASSERT(0 != entry); + FLAC__ASSERT(0 != field_name); + FLAC__ASSERT(0 != field_value); + + if(!FLAC__format_vorbiscomment_entry_name_is_legal(field_name)) + return false; + if(!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (unsigned)(-1))) + return false; + + { + const size_t nn = strlen(field_name); + const size_t nv = strlen(field_value); + entry->length = nn + 1 /*=*/ + nv; + if(0 == (entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1))) + return false; + memcpy(entry->entry, field_name, nn); + entry->entry[nn] = '='; + memcpy(entry->entry+nn+1, field_value, nv); + entry->entry[entry->length] = '\0'; + } + + return true; } -FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name) +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value) { - const unsigned field_name_length = strlen(field_name); - unsigned i; + FLAC__ASSERT(0 != entry.entry && entry.length > 0); + FLAC__ASSERT(0 != field_name); + FLAC__ASSERT(0 != field_value); - FLAC__ASSERT(0 != object); - FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) + return false; - for(i = offset; i < object->data.vorbis_comment.num_comments; i++) { - if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments + i, field_name, field_name_length)) - return (int)i; + { + const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); + const size_t nn = eq-entry.entry; + const size_t nv = entry.length-nn-1; /* -1 for the '=' */ + FLAC__ASSERT(0 != eq); + if(0 == eq) + return false; /* double protection */ + if(0 == (*field_name = safe_malloc_add_2op_(nn, /*+*/1))) + return false; + if(0 == (*field_value = safe_malloc_add_2op_(nv, /*+*/1))) { + free(*field_name); + return false; + } + memcpy(*field_name, entry.entry, nn); + memcpy(*field_value, entry.entry+nn+1, nv); + (*field_name)[nn] = '\0'; + (*field_value)[nv] = '\0'; } - return -1; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length) +{ + FLAC__ASSERT(0 != entry.entry && entry.length > 0); + { + const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length); + return (0 != eq && (unsigned)(eq-entry.entry) == field_name_length && 0 == FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length)); + } +} + +FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name) +{ + FLAC__ASSERT(0 != field_name); + + return vorbiscomment_find_entry_from_(object, offset, field_name, strlen(field_name)); } FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name) @@ -1053,7 +1401,7 @@ FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__Str FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); for(i = 0; i < object->data.vorbis_comment.num_comments; i++) { - if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments + i, field_name, field_name_length)) { + if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) { if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, i)) return -1; else @@ -1076,7 +1424,7 @@ FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__S /* must delete from end to start otherwise it will interfere with our iteration */ for(i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) { - if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments + i, field_name, field_name_length)) { + if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) { matching++; ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i); } @@ -1087,7 +1435,7 @@ FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__S FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void) { - return (FLAC__StreamMetadata_CueSheet_Track*)calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track)); + return calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track)); } FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object) @@ -1139,8 +1487,12 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__St return false; } else { - const unsigned old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); - const unsigned new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); + const size_t old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); + const size_t new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index); + + /* overflow check */ + if(new_num_indices > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Index)) + return false; FLAC__ASSERT(track->num_indices > 0); @@ -1148,7 +1500,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__St free(track->indices); track->indices = 0; } - else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)realloc(track->indices, new_size))) + else if(0 == (track->indices = realloc(track->indices, new_size))) return false; /* if growing, zero all the lengths/pointers of new elements */ @@ -1162,7 +1514,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__St return true; } -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index) +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index indx) { FLAC__StreamMetadata_CueSheet_Track *track; @@ -1179,16 +1531,16 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__Stre /* move all indices >= index_num forward one space */ memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num)); - track->indices[index_num] = index; + track->indices[index_num] = indx; cuesheet_calculate_length_(object); return true; } FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num) { - FLAC__StreamMetadata_CueSheet_Index index; - memset(&index, 0, sizeof(index)); - return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, index); + FLAC__StreamMetadata_CueSheet_Index indx; + memset(&indx, 0, sizeof(indx)); + return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, indx); } FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num) @@ -1223,8 +1575,12 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMet return false; } else { - const unsigned old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); - const unsigned new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); + const size_t old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); + const size_t new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track); + + /* overflow check */ + if(new_num_tracks > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Track)) + return false; FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0); @@ -1240,7 +1596,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMet free(object->data.cue_sheet.tracks); object->data.cue_sheet.tracks = 0; } - else if(0 == (object->data.cue_sheet.tracks = (FLAC__StreamMetadata_CueSheet_Track*)realloc(object->data.cue_sheet.tracks, new_size))) + else if(0 == (object->data.cue_sheet.tracks = realloc(object->data.cue_sheet.tracks, new_size))) return false; /* if growing, zero all the lengths/pointers of new elements */ @@ -1319,3 +1675,150 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMe return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation); } + +static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, unsigned track) +{ + if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1) + return 0; + else if (cs->tracks[track].indices[0].number == 1) + return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in; + else if (cs->tracks[track].num_indices < 2) + return 0; + else if (cs->tracks[track].indices[1].number == 1) + return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in; + else + return 0; +} + +static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x) +{ + FLAC__uint32 n = 0; + while (x) { + n += (x%10); + x /= 10; + } + return n; +} + +/*@@@@add to tests*/ +FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object) +{ + const FLAC__StreamMetadata_CueSheet *cs; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + + cs = &object->data.cue_sheet; + + if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */ + return 0; + + { + FLAC__uint32 i, length, sum = 0; + for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */ + sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100)); + length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100); + + return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1); + } +} + +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy) +{ + char *old; + size_t old_length, new_length; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + FLAC__ASSERT(0 != mime_type); + + old = object->data.picture.mime_type; + old_length = old? strlen(old) : 0; + new_length = strlen(mime_type); + + /* do the copy first so that if we fail we leave the object untouched */ + if(copy) { + if(new_length >= SIZE_MAX) /* overflow check */ + return false; + if(!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1)) + return false; + } + else { + object->data.picture.mime_type = mime_type; + } + + if(0 != old) + free(old); + + object->length -= old_length; + object->length += new_length; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy) +{ + FLAC__byte *old; + size_t old_length, new_length; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + FLAC__ASSERT(0 != description); + + old = object->data.picture.description; + old_length = old? strlen((const char *)old) : 0; + new_length = strlen((const char *)description); + + /* do the copy first so that if we fail we leave the object untouched */ + if(copy) { + if(new_length >= SIZE_MAX) /* overflow check */ + return false; + if(!copy_bytes_(&object->data.picture.description, description, new_length+1)) + return false; + } + else { + object->data.picture.description = description; + } + + if(0 != old) + free(old); + + object->length -= old_length; + object->length += new_length; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy) +{ + FLAC__byte *old; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false)); + + old = object->data.picture.data; + + /* do the copy first so that if we fail we leave the object untouched */ + if(copy) { + if(!copy_bytes_(&object->data.picture.data, data, length)) + return false; + } + else { + object->data.picture.data = data; + } + + if(0 != old) + free(old); + + object->length -= object->data.picture.data_length; + object->data.picture.data_length = length; + object->length += length; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + + return FLAC__format_picture_is_legal(&object->data.picture, violation); +} diff --git a/sys/src/cmd/audio/libFLAC/mkfile b/sys/src/cmd/audio/libFLAC/mkfile index 1f884c766..5cf6486eb 100644 --- a/sys/src/cmd/audio/libFLAC/mkfile +++ b/sys/src/cmd/audio/libFLAC/mkfile @@ -3,26 +3,29 @@ LIB=libFLAC.a$O OFILES=\ - bitbuffer.$O\ bitmath.$O\ + bitreader.$O\ + bitwriter.$O\ cpu.$O\ crc.$O\ fixed.$O\ + float.$O\ format.$O\ lpc.$O\ md5.$O\ memory.$O\ metadata_iterators.$O\ metadata_object.$O\ - file_encoder.$O\ - file_decoder.$O\ - seekable_stream_encoder.$O\ - seekable_stream_decoder.$O\ - stream_encoder.$O\ + ogg_decoder_aspect.$O\ + ogg_encoder_aspect.$O\ + ogg_helper.$O\ + ogg_mapping.$O\ stream_decoder.$O\ + stream_encoder.$O\ stream_encoder_framing.$O\ + window.$O\ CC=pcc -CFLAGS=-I. -DVERSION="1.1.1" -DPlan9 -DFLAC__NO_NASM -DFLAC__ALIGN_MALLOC_DATA -D_BSD_EXTENSION -D_POSIX_SOURCE -c +CFLAGS=-I. -I../libogg -DVERSION="1.3.1" -DPlan9 -DFLAC__HAS_OGG -DFLAC__ALIGN_MALLOC_DATA -D_C99_SNPRINTF_EXTENSION -D_BSD_EXTENSION -D_POSIX_SOURCE -c </sys/src/cmd/mklib diff --git a/sys/src/cmd/audio/libFLAC/ogg_decoder_aspect.c b/sys/src/cmd/audio/libFLAC/ogg_decoder_aspect.c new file mode 100644 index 000000000..219c47953 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/ogg_decoder_aspect.c @@ -0,0 +1,251 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> /* for memcpy() */ +#include "FLAC/assert.h" +#include "private/ogg_decoder_aspect.h" +#include "private/ogg_mapping.h" +#include "private/macros.h" + + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect) +{ + /* 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; + + aspect->version_major = ~(0u); + aspect->version_minor = ~(0u); + + aspect->need_serial_number = aspect->use_first_serial_number; + + aspect->end_of_stream = false; + aspect->have_working_page = false; + + return true; +} + +void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect) +{ + (void)ogg_sync_clear(&aspect->sync_state); + (void)ogg_stream_clear(&aspect->stream_state); +} + +void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value) +{ + aspect->use_first_serial_number = false; + aspect->serial_number = value; +} + +void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect) +{ + aspect->use_first_serial_number = true; +} + +void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect) +{ + (void)ogg_stream_reset(&aspect->stream_state); + (void)ogg_sync_reset(&aspect->sync_state); + aspect->end_of_stream = false; + aspect->have_working_page = false; +} + +void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect) +{ + FLAC__ogg_decoder_aspect_flush(aspect); + + if(aspect->use_first_serial_number) + aspect->need_serial_number = true; +} + +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) +{ + static const size_t OGG_BYTES_CHUNK = 8192; + const size_t bytes_requested = *bytes; + + /* + * The FLAC decoding API uses pull-based reads, whereas Ogg decoding + * is push-based. In libFLAC, when you ask to decode a frame, the + * decoder will eventually call the read callback to supply some data, + * but how much it asks for depends on how much free space it has in + * its internal buffer. It does not try to grow its internal buffer + * to accomodate a whole frame because then the internal buffer size + * could not be limited, which is necessary in embedded applications. + * + * Ogg however grows its internal buffer until a whole page is present; + * only then can you get decoded data out. So we can't just ask for + * the same number of bytes from Ogg, then pass what's decoded down to + * libFLAC. If what libFLAC is asking for will not contain a whole + * page, then we will get no data from ogg_sync_pageout(), and at the + * same time cannot just read more data from the client for the purpose + * of getting a whole decoded page because the decoded size might be + * larger than libFLAC's internal buffer. + * + * Instead, whenever this read callback wrapper is called, we will + * continually request data from the client until we have at least one + * page, and manage pages internally so that we can send pieces of + * pages down to libFLAC in such a way that we obey its size + * requirement. To limit the amount of callbacks, we will always try + * to read in enough pages to return the full number of bytes + * requested. + */ + *bytes = 0; + while (*bytes < bytes_requested && !aspect->end_of_stream) { + if (aspect->have_working_page) { + if (aspect->have_working_packet) { + size_t n = bytes_requested - *bytes; + if ((size_t)aspect->working_packet.bytes <= n) { + /* the rest of the packet will fit in the buffer */ + n = aspect->working_packet.bytes; + memcpy(buffer, aspect->working_packet.packet, n); + *bytes += n; + buffer += n; + aspect->have_working_packet = false; + } + else { + /* only n bytes of the packet will fit in the buffer */ + memcpy(buffer, aspect->working_packet.packet, n); + *bytes += n; + buffer += n; + aspect->working_packet.packet += n; + aspect->working_packet.bytes -= n; + } + } + else { + /* try and get another packet */ + const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet); + if (ret > 0) { + aspect->have_working_packet = true; + /* if it is the first header packet, check for magic and a supported Ogg FLAC mapping version */ + if (aspect->working_packet.bytes > 0 && aspect->working_packet.packet[0] == FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE) { + const FLAC__byte *b = aspect->working_packet.packet; + const unsigned header_length = + FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH + + FLAC__OGG_MAPPING_MAGIC_LENGTH + + FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH + + FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH + + FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH; + if (aspect->working_packet.bytes < (long)header_length) + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC; + b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH; + if (memcmp(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH)) + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC; + b += FLAC__OGG_MAPPING_MAGIC_LENGTH; + aspect->version_major = (unsigned)(*b); + b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH; + aspect->version_minor = (unsigned)(*b); + if (aspect->version_major != 1) + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION; + aspect->working_packet.packet += header_length; + aspect->working_packet.bytes -= header_length; + } + } + else if (ret == 0) { + aspect->have_working_page = false; + } + else { /* ret < 0 */ + /* lost sync, we'll leave the working page for the next call */ + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC; + } + } + } + else { + /* try and get another page */ + const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page); + if (ret > 0) { + /* got a page, grab the serial number if necessary */ + if(aspect->need_serial_number) { + aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&aspect->working_page); + aspect->need_serial_number = false; + } + if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) { + aspect->have_working_page = true; + aspect->have_working_packet = false; + } + /* else do nothing, could be a page from another stream */ + } + else if (ret == 0) { + /* need more data */ + const size_t ogg_bytes_to_read = flac_max(bytes_requested - *bytes, OGG_BYTES_CHUNK); + char *oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read); + + if(0 == oggbuf) { + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR; + } + else { + size_t ogg_bytes_read = ogg_bytes_to_read; + + switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) { + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK: + break; + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM: + aspect->end_of_stream = true; + break; + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT: + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT; + default: + FLAC__ASSERT(0); + } + + if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0) { + /* double protection; this will happen if the read callback returns more bytes than the max requested, which would overflow Ogg's internal buffer */ + FLAC__ASSERT(0); + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR; + } + } + } + else { /* ret < 0 */ + /* lost sync, bail out */ + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC; + } + } + } + + if (aspect->end_of_stream && *bytes == 0) { + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM; + } + + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK; +} diff --git a/sys/src/cmd/audio/libFLAC/ogg_encoder_aspect.c b/sys/src/cmd/audio/libFLAC/ogg_encoder_aspect.c new file mode 100644 index 000000000..39bb9e962 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/ogg_encoder_aspect.c @@ -0,0 +1,228 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> /* for memset() */ +#include "FLAC/assert.h" +#include "private/ogg_encoder_aspect.h" +#include "private/ogg_mapping.h" + +static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MAJOR = 1; +static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MINOR = 0; + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect) +{ + /* we will determine the serial number later if necessary */ + if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0) + return false; + + aspect->seen_magic = false; + aspect->is_first_packet = true; + aspect->samples_written = 0; + + return true; +} + +void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect) +{ + (void)ogg_stream_clear(&aspect->stream_state); + /*@@@ what about the page? */ +} + +void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value) +{ + aspect->serial_number = value; +} + +FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, unsigned value) +{ + if(value < (1u << FLAC__OGG_MAPPING_NUM_HEADERS_LEN)) { + aspect->num_metadata = value; + return true; + } + else + return false; +} + +void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect) +{ + aspect->serial_number = 0; + aspect->num_metadata = 0; +} + +/* + * The basic FLAC -> Ogg mapping goes like this: + * + * - 'fLaC' magic and STREAMINFO block get combined into the first + * packet. The packet is prefixed with + * + the one-byte packet type 0x7F + * + 'FLAC' magic + * + the 2 byte Ogg FLAC mapping version number + * + tne 2 byte big-endian # of header packets + * - The first packet is flushed to the first page. + * - Each subsequent metadata block goes into its own packet. + * - Each metadata packet is flushed to page (this is not required, + * the mapping only requires that a flush must occur after all + * metadata is written). + * - Each subsequent FLAC audio frame goes into its own packet. + * + * WATCHOUT: + * This depends on the behavior of FLAC__StreamEncoder that we get a + * separate write callback for the fLaC magic, and then separate write + * callbacks for each metadata block and audio frame. + */ +FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data) +{ + /* WATCHOUT: + * This depends on the behavior of FLAC__StreamEncoder that 'samples' + * will be 0 for metadata writes. + */ + const FLAC__bool is_metadata = (samples == 0); + + /* + * Treat fLaC magic packet specially. We will note when we see it, then + * wait until we get the STREAMINFO and prepend it in that packet + */ + if(aspect->seen_magic) { + ogg_packet packet; + FLAC__byte synthetic_first_packet_body[ + FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH + + FLAC__OGG_MAPPING_MAGIC_LENGTH + + FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH + + FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH + + FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH + + FLAC__STREAM_SYNC_LENGTH + + FLAC__STREAM_METADATA_HEADER_LENGTH + + FLAC__STREAM_METADATA_STREAMINFO_LENGTH + ]; + + memset(&packet, 0, sizeof(packet)); + packet.granulepos = aspect->samples_written + samples; + + if(aspect->is_first_packet) { + FLAC__byte *b = synthetic_first_packet_body; + if(bytes != FLAC__STREAM_METADATA_HEADER_LENGTH + FLAC__STREAM_METADATA_STREAMINFO_LENGTH) { + /* + * If we get here, our assumption about the way write callbacks happen + * (explained above) is wrong + */ + FLAC__ASSERT(0); + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + /* add first header packet type */ + *b = FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE; + b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH; + /* add 'FLAC' mapping magic */ + memcpy(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH); + b += FLAC__OGG_MAPPING_MAGIC_LENGTH; + /* add Ogg FLAC mapping major version number */ + memcpy(b, &FLAC__OGG_MAPPING_VERSION_MAJOR, FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH); + b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH; + /* add Ogg FLAC mapping minor version number */ + memcpy(b, &FLAC__OGG_MAPPING_VERSION_MINOR, FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH); + b += FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH; + /* add number of header packets */ + *b = (FLAC__byte)(aspect->num_metadata >> 8); + b++; + *b = (FLAC__byte)(aspect->num_metadata); + b++; + /* add native FLAC 'fLaC' magic */ + memcpy(b, FLAC__STREAM_SYNC_STRING, FLAC__STREAM_SYNC_LENGTH); + b += FLAC__STREAM_SYNC_LENGTH; + /* add STREAMINFO */ + memcpy(b, buffer, bytes); + FLAC__ASSERT(b + bytes - synthetic_first_packet_body == sizeof(synthetic_first_packet_body)); + packet.packet = (unsigned char *)synthetic_first_packet_body; + packet.bytes = sizeof(synthetic_first_packet_body); + + packet.b_o_s = 1; + aspect->is_first_packet = false; + } + else { + packet.packet = (unsigned char *)buffer; + packet.bytes = bytes; + } + + if(is_last_block) { + /* we used to check: + * FLAC__ASSERT(total_samples_estimate == 0 || total_samples_estimate == aspect->samples_written + samples); + * but it's really not useful since total_samples_estimate is an estimate and can be inexact + */ + packet.e_o_s = 1; + } + + if(ogg_stream_packetin(&aspect->stream_state, &packet) != 0) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + + /*@@@ can't figure out a way to pass a useful number for 'samples' to the write_callback, so we'll just pass 0 */ + if(is_metadata) { + while(ogg_stream_flush(&aspect->stream_state, &aspect->page) != 0) { + if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + } + else { + while(ogg_stream_pageout(&aspect->stream_state, &aspect->page) != 0) { + if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + } + } + else if(is_metadata && current_frame == 0 && samples == 0 && bytes == 4 && 0 == memcmp(buffer, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING))) { + aspect->seen_magic = true; + } + else { + /* + * If we get here, our assumption about the way write callbacks happen + * explained above is wrong + */ + FLAC__ASSERT(0); + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + + aspect->samples_written += samples; + + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; +} diff --git a/sys/src/cmd/audio/libFLAC/ogg_helper.c b/sys/src/cmd/audio/libFLAC/ogg_helper.c new file mode 100644 index 000000000..8b3a655ad --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/ogg_helper.c @@ -0,0 +1,210 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> /* for malloc() */ +#include <string.h> /* for memcmp(), memcpy() */ +#include "FLAC/assert.h" +#include "share/alloc.h" +#include "private/ogg_helper.h" +#include "protected/stream_encoder.h" + + +static FLAC__bool full_read_(FLAC__StreamEncoder *encoder, FLAC__byte *buffer, size_t bytes, FLAC__StreamEncoderReadCallback read_callback, void *client_data) +{ + while(bytes > 0) { + size_t bytes_read = bytes; + switch(read_callback(encoder, buffer, &bytes_read, client_data)) { + case FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE: + bytes -= bytes_read; + buffer += bytes_read; + break; + case FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM: + if(bytes_read == 0) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + return false; + } + bytes -= bytes_read; + buffer += bytes_read; + break; + case FLAC__STREAM_ENCODER_READ_STATUS_ABORT: + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + case FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED: + return false; + default: + /* double protection: */ + FLAC__ASSERT(0); + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + } + + return true; +} + +void simple_ogg_page__init(ogg_page *page) +{ + page->header = 0; + page->header_len = 0; + page->body = 0; + page->body_len = 0; +} + +void simple_ogg_page__clear(ogg_page *page) +{ + if(page->header) + free(page->header); + if(page->body) + free(page->body); + simple_ogg_page__init(page); +} + +FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data) +{ + static const unsigned OGG_HEADER_FIXED_PORTION_LEN = 27; + static const unsigned OGG_MAX_HEADER_LEN = 27/*OGG_HEADER_FIXED_PORTION_LEN*/ + 255; + FLAC__byte crc[4]; + FLAC__StreamEncoderSeekStatus seek_status; + + FLAC__ASSERT(page->header == 0); + FLAC__ASSERT(page->header_len == 0); + FLAC__ASSERT(page->body == 0); + FLAC__ASSERT(page->body_len == 0); + + /* move the stream pointer to the supposed beginning of the page */ + if(0 == seek_callback) + return false; + if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + + /* allocate space for the page header */ + if(0 == (page->header = safe_malloc_(OGG_MAX_HEADER_LEN))) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + /* read in the fixed part of the page header (up to but not including + * the segment table */ + if(!full_read_(encoder, page->header, OGG_HEADER_FIXED_PORTION_LEN, read_callback, client_data)) + return false; + + page->header_len = OGG_HEADER_FIXED_PORTION_LEN + page->header[26]; + + /* check to see if it's a correct, "simple" page (one packet only) */ + if( + memcmp(page->header, "OggS", 4) || /* doesn't start with OggS */ + (page->header[5] & 0x01) || /* continued packet */ + memcmp(page->header+6, "\0\0\0\0\0\0\0\0", 8) || /* granulepos is non-zero */ + page->header[26] == 0 /* packet is 0-size */ + ) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + return false; + } + + /* read in the segment table */ + if(!full_read_(encoder, page->header + OGG_HEADER_FIXED_PORTION_LEN, page->header[26], read_callback, client_data)) + return false; + + { + unsigned i; + + /* check to see that it specifies a single packet */ + for(i = 0; i < (unsigned)page->header[26] - 1; i++) { + if(page->header[i + OGG_HEADER_FIXED_PORTION_LEN] != 255) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + return false; + } + } + + page->body_len = 255 * i + page->header[i + OGG_HEADER_FIXED_PORTION_LEN]; + } + + /* allocate space for the page body */ + if(0 == (page->body = safe_malloc_(page->body_len))) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + /* read in the page body */ + if(!full_read_(encoder, page->body, page->body_len, read_callback, client_data)) + return false; + + /* check the CRC */ + memcpy(crc, page->header+22, 4); + ogg_page_checksum_set(page); + if(memcmp(crc, page->header+22, 4)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + return false; + } + + return true; +} + +FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data) +{ + FLAC__StreamEncoderSeekStatus seek_status; + + FLAC__ASSERT(page->header != 0); + FLAC__ASSERT(page->header_len != 0); + FLAC__ASSERT(page->body != 0); + FLAC__ASSERT(page->body_len != 0); + + /* move the stream pointer to the supposed beginning of the page */ + if(0 == seek_callback) + return false; + if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + + ogg_page_checksum_set(page); + + /* re-write the page */ + if(write_callback((FLAC__StreamEncoder*)encoder, page->header, page->header_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + if(write_callback((FLAC__StreamEncoder*)encoder, page->body, page->body_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return false; + } + + return true; +} diff --git a/sys/src/cmd/audio/libFLAC/protected/seekable_stream_encoder.h b/sys/src/cmd/audio/libFLAC/ogg_mapping.c index b2b13fa99..125b4587e 100644 --- a/sys/src/cmd/audio/libFLAC/protected/seekable_stream_encoder.h +++ b/sys/src/cmd/audio/libFLAC/ogg_mapping.c @@ -1,5 +1,6 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2002,2003,2004 Josh Coalson +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,14 +30,19 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FLAC__PROTECTED__SEEKABLE_STREAM_ENCODER_H -#define FLAC__PROTECTED__SEEKABLE_STREAM_ENCODER_H +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif -#include "FLAC/seekable_stream_encoder.h" +#include "private/ogg_mapping.h" -typedef struct FLAC__SeekableStreamEncoderProtected { - FLAC__SeekableStreamEncoderState state; - FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset; -} FLAC__SeekableStreamEncoderProtected; +const unsigned FLAC__OGG_MAPPING_PACKET_TYPE_LEN = 8; /* bits */ -#endif +const FLAC__byte FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE = 0x7f; + +const FLAC__byte * const FLAC__OGG_MAPPING_MAGIC = (const FLAC__byte * const)"FLAC"; + +const unsigned FLAC__OGG_MAPPING_VERSION_MAJOR_LEN = 8; /* bits */ +const unsigned FLAC__OGG_MAPPING_VERSION_MINOR_LEN = 8; /* bits */ + +const unsigned FLAC__OGG_MAPPING_NUM_HEADERS_LEN = 16; /* bits */ diff --git a/sys/src/cmd/audio/libFLAC/private/all.h b/sys/src/cmd/audio/libFLAC/private/all.h index d1873951f..a4463d26d 100644 --- a/sys/src/cmd/audio/libFLAC/private/all.h +++ b/sys/src/cmd/audio/libFLAC/private/all.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,11 +33,13 @@ #ifndef FLAC__PRIVATE__ALL_H #define FLAC__PRIVATE__ALL_H -#include "bitbuffer.h" #include "bitmath.h" +#include "bitreader.h" +#include "bitwriter.h" #include "cpu.h" #include "crc.h" #include "fixed.h" +#include "float.h" #include "format.h" #include "lpc.h" #include "md5.h" diff --git a/sys/src/cmd/audio/libFLAC/private/bitbuffer.h b/sys/src/cmd/audio/libFLAC/private/bitbuffer.h deleted file mode 100644 index 2efe68329..000000000 --- a/sys/src/cmd/audio/libFLAC/private/bitbuffer.h +++ /dev/null @@ -1,159 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 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. - */ - -#ifndef FLAC__PRIVATE__BITBUFFER_H -#define FLAC__PRIVATE__BITBUFFER_H - -#include <stdio.h> /* for FILE */ -#include "FLAC/ordinals.h" - -/* @@@ This should be configurable. Valid values are currently 8 and 32. */ -/* @@@ WATCHOUT! do not use 32 with a little endian system yet. */ -#define FLAC__BITS_PER_BLURB 8 - -#if FLAC__BITS_PER_BLURB == 8 -typedef FLAC__byte FLAC__blurb; -#elif FLAC__BITS_PER_BLURB == 32 -typedef FLAC__uint32 FLAC__blurb; -#else -/* ERROR, only sizes of 8 and 32 are supported */ -#endif - -/* - * opaque structure definition - */ -struct FLAC__BitBuffer; -typedef struct FLAC__BitBuffer FLAC__BitBuffer; - -/* - * construction, deletion, initialization, cloning functions - */ -FLAC__BitBuffer *FLAC__bitbuffer_new(); -void FLAC__bitbuffer_delete(FLAC__BitBuffer *bb); -FLAC__bool FLAC__bitbuffer_init(FLAC__BitBuffer *bb); -FLAC__bool FLAC__bitbuffer_init_from(FLAC__BitBuffer *bb, const FLAC__byte buffer[], unsigned bytes); -FLAC__bool FLAC__bitbuffer_concatenate_aligned(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src); -void FLAC__bitbuffer_free(FLAC__BitBuffer *bb); /* does not 'free(buffer)' */ -FLAC__bool FLAC__bitbuffer_clear(FLAC__BitBuffer *bb); -FLAC__bool FLAC__bitbuffer_clone(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src); - -/* - * CRC functions - */ -void FLAC__bitbuffer_reset_read_crc16(FLAC__BitBuffer *bb, FLAC__uint16 seed); -FLAC__uint16 FLAC__bitbuffer_get_read_crc16(FLAC__BitBuffer *bb); -FLAC__uint16 FLAC__bitbuffer_get_write_crc16(const FLAC__BitBuffer *bb); -FLAC__byte FLAC__bitbuffer_get_write_crc8(const FLAC__BitBuffer *bb); - -/* - * info functions - */ -FLAC__bool FLAC__bitbuffer_is_byte_aligned(const FLAC__BitBuffer *bb); -FLAC__bool FLAC__bitbuffer_is_consumed_byte_aligned(const FLAC__BitBuffer *bb); -unsigned FLAC__bitbuffer_bits_left_for_byte_alignment(const FLAC__BitBuffer *bb); -unsigned FLAC__bitbuffer_get_input_bytes_unconsumed(const FLAC__BitBuffer *bb); /* do not call unless byte-aligned */ - -/* - * direct buffer access - */ -void FLAC__bitbuffer_get_buffer(FLAC__BitBuffer *bb, const FLAC__byte **buffer, unsigned *bytes); -void FLAC__bitbuffer_release_buffer(FLAC__BitBuffer *bb); - -/* - * write functions - */ -FLAC__bool FLAC__bitbuffer_write_zeroes(FLAC__BitBuffer *bb, unsigned bits); -FLAC__bool FLAC__bitbuffer_write_raw_uint32(FLAC__BitBuffer *bb, FLAC__uint32 val, unsigned bits); -FLAC__bool FLAC__bitbuffer_write_raw_int32(FLAC__BitBuffer *bb, FLAC__int32 val, unsigned bits); -FLAC__bool FLAC__bitbuffer_write_raw_uint64(FLAC__BitBuffer *bb, FLAC__uint64 val, unsigned bits); -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_write_raw_int64(FLAC__BitBuffer *bb, FLAC__int64 val, unsigned bits); -#endif -FLAC__bool FLAC__bitbuffer_write_raw_uint32_little_endian(FLAC__BitBuffer *bb, FLAC__uint32 val); /*only for bits=32*/ -FLAC__bool FLAC__bitbuffer_write_byte_block(FLAC__BitBuffer *bb, const FLAC__byte vals[], unsigned nvals); -FLAC__bool FLAC__bitbuffer_write_unary_unsigned(FLAC__BitBuffer *bb, unsigned val); -unsigned FLAC__bitbuffer_rice_bits(int val, unsigned parameter); -#if 0 /* UNUSED */ -unsigned FLAC__bitbuffer_golomb_bits_signed(int val, unsigned parameter); -unsigned FLAC__bitbuffer_golomb_bits_unsigned(unsigned val, unsigned parameter); -#endif -#ifdef FLAC__SYMMETRIC_RICE -FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter); -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow); -#endif -FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed_escape(FLAC__BitBuffer *bb, int val, unsigned parameter); -#endif -FLAC__bool FLAC__bitbuffer_write_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter); -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_write_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow); -#endif -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_write_golomb_signed(FLAC__BitBuffer *bb, int val, unsigned parameter); -FLAC__bool FLAC__bitbuffer_write_golomb_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow); -FLAC__bool FLAC__bitbuffer_write_golomb_unsigned(FLAC__BitBuffer *bb, unsigned val, unsigned parameter); -FLAC__bool FLAC__bitbuffer_write_golomb_unsigned_guarded(FLAC__BitBuffer *bb, unsigned val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow); -#endif -FLAC__bool FLAC__bitbuffer_write_utf8_uint32(FLAC__BitBuffer *bb, FLAC__uint32 val); -FLAC__bool FLAC__bitbuffer_write_utf8_uint64(FLAC__BitBuffer *bb, FLAC__uint64 val); -FLAC__bool FLAC__bitbuffer_zero_pad_to_byte_boundary(FLAC__BitBuffer *bb); - -/* - * read functions - */ -FLAC__bool FLAC__bitbuffer_peek_bit(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -FLAC__bool FLAC__bitbuffer_read_bit(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -FLAC__bool FLAC__bitbuffer_read_bit_to_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -FLAC__bool FLAC__bitbuffer_read_bit_to_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -FLAC__bool FLAC__bitbuffer_read_raw_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -FLAC__bool FLAC__bitbuffer_read_raw_int32(FLAC__BitBuffer *bb, FLAC__int32 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -FLAC__bool FLAC__bitbuffer_read_raw_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_read_raw_int64(FLAC__BitBuffer *bb, FLAC__int64 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -#endif -FLAC__bool FLAC__bitbuffer_read_raw_uint32_little_endian(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); /*only for bits=32*/ -FLAC__bool FLAC__bitbuffer_skip_bits_no_crc(FLAC__BitBuffer *bb, unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */ -FLAC__bool FLAC__bitbuffer_read_byte_block_aligned_no_crc(FLAC__BitBuffer *bb, FLAC__byte *val, unsigned nvals, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); /* val may be 0 to skip bytes instead of reading them */ /* WATCHOUT: does not CRC the read data! */ -FLAC__bool FLAC__bitbuffer_read_unary_unsigned(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -#ifdef FLAC__SYMMETRIC_RICE -FLAC__bool FLAC__bitbuffer_read_symmetric_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -#endif -FLAC__bool FLAC__bitbuffer_read_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -FLAC__bool FLAC__bitbuffer_read_rice_signed_block(FLAC__BitBuffer *bb, int vals[], unsigned nvals, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitbuffer_read_golomb_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -FLAC__bool FLAC__bitbuffer_read_golomb_unsigned(FLAC__BitBuffer *bb, unsigned *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); -#endif -FLAC__bool FLAC__bitbuffer_read_utf8_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data, FLAC__byte *raw, unsigned *rawlen); -FLAC__bool FLAC__bitbuffer_read_utf8_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data, FLAC__byte *raw, unsigned *rawlen); -void FLAC__bitbuffer_dump(const FLAC__BitBuffer *bb, FILE *out); - -#endif diff --git a/sys/src/cmd/audio/libFLAC/private/bitmath.h b/sys/src/cmd/audio/libFLAC/private/bitmath.h index ce4eeaa03..22d894f83 100644 --- a/sys/src/cmd/audio/libFLAC/private/bitmath.h +++ b/sys/src/cmd/audio/libFLAC/private/bitmath.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,8 +34,152 @@ #define FLAC__PRIVATE__BITMATH_H #include "FLAC/ordinals.h" +#include "FLAC/assert.h" + +/* for CHAR_BIT */ +#include <limits.h> +#include "share/compat.h" + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#include <intrin.h> /* for _BitScanReverse* */ +#endif + +/* Will never be emitted for MSVC, GCC, Intel compilers */ +static inline unsigned int FLAC__clz_soft_uint32(unsigned int word) +{ + static const unsigned char byte_to_unary_table[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + return (word) > 0xffffff ? byte_to_unary_table[(word) >> 24] : + (word) > 0xffff ? byte_to_unary_table[(word) >> 16] + 8 : + (word) > 0xff ? byte_to_unary_table[(word) >> 8] + 16 : + byte_to_unary_table[(word)] + 24; +} + +static inline unsigned int FLAC__clz_uint32(FLAC__uint32 v) +{ +/* Never used with input 0 */ + FLAC__ASSERT(v > 0); +#if defined(__INTEL_COMPILER) + return _bit_scan_reverse(v) ^ 31U; +#elif defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +/* This will translate either to (bsr ^ 31U), clz , ctlz, cntlz, lzcnt depending on + * -march= setting or to a software routine in exotic machines. */ + return __builtin_clz(v); +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + { + unsigned long idx; + _BitScanReverse(&idx, v); + return idx ^ 31U; + } +#else + return FLAC__clz_soft_uint32(v); +#endif +} + +/* This one works with input 0 */ +static inline unsigned int FLAC__clz2_uint32(FLAC__uint32 v) +{ + if (!v) + return 32; + return FLAC__clz_uint32(v); +} + +/* An example of what FLAC__bitmath_ilog2() computes: + * + * ilog2( 0) = assertion failure + * ilog2( 1) = 0 + * ilog2( 2) = 1 + * ilog2( 3) = 1 + * ilog2( 4) = 2 + * ilog2( 5) = 2 + * ilog2( 6) = 2 + * ilog2( 7) = 2 + * ilog2( 8) = 3 + * ilog2( 9) = 3 + * ilog2(10) = 3 + * ilog2(11) = 3 + * ilog2(12) = 3 + * ilog2(13) = 3 + * ilog2(14) = 3 + * ilog2(15) = 3 + * ilog2(16) = 4 + * ilog2(17) = 4 + * ilog2(18) = 4 + */ + +static inline unsigned FLAC__bitmath_ilog2(FLAC__uint32 v) +{ + FLAC__ASSERT(v > 0); +#if defined(__INTEL_COMPILER) + return _bit_scan_reverse(v); +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + { + unsigned long idx; + _BitScanReverse(&idx, v); + return idx; + } +#else + return sizeof(FLAC__uint32) * CHAR_BIT - 1 - FLAC__clz_uint32(v); +#endif +} + + +#ifdef FLAC__INTEGER_ONLY_LIBRARY /* Unused otherwise */ + +static inline unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v) +{ + FLAC__ASSERT(v > 0); +#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) + return sizeof(FLAC__uint64) * CHAR_BIT - 1 - __builtin_clzll(v); +/* Sorry, only supported in x64/Itanium.. and both have fast FPU which makes integer-only encoder pointless */ +#elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && (defined(_M_IA64) || defined(_M_X64)) + { + unsigned long idx; + _BitScanReverse64(&idx, v); + return idx; + } +#else +/* Brain-damaged compilers will use the fastest possible way that is, + de Bruijn sequences (http://supertech.csail.mit.edu/papers/debruijn.pdf) + (C) Timothy B. Terriberry (tterribe@xiph.org) 2001-2009 CC0 (Public domain). +*/ + { + static const unsigned char DEBRUIJN_IDX64[64]={ + 0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40, + 5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57, + 63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56, + 62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58 + }; + v|= v>>1; + v|= v>>2; + v|= v>>4; + v|= v>>8; + v|= v>>16; + v|= v>>32; + v= (v>>1)+1; + return DEBRUIJN_IDX64[v*0x218A392CD3D5DBF>>58&0x3F]; + } +#endif +} +#endif -unsigned FLAC__bitmath_ilog2(unsigned v); unsigned FLAC__bitmath_silog2(int v); unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v); diff --git a/sys/src/cmd/audio/libFLAC/private/bitreader.h b/sys/src/cmd/audio/libFLAC/private/bitreader.h new file mode 100644 index 000000000..4dea8d03b --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/private/bitreader.h @@ -0,0 +1,91 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifndef FLAC__PRIVATE__BITREADER_H +#define FLAC__PRIVATE__BITREADER_H + +#include <stdio.h> /* for FILE */ +#include "FLAC/ordinals.h" +#include "cpu.h" + +/* + * opaque structure definition + */ +struct FLAC__BitReader; +typedef struct FLAC__BitReader FLAC__BitReader; + +typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *bytes, void *client_data); + +/* + * construction, deletion, initialization, etc functions + */ +FLAC__BitReader *FLAC__bitreader_new(void); +void FLAC__bitreader_delete(FLAC__BitReader *br); +FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd); +void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */ +FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br); +void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out); + +/* + * CRC functions + */ +void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed); +FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br); + +/* + * info functions + */ +FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br); +unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br); +unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br); + +/* + * read functions + */ + +FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, unsigned bits); +FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, unsigned bits); +FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, unsigned bits); +FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); /*only for bits=32*/ +FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, unsigned bits); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */ +FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, unsigned nvals); /* WATCHOUT: does not CRC the read data! */ +FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, unsigned nvals); /* WATCHOUT: does not CRC the read data! */ +FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, unsigned *val); +FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, unsigned parameter); +FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter); +#if 0 /* UNUSED */ +FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, unsigned parameter); +FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, unsigned *val, unsigned parameter); +#endif +FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, unsigned *rawlen); +FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, unsigned *rawlen); +#endif diff --git a/sys/src/cmd/audio/libFLAC/private/bitwriter.h b/sys/src/cmd/audio/libFLAC/private/bitwriter.h new file mode 100644 index 000000000..3b1362d86 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/private/bitwriter.h @@ -0,0 +1,104 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifndef FLAC__PRIVATE__BITWRITER_H +#define FLAC__PRIVATE__BITWRITER_H + +#include <stdio.h> /* for FILE */ +#include "FLAC/ordinals.h" + +/* + * opaque structure definition + */ +struct FLAC__BitWriter; +typedef struct FLAC__BitWriter FLAC__BitWriter; + +/* + * construction, deletion, initialization, etc functions + */ +FLAC__BitWriter *FLAC__bitwriter_new(void); +void FLAC__bitwriter_delete(FLAC__BitWriter *bw); +FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw); +void FLAC__bitwriter_free(FLAC__BitWriter *bw); /* does not 'free(buffer)' */ +void FLAC__bitwriter_clear(FLAC__BitWriter *bw); +void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out); + +/* + * CRC functions + * + * non-const *bw because they have to cal FLAC__bitwriter_get_buffer() + */ +FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc); +FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc); + +/* + * info functions + */ +FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw); +unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw); /* can be called anytime, returns total # of bits unconsumed */ + +/* + * direct buffer access + * + * there may be no calls on the bitwriter between get and release. + * the bitwriter continues to own the returned buffer. + * before get, bitwriter MUST be byte aligned: check with FLAC__bitwriter_is_byte_aligned() + */ +FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes); +void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw); + +/* + * write functions + */ +FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits); +FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits); +FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits); +FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits); +FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val); /*only for bits=32*/ +FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals); +FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val); +unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter); +#if 0 /* UNUSED */ +unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter); +unsigned FLAC__bitwriter_golomb_bits_unsigned(unsigned val, unsigned parameter); +#endif +FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter); +FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter); +#if 0 /* UNUSED */ +FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter); +FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned val, unsigned parameter); +#endif +FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val); +FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val); +FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw); + +#endif diff --git a/sys/src/cmd/audio/libFLAC/private/cpu.h b/sys/src/cmd/audio/libFLAC/private/cpu.h index b8c001a1e..8927897a4 100644 --- a/sys/src/cmd/audio/libFLAC/private/cpu.h +++ b/sys/src/cmd/audio/libFLAC/private/cpu.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,56 +39,130 @@ #include <config.h> #endif +#if defined FLAC__HAS_X86INTRIN +/* SSE intrinsics support by ICC/MSVC/GCC */ +#if defined __INTEL_COMPILER + #define FLAC__SSE_TARGET(x) + #define FLAC__SSE_SUPPORTED 1 + #define FLAC__SSE2_SUPPORTED 1 + #if (__INTEL_COMPILER >= 1000) /* Intel C++ Compiler 10.0 */ + #define FLAC__SSSE3_SUPPORTED 1 + #define FLAC__SSE4_1_SUPPORTED 1 + #endif + #if (__INTEL_COMPILER >= 1110) /* Intel C++ Compiler 11.1 */ + #define FLAC__AVX_SUPPORTED 1 + #endif + #if (__INTEL_COMPILER >= 1300) /* Intel C++ Compiler 13.0 */ + #define FLAC__AVX2_SUPPORTED 1 + #define FLAC__FMA_SUPPORTED 1 + #endif +#elif defined _MSC_VER + #define FLAC__SSE_TARGET(x) + #define FLAC__SSE_SUPPORTED 1 + #define FLAC__SSE2_SUPPORTED 1 + #if (_MSC_VER >= 1500) /* MS Visual Studio 2008 */ + #define FLAC__SSSE3_SUPPORTED 1 + #define FLAC__SSE4_1_SUPPORTED 1 + #endif + #if (_MSC_FULL_VER >= 160040219) /* MS Visual Studio 2010 SP1 */ + #define FLAC__AVX_SUPPORTED 1 + #endif + #if (_MSC_VER >= 1700) /* MS Visual Studio 2012 */ + #define FLAC__AVX2_SUPPORTED 1 + #define FLAC__FMA_SUPPORTED 1 + #endif +#elif defined __GNUC__ + #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) /* since GCC 4.9 -msse.. compiler options aren't necessary */ + #define FLAC__SSE_TARGET(x) __attribute__ ((__target__ (x))) + #define FLAC__SSE_SUPPORTED 1 + #define FLAC__SSE2_SUPPORTED 1 + #define FLAC__SSSE3_SUPPORTED 1 + #define FLAC__SSE4_1_SUPPORTED 1 + #define FLAC__AVX_SUPPORTED 1 + #define FLAC__AVX2_SUPPORTED 1 + #define FLAC__FMA_SUPPORTED 1 + #else /* for GCC older than 4.9 */ + #define FLAC__SSE_TARGET(x) + #ifdef __SSE__ + #define FLAC__SSE_SUPPORTED 1 + #endif + #ifdef __SSE2__ + #define FLAC__SSE2_SUPPORTED 1 + #endif + #ifdef __SSSE3__ + #define FLAC__SSSE3_SUPPORTED 1 + #endif + #ifdef __SSE4_1__ + #define FLAC__SSE4_1_SUPPORTED 1 + #endif + #ifdef __AVX__ + #define FLAC__AVX_SUPPORTED 1 + #endif + #ifdef __AVX2__ + #define FLAC__AVX2_SUPPORTED 1 + #endif + #ifdef __FMA__ + #define FLAC__FMA_SUPPORTED 1 + #endif + #endif /* GCC version */ +#endif /* compiler version */ +#endif /* intrinsics support */ + typedef enum { FLAC__CPUINFO_TYPE_IA32, - FLAC__CPUINFO_TYPE_PPC, + FLAC__CPUINFO_TYPE_X86_64, FLAC__CPUINFO_TYPE_UNKNOWN } FLAC__CPUInfo_Type; +#if defined FLAC__CPU_IA32 typedef struct { FLAC__bool cmov; FLAC__bool mmx; - FLAC__bool fxsr; FLAC__bool sse; FLAC__bool sse2; - FLAC__bool _3dnow; - FLAC__bool ext3dnow; - FLAC__bool extmmx; -} FLAC__CPUInfo_IA32; + FLAC__bool sse3; + FLAC__bool ssse3; + FLAC__bool sse41; + FLAC__bool sse42; + FLAC__bool avx; + FLAC__bool avx2; + FLAC__bool fma; +} FLAC__CPUInfo_IA32; +#elif defined FLAC__CPU_X86_64 typedef struct { - FLAC__bool altivec; -} FLAC__CPUInfo_PPC; - -extern const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV; -extern const unsigned FLAC__CPUINFO_IA32_CPUID_MMX; -extern const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR; -extern const unsigned FLAC__CPUINFO_IA32_CPUID_SSE; -extern const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2; - -extern const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW; -extern const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW; -extern const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX; + FLAC__bool sse3; + FLAC__bool ssse3; + FLAC__bool sse41; + FLAC__bool sse42; + FLAC__bool avx; + FLAC__bool avx2; + FLAC__bool fma; +} FLAC__CPUInfo_x86; +#endif typedef struct { FLAC__bool use_asm; FLAC__CPUInfo_Type type; - union { - FLAC__CPUInfo_IA32 ia32; - FLAC__CPUInfo_PPC ppc; - } data; +#if defined FLAC__CPU_IA32 + FLAC__CPUInfo_IA32 ia32; +#elif defined FLAC__CPU_X86_64 + FLAC__CPUInfo_x86 x86; +#endif } FLAC__CPUInfo; void FLAC__cpu_info(FLAC__CPUInfo *info); #ifndef FLAC__NO_ASM -#ifdef FLAC__CPU_IA32 -#ifdef FLAC__HAS_NASM -unsigned FLAC__cpu_info_asm_ia32(); -unsigned FLAC__cpu_info_extended_amd_asm_ia32(); -unsigned FLAC__cpu_info_sse_test_asm_ia32(); -#endif -#endif +# if defined FLAC__CPU_IA32 && defined FLAC__HAS_NASM +FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void); +void FLAC__cpu_info_asm_ia32(FLAC__uint32 *flags_edx, FLAC__uint32 *flags_ecx); +# endif +# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN +FLAC__uint32 FLAC__cpu_have_cpuid_x86(void); +void FLAC__cpu_info_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx); +FLAC__uint32 FLAC__cpu_xgetbv_x86(void); +# endif #endif #endif diff --git a/sys/src/cmd/audio/libFLAC/private/crc.h b/sys/src/cmd/audio/libFLAC/private/crc.h index 8256acb2c..29c512ced 100644 --- a/sys/src/cmd/audio/libFLAC/private/crc.h +++ b/sys/src/cmd/audio/libFLAC/private/crc.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,10 +49,14 @@ FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len); ** polynomial = x^16 + x^15 + x^2 + x^0 ** init = 0 */ -extern FLAC__uint16 FLAC__crc16_table[256]; -#define FLAC__CRC16_UPDATE(data, crc) (crc) = ((crc)<<8) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]; -void FLAC__crc16_update(const FLAC__byte data, FLAC__uint16 *crc); -void FLAC__crc16_update_block(const FLAC__byte *data, unsigned len, FLAC__uint16 *crc); -FLAC__uint16 FLAC__crc16(const FLAC__byte *data, unsigned len); +extern unsigned const FLAC__crc16_table[256]; + +#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]) +/* this alternate may be faster on some systems/compilers */ +#if 0 +#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]) & 0xffff) +#endif + +unsigned FLAC__crc16(const FLAC__byte *data, unsigned len); #endif diff --git a/sys/src/cmd/audio/libFLAC/private/fixed.h b/sys/src/cmd/audio/libFLAC/private/fixed.h index 8f463a8f4..dcc471510 100644 --- a/sys/src/cmd/audio/libFLAC/private/fixed.h +++ b/sys/src/cmd/audio/libFLAC/private/fixed.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,12 +33,14 @@ #ifndef FLAC__PRIVATE__FIXED_H #define FLAC__PRIVATE__FIXED_H -#include "FLAC/format.h" - #ifdef HAVE_CONFIG_H #include <config.h> #endif +#include "private/cpu.h" +#include "private/float.h" +#include "FLAC/format.h" + /* * FLAC__fixed_compute_best_predictor() * -------------------------------------------------------------------- @@ -50,15 +53,28 @@ * IN data_len * OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER] */ -unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -#ifndef FLAC__NO_ASM -#ifdef FLAC__CPU_IA32 -#ifdef FLAC__HAS_NASM -unsigned FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -#endif -#endif +#ifndef FLAC__INTEGER_ONLY_LIBRARY +unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +# ifndef FLAC__NO_ASM +# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN +# ifdef FLAC__SSE2_SUPPORTED +unsigned FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]); +unsigned FLAC__fixed_compute_best_predictor_wide_intrin_sse2(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]); +# endif +# ifdef FLAC__SSSE3_SUPPORTED +unsigned FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +unsigned FLAC__fixed_compute_best_predictor_wide_intrin_ssse3(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]); +# endif +# endif +# if defined FLAC__CPU_IA32 && defined FLAC__HAS_NASM +unsigned FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +# endif +# endif +#else +unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); #endif -unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); /* * FLAC__fixed_compute_residual() diff --git a/sys/src/cmd/audio/libFLAC/private/float.h b/sys/src/cmd/audio/libFLAC/private/float.h new file mode 100644 index 000000000..ab2643246 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/private/float.h @@ -0,0 +1,98 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifndef FLAC__PRIVATE__FLOAT_H +#define FLAC__PRIVATE__FLOAT_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "FLAC/ordinals.h" + +/* + * These typedefs make it easier to ensure that integer versions of + * the library really only contain integer operations. All the code + * in libFLAC should use FLAC__float and FLAC__double in place of + * float and double, and be protected by checks of the macro + * FLAC__INTEGER_ONLY_LIBRARY. + * + * FLAC__real is the basic floating point type used in LPC analysis. + */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY +typedef double FLAC__double; +typedef float FLAC__float; +/* + * WATCHOUT: changing FLAC__real will change the signatures of many + * functions that have assembly language equivalents and break them. + */ +typedef float FLAC__real; +#else +/* + * The convention for FLAC__fixedpoint is to use the upper 16 bits + * for the integer part and lower 16 bits for the fractional part. + */ +typedef FLAC__int32 FLAC__fixedpoint; +extern const FLAC__fixedpoint FLAC__FP_ZERO; +extern const FLAC__fixedpoint FLAC__FP_ONE_HALF; +extern const FLAC__fixedpoint FLAC__FP_ONE; +extern const FLAC__fixedpoint FLAC__FP_LN2; +extern const FLAC__fixedpoint FLAC__FP_E; + +#define FLAC__fixedpoint_trunc(x) ((x)>>16) + +#define FLAC__fixedpoint_mul(x, y) ( (FLAC__fixedpoint) ( ((FLAC__int64)(x)*(FLAC__int64)(y)) >> 16 ) ) + +#define FLAC__fixedpoint_div(x, y) ( (FLAC__fixedpoint) ( ( ((FLAC__int64)(x)<<32) / (FLAC__int64)(y) ) >> 16 ) ) + +/* + * FLAC__fixedpoint_log2() + * -------------------------------------------------------------------- + * Returns the base-2 logarithm of the fixed-point number 'x' using an + * algorithm by Knuth for x >= 1.0 + * + * 'fracbits' is the number of fractional bits of 'x'. 'fracbits' must + * be < 32 and evenly divisible by 4 (0 is OK but not very precise). + * + * 'precision' roughly limits the number of iterations that are done; + * use (unsigned)(-1) for maximum precision. + * + * If 'x' is less than one -- that is, x < (1<<fracbits) -- then this + * function will punt and return 0. + * + * The return value will also have 'fracbits' fractional bits. + */ +FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision); + +#endif + +#endif diff --git a/sys/src/cmd/audio/libFLAC/private/format.h b/sys/src/cmd/audio/libFLAC/private/format.h index 490cfaaf8..2fd346087 100644 --- a/sys/src/cmd/audio/libFLAC/private/format.h +++ b/sys/src/cmd/audio/libFLAC/private/format.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sys/src/cmd/audio/libFLAC/private/lpc.h b/sys/src/cmd/audio/libFLAC/private/lpc.h index aa01b20cc..d36b30be9 100644 --- a/sys/src/cmd/audio/libFLAC/private/lpc.h +++ b/sys/src/cmd/audio/libFLAC/private/lpc.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,12 +33,29 @@ #ifndef FLAC__PRIVATE__LPC_H #define FLAC__PRIVATE__LPC_H -#include "FLAC/format.h" - #ifdef HAVE_CONFIG_H #include <config.h> #endif +#include "private/cpu.h" +#include "private/float.h" +#include "FLAC/format.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +/* + * FLAC__lpc_window_data() + * -------------------------------------------------------------------- + * Applies the given window to the data. + * OPT: asm implementation + * + * IN in[0,data_len-1] + * IN window[0,data_len-1] + * OUT out[0,lag-1] + * IN data_len + */ +void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], unsigned data_len); + /* * FLAC__lpc_compute_autocorrelation() * -------------------------------------------------------------------- @@ -52,14 +70,23 @@ */ void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); #ifndef FLAC__NO_ASM -#ifdef FLAC__CPU_IA32 -#ifdef FLAC__HAS_NASM +# ifdef FLAC__CPU_IA32 +# ifdef FLAC__HAS_NASM void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); -void FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); -#endif +void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); +# endif +# endif +# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN +# ifdef FLAC__SSE_SUPPORTED +void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); +void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); +void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); +void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); +# endif +# endif #endif /* @@ -74,13 +101,16 @@ void FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow(const FLAC__real data[], u * OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order * *** IMPORTANT: * *** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched - * OUT error[0,max_order-1] error for each order + * OUT error[0,max_order-1] error for each order (more + * specifically, the variance of + * the error signal times # of + * samples in the signal) * * Example: if max_order is 9, the LP coefficients for order 9 will be * in lp_coeff[8][0,8], the LP coefficients for order 8 will be * in lp_coeff[7][0,7], etc. */ -void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__real error[]); +void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[]); /* * FLAC__lpc_quantize_coefficients() @@ -117,17 +147,35 @@ int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, * IN lp_quantization quantization of LP coefficients in bits * OUT residual[0,data_len-1] residual signal */ -void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); #ifndef FLAC__NO_ASM -#ifdef FLAC__CPU_IA32 -#ifdef FLAC__HAS_NASM -void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); -#endif -#endif +# ifdef FLAC__CPU_IA32 +# ifdef FLAC__HAS_NASM +void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +# endif +# endif +# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN +# ifdef FLAC__SSE2_SUPPORTED +void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +# endif +# ifdef FLAC__SSE4_1_SUPPORTED +void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +# endif +# ifdef FLAC__AVX2_SUPPORTED +void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +# endif +# endif #endif +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ + /* * FLAC__lpc_restore_signal() * -------------------------------------------------------------------- @@ -146,17 +194,24 @@ void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__i void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); #ifndef FLAC__NO_ASM -#ifdef FLAC__CPU_IA32 -#ifdef FLAC__HAS_NASM +# ifdef FLAC__CPU_IA32 +# ifdef FLAC__HAS_NASM void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); -#endif -#elif defined FLAC__CPU_PPC -void FLAC__lpc_restore_signal_asm_ppc_altivec_16(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); -void FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); -#endif -#endif -#endif +void FLAC__lpc_restore_signal_wide_asm_ia32(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); +# endif /* FLAC__HAS_NASM */ +# endif /* FLAC__CPU_IA32 */ +# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN +# ifdef FLAC__SSE2_SUPPORTED +void FLAC__lpc_restore_signal_16_intrin_sse2(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); +# endif +# ifdef FLAC__SSE4_1_SUPPORTED +void FLAC__lpc_restore_signal_wide_intrin_sse41(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); +# endif +# endif +#endif /* FLAC__NO_ASM */ + +#ifndef FLAC__INTEGER_ONLY_LIBRARY /* * FLAC__lpc_compute_expected_bits_per_residual_sample() @@ -168,8 +223,8 @@ void FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8(const FLAC__int32 residu * IN total_samples > 0 # of samples in residual signal * RETURN expected bits per sample */ -FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__real lpc_error, unsigned total_samples); -FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__real lpc_error, double error_scale); +FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples); +FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale); /* * FLAC__lpc_compute_best_order() @@ -180,9 +235,12 @@ FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale( * IN lpc_error[0,max_order-1] >= 0.0 error returned from calculating LP coefficients * IN max_order > 0 max LP order * IN total_samples > 0 # of samples in residual signal - * IN bits_per_signal_sample # of bits per sample in the original signal + * IN overhead_bits_per_order # of bits overhead for each increased LP order + * (includes warmup sample size and quantized LP coefficient) * RETURN [1,max_order] best order */ -unsigned FLAC__lpc_compute_best_order(const FLAC__real lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample); +unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order); + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ #endif diff --git a/sys/src/cmd/audio/libFLAC/private/macros.h b/sys/src/cmd/audio/libFLAC/private/macros.h new file mode 100644 index 000000000..9feb9508b --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/private/macros.h @@ -0,0 +1,77 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2012-2014 Xiph.org Foundation + * + * 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. + */ + +#ifndef FLAC__PRIVATE__MACROS_H +#define FLAC__PRIVATE__MACROS_H + +#ifdef Plan9 +#define flac_min(x,y) MIN(x,y) +#define flac_max(x,y) MAX(x,y) +#endif + +#if defined(__GNUC__) && (__GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + +#define flac_max(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) + +#define MIN_PASTE(A,B) A##B +#define MIN_IMPL(A,B,L) ({ \ + __typeof__(A) MIN_PASTE(__a,L) = (A); \ + __typeof__(B) MIN_PASTE(__b,L) = (B); \ + MIN_PASTE(__a,L) < MIN_PASTE(__b,L) ? MIN_PASTE(__a,L) : MIN_PASTE(__b,L); \ + }) + +#define flac_min(A,B) MIN_IMPL(A,B,__COUNTER__) + +/* Whatever other unix that has sys/param.h */ +#elif defined(HAVE_SYS_PARAM_H) +#include <sys/param.h> +#define flac_max(a,b) MAX(a,b) +#define flac_min(a,b) MIN(a,b) + +/* Windows VS has them in stdlib.h.. XXX:Untested */ +#elif defined(_MSC_VER) +#include <stdlib.h> +#define flac_max(a,b) __max(a,b) +#define flac_min(a,b) __min(a,b) +#endif + +#ifndef MIN +#define MIN(x,y) ((x) <= (y) ? (x) : (y)) +#endif + +#ifndef MAX +#define MAX(x,y) ((x) >= (y) ? (x) : (y)) +#endif + +#endif diff --git a/sys/src/cmd/audio/libFLAC/private/md5.h b/sys/src/cmd/audio/libFLAC/private/md5.h index e85326015..c665ab313 100644 --- a/sys/src/cmd/audio/libFLAC/private/md5.h +++ b/sys/src/cmd/audio/libFLAC/private/md5.h @@ -1,3 +1,6 @@ +#ifndef FLAC__PRIVATE__MD5_H +#define FLAC__PRIVATE__MD5_H + /* * This is the header file for the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was @@ -20,35 +23,28 @@ * Still in the public domain. * * Josh Coalson: made some changes to integrate with libFLAC. - * Still in the public domain. + * Still in the public domain, with no warranty. */ -#ifndef FLAC__PRIVATE__MD5_H -#define FLAC__PRIVATE__MD5_H - -#define md5byte unsigned char - -/* - * Due to an unholy abomination in libOggFLAC (it requires access to - * these internal MD5 functions) we have to #include "FLAC/export.h" - * and export them when building a DLL - */ -#include "FLAC/export.h" #include "FLAC/ordinals.h" -struct FLAC__MD5Context { +typedef union { + FLAC__byte *p8; + FLAC__int16 *p16; + FLAC__int32 *p32; +} FLAC__multibyte; + +typedef struct { + FLAC__uint32 in[16]; FLAC__uint32 buf[4]; FLAC__uint32 bytes[2]; - FLAC__uint32 in[16]; - FLAC__byte *internal_buf; - unsigned capacity; -}; + FLAC__multibyte internal_buf; + size_t capacity; +} FLAC__MD5Context; -FLAC_API void FLAC__MD5Init(struct FLAC__MD5Context *context); -FLAC_API void FLAC__MD5Update(struct FLAC__MD5Context *context, md5byte const *buf, unsigned len); -FLAC_API void FLAC__MD5Final(md5byte digest[16], struct FLAC__MD5Context *context); -void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16]); +void FLAC__MD5Init(FLAC__MD5Context *context); +void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context); -FLAC_API FLAC__bool FLAC__MD5Accumulate(struct FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample); +FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample); -#endif /* !MD5_H */ +#endif diff --git a/sys/src/cmd/audio/libFLAC/private/memory.h b/sys/src/cmd/audio/libFLAC/private/memory.h index 0445ba018..c9f27129e 100644 --- a/sys/src/cmd/audio/libFLAC/private/memory.h +++ b/sys/src/cmd/audio/libFLAC/private/memory.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,18 +33,26 @@ #ifndef FLAC__PRIVATE__MEMORY_H #define FLAC__PRIVATE__MEMORY_H +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + #include <stdlib.h> /* for size_t */ +#include "private/float.h" #include "FLAC/ordinals.h" /* for FLAC__bool */ /* Returns the unaligned address returned by malloc. * Use free() on this address to deallocate. */ void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address); -FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer); -FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer); -FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer); -FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer); -FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer); +FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer); +FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer); +FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer); +FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, unsigned **unaligned_pointer, unsigned **aligned_pointer); +#ifndef FLAC__INTEGER_ONLY_LIBRARY +FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer); +#endif +void *safe_malloc_mul_2op_p(size_t size1, size_t size2); #endif diff --git a/sys/src/cmd/audio/libFLAC/private/metadata.h b/sys/src/cmd/audio/libFLAC/private/metadata.h index 14c2744bd..092764c26 100644 --- a/sys/src/cmd/audio/libFLAC/private/metadata.h +++ b/sys/src/cmd/audio/libFLAC/private/metadata.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2002,2003,2004 Josh Coalson + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,7 +35,12 @@ #include "FLAC/metadata.h" +/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not + * be a consistent state (e.g. PICTURE) or equivalent to the initial + * state after FLAC__metadata_object_new() + */ void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object); + void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object); #endif diff --git a/sys/src/cmd/audio/libFLAC/private/ogg_decoder_aspect.h b/sys/src/cmd/audio/libFLAC/private/ogg_decoder_aspect.h new file mode 100644 index 000000000..439bf8e4d --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/private/ogg_decoder_aspect.h @@ -0,0 +1,80 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifndef FLAC__PRIVATE__OGG_DECODER_ASPECT_H +#define FLAC__PRIVATE__OGG_DECODER_ASPECT_H + +#include <ogg/ogg.h> + +#include "FLAC/ordinals.h" +#include "FLAC/stream_decoder.h" /* for FLAC__StreamDecoderReadStatus */ + +typedef struct FLAC__OggDecoderAspect { + /* these are storage for values that can be set through the API */ + FLAC__bool use_first_serial_number; + long serial_number; + + /* these are for internal state related to Ogg decoding */ + ogg_stream_state stream_state; + ogg_sync_state sync_state; + unsigned version_major, version_minor; + FLAC__bool need_serial_number; + FLAC__bool end_of_stream; + FLAC__bool have_working_page; /* only if true will the following vars be valid */ + ogg_page working_page; + FLAC__bool have_working_packet; /* only if true will the following vars be valid */ + ogg_packet working_packet; /* as we work through the packet we will move working_packet.packet forward and working_packet.bytes down */ +} FLAC__OggDecoderAspect; + +void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value); +void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect); +FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect); +void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect); +void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect); +void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect); + +typedef enum { + FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK = 0, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR, + FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR +} FLAC__OggDecoderAspectReadStatus; + +typedef FLAC__OggDecoderAspectReadStatus (*FLAC__OggDecoderAspectReadCallbackProxy)(const void *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); + +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); + +#endif diff --git a/sys/src/cmd/audio/libFLAC/private/ogg_encoder_aspect.h b/sys/src/cmd/audio/libFLAC/private/ogg_encoder_aspect.h new file mode 100644 index 000000000..709597d44 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/private/ogg_encoder_aspect.h @@ -0,0 +1,63 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2002-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifndef FLAC__PRIVATE__OGG_ENCODER_ASPECT_H +#define FLAC__PRIVATE__OGG_ENCODER_ASPECT_H + +#include <ogg/ogg.h> + +#include "FLAC/ordinals.h" +#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoderWriteStatus */ + +typedef struct FLAC__OggEncoderAspect { + /* these are storage for values that can be set through the API */ + long serial_number; + unsigned num_metadata; + + /* these are for internal state related to Ogg encoding */ + ogg_stream_state stream_state; + ogg_page page; + FLAC__bool seen_magic; /* true if we've seen the fLaC magic in the write callback yet */ + FLAC__bool is_first_packet; + FLAC__uint64 samples_written; +} FLAC__OggEncoderAspect; + +void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value); +FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, unsigned value); +void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect); +FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect); +void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect); + +typedef FLAC__StreamEncoderWriteStatus (*FLAC__OggEncoderAspectWriteCallbackProxy)(const void *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data); + +FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data); +#endif diff --git a/sys/src/cmd/audio/libFLAC/protected/seekable_stream_decoder.h b/sys/src/cmd/audio/libFLAC/private/ogg_helper.h index 67007ae3e..87b96ef89 100644 --- a/sys/src/cmd/audio/libFLAC/protected/seekable_stream_decoder.h +++ b/sys/src/cmd/audio/libFLAC/private/ogg_helper.h @@ -1,5 +1,6 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,14 +30,15 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FLAC__PROTECTED__SEEKABLE_STREAM_DECODER_H -#define FLAC__PROTECTED__SEEKABLE_STREAM_DECODER_H +#ifndef FLAC__PRIVATE__OGG_HELPER_H +#define FLAC__PRIVATE__OGG_HELPER_H -#include "FLAC/seekable_stream_decoder.h" +#include <ogg/ogg.h> +#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoder */ -typedef struct FLAC__SeekableStreamDecoderProtected { - FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */ - FLAC__SeekableStreamDecoderState state; -} FLAC__SeekableStreamDecoderProtected; +void simple_ogg_page__init(ogg_page *page); +void simple_ogg_page__clear(ogg_page *page); +FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data); +FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data); #endif diff --git a/sys/src/cmd/audio/libFLAC/private/ogg_mapping.h b/sys/src/cmd/audio/libFLAC/private/ogg_mapping.h new file mode 100644 index 000000000..d35a46cd8 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/private/ogg_mapping.h @@ -0,0 +1,64 @@ +/* libFLAC - Free Lossless Audio Codec + * Copyright (C) 2004-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifndef FLAC__PRIVATE__OGG_MAPPING_H +#define FLAC__PRIVATE__OGG_MAPPING_H + +#include "FLAC/ordinals.h" + +/** The length of the packet type field in bytes. */ +#define FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH (1u) + +extern const unsigned FLAC__OGG_MAPPING_PACKET_TYPE_LEN; /* = 8 bits */ + +extern const FLAC__byte FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE; /* = 0x7f */ + +/** The length of the 'FLAC' magic in bytes. */ +#define FLAC__OGG_MAPPING_MAGIC_LENGTH (4u) + +extern const FLAC__byte * const FLAC__OGG_MAPPING_MAGIC; /* = "FLAC" */ + +extern const unsigned FLAC__OGG_MAPPING_VERSION_MAJOR_LEN; /* = 8 bits */ +extern const unsigned FLAC__OGG_MAPPING_VERSION_MINOR_LEN; /* = 8 bits */ + +/** The length of the Ogg FLAC mapping major version number in bytes. */ +#define FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH (1u) + +/** The length of the Ogg FLAC mapping minor version number in bytes. */ +#define FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH (1u) + +extern const unsigned FLAC__OGG_MAPPING_NUM_HEADERS_LEN; /* = 16 bits */ + +/** The length of the #-of-header-packets number bytes. */ +#define FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH (2u) + +#endif diff --git a/sys/src/cmd/audio/libFLAC/private/stream_encoder.h b/sys/src/cmd/audio/libFLAC/private/stream_encoder.h new file mode 100644 index 000000000..96d313586 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/private/stream_encoder.h @@ -0,0 +1,67 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifndef FLAC__PRIVATE__STREAM_ENCODER_H +#define FLAC__PRIVATE__STREAM_ENCODER_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +/* + * This is used to avoid overflow with unusual signals in 32-bit + * accumulator in the *precompute_partition_info_sums_* functions. + */ +#define FLAC__MAX_EXTRA_RESIDUAL_BPS 4 + +#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN +#include "private/cpu.h" +#include "FLAC/format.h" + +#ifdef FLAC__SSE2_SUPPORTED +extern void FLAC__precompute_partition_info_sums_intrin_sse2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], + unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps); +#endif + +#ifdef FLAC__SSSE3_SUPPORTED +extern void FLAC__precompute_partition_info_sums_intrin_ssse3(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], + unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps); +#endif + +#ifdef FLAC__AVX2_SUPPORTED +extern void FLAC__precompute_partition_info_sums_intrin_avx2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], + unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps); +#endif + +#endif + +#endif diff --git a/sys/src/cmd/audio/libFLAC/private/stream_encoder_framing.h b/sys/src/cmd/audio/libFLAC/private/stream_encoder_framing.h index 359fddc9b..2b7387a76 100644 --- a/sys/src/cmd/audio/libFLAC/private/stream_encoder_framing.h +++ b/sys/src/cmd/audio/libFLAC/private/stream_encoder_framing.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,13 +34,13 @@ #define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H #include "FLAC/format.h" -#include "bitbuffer.h" +#include "bitwriter.h" -FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitBuffer *bb); -FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__bool streamable_subset, FLAC__BitBuffer *bb); -FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb); -FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb); -FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb); -FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb); +FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw); +FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw); +FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw); +FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw); +FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw); +FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw); #endif diff --git a/sys/src/cmd/audio/libFLAC/private/window.h b/sys/src/cmd/audio/libFLAC/private/window.h new file mode 100644 index 000000000..52c92621d --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/private/window.h @@ -0,0 +1,74 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2006-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifndef FLAC__PRIVATE__WINDOW_H +#define FLAC__PRIVATE__WINDOW_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "private/float.h" +#include "FLAC/format.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +/* + * FLAC__window_*() + * -------------------------------------------------------------------- + * Calculates window coefficients according to different apodization + * functions. + * + * OUT window[0,L-1] + * IN L (number of points in window) + */ +void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev); /* 0.0 < stddev <= 0.5 */ +void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L); +void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p); +void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end); +void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end); +void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L); + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ + +#endif diff --git a/sys/src/cmd/audio/libFLAC/protected/all.h b/sys/src/cmd/audio/libFLAC/protected/all.h index 3569418f5..90912af5c 100644 --- a/sys/src/cmd/audio/libFLAC/protected/all.h +++ b/sys/src/cmd/audio/libFLAC/protected/all.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,10 +33,6 @@ #ifndef FLAC__PROTECTED__ALL_H #define FLAC__PROTECTED__ALL_H -#include "file_decoder.h" -#include "file_encoder.h" -#include "seekable_stream_decoder.h" -#include "seekable_stream_encoder.h" #include "stream_decoder.h" #include "stream_encoder.h" diff --git a/sys/src/cmd/audio/libFLAC/protected/stream_decoder.h b/sys/src/cmd/audio/libFLAC/protected/stream_decoder.h index 928977d37..7be95afda 100644 --- a/sys/src/cmd/audio/libFLAC/protected/stream_decoder.h +++ b/sys/src/cmd/audio/libFLAC/protected/stream_decoder.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,14 +34,22 @@ #define FLAC__PROTECTED__STREAM_DECODER_H #include "FLAC/stream_decoder.h" +#if FLAC__HAS_OGG +#include "private/ogg_decoder_aspect.h" +#endif typedef struct FLAC__StreamDecoderProtected { FLAC__StreamDecoderState state; + FLAC__StreamDecoderInitStatus initstate; unsigned channels; FLAC__ChannelAssignment channel_assignment; unsigned bits_per_sample; unsigned sample_rate; /* in Hz */ unsigned blocksize; /* in samples (per channel) */ + FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */ +#if FLAC__HAS_OGG + FLAC__OggDecoderAspect ogg_decoder_aspect; +#endif } FLAC__StreamDecoderProtected; /* diff --git a/sys/src/cmd/audio/libFLAC/protected/stream_encoder.h b/sys/src/cmd/audio/libFLAC/protected/stream_encoder.h index cfee69935..066385be5 100644 --- a/sys/src/cmd/audio/libFLAC/protected/stream_encoder.h +++ b/sys/src/cmd/audio/libFLAC/protected/stream_encoder.h @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2001-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,17 +34,70 @@ #define FLAC__PROTECTED__STREAM_ENCODER_H #include "FLAC/stream_encoder.h" +#if FLAC__HAS_OGG +#include "private/ogg_encoder_aspect.h" +#endif + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +#include "private/float.h" + +#define FLAC__MAX_APODIZATION_FUNCTIONS 32 + +typedef enum { + FLAC__APODIZATION_BARTLETT, + FLAC__APODIZATION_BARTLETT_HANN, + FLAC__APODIZATION_BLACKMAN, + FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE, + FLAC__APODIZATION_CONNES, + FLAC__APODIZATION_FLATTOP, + FLAC__APODIZATION_GAUSS, + FLAC__APODIZATION_HAMMING, + FLAC__APODIZATION_HANN, + FLAC__APODIZATION_KAISER_BESSEL, + FLAC__APODIZATION_NUTTALL, + FLAC__APODIZATION_RECTANGLE, + FLAC__APODIZATION_TRIANGLE, + FLAC__APODIZATION_TUKEY, + FLAC__APODIZATION_PARTIAL_TUKEY, + FLAC__APODIZATION_PUNCHOUT_TUKEY, + FLAC__APODIZATION_WELCH +} FLAC__ApodizationFunction; + +typedef struct { + FLAC__ApodizationFunction type; + union { + struct { + FLAC__real stddev; + } gauss; + struct { + FLAC__real p; + } tukey; + struct { + FLAC__real p; + FLAC__real start; + FLAC__real end; + } multiple_tukey; + } parameters; +} FLAC__ApodizationSpecification; + +#endif typedef struct FLAC__StreamEncoderProtected { FLAC__StreamEncoderState state; FLAC__bool verify; FLAC__bool streamable_subset; + FLAC__bool do_md5; FLAC__bool do_mid_side_stereo; FLAC__bool loose_mid_side_stereo; unsigned channels; unsigned bits_per_sample; unsigned sample_rate; unsigned blocksize; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + unsigned num_apodizations; + FLAC__ApodizationSpecification apodizations[FLAC__MAX_APODIZATION_FUNCTIONS]; +#endif unsigned max_lpc_order; unsigned qlp_coeff_precision; FLAC__bool do_qlp_coeff_prec_search; @@ -55,6 +109,10 @@ typedef struct FLAC__StreamEncoderProtected { FLAC__uint64 total_samples_estimate; FLAC__StreamMetadata **metadata; unsigned num_metadata_blocks; + FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset; +#if FLAC__HAS_OGG + FLAC__OggEncoderAspect ogg_encoder_aspect; +#endif } FLAC__StreamEncoderProtected; #endif diff --git a/sys/src/cmd/audio/libFLAC/seekable_stream_decoder.c b/sys/src/cmd/audio/libFLAC/seekable_stream_decoder.c deleted file mode 100644 index b66d14924..000000000 --- a/sys/src/cmd/audio/libFLAC/seekable_stream_decoder.c +++ /dev/null @@ -1,1087 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 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 <stdio.h> -#include <stdlib.h> /* for calloc() */ -#include <string.h> /* for memcpy()/memcmp() */ -#include "FLAC/assert.h" -#include "protected/seekable_stream_decoder.h" -#include "protected/stream_decoder.h" -#include "private/md5.h" - -/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */ -#ifdef _MSC_VER -#define FLAC__U64L(x) x -#else -#define FLAC__U64L(x) x##LLU -#endif - -/*********************************************************************** - * - * Private class method prototypes - * - ***********************************************************************/ - -static void set_defaults_(FLAC__SeekableStreamDecoder *decoder); -static FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data); -static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); -static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); -static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); -static FLAC__bool seek_to_absolute_sample_(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample); - -/*********************************************************************** - * - * Private class data - * - ***********************************************************************/ - -typedef struct FLAC__SeekableStreamDecoderPrivate { - FLAC__SeekableStreamDecoderReadCallback read_callback; - FLAC__SeekableStreamDecoderSeekCallback seek_callback; - FLAC__SeekableStreamDecoderTellCallback tell_callback; - FLAC__SeekableStreamDecoderLengthCallback length_callback; - FLAC__SeekableStreamDecoderEofCallback eof_callback; - FLAC__SeekableStreamDecoderWriteCallback write_callback; - FLAC__SeekableStreamDecoderMetadataCallback metadata_callback; - FLAC__SeekableStreamDecoderErrorCallback error_callback; - void *client_data; - FLAC__StreamDecoder *stream_decoder; - FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek */ - struct FLAC__MD5Context md5context; - FLAC__byte stored_md5sum[16]; /* this is what is stored in the metadata */ - FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */ - /* the rest of these are only used for seeking: */ - FLAC__StreamMetadata_StreamInfo stream_info; /* we keep this around so we can figure out how to seek quickly */ - const FLAC__StreamMetadata_SeekTable *seek_table; /* we hold a pointer to the stream decoder's seek table for the same reason */ - /* Since we always want to see the STREAMINFO and SEEK_TABLE blocks at this level, we need some extra flags to keep track of whether they should be passed on up through the metadata_callback */ - FLAC__bool ignore_stream_info_block; - FLAC__bool ignore_seek_table_block; - FLAC__Frame last_frame; /* holds the info of the last frame we seeked to */ - FLAC__uint64 target_sample; -} FLAC__SeekableStreamDecoderPrivate; - -/*********************************************************************** - * - * Public static class data - * - ***********************************************************************/ - -FLAC_API const char * const FLAC__SeekableStreamDecoderStateString[] = { - "FLAC__SEEKABLE_STREAM_DECODER_OK", - "FLAC__SEEKABLE_STREAM_DECODER_SEEKING", - "FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM", - "FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR", - "FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR", - "FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR", - "FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR", - "FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED", - "FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK", - "FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED" -}; - -FLAC_API const char * const FLAC__SeekableStreamDecoderReadStatusString[] = { - "FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK", - "FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR" -}; - -FLAC_API const char * const FLAC__SeekableStreamDecoderSeekStatusString[] = { - "FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK", - "FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR" -}; - -FLAC_API const char * const FLAC__SeekableStreamDecoderTellStatusString[] = { - "FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK", - "FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR" -}; - -FLAC_API const char * const FLAC__SeekableStreamDecoderLengthStatusString[] = { - "FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK", - "FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR" -}; - - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -FLAC_API FLAC__SeekableStreamDecoder *FLAC__seekable_stream_decoder_new(void) -{ - FLAC__SeekableStreamDecoder *decoder; - - FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ - - decoder = (FLAC__SeekableStreamDecoder*)calloc(1, sizeof(FLAC__SeekableStreamDecoder)); - if(decoder == 0) { - return 0; - } - - decoder->protected_ = (FLAC__SeekableStreamDecoderProtected*)calloc(1, sizeof(FLAC__SeekableStreamDecoderProtected)); - if(decoder->protected_ == 0) { - free(decoder); - return 0; - } - - decoder->private_ = (FLAC__SeekableStreamDecoderPrivate*)calloc(1, sizeof(FLAC__SeekableStreamDecoderPrivate)); - if(decoder->private_ == 0) { - free(decoder->protected_); - free(decoder); - return 0; - } - - decoder->private_->stream_decoder = FLAC__stream_decoder_new(); - if(0 == decoder->private_->stream_decoder) { - free(decoder->private_); - free(decoder->protected_); - free(decoder); - return 0; - } - - set_defaults_(decoder); - - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED; - - return decoder; -} - -FLAC_API void FLAC__seekable_stream_decoder_delete(FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->private_->stream_decoder); - - (void)FLAC__seekable_stream_decoder_finish(decoder); - - FLAC__stream_decoder_delete(decoder->private_->stream_decoder); - - free(decoder->private_); - free(decoder->protected_); - free(decoder); -} - -/*********************************************************************** - * - * Public class methods - * - ***********************************************************************/ - -FLAC_API FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_init(FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED; - - if(0 == decoder->private_->read_callback || 0 == decoder->private_->seek_callback || 0 == decoder->private_->tell_callback || 0 == decoder->private_->length_callback || 0 == decoder->private_->eof_callback) - return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK; - - if(0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback) - return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK; - - decoder->private_->seek_table = 0; - - decoder->private_->do_md5_checking = decoder->protected_->md5_checking; - - /* We initialize the FLAC__MD5Context even though we may never use it. This - * is because md5 checking may be turned on to start and then turned off if - * a seek occurs. So we always init the context here and finalize it in - * FLAC__seekable_stream_decoder_finish() to make sure things are always - * cleaned up properly. - */ - FLAC__MD5Init(&decoder->private_->md5context); - - FLAC__stream_decoder_set_read_callback(decoder->private_->stream_decoder, read_callback_); - FLAC__stream_decoder_set_write_callback(decoder->private_->stream_decoder, write_callback_); - FLAC__stream_decoder_set_metadata_callback(decoder->private_->stream_decoder, metadata_callback_); - FLAC__stream_decoder_set_error_callback(decoder->private_->stream_decoder, error_callback_); - FLAC__stream_decoder_set_client_data(decoder->private_->stream_decoder, decoder); - - /* We always want to see these blocks. Whether or not we pass them up - * through the metadata callback will be determined by flags set in our - * implementation of ..._set_metadata_respond/ignore...() - */ - FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_STREAMINFO); - FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_SEEKTABLE); - - if(FLAC__stream_decoder_init(decoder->private_->stream_decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA) - return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; - - return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_finish(FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__bool md5_failed = false; - - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - - if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return true; - - FLAC__ASSERT(0 != decoder->private_->stream_decoder); - - /* see the comment in FLAC__seekable_stream_decoder_init() as to why we - * always call FLAC__MD5Final() - */ - FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context); - - FLAC__stream_decoder_finish(decoder->private_->stream_decoder); - - if(decoder->private_->do_md5_checking) { - if(memcmp(decoder->private_->stored_md5sum, decoder->private_->computed_md5sum, 16)) - md5_failed = true; - } - - set_defaults_(decoder); - - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED; - - return !md5_failed; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_md5_checking(FLAC__SeekableStreamDecoder *decoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->protected_->md5_checking = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_read_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderReadCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->read_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_seek_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderSeekCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->seek_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_tell_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderTellCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->tell_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_length_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderLengthCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->length_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_eof_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderEofCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->eof_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_write_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderWriteCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->write_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderMetadataCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->metadata_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_error_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderErrorCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->error_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_client_data(FLAC__SeekableStreamDecoder *decoder, void *value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->client_data = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->stream_decoder); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - if(type == FLAC__METADATA_TYPE_STREAMINFO) - decoder->private_->ignore_stream_info_block = false; - else if(type == FLAC__METADATA_TYPE_SEEKTABLE) - decoder->private_->ignore_seek_table_block = false; - return FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, type); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4]) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->stream_decoder); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - return FLAC__stream_decoder_set_metadata_respond_application(decoder->private_->stream_decoder, id); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_all(FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->stream_decoder); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->ignore_stream_info_block = false; - decoder->private_->ignore_seek_table_block = false; - return FLAC__stream_decoder_set_metadata_respond_all(decoder->private_->stream_decoder); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->stream_decoder); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - if(type == FLAC__METADATA_TYPE_STREAMINFO) { - decoder->private_->ignore_stream_info_block = true; - return true; - } - else if(type == FLAC__METADATA_TYPE_SEEKTABLE) { - decoder->private_->ignore_seek_table_block = true; - return true; - } - else - return FLAC__stream_decoder_set_metadata_ignore(decoder->private_->stream_decoder, type); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4]) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->stream_decoder); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - return FLAC__stream_decoder_set_metadata_ignore_application(decoder->private_->stream_decoder, id); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_all(FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_->stream_decoder); - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->ignore_stream_info_block = true; - decoder->private_->ignore_seek_table_block = true; - return - FLAC__stream_decoder_set_metadata_ignore_all(decoder->private_->stream_decoder) && - FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_STREAMINFO) && - FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_SEEKTABLE); -} - -FLAC_API FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_get_state(const FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->state; -} - -FLAC_API FLAC__StreamDecoderState FLAC__seekable_stream_decoder_get_stream_decoder_state(const FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__stream_decoder_get_state(decoder->private_->stream_decoder); -} - -FLAC_API const char *FLAC__seekable_stream_decoder_get_resolved_state_string(const FLAC__SeekableStreamDecoder *decoder) -{ - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR) - return FLAC__SeekableStreamDecoderStateString[decoder->protected_->state]; - else - return FLAC__stream_decoder_get_resolved_state_string(decoder->private_->stream_decoder); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_get_md5_checking(const FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->md5_checking; -} - -FLAC_API unsigned FLAC__seekable_stream_decoder_get_channels(const FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__stream_decoder_get_channels(decoder->private_->stream_decoder); -} - -FLAC_API FLAC__ChannelAssignment FLAC__seekable_stream_decoder_get_channel_assignment(const FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__stream_decoder_get_channel_assignment(decoder->private_->stream_decoder); -} - -FLAC_API unsigned FLAC__seekable_stream_decoder_get_bits_per_sample(const FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__stream_decoder_get_bits_per_sample(decoder->private_->stream_decoder); -} - -FLAC_API unsigned FLAC__seekable_stream_decoder_get_sample_rate(const FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__stream_decoder_get_sample_rate(decoder->private_->stream_decoder); -} - -FLAC_API unsigned FLAC__seekable_stream_decoder_get_blocksize(const FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - return FLAC__stream_decoder_get_blocksize(decoder->private_->stream_decoder); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_get_decode_position(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *position) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != position); - - if(decoder->private_->tell_callback(decoder, position, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK) - return false; - FLAC__ASSERT(*position >= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder->private_->stream_decoder)); - *position -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder->private_->stream_decoder); - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_flush(FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - - decoder->private_->do_md5_checking = false; - - if(!FLAC__stream_decoder_flush(decoder->private_->stream_decoder)) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; - return false; - } - - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK; - - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_reset(FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - - if(!FLAC__seekable_stream_decoder_flush(decoder)) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; - return false; - } - - if(!FLAC__stream_decoder_reset(decoder->private_->stream_decoder)) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; - return false; - } - - decoder->private_->seek_table = 0; - - decoder->private_->do_md5_checking = decoder->protected_->md5_checking; - - /* We initialize the FLAC__MD5Context even though we may never use it. This - * is because md5 checking may be turned on to start and then turned off if - * a seek occurs. So we always init the context here and finalize it in - * FLAC__seekable_stream_decoder_finish() to make sure things are always - * cleaned up properly. - */ - FLAC__MD5Init(&decoder->private_->md5context); - - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK; - - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_single(FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__bool ret; - FLAC__ASSERT(0 != decoder); - - if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; - - if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) - return true; - - FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK); - - ret = FLAC__stream_decoder_process_single(decoder->private_->stream_decoder); - if(!ret) - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; - - return ret; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_metadata(FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__bool ret; - FLAC__ASSERT(0 != decoder); - - if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; - - if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) - return true; - - FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK); - - ret = FLAC__stream_decoder_process_until_end_of_metadata(decoder->private_->stream_decoder); - if(!ret) - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; - - return ret; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_stream(FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__bool ret; - FLAC__ASSERT(0 != decoder); - - if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; - - if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) - return true; - - FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK); - - ret = FLAC__stream_decoder_process_until_end_of_stream(decoder->private_->stream_decoder); - if(!ret) - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; - - return ret; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_skip_single_frame(FLAC__SeekableStreamDecoder *decoder) -{ - FLAC__bool ret; - FLAC__ASSERT(0 != decoder); - - if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; - - if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) - return true; - - FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK); - - ret = FLAC__stream_decoder_skip_single_frame(decoder->private_->stream_decoder); - if(!ret) - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; - - return ret; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_decoder_seek_absolute(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 sample) -{ - FLAC__uint64 length; - - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK || decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM); - - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEKING; - - /* turn off md5 checking if a seek is attempted */ - decoder->private_->do_md5_checking = false; - - if(!FLAC__stream_decoder_reset(decoder->private_->stream_decoder)) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; - return false; - } - /* get the file length */ - if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; - return false; - } - /* rewind */ - if(decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; - return false; - } - if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder->private_->stream_decoder)) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; - return false; - } - if(decoder->private_->stream_info.total_samples > 0 && sample >= decoder->private_->stream_info.total_samples) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; - return false; - } - - return seek_to_absolute_sample_(decoder, length, sample); -} - -/*********************************************************************** - * - * Private class methods - * - ***********************************************************************/ - -void set_defaults_(FLAC__SeekableStreamDecoder *decoder) -{ - decoder->private_->read_callback = 0; - decoder->private_->seek_callback = 0; - decoder->private_->tell_callback = 0; - decoder->private_->length_callback = 0; - decoder->private_->eof_callback = 0; - decoder->private_->write_callback = 0; - decoder->private_->metadata_callback = 0; - decoder->private_->error_callback = 0; - decoder->private_->client_data = 0; - /* WATCHOUT: these should match the default behavior of FLAC__StreamDecoder */ - decoder->private_->ignore_stream_info_block = false; - decoder->private_->ignore_seek_table_block = true; - - decoder->protected_->md5_checking = false; -} - -FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) -{ - FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data; - (void)decoder; - if(seekable_stream_decoder->private_->eof_callback(seekable_stream_decoder, seekable_stream_decoder->private_->client_data)) { - *bytes = 0; -#if 0 -@@@@@@ verify that this is not needed - seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; -#endif - return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - } - else if(*bytes > 0) { - if(seekable_stream_decoder->private_->read_callback(seekable_stream_decoder, buffer, bytes, seekable_stream_decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK) { - seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR; - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - } - if(*bytes == 0) { - if(seekable_stream_decoder->private_->eof_callback(seekable_stream_decoder, seekable_stream_decoder->private_->client_data)) { -#if 0 -@@@@@@ verify that this is not needed - seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; -#endif - return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - } - else - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - } - else { - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - } - } - else - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */ -} - -FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) -{ - FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data; - (void)decoder; - - if(seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_SEEKING) { - FLAC__uint64 this_frame_sample = frame->header.number.sample_number; - FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize; - FLAC__uint64 target_sample = seekable_stream_decoder->private_->target_sample; - - FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - - seekable_stream_decoder->private_->last_frame = *frame; /* save the frame */ - if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */ - unsigned delta = (unsigned)(target_sample - this_frame_sample); - /* kick out of seek mode */ - seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK; - /* shift out the samples before target_sample */ - if(delta > 0) { - unsigned channel; - const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS]; - for(channel = 0; channel < frame->header.channels; channel++) - newbuffer[channel] = buffer[channel] + delta; - seekable_stream_decoder->private_->last_frame.header.blocksize -= delta; - seekable_stream_decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta; - /* write the relevant samples */ - return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, &seekable_stream_decoder->private_->last_frame, newbuffer, seekable_stream_decoder->private_->client_data); - } - else { - /* write the relevant samples */ - return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, frame, buffer, seekable_stream_decoder->private_->client_data); - } - } - else { - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; - } - } - else { - if(seekable_stream_decoder->private_->do_md5_checking) { - if(!FLAC__MD5Accumulate(&seekable_stream_decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8)) - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; - } - return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, frame, buffer, seekable_stream_decoder->private_->client_data); - } -} - -void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) -{ - FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data; - (void)decoder; - - if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { - seekable_stream_decoder->private_->stream_info = metadata->data.stream_info; - /* save the MD5 signature for comparison later */ - memcpy(seekable_stream_decoder->private_->stored_md5sum, metadata->data.stream_info.md5sum, 16); - if(0 == memcmp(seekable_stream_decoder->private_->stored_md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) - seekable_stream_decoder->private_->do_md5_checking = false; - } - else if(metadata->type == FLAC__METADATA_TYPE_SEEKTABLE) { - seekable_stream_decoder->private_->seek_table = &metadata->data.seek_table; - } - - if(seekable_stream_decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING) { - FLAC__bool ignore_block = false; - if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && seekable_stream_decoder->private_->ignore_stream_info_block) - ignore_block = true; - else if(metadata->type == FLAC__METADATA_TYPE_SEEKTABLE && seekable_stream_decoder->private_->ignore_seek_table_block) - ignore_block = true; - if(!ignore_block) - seekable_stream_decoder->private_->metadata_callback(seekable_stream_decoder, metadata, seekable_stream_decoder->private_->client_data); - } -} - -void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) -{ - FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data; - (void)decoder; - - if(seekable_stream_decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING) - seekable_stream_decoder->private_->error_callback(seekable_stream_decoder, status, seekable_stream_decoder->private_->client_data); -} - -FLAC__bool seek_to_absolute_sample_(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample) -{ - FLAC__uint64 first_frame_offset, lower_bound, upper_bound; - FLAC__int64 pos = -1, last_pos = -1; - int i, lower_seek_point = -1, upper_seek_point = -1; - unsigned approx_bytes_per_frame; - FLAC__uint64 last_frame_sample = FLAC__U64L(0xffffffffffffffff); - FLAC__bool needs_seek; - const FLAC__uint64 total_samples = decoder->private_->stream_info.total_samples; - const unsigned min_blocksize = decoder->private_->stream_info.min_blocksize; - const unsigned max_blocksize = decoder->private_->stream_info.max_blocksize; - const unsigned max_framesize = decoder->private_->stream_info.max_framesize; - const unsigned channels = FLAC__seekable_stream_decoder_get_channels(decoder); - const unsigned bps = FLAC__seekable_stream_decoder_get_bits_per_sample(decoder); - - /* we are just guessing here, but we want to guess high, not low */ - if(max_framesize > 0) { - approx_bytes_per_frame = max_framesize; - } - /* - * Check if it's a known fixed-blocksize stream. Note that though - * the spec doesn't allow zeroes in the STREAMINFO block, we may - * never get a STREAMINFO block when decoding so the value of - * min_blocksize might be zero. - */ - else if(min_blocksize == max_blocksize && min_blocksize > 0) { - /* note there are no () around 'bps/8' to keep precision up since it's an integer calulation */ - approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64; - } - else - approx_bytes_per_frame = 4608 * channels * bps/8 + 64; - - /* - * The decode position is currently at the first frame since we - * rewound and processed metadata. - */ - if(!FLAC__seekable_stream_decoder_get_decode_position(decoder, &first_frame_offset)) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; - return false; - } - - /* - * First, we set an upper and lower bound on where in the - * stream we will search. For now we assume the worst case - * scenario, which is our best guess at the beginning of - * the first and last frames. - */ - lower_bound = first_frame_offset; - - /* calc the upper_bound, beyond which we never want to seek */ - if(max_framesize > 0) - upper_bound = stream_length - (max_framesize + 128 + 2); /* 128 for a possible ID3V1 tag, 2 for indexing differences */ - else - upper_bound = stream_length - ((channels * bps * FLAC__MAX_BLOCK_SIZE) / 8 + 128 + 2); - - /* - * Now we refine the bounds if we have a seektable with - * suitable points. Note that according to the spec they - * must be ordered by ascending sample number. - */ - if(0 != decoder->private_->seek_table) { - /* find the closest seek point <= target_sample, if it exists */ - for(i = (int)decoder->private_->seek_table->num_points - 1; i >= 0; i--) { - if(decoder->private_->seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && decoder->private_->seek_table->points[i].sample_number <= target_sample) - break; - } - if(i >= 0) { /* i.e. we found a suitable seek point... */ - lower_bound = first_frame_offset + decoder->private_->seek_table->points[i].stream_offset; - lower_seek_point = i; - } - - /* find the closest seek point > target_sample, if it exists */ - for(i = 0; i < (int)decoder->private_->seek_table->num_points; i++) { - if(decoder->private_->seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && decoder->private_->seek_table->points[i].sample_number > target_sample) - break; - } - if(i < (int)decoder->private_->seek_table->num_points) { /* i.e. we found a suitable seek point... */ - upper_bound = first_frame_offset + decoder->private_->seek_table->points[i].stream_offset; - upper_seek_point = i; - } - } - - /* - * Now guess at where within those bounds our target - * sample will be. - */ - if(lower_seek_point >= 0) { - /* first see if our sample is within a few frames of the lower seekpoint */ - if(decoder->private_->seek_table->points[lower_seek_point].sample_number <= target_sample && target_sample < decoder->private_->seek_table->points[lower_seek_point].sample_number + (decoder->private_->seek_table->points[lower_seek_point].frame_samples * 4)) { - pos = (FLAC__int64)lower_bound; - } - else if(upper_seek_point >= 0) { - const FLAC__uint64 target_offset = target_sample - decoder->private_->seek_table->points[lower_seek_point].sample_number; - const FLAC__uint64 range_samples = decoder->private_->seek_table->points[upper_seek_point].sample_number - decoder->private_->seek_table->points[lower_seek_point].sample_number; - const FLAC__uint64 range_bytes = upper_bound - lower_bound; -#if defined _MSC_VER || defined __MINGW32__ - /* with VC++ you have to spoon feed it the casting */ - pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)(FLAC__int64)target_offset / (double)(FLAC__int64)range_samples * (double)(FLAC__int64)(range_bytes-1)) - approx_bytes_per_frame; -#else - pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)target_offset / (double)range_samples * (double)(range_bytes-1)) - approx_bytes_per_frame; -#endif - } - } - - /* - * If there's no seek table, we need to use the metadata (if we - * have it) and the filelength to estimate the position of the - * frame with the correct sample. - */ - if(pos < 0 && total_samples > 0) { -#if defined _MSC_VER || defined __MINGW32__ - /* with VC++ you have to spoon feed it the casting */ - pos = (FLAC__int64)first_frame_offset + (FLAC__int64)((double)(FLAC__int64)target_sample / (double)(FLAC__int64)total_samples * (double)(FLAC__int64)(stream_length-first_frame_offset-1)) - approx_bytes_per_frame; -#else - pos = (FLAC__int64)first_frame_offset + (FLAC__int64)((double)target_sample / (double)total_samples * (double)(stream_length-first_frame_offset-1)) - approx_bytes_per_frame; -#endif - } - - /* - * If there's no seek table and total_samples is unknown, we - * don't even bother trying to figure out a target, we just use - * our current position. - */ - if(pos < 0) { - FLAC__uint64 upos; - if(decoder->private_->tell_callback(decoder, &upos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; - return false; - } - pos = (FLAC__int64)upos; - needs_seek = false; - } - else - needs_seek = true; - - /* clip the position to the bounds, lower bound takes precedence */ - if(pos >= (FLAC__int64)upper_bound) { - pos = (FLAC__int64)upper_bound-1; - needs_seek = true; - } - if(pos < (FLAC__int64)lower_bound) { - pos = (FLAC__int64)lower_bound; - needs_seek = true; - } - - decoder->private_->target_sample = target_sample; - while(1) { - if(needs_seek) { - if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; - return false; - } - if(!FLAC__stream_decoder_flush(decoder->private_->stream_decoder)) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; - return false; - } - } - /* Now we need to get a frame. It is possible for our seek - * to land in the middle of audio data that looks exactly like - * a frame header from a future version of an encoder. When - * that happens, FLAC__stream_decoder_process_single() will - * return false and the state will be - * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM. But there is a - * remote possibility that it is properly synced at such a - * "future-codec frame", so to make sure, we wait to see - * several "unparseable" errors in a row before bailing out. - */ - { - unsigned unparseable_count; - FLAC__bool got_a_frame = false; - for (unparseable_count = 0; !got_a_frame && unparseable_count < 10; unparseable_count++) { - if(FLAC__stream_decoder_process_single(decoder->private_->stream_decoder)) - got_a_frame = true; - else if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_UNPARSEABLE_STREAM) - /* try again. we don't want to flush the decoder since that clears the bitbuffer */ - decoder->private_->stream_decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - else /* it's a real error */ - break; - } - if (!got_a_frame) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; - return false; - } - } - /* our write callback will change the state when it gets to the target frame */ - if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING) { - break; - } - else { /* we need to narrow the search */ - const FLAC__uint64 this_frame_sample = decoder->private_->last_frame.header.number.sample_number; - FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - if(this_frame_sample == last_frame_sample && pos < last_pos) { - /* our last move backwards wasn't big enough, double it */ - pos -= (last_pos - pos); - needs_seek = true; - } - else { - if(target_sample < this_frame_sample) { - last_pos = pos; - approx_bytes_per_frame = decoder->private_->last_frame.header.blocksize * channels * bps/8 + 64; - pos -= approx_bytes_per_frame; - needs_seek = true; - } - else { /* target_sample >= this_frame_sample + this frame's blocksize */ - FLAC__uint64 upos; - if(decoder->private_->tell_callback(decoder, &upos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; - return false; - } - last_pos = pos; - pos = (FLAC__int64)upos; - pos -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder->private_->stream_decoder); - needs_seek = false; - /* - * if we haven't hit the target frame yet and our position hasn't changed, - * it means we're at the end of the stream and the seek target does not exist. - */ - if(last_pos == pos) { - decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; - return false; - } - } - } - if(pos < (FLAC__int64)lower_bound) - pos = (FLAC__int64)lower_bound; - last_frame_sample = this_frame_sample; - } - } - - return true; -} diff --git a/sys/src/cmd/audio/libFLAC/seekable_stream_encoder.c b/sys/src/cmd/audio/libFLAC/seekable_stream_encoder.c deleted file mode 100644 index fd3d815aa..000000000 --- a/sys/src/cmd/audio/libFLAC/seekable_stream_encoder.c +++ /dev/null @@ -1,944 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2002,2003,2004 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 <stdio.h> -#include <stdlib.h> /* for calloc() */ -#include <string.h> /* for memcpy() */ -#include "FLAC/assert.h" -#include "protected/seekable_stream_encoder.h" - -#ifdef max -#undef max -#endif -#define max(a,b) ((a)>(b)?(a):(b)) - -/*********************************************************************** - * - * Private class method prototypes - * - ***********************************************************************/ - -/* unpublished debug routines */ -extern FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); -extern FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); -extern FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); - -static void set_defaults_(FLAC__SeekableStreamEncoder *encoder); -static FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data); -static void metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data); - -/*********************************************************************** - * - * Private class data - * - ***********************************************************************/ - -typedef struct FLAC__SeekableStreamEncoderPrivate { - FLAC__SeekableStreamEncoderSeekCallback seek_callback; - FLAC__SeekableStreamEncoderTellCallback tell_callback; - FLAC__SeekableStreamEncoderWriteCallback write_callback; - void *client_data; - FLAC__StreamEncoder *stream_encoder; - FLAC__StreamMetadata_SeekTable *seek_table; - /* internal vars (all the above are class settings) */ - unsigned first_seekpoint_to_check; - FLAC__uint64 samples_written; -} FLAC__SeekableStreamEncoderPrivate; - -/*********************************************************************** - * - * Public static class data - * - ***********************************************************************/ - -FLAC_API const char * const FLAC__SeekableStreamEncoderStateString[] = { - "FLAC__SEEKABLE_STREAM_ENCODER_OK", - "FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR", - "FLAC__SEEKABLE_STREAM_ENCODER_MEMORY_ALLOCATION_ERROR", - "FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR", - "FLAC__SEEKABLE_STREAM_ENCODER_READ_ERROR", - "FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR", - "FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR", - "FLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED", - "FLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK", - "FLAC__SEEKABLE_STREAM_ENCODER_INVALID_SEEKTABLE", - "FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED" -}; - -FLAC_API const char * const FLAC__SeekableStreamEncoderSeekStatusString[] = { - "FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK", - "FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR" -}; - -FLAC_API const char * const FLAC__SeekableStreamEncoderTellStatusString[] = { - "FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK", - "FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR" -}; - -FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void); - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -FLAC_API FLAC__SeekableStreamEncoder *FLAC__seekable_stream_encoder_new(void) -{ - FLAC__SeekableStreamEncoder *encoder; - - FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ - - encoder = (FLAC__SeekableStreamEncoder*)calloc(1, sizeof(FLAC__SeekableStreamEncoder)); - if(encoder == 0) { - return 0; - } - - encoder->protected_ = (FLAC__SeekableStreamEncoderProtected*)calloc(1, sizeof(FLAC__SeekableStreamEncoderProtected)); - if(encoder->protected_ == 0) { - free(encoder); - return 0; - } - - encoder->private_ = (FLAC__SeekableStreamEncoderPrivate*)calloc(1, sizeof(FLAC__SeekableStreamEncoderPrivate)); - if(encoder->private_ == 0) { - free(encoder->protected_); - free(encoder); - return 0; - } - - encoder->private_->stream_encoder = FLAC__stream_encoder_new(); - if(0 == encoder->private_->stream_encoder) { - free(encoder->private_); - free(encoder->protected_); - free(encoder); - return 0; - } - - set_defaults_(encoder); - - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED; - - return encoder; -} - -FLAC_API void FLAC__seekable_stream_encoder_delete(FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - - (void)FLAC__seekable_stream_encoder_finish(encoder); - - FLAC__stream_encoder_delete(encoder->private_->stream_encoder); - - free(encoder->private_); - free(encoder->protected_); - free(encoder); -} - - -/*********************************************************************** - * - * Public class methods - * - ***********************************************************************/ - -FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_init(FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED; - - if(0 == encoder->private_->seek_callback || 0 == encoder->private_->tell_callback || 0 == encoder->private_->write_callback) - return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK; - - if(0 != encoder->private_->seek_table && !FLAC__format_seektable_is_legal(encoder->private_->seek_table)) - return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_INVALID_SEEKTABLE; - - /* - * These must be done before we init the stream encoder because that - * calls the write_callback, which uses these values. - */ - encoder->private_->first_seekpoint_to_check = 0; - encoder->private_->samples_written = 0; - encoder->protected_->streaminfo_offset = 0; - encoder->protected_->seektable_offset = 0; - encoder->protected_->audio_offset = 0; - - FLAC__stream_encoder_set_write_callback(encoder->private_->stream_encoder, write_callback_); - FLAC__stream_encoder_set_metadata_callback(encoder->private_->stream_encoder, metadata_callback_); - FLAC__stream_encoder_set_client_data(encoder->private_->stream_encoder, encoder); - - if(FLAC__stream_encoder_init(encoder->private_->stream_encoder) != FLAC__STREAM_ENCODER_OK) - return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR; - - /* - * Initializing the stream encoder writes all the metadata, so we - * save the stream offset now. - */ - if(encoder->private_->tell_callback(encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK) - return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR; - - return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_OK; -} - -FLAC_API void FLAC__seekable_stream_encoder_finish(FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - - if(encoder->protected_->state == FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return; - - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - - FLAC__stream_encoder_finish(encoder->private_->stream_encoder); - - set_defaults_(encoder); - - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_verify(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_verify(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_streamable_subset(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_streamable_subset(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_mid_side_stereo(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_do_mid_side_stereo(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_loose_mid_side_stereo(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_channels(FLAC__SeekableStreamEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_channels(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_bits_per_sample(FLAC__SeekableStreamEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_bits_per_sample(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_sample_rate(FLAC__SeekableStreamEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_sample_rate(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_blocksize(FLAC__SeekableStreamEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_blocksize(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_max_lpc_order(FLAC__SeekableStreamEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_max_lpc_order(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_qlp_coeff_precision(FLAC__SeekableStreamEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_qlp_coeff_precision(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_escape_coding(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_do_escape_coding(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_exhaustive_model_search(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_do_exhaustive_model_search(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_min_residual_partition_order(FLAC__SeekableStreamEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_min_residual_partition_order(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_max_residual_partition_order(FLAC__SeekableStreamEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_max_residual_partition_order(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_rice_parameter_search_dist(FLAC__SeekableStreamEncoder *encoder, unsigned value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_rice_parameter_search_dist(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_total_samples_estimate(FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_set_total_samples_estimate(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_metadata(FLAC__SeekableStreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - FLAC__ASSERT(0 != encoder->private_->stream_encoder); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - if(0 != metadata && num_blocks > 0) { - unsigned i; - for(i = 0; i < num_blocks; i++) { - if(0 != metadata[i] && metadata[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) { - encoder->private_->seek_table = &metadata[i]->data.seek_table; - break; /* take only the first one */ - } - } - } - return FLAC__stream_encoder_set_metadata(encoder->private_->stream_encoder, metadata, num_blocks); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_seek_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderSeekCallback value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->private_->seek_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_tell_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderTellCallback value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->private_->tell_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_write_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderWriteCallback value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->private_->write_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_client_data(FLAC__SeekableStreamEncoder *encoder, void *value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->private_->client_data = value; - return true; -} - -/* - * These three functions are not static, but not publically exposed in - * include/FLAC/ either. They are used by the test suite. - */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_disable_constant_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_disable_constant_subframes(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_disable_fixed_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_disable_fixed_subframes(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_disable_verbatim_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) - return false; - return FLAC__stream_encoder_disable_verbatim_subframes(encoder->private_->stream_encoder, value); -} - -FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_get_state(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->protected_); - return encoder->protected_->state; -} - -FLAC_API FLAC__StreamEncoderState FLAC__seekable_stream_encoder_get_stream_encoder_state(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_state(encoder->private_->stream_encoder); -} - -FLAC_API FLAC__StreamDecoderState FLAC__seekable_stream_encoder_get_verify_decoder_state(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_verify_decoder_state(encoder->private_->stream_encoder); -} - -FLAC_API const char *FLAC__seekable_stream_encoder_get_resolved_state_string(const FLAC__SeekableStreamEncoder *encoder) -{ - if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR) - return FLAC__SeekableStreamEncoderStateString[encoder->protected_->state]; - else - return FLAC__stream_encoder_get_resolved_state_string(encoder->private_->stream_encoder); -} - -FLAC_API void FLAC__seekable_stream_encoder_get_verify_decoder_error_stats(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__stream_encoder_get_verify_decoder_error_stats(encoder->private_->stream_encoder, absolute_sample, frame_number, channel, sample, expected, got); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_verify(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_verify(encoder->private_->stream_encoder); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_streamable_subset(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_streamable_subset(encoder->private_->stream_encoder); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_mid_side_stereo(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_do_mid_side_stereo(encoder->private_->stream_encoder); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_loose_mid_side_stereo(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_loose_mid_side_stereo(encoder->private_->stream_encoder); -} - -FLAC_API unsigned FLAC__seekable_stream_encoder_get_channels(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_channels(encoder->private_->stream_encoder); -} - -FLAC_API unsigned FLAC__seekable_stream_encoder_get_bits_per_sample(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_bits_per_sample(encoder->private_->stream_encoder); -} - -FLAC_API unsigned FLAC__seekable_stream_encoder_get_sample_rate(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_sample_rate(encoder->private_->stream_encoder); -} - -FLAC_API unsigned FLAC__seekable_stream_encoder_get_blocksize(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_blocksize(encoder->private_->stream_encoder); -} - -FLAC_API unsigned FLAC__seekable_stream_encoder_get_max_lpc_order(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_max_lpc_order(encoder->private_->stream_encoder); -} - -FLAC_API unsigned FLAC__seekable_stream_encoder_get_qlp_coeff_precision(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_qlp_coeff_precision(encoder->private_->stream_encoder); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder->private_->stream_encoder); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_escape_coding(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_do_escape_coding(encoder->private_->stream_encoder); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_exhaustive_model_search(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_do_exhaustive_model_search(encoder->private_->stream_encoder); -} - -FLAC_API unsigned FLAC__seekable_stream_encoder_get_min_residual_partition_order(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_min_residual_partition_order(encoder->private_->stream_encoder); -} - -FLAC_API unsigned FLAC__seekable_stream_encoder_get_max_residual_partition_order(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_max_residual_partition_order(encoder->private_->stream_encoder); -} - -FLAC_API unsigned FLAC__seekable_stream_encoder_get_rice_parameter_search_dist(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_rice_parameter_search_dist(encoder->private_->stream_encoder); -} - -FLAC_API FLAC__uint64 FLAC__seekable_stream_encoder_get_total_samples_estimate(const FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - return FLAC__stream_encoder_get_total_samples_estimate(encoder->private_->stream_encoder); -} - -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_process(FLAC__SeekableStreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - if(!FLAC__stream_encoder_process(encoder->private_->stream_encoder, buffer, samples)) { - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR; - return false; - } - else - return true; -} - -/* 'samples' is channel-wide samples, e.g. for 1 second at 44100Hz, 'samples' = 44100 regardless of the number of channels */ -FLAC_API FLAC__bool FLAC__seekable_stream_encoder_process_interleaved(FLAC__SeekableStreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - if(!FLAC__stream_encoder_process_interleaved(encoder->private_->stream_encoder, buffer, samples)) { - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR; - return false; - } - else - return true; -} - -/*********************************************************************** - * - * Private class methods - * - ***********************************************************************/ - -void set_defaults_(FLAC__SeekableStreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != encoder->private_); - FLAC__ASSERT(0 != encoder->protected_); - - encoder->private_->seek_callback = 0; - encoder->private_->tell_callback = 0; - encoder->private_->write_callback = 0; - encoder->private_->client_data = 0; - - encoder->private_->seek_table = 0; -} - -FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *unused, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data) -{ - FLAC__SeekableStreamEncoder *encoder = (FLAC__SeekableStreamEncoder*)client_data; - FLAC__StreamEncoderWriteStatus status; - FLAC__uint64 output_position; - - (void)unused; /* silence compiler warning about unused parameter */ - FLAC__ASSERT(encoder->private_->stream_encoder == unused); - - if(encoder->private_->tell_callback(encoder, &output_position, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK) - return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR; - - /* - * Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets. - */ - if(samples == 0) { - FLAC__MetadataType type = (buffer[0] & 0x7f); - if(type == FLAC__METADATA_TYPE_STREAMINFO) - encoder->protected_->streaminfo_offset = output_position; - else if(type == FLAC__METADATA_TYPE_SEEKTABLE && encoder->protected_->seektable_offset == 0) - encoder->protected_->seektable_offset = output_position; - } - - /* - * Mark the current seek point if hit (if audio_offset == 0 that - * means we're still writing metadata and haven't hit the first - * frame yet) - */ - if(0 != encoder->private_->seek_table && encoder->protected_->audio_offset > 0 && encoder->private_->seek_table->num_points > 0) { - const unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder->private_->stream_encoder); - const FLAC__uint64 frame_first_sample = encoder->private_->samples_written; - const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1; - FLAC__uint64 test_sample; - unsigned i; - for(i = encoder->private_->first_seekpoint_to_check; i < encoder->private_->seek_table->num_points; i++) { - test_sample = encoder->private_->seek_table->points[i].sample_number; - if(test_sample > frame_last_sample) { - break; - } - else if(test_sample >= frame_first_sample) { - encoder->private_->seek_table->points[i].sample_number = frame_first_sample; - encoder->private_->seek_table->points[i].stream_offset = output_position - encoder->protected_->audio_offset; - encoder->private_->seek_table->points[i].frame_samples = blocksize; - encoder->private_->first_seekpoint_to_check++; - /* DO NOT: "break;" and here's why: - * The seektable template may contain more than one target - * sample for any given frame; we will keep looping, generating - * duplicate seekpoints for them, and we'll clean it up later, - * just before writing the seektable back to the metadata. - */ - } - else { - encoder->private_->first_seekpoint_to_check++; - } - } - } - - status = encoder->private_->write_callback(encoder, buffer, bytes, samples, current_frame, encoder->private_->client_data); - - if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - encoder->private_->samples_written += samples; - } - else - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR; - - return status; -} - -void metadata_callback_(const FLAC__StreamEncoder *unused, const FLAC__StreamMetadata *metadata, void *client_data) -{ - FLAC__SeekableStreamEncoder *encoder = (FLAC__SeekableStreamEncoder*)client_data; - FLAC__byte b[max(6, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)]; - const FLAC__uint64 samples = metadata->data.stream_info.total_samples; - const unsigned min_framesize = metadata->data.stream_info.min_framesize; - const unsigned max_framesize = metadata->data.stream_info.max_framesize; - const unsigned bps = metadata->data.stream_info.bits_per_sample; - - FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); - - /* We get called by the stream encoder when the encoding process - * has finished so that we can update the STREAMINFO and SEEKTABLE - * blocks. - */ - - (void)unused; /* silence compiler warning about unused parameter */ - FLAC__ASSERT(encoder->private_->stream_encoder == unused); - - /*@@@ reopen callback here? The docs currently require user to open files in update mode from the start */ - - /* All this is based on intimate knowledge of the stream header - * layout, but a change to the header format that would break this - * would also break all streams encoded in the previous format. - */ - - /* - * Write MD5 signature - */ - { - const unsigned md5_offset = - FLAC__STREAM_METADATA_HEADER_LENGTH + - ( - FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + - FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN - ) / 8; - - if(encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + md5_offset, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR; - return; - } - if(encoder->private_->write_callback(encoder, metadata->data.stream_info.md5sum, 16, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR; - return; - } - } - - /* - * Write total samples - */ - { - const unsigned total_samples_byte_offset = - FLAC__STREAM_METADATA_HEADER_LENGTH + - ( - FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + - FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN - - 4 - ) / 8; - - b[0] = ((FLAC__byte)(bps-1) << 4) | (FLAC__byte)((samples >> 32) & 0x0F); - b[1] = (FLAC__byte)((samples >> 24) & 0xFF); - b[2] = (FLAC__byte)((samples >> 16) & 0xFF); - b[3] = (FLAC__byte)((samples >> 8) & 0xFF); - b[4] = (FLAC__byte)(samples & 0xFF); - if(encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + total_samples_byte_offset, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR; - return; - } - if(encoder->private_->write_callback(encoder, b, 5, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR; - return; - } - } - - /* - * Write min/max framesize - */ - { - const unsigned min_framesize_offset = - FLAC__STREAM_METADATA_HEADER_LENGTH + - ( - FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + - FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN - ) / 8; - - b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF); - b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF); - b[2] = (FLAC__byte)(min_framesize & 0xFF); - b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF); - b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF); - b[5] = (FLAC__byte)(max_framesize & 0xFF); - if(encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + min_framesize_offset, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR; - return; - } - if(encoder->private_->write_callback(encoder, b, 6, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR; - return; - } - } - - /* - * Write seektable - */ - if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) { - unsigned i; - - FLAC__format_seektable_sort(encoder->private_->seek_table); - - FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table)); - - if(encoder->private_->seek_callback(encoder, encoder->protected_->seektable_offset + FLAC__STREAM_METADATA_HEADER_LENGTH, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR; - return; - } - - for(i = 0; i < encoder->private_->seek_table->num_points; i++) { - FLAC__uint64 xx; - unsigned x; - xx = encoder->private_->seek_table->points[i].sample_number; - b[7] = (FLAC__byte)xx; xx >>= 8; - b[6] = (FLAC__byte)xx; xx >>= 8; - b[5] = (FLAC__byte)xx; xx >>= 8; - b[4] = (FLAC__byte)xx; xx >>= 8; - b[3] = (FLAC__byte)xx; xx >>= 8; - b[2] = (FLAC__byte)xx; xx >>= 8; - b[1] = (FLAC__byte)xx; xx >>= 8; - b[0] = (FLAC__byte)xx; xx >>= 8; - xx = encoder->private_->seek_table->points[i].stream_offset; - b[15] = (FLAC__byte)xx; xx >>= 8; - b[14] = (FLAC__byte)xx; xx >>= 8; - b[13] = (FLAC__byte)xx; xx >>= 8; - b[12] = (FLAC__byte)xx; xx >>= 8; - b[11] = (FLAC__byte)xx; xx >>= 8; - b[10] = (FLAC__byte)xx; xx >>= 8; - b[9] = (FLAC__byte)xx; xx >>= 8; - b[8] = (FLAC__byte)xx; xx >>= 8; - x = encoder->private_->seek_table->points[i].frame_samples; - b[17] = (FLAC__byte)x; x >>= 8; - b[16] = (FLAC__byte)x; x >>= 8; - if(encoder->private_->write_callback(encoder, b, 18, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR; - return; - } - } - } -} diff --git a/sys/src/cmd/audio/libFLAC/share/alloc.h b/sys/src/cmd/audio/libFLAC/share/alloc.h new file mode 100644 index 000000000..5e1f1e26f --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/share/alloc.h @@ -0,0 +1,209 @@ +/* alloc - Convenience routines for safely allocating memory + * Copyright (C) 2007-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifndef FLAC__SHARE__ALLOC_H +#define FLAC__SHARE__ALLOC_H + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early + * before #including this file, otherwise SIZE_MAX might not be defined + */ + +#include <limits.h> /* for SIZE_MAX */ +#if HAVE_STDINT_H +#include <stdint.h> /* for SIZE_MAX in case limits.h didn't get it */ +#endif +#include <stdlib.h> /* for size_t, malloc(), etc */ +#include "share/compat.h" + +#ifndef SIZE_MAX +# ifndef SIZE_T_MAX +# ifdef _MSC_VER +# ifdef _WIN64 +# define SIZE_T_MAX 0xffffffffffffffffui64 +# else +# define SIZE_T_MAX 0xffffffff +# endif +# else +# error +# endif +# endif +# define SIZE_MAX SIZE_T_MAX +#endif + +/* avoid malloc()ing 0 bytes, see: + * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003 +*/ +static inline void *safe_malloc_(size_t size) +{ + /* malloc(0) is undefined; FLAC src convention is to always allocate */ + if(!size) + size++; + return malloc(size); +} + +static inline void *safe_calloc_(size_t nmemb, size_t size) +{ + if(!nmemb || !size) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + return calloc(nmemb, size); +} + +/*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */ + +static inline void *safe_malloc_add_2op_(size_t size1, size_t size2) +{ + size2 += size1; + if(size2 < size1) + return 0; + return safe_malloc_(size2); +} + +static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3) +{ + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + return safe_malloc_(size3); +} + +static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4) +{ + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + size4 += size3; + if(size4 < size3) + return 0; + return safe_malloc_(size4); +} + +void *safe_malloc_mul_2op_(size_t size1, size_t size2) ; + +static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3) +{ + if(!size1 || !size2 || !size3) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + if(size1 > SIZE_MAX / size2) + return 0; + size1 *= size2; + if(size1 > SIZE_MAX / size3) + return 0; + return malloc(size1*size3); +} + +/* size1*size2 + size3 */ +static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3) +{ + if(!size1 || !size2) + return safe_malloc_(size3); + if(size1 > SIZE_MAX / size2) + return 0; + return safe_malloc_add_2op_(size1*size2, size3); +} + +/* size1 * (size2 + size3) */ +static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3) +{ + if(!size1 || (!size2 && !size3)) + return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ + size2 += size3; + if(size2 < size3) + return 0; + if(size1 > SIZE_MAX / size2) + return 0; + return malloc(size1*size2); +} + +static inline void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2) +{ + size2 += size1; + if(size2 < size1) + return 0; + return realloc(ptr, size2); +} + +static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) +{ + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + return realloc(ptr, size3); +} + +static inline void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4) +{ + size2 += size1; + if(size2 < size1) + return 0; + size3 += size2; + if(size3 < size2) + return 0; + size4 += size3; + if(size4 < size3) + return 0; + return realloc(ptr, size4); +} + +static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2) +{ + if(!size1 || !size2) + return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ + if(size1 > SIZE_MAX / size2) + return 0; + return realloc(ptr, size1*size2); +} + +/* size1 * (size2 + size3) */ +static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) +{ + if(!size1 || (!size2 && !size3)) + return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ + size2 += size3; + if(size2 < size3) + return 0; + return safe_realloc_mul_2op_(ptr, size1, size2); +} + +#endif diff --git a/sys/src/cmd/audio/libFLAC/share/compat.h b/sys/src/cmd/audio/libFLAC/share/compat.h new file mode 100644 index 000000000..0dc5673d7 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/share/compat.h @@ -0,0 +1,201 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2012-2014 Xiph.org Foundation + * + * 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. + */ + +/* This is the prefered location of all CPP hackery to make $random_compiler + * work like something approaching a C99 (or maybe more accurately GNU99) + * compiler. + * + * It is assumed that this header will be included after "config.h". + */ + +#ifndef FLAC__SHARE__COMPAT_H +#define FLAC__SHARE__COMPAT_H + +#if defined _WIN32 && !defined __CYGWIN__ +/* where MSVC puts unlink() */ +# include <io.h> +#else +# include <unistd.h> +#endif + +#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ +#include <sys/types.h> /* for off_t */ +#define FLAC__off_t __int64 /* use this instead of off_t to fix the 2 GB limit */ +#if !defined __MINGW32__ +#define fseeko _fseeki64 +#define ftello _ftelli64 +#else /* MinGW */ +#if !defined(HAVE_FSEEKO) +#define fseeko fseeko64 +#define ftello ftello64 +#endif +#endif +#else +#define FLAC__off_t off_t +#endif + +#if HAVE_INTTYPES_H +#define __STDC_FORMAT_MACROS +#include <inttypes.h> +#endif + +#if defined(_MSC_VER) +#define strtoll _strtoi64 +#define strtoull _strtoui64 +#endif + +#if defined(_MSC_VER) +#define inline __inline +#endif + +#if defined __INTEL_COMPILER || (defined _MSC_VER && defined _WIN64) +/* MSVS generates VERY slow 32-bit code with __restrict */ +#define flac_restrict __restrict +#elif defined __GNUC__ +#define flac_restrict __restrict__ +#else +#define flac_restrict +#endif + +#define FLAC__U64L(x) x##ULL + +#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ +#define FLAC__STRCASECMP stricmp +#define FLAC__STRNCASECMP strnicmp +#else +#define FLAC__STRCASECMP strcasecmp +#define FLAC__STRNCASECMP strncasecmp +#endif + +#if defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ || defined __EMX__ +#include <io.h> /* for _setmode(), chmod() */ +#include <fcntl.h> /* for _O_BINARY */ +#else +#include <unistd.h> /* for chown(), unlink() */ +#endif + +#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ +#if defined __BORLANDC__ +#include <utime.h> /* for utime() */ +#else +#include <sys/utime.h> /* for utime() */ +#endif +#else +#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */ +#include <utime.h> /* for utime() */ +#endif + +#if defined _MSC_VER +# if _MSC_VER >= 1600 +/* Visual Studio 2010 has decent C99 support */ +# include <stdint.h> +# define PRIu64 "llu" +# define PRId64 "lld" +# define PRIx64 "llx" +# else +# include <limits.h> +# ifndef UINT32_MAX +# define UINT32_MAX _UI32_MAX +# endif + typedef unsigned __int64 uint64_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int8 uint8_t; + typedef __int64 int64_t; + typedef __int32 int32_t; + typedef __int16 int16_t; + typedef __int8 int8_t; +# define PRIu64 "I64u" +# define PRId64 "I64d" +# define PRIx64 "I64x" +# endif +#endif /* defined _MSC_VER */ + +#ifdef _WIN32 +/* All char* strings are in UTF-8 format. Added to support Unicode files on Windows */ +#include "share/win_utf8_io.h" + +#define flac_printf printf_utf8 +#define flac_fprintf fprintf_utf8 +#define flac_vfprintf vfprintf_utf8 +#define flac_fopen fopen_utf8 +#define flac_chmod chmod_utf8 +#define flac_utime utime_utf8 +#define flac_unlink unlink_utf8 +#define flac_rename rename_utf8 +#define flac_stat _stat64_utf8 + +#else + +#define flac_printf printf +#define flac_fprintf fprintf +#define flac_vfprintf vfprintf +#define flac_fopen fopen +#define flac_chmod chmod +#define flac_utime utime +#define flac_unlink unlink +#define flac_rename rename +#define flac_stat stat + +#endif + +#ifdef _WIN32 +#define flac_stat_s __stat64 /* stat struct */ +#define flac_fstat _fstat64 +#else +#define flac_stat_s stat /* stat struct */ +#define flac_fstat fstat +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +/* FLAC needs to compile and work correctly on systems with a normal ISO C99 + * snprintf as well as Microsoft Visual Studio which has an non-standards + * conformant snprint_s function. + * + * This function wraps the MS version to behave more like the the ISO version. + */ +#include <stdarg.h> +#ifdef __cplusplus +extern "C" { +#endif +int flac_snprintf(char *str, size_t size, const char *fmt, ...); +int flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va); +#ifdef __cplusplus +}; +#endif + +#endif /* FLAC__SHARE__COMPAT_H */ diff --git a/sys/src/cmd/audio/libFLAC/share/endswap.h b/sys/src/cmd/audio/libFLAC/share/endswap.h new file mode 100644 index 000000000..4fde4c156 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/share/endswap.h @@ -0,0 +1,78 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2012-2014 Xiph.org Foundation + * + * 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. + */ + +/* It is assumed that this header will be included after "config.h". */ + +#if HAVE_BSWAP32 /* GCC and Clang */ + +/* GCC prior to 4.8 didn't provide bswap16 on x86_64 */ +#if ! HAVE_BSWAP16 +static inline unsigned short __builtin_bswap16(unsigned short a) +{ + return (a<<8)|(a>>8); +} +#endif + +#define ENDSWAP_16(x) (__builtin_bswap16 (x)) +#define ENDSWAP_32(x) (__builtin_bswap32 (x)) + +#elif defined _MSC_VER /* Windows. Apparently in <stdlib.h>. */ + +#define ENDSWAP_16(x) (_byteswap_ushort (x)) +#define ENDSWAP_32(x) (_byteswap_ulong (x)) + +#elif defined HAVE_BYTESWAP_H /* Linux */ + +#include <byteswap.h> + +#define ENDSWAP_16(x) (bswap_16 (x)) +#define ENDSWAP_32(x) (bswap_32 (x)) + +#else + +#define ENDSWAP_16(x) ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8)) +#define ENDSWAP_32(x) ((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) & 0xFF00) << 8) | (((x) & 0xFF) << 24)) + +#endif + + +/* Host to little-endian byte swapping. */ +#if CPU_IS_BIG_ENDIAN + +#define H2LE_16(x) ENDSWAP_16 (x) +#define H2LE_32(x) ENDSWAP_32 (x) + +#else + +#define H2LE_16(x) (x) +#define H2LE_32(x) (x) + +#endif diff --git a/sys/src/cmd/audio/libFLAC/protected/file_decoder.h b/sys/src/cmd/audio/libFLAC/share/macros.h index 9f1a40a87..b4254b9fc 100644 --- a/sys/src/cmd/audio/libFLAC/protected/file_decoder.h +++ b/sys/src/cmd/audio/libFLAC/share/macros.h @@ -1,5 +1,5 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2013-2014 Xiph.org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,13 +29,13 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FLAC__PROTECTED__FILE_DECODER_H -#define FLAC__PROTECTED__FILE_DECODER_H +#include <errno.h> -#include "FLAC/file_decoder.h" - -typedef struct FLAC__FileDecoderProtected { - FLAC__FileDecoderState state; -} FLAC__FileDecoderProtected; +/* FLAC_CHECK_RETURN : Check the return value of of the provided function and + * print and error message if it fails (ie returns a value < 0). + */ -#endif +#define FLAC_CHECK_RETURN(x) \ + { if ((x) < 0) \ + printf ("%s : %s\n", #x, strerror (errno)) ; \ + } diff --git a/sys/src/cmd/audio/libFLAC/protected/file_encoder.h b/sys/src/cmd/audio/libFLAC/share/private.h index e04e1654d..3a500d3ca 100644 --- a/sys/src/cmd/audio/libFLAC/protected/file_encoder.h +++ b/sys/src/cmd/audio/libFLAC/share/private.h @@ -1,5 +1,5 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2013-2014 Xiph.org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,13 +29,17 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FLAC__PROTECTED__FILE_ENCODER_H -#define FLAC__PROTECTED__FILE_ENCODER_H +#ifndef FLAC__SHARE__PRIVATE_H +#define FLAC__SHARE__PRIVATE_H -#include "FLAC/file_encoder.h" - -typedef struct FLAC__FileEncoderProtected { - FLAC__FileEncoderState state; -} FLAC__FileEncoderProtected; +/* + * Unpublished debug routines from libFLAC> This should not be used from any + * client code other than code shipped with the FLAC sources. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); +FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); +FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value); +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value); +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_md5(const FLAC__StreamEncoder *encoder); -#endif +#endif /* FLAC__SHARE__PRIVATE_H */ diff --git a/sys/src/cmd/audio/libFLAC/share/safe_str.h b/sys/src/cmd/audio/libFLAC/share/safe_str.h new file mode 100644 index 000000000..dd1e4ed91 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/share/safe_str.h @@ -0,0 +1,69 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2013-2014 Xiph.org Foundation + * + * 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. + */ + +/* Safe string handling functions to replace things like strcpy, strncpy, + * strcat, strncat etc. + * All of these functions guarantee a correctly NUL terminated string but + * the string may be truncated if the destination buffer was too short. + */ + +#ifndef FLAC__SHARE_SAFE_STR_H +#define FLAC__SHARE_SAFE_STR_H + +static inline char * +safe_strncat(char *dest, const char *src, size_t dest_size) +{ + char * ret; + + if (dest_size < 1) + return dest; + + ret = strncat(dest, src, dest_size - strlen (dest)); + dest [dest_size - 1] = 0; + + return ret; +} + +static inline char * +safe_strncpy(char *dest, const char *src, size_t dest_size) +{ + char * ret; + + if (dest_size < 1) + return dest; + + ret = strncpy(dest, src, dest_size); + dest [dest_size - 1] = 0; + + return ret; +} + +#endif /* FLAC__SHARE_SAFE_STR_H */ diff --git a/sys/src/cmd/audio/libFLAC/stream_decoder.c b/sys/src/cmd/audio/libFLAC/stream_decoder.c index 09f0f832e..6632d3127 100644 --- a/sys/src/cmd/audio/libFLAC/stream_decoder.c +++ b/sys/src/cmd/audio/libFLAC/stream_decoder.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,35 +30,40 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include <stdio.h> #include <stdlib.h> /* for malloc() */ #include <string.h> /* for memset/memcpy() */ +#include <sys/stat.h> /* for stat() */ +#include <sys/types.h> /* for off_t */ +#include "share/compat.h" #include "FLAC/assert.h" +#include "share/alloc.h" #include "protected/stream_decoder.h" -#include "private/bitbuffer.h" +#include "private/bitreader.h" #include "private/bitmath.h" #include "private/cpu.h" #include "private/crc.h" #include "private/fixed.h" #include "private/format.h" #include "private/lpc.h" +#include "private/md5.h" #include "private/memory.h" +#include "private/macros.h" -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#ifdef max -#undef max -#endif -#define max(a,b) ((a)>(b)?(a):(b)) - -/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */ -#ifdef _MSC_VER -#define FLAC__U64L(x) x +/* technically this should be in an "export.c" but this is convenient enough */ +FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC = +#if FLAC__HAS_OGG + 1 #else -#define FLAC__U64L(x) x##LLU + 0 #endif +; + /*********************************************************************** * @@ -65,7 +71,7 @@ * ***********************************************************************/ -static FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' }; +static const FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' }; /*********************************************************************** * @@ -74,14 +80,16 @@ static FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' }; ***********************************************************************/ static void set_defaults_(FLAC__StreamDecoder *decoder); +static FILE *get_binary_stdin_(void); static FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels); static FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id); static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder); static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder); static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length); static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length); -static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj); +static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, unsigned length); static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj); +static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj); static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder); static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder); static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode); @@ -91,9 +99,24 @@ static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode); static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode); static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode); -static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual); +static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended); static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder); -static FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *client_data); +static FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data); +#if FLAC__HAS_OGG +static FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes); +static FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +#endif +static FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); +static void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status); +static FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample); +#if FLAC__HAS_OGG +static FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample); +#endif +static FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +static FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); +static FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); +static FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); +static FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data); /*********************************************************************** * @@ -102,7 +125,14 @@ static FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *cli ***********************************************************************/ typedef struct FLAC__StreamDecoderPrivate { +#if FLAC__HAS_OGG + FLAC__bool is_ogg; +#endif FLAC__StreamDecoderReadCallback read_callback; + FLAC__StreamDecoderSeekCallback seek_callback; + FLAC__StreamDecoderTellCallback tell_callback; + FLAC__StreamDecoderLengthCallback length_callback; + FLAC__StreamDecoderEofCallback eof_callback; FLAC__StreamDecoderWriteCallback write_callback; FLAC__StreamDecoderMetadataCallback metadata_callback; FLAC__StreamDecoderErrorCallback error_callback; @@ -112,22 +142,21 @@ typedef struct FLAC__StreamDecoderPrivate { void (*local_lpc_restore_signal_64bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); /* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit): */ void (*local_lpc_restore_signal_16bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); - /* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit), AND order <= 8: */ - void (*local_lpc_restore_signal_16bit_order8)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); void *client_data; - FLAC__BitBuffer *input; + FILE *file; /* only used if FLAC__stream_decoder_init_file()/FLAC__stream_decoder_init_file() called, else NULL */ + FLAC__BitReader *input; FLAC__int32 *output[FLAC__MAX_CHANNELS]; FLAC__int32 *residual[FLAC__MAX_CHANNELS]; /* WATCHOUT: these are the aligned pointers; the real pointers that should be free()'d are residual_unaligned[] below */ FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS]; unsigned output_capacity, output_channels; - FLAC__uint32 last_frame_number; + FLAC__uint32 fixed_block_size, next_fixed_block_size; FLAC__uint64 samples_decoded; FLAC__bool has_stream_info, has_seek_table; FLAC__StreamMetadata stream_info; FLAC__StreamMetadata seek_table; FLAC__bool metadata_filter[128]; /* MAGIC number 128 == total number of metadata block types == 1 << 7 */ FLAC__byte *metadata_filter_ids; - unsigned metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */ + size_t metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */ FLAC__Frame frame; FLAC__bool cached; /* true if there is a byte in lookahead */ FLAC__CPUInfo cpuinfo; @@ -135,6 +164,19 @@ typedef struct FLAC__StreamDecoderPrivate { FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */ /* unaligned (original) pointers to allocated data */ FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS]; + FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek or if the metadata has a zero MD5 */ + FLAC__bool internal_reset_hack; /* used only during init() so we can call reset to set up the decoder without rewinding the input */ + FLAC__bool is_seeking; + FLAC__MD5Context md5context; + FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */ + /* (the rest of these are only used for seeking) */ + FLAC__Frame last_frame; /* holds the info of the last frame we seeked to */ + FLAC__uint64 first_frame_offset; /* hint to the seek routine of where in the stream the first audio frame starts */ + FLAC__uint64 target_sample; + unsigned unparseable_frame_count; /* used to tell whether we're decoding a future version of FLAC or just got a bad sync */ +#if FLAC__HAS_OGG + FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine to check when process_single() actually writes a frame */ +#endif } FLAC__StreamDecoderPrivate; /*********************************************************************** @@ -149,20 +191,46 @@ FLAC_API const char * const FLAC__StreamDecoderStateString[] = { "FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC", "FLAC__STREAM_DECODER_READ_FRAME", "FLAC__STREAM_DECODER_END_OF_STREAM", + "FLAC__STREAM_DECODER_OGG_ERROR", + "FLAC__STREAM_DECODER_SEEK_ERROR", "FLAC__STREAM_DECODER_ABORTED", - "FLAC__STREAM_DECODER_UNPARSEABLE_STREAM", "FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR", - "FLAC__STREAM_DECODER_ALREADY_INITIALIZED", - "FLAC__STREAM_DECODER_INVALID_CALLBACK", "FLAC__STREAM_DECODER_UNINITIALIZED" }; +FLAC_API const char * const FLAC__StreamDecoderInitStatusString[] = { + "FLAC__STREAM_DECODER_INIT_STATUS_OK", + "FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER", + "FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS", + "FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR", + "FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE", + "FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED" +}; + FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = { "FLAC__STREAM_DECODER_READ_STATUS_CONTINUE", "FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM", "FLAC__STREAM_DECODER_READ_STATUS_ABORT" }; +FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[] = { + "FLAC__STREAM_DECODER_SEEK_STATUS_OK", + "FLAC__STREAM_DECODER_SEEK_STATUS_ERROR", + "FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED" +}; + +FLAC_API const char * const FLAC__StreamDecoderTellStatusString[] = { + "FLAC__STREAM_DECODER_TELL_STATUS_OK", + "FLAC__STREAM_DECODER_TELL_STATUS_ERROR", + "FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED" +}; + +FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[] = { + "FLAC__STREAM_DECODER_LENGTH_STATUS_OK", + "FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR", + "FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED" +}; + FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = { "FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE", "FLAC__STREAM_DECODER_WRITE_STATUS_ABORT" @@ -171,42 +239,41 @@ FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = { FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[] = { "FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC", "FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER", - "FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH" + "FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH", + "FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM" }; -FLAC__BitBuffer *FLAC__bitbuffer_new(void); - /*********************************************************************** * * Class constructor/destructor * ***********************************************************************/ -FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new() +FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void) { FLAC__StreamDecoder *decoder; unsigned i; FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ - decoder = (FLAC__StreamDecoder*)calloc(1, sizeof(FLAC__StreamDecoder)); + decoder = calloc(1, sizeof(FLAC__StreamDecoder)); if(decoder == 0) { return 0; } - decoder->protected_ = (FLAC__StreamDecoderProtected*)calloc(1, sizeof(FLAC__StreamDecoderProtected)); + decoder->protected_ = calloc(1, sizeof(FLAC__StreamDecoderProtected)); if(decoder->protected_ == 0) { free(decoder); return 0; } - decoder->private_ = (FLAC__StreamDecoderPrivate*)calloc(1, sizeof(FLAC__StreamDecoderPrivate)); + decoder->private_ = calloc(1, sizeof(FLAC__StreamDecoderPrivate)); if(decoder->private_ == 0) { free(decoder->protected_); free(decoder); return 0; } - decoder->private_->input = FLAC__bitbuffer_new(); + decoder->private_->input = FLAC__bitreader_new(); if(decoder->private_->input == 0) { free(decoder->private_); free(decoder->protected_); @@ -215,8 +282,8 @@ FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new() } decoder->private_->metadata_filter_ids_capacity = 16; - if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) { - FLAC__bitbuffer_delete(decoder->private_->input); + if(0 == (decoder->private_->metadata_filter_ids = malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) { + FLAC__bitreader_delete(decoder->private_->input); free(decoder->private_); free(decoder->protected_); free(decoder); @@ -235,6 +302,8 @@ FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new() for(i = 0; i < FLAC__MAX_CHANNELS; i++) FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]); + decoder->private_->file = 0; + set_defaults_(decoder); decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; @@ -246,17 +315,19 @@ FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder) { unsigned i; - FLAC__ASSERT(0 != decoder); + if (decoder == NULL) + return ; + FLAC__ASSERT(0 != decoder->protected_); FLAC__ASSERT(0 != decoder->private_); FLAC__ASSERT(0 != decoder->private_->input); - FLAC__stream_decoder_finish(decoder); + (void)FLAC__stream_decoder_finish(decoder); if(0 != decoder->private_->metadata_filter_ids) free(decoder->private_->metadata_filter_ids); - FLAC__bitbuffer_delete(decoder->private_->input); + FLAC__bitreader_delete(decoder->private_->input); for(i = 0; i < FLAC__MAX_CHANNELS; i++) FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&decoder->private_->partitioned_rice_contents[i]); @@ -272,23 +343,43 @@ FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder) * ***********************************************************************/ -FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *decoder) +static FLAC__StreamDecoderInitStatus init_stream_internal_( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadCallback read_callback, + FLAC__StreamDecoderSeekCallback seek_callback, + FLAC__StreamDecoderTellCallback tell_callback, + FLAC__StreamDecoderLengthCallback length_callback, + FLAC__StreamDecoderEofCallback eof_callback, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data, + FLAC__bool is_ogg +) { FLAC__ASSERT(0 != decoder); if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return decoder->protected_->state = FLAC__STREAM_DECODER_ALREADY_INITIALIZED; + return FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; - if(0 == decoder->private_->read_callback || 0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback) - return decoder->protected_->state = FLAC__STREAM_DECODER_INVALID_CALLBACK; - - if(!FLAC__bitbuffer_init(decoder->private_->input)) - return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; +#if !FLAC__HAS_OGG + if(is_ogg) + return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER; +#endif - decoder->private_->last_frame_number = 0; - decoder->private_->samples_decoded = 0; - decoder->private_->has_stream_info = false; - decoder->private_->cached = false; + if( + 0 == read_callback || + 0 == write_callback || + 0 == error_callback || + (seek_callback && (0 == tell_callback || 0 == length_callback || 0 == eof_callback)) + ) + return FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; + +#if FLAC__HAS_OGG + decoder->private_->is_ogg = is_ogg; + if(is_ogg && !FLAC__ogg_decoder_aspect_init(&decoder->protected_->ogg_decoder_aspect)) + return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE; +#endif /* * get the CPU info and set the function pointers @@ -298,52 +389,278 @@ FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal; decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide; decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal; - decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal; /* now override with asm where appropriate */ #ifndef FLAC__NO_ASM if(decoder->private_->cpuinfo.use_asm) { #ifdef FLAC__CPU_IA32 FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32); #ifdef FLAC__HAS_NASM - if(decoder->private_->cpuinfo.data.ia32.mmx) { + decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide_asm_ia32; /* OPT_IA32: was really necessary for GCC < 4.9 */ + if(decoder->private_->cpuinfo.ia32.mmx) { decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32; decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32_mmx; - decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32_mmx; } else { decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32; decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32; - decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32; } #endif -#elif defined FLAC__CPU_PPC - FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_PPC); - if(decoder->private_->cpuinfo.data.ppc.altivec) { - decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ppc_altivec_16; - decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8; +#ifdef FLAC__HAS_X86INTRIN +# if defined FLAC__SSE2_SUPPORTED && !defined FLAC__HAS_NASM /* OPT_SSE: not better than MMX asm */ + if(decoder->private_->cpuinfo.ia32.sse2) { + decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_16_intrin_sse2; } +# endif +# if defined FLAC__SSE4_1_SUPPORTED + if(decoder->private_->cpuinfo.ia32.sse41) { + decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide_intrin_sse41; + } +# endif +#endif +#elif defined FLAC__CPU_X86_64 + FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_X86_64); + /* No useful SSE optimizations yet */ #endif } #endif - if(!FLAC__stream_decoder_reset(decoder)) - return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + /* from here on, errors are fatal */ - return decoder->protected_->state; + if(!FLAC__bitreader_init(decoder->private_->input, read_callback_, decoder)) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR; + } + + decoder->private_->read_callback = read_callback; + decoder->private_->seek_callback = seek_callback; + decoder->private_->tell_callback = tell_callback; + decoder->private_->length_callback = length_callback; + decoder->private_->eof_callback = eof_callback; + decoder->private_->write_callback = write_callback; + decoder->private_->metadata_callback = metadata_callback; + decoder->private_->error_callback = error_callback; + decoder->private_->client_data = client_data; + decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0; + decoder->private_->samples_decoded = 0; + decoder->private_->has_stream_info = false; + decoder->private_->cached = false; + + decoder->private_->do_md5_checking = decoder->protected_->md5_checking; + decoder->private_->is_seeking = false; + + decoder->private_->internal_reset_hack = true; /* so the following reset does not try to rewind the input */ + if(!FLAC__stream_decoder_reset(decoder)) { + /* above call sets the state for us */ + return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR; + } + + return FLAC__STREAM_DECODER_INIT_STATUS_OK; +} + +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadCallback read_callback, + FLAC__StreamDecoderSeekCallback seek_callback, + FLAC__StreamDecoderTellCallback tell_callback, + FLAC__StreamDecoderLengthCallback length_callback, + FLAC__StreamDecoderEofCallback eof_callback, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) +{ + return init_stream_internal_( + decoder, + read_callback, + seek_callback, + tell_callback, + length_callback, + eof_callback, + write_callback, + metadata_callback, + error_callback, + client_data, + /*is_ogg=*/false + ); +} + +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadCallback read_callback, + FLAC__StreamDecoderSeekCallback seek_callback, + FLAC__StreamDecoderTellCallback tell_callback, + FLAC__StreamDecoderLengthCallback length_callback, + FLAC__StreamDecoderEofCallback eof_callback, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) +{ + return init_stream_internal_( + decoder, + read_callback, + seek_callback, + tell_callback, + length_callback, + eof_callback, + write_callback, + metadata_callback, + error_callback, + client_data, + /*is_ogg=*/true + ); +} + +static FLAC__StreamDecoderInitStatus init_FILE_internal_( + FLAC__StreamDecoder *decoder, + FILE *file, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data, + FLAC__bool is_ogg +) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != file); + + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; + + if(0 == write_callback || 0 == error_callback) + return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; + + /* + * To make sure that our file does not go unclosed after an error, we + * must assign the FILE pointer before any further error can occur in + * this routine. + */ + if(file == stdin) + file = get_binary_stdin_(); /* just to be safe */ + + decoder->private_->file = file; + + return init_stream_internal_( + decoder, + file_read_callback_, + decoder->private_->file == stdin? 0: file_seek_callback_, + decoder->private_->file == stdin? 0: file_tell_callback_, + decoder->private_->file == stdin? 0: file_length_callback_, + file_eof_callback_, + write_callback, + metadata_callback, + error_callback, + client_data, + is_ogg + ); +} + +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE( + FLAC__StreamDecoder *decoder, + FILE *file, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) +{ + return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false); +} + +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE( + FLAC__StreamDecoder *decoder, + FILE *file, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) +{ + return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true); +} + +static FLAC__StreamDecoderInitStatus init_file_internal_( + FLAC__StreamDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data, + FLAC__bool is_ogg +) +{ + FILE *file; + + FLAC__ASSERT(0 != decoder); + + /* + * To make sure that our file does not go unclosed after an error, we + * have to do the same entrance checks here that are later performed + * in FLAC__stream_decoder_init_FILE() before the FILE* is assigned. + */ + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; + + if(0 == write_callback || 0 == error_callback) + return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; + + file = filename? flac_fopen(filename, "rb") : stdin; + + if(0 == file) + return FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE; + + return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, is_ogg); } -FLAC_API void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder) +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file( + FLAC__StreamDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) { + return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false); +} + +FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file( + FLAC__StreamDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data +) +{ + return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true); +} + +FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder) +{ + FLAC__bool md5_failed = false; unsigned i; + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) - return; - if(0 != decoder->private_->seek_table.data.seek_table.points) { + return true; + + /* see the comment in FLAC__stream_decoder_reset() as to why we + * always call FLAC__MD5Final() + */ + FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context); + + if(decoder->private_->has_seek_table && 0 != decoder->private_->seek_table.data.seek_table.points) { free(decoder->private_->seek_table.data.seek_table.points); decoder->private_->seek_table.data.seek_table.points = 0; decoder->private_->has_seek_table = false; } - FLAC__bitbuffer_free(decoder->private_->input); + FLAC__bitreader_free(decoder->private_->input); for(i = 0; i < FLAC__MAX_CHANNELS; i++) { /* WATCHOUT: * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the @@ -363,63 +680,54 @@ FLAC_API void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder) decoder->private_->output_capacity = 0; decoder->private_->output_channels = 0; - set_defaults_(decoder); +#if FLAC__HAS_OGG + if(decoder->private_->is_ogg) + FLAC__ogg_decoder_aspect_finish(&decoder->protected_->ogg_decoder_aspect); +#endif - decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; -} + if(0 != decoder->private_->file) { + if(decoder->private_->file != stdin) + fclose(decoder->private_->file); + decoder->private_->file = 0; + } -FLAC_API FLAC__bool FLAC__stream_decoder_set_read_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderReadCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->read_callback = value; - return true; -} + if(decoder->private_->do_md5_checking) { + if(memcmp(decoder->private_->stream_info.data.stream_info.md5sum, decoder->private_->computed_md5sum, 16)) + md5_failed = true; + } + decoder->private_->is_seeking = false; -FLAC_API FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->write_callback = value; - return true; -} + set_defaults_(decoder); -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderMetadataCallback value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - decoder->private_->metadata_callback = value; - return true; + decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; + + return !md5_failed; } -FLAC_API FLAC__bool FLAC__stream_decoder_set_error_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorCallback value) +FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long value) { FLAC__ASSERT(0 != decoder); FLAC__ASSERT(0 != decoder->private_); FLAC__ASSERT(0 != decoder->protected_); if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) return false; - decoder->private_->error_callback = value; +#if FLAC__HAS_OGG + /* can't check decoder->private_->is_ogg since that's not set until init time */ + FLAC__ogg_decoder_aspect_set_serial_number(&decoder->protected_->ogg_decoder_aspect, value); return true; +#else + (void)value; + return false; +#endif } -FLAC_API FLAC__bool FLAC__stream_decoder_set_client_data(FLAC__StreamDecoder *decoder, void *value) +FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value) { FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); FLAC__ASSERT(0 != decoder->protected_); if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) return false; - decoder->private_->client_data = value; + decoder->protected_->md5_checking = value; return true; } @@ -455,8 +763,10 @@ FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__ FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids); if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) { - if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2))) - return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } decoder->private_->metadata_filter_ids_capacity *= 2; } @@ -512,8 +822,10 @@ FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__S FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids); if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) { - if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2))) - return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } decoder->private_->metadata_filter_ids_capacity *= 2; } @@ -547,6 +859,20 @@ FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__ return FLAC__StreamDecoderStateString[decoder->protected_->state]; } +FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->md5_checking; +} + +FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->private_->has_stream_info? decoder->private_->stream_info.data.stream_info.total_samples : 0; +} + FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder) { FLAC__ASSERT(0 != decoder); @@ -582,13 +908,43 @@ FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder * return decoder->protected_->blocksize; } +FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != position); + +#if FLAC__HAS_OGG + if(decoder->private_->is_ogg) + return false; +#endif + if(0 == decoder->private_->tell_callback) + return false; + if(decoder->private_->tell_callback(decoder, position, decoder->private_->client_data) != FLAC__STREAM_DECODER_TELL_STATUS_OK) + return false; + /* should never happen since all FLAC frames and metadata blocks are byte aligned, but check just in case */ + if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) + return false; + FLAC__ASSERT(*position >= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder)); + *position -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder); + return true; +} + FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder) { FLAC__ASSERT(0 != decoder); FLAC__ASSERT(0 != decoder->private_); FLAC__ASSERT(0 != decoder->protected_); - if(!FLAC__bitbuffer_clear(decoder->private_->input)) { + decoder->private_->samples_decoded = 0; + decoder->private_->do_md5_checking = false; + +#if FLAC__HAS_OGG + if(decoder->private_->is_ogg) + FLAC__ogg_decoder_aspect_flush(&decoder->protected_->ogg_decoder_aspect); +#endif + + if(!FLAC__bitreader_clear(decoder->private_->input)) { decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; return false; } @@ -604,12 +960,55 @@ FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder) FLAC__ASSERT(0 != decoder->protected_); if(!FLAC__stream_decoder_flush(decoder)) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + /* above call sets the state for us */ return false; } + +#if FLAC__HAS_OGG + /*@@@ could go in !internal_reset_hack block below */ + if(decoder->private_->is_ogg) + FLAC__ogg_decoder_aspect_reset(&decoder->protected_->ogg_decoder_aspect); +#endif + + /* Rewind if necessary. If FLAC__stream_decoder_init() is calling us, + * (internal_reset_hack) don't try to rewind since we are already at + * the beginning of the stream and don't want to fail if the input is + * not seekable. + */ + if(!decoder->private_->internal_reset_hack) { + if(decoder->private_->file == stdin) + return false; /* can't rewind stdin, reset fails */ + if(decoder->private_->seek_callback && decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR) + return false; /* seekable and seek fails, reset fails */ + } + else + decoder->private_->internal_reset_hack = false; + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA; - decoder->private_->samples_decoded = 0; + decoder->private_->has_stream_info = false; + if(decoder->private_->has_seek_table && 0 != decoder->private_->seek_table.data.seek_table.points) { + free(decoder->private_->seek_table.data.seek_table.points); + decoder->private_->seek_table.data.seek_table.points = 0; + decoder->private_->has_seek_table = false; + } + decoder->private_->do_md5_checking = decoder->protected_->md5_checking; + /* + * This goes in reset() and not flush() because according to the spec, a + * fixed-blocksize stream must stay that way through the whole stream. + */ + decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0; + + /* We initialize the FLAC__MD5Context even though we may never use it. This + * is because md5 checking may be turned on to start and then turned off if + * a seek occurs. So we init the context here and finalize it in + * FLAC__stream_decoder_finish() to make sure things are always cleaned up + * properly. + */ + FLAC__MD5Init(&decoder->private_->md5context); + + decoder->private_->first_frame_offset = 0; + decoder->private_->unparseable_frame_count = 0; return true; } @@ -743,6 +1142,73 @@ FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder * } } +FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample) +{ + FLAC__uint64 length; + + FLAC__ASSERT(0 != decoder); + + if( + decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA && + decoder->protected_->state != FLAC__STREAM_DECODER_READ_METADATA && + decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC && + decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME && + decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM + ) + return false; + + if(0 == decoder->private_->seek_callback) + return false; + + FLAC__ASSERT(decoder->private_->seek_callback); + FLAC__ASSERT(decoder->private_->tell_callback); + FLAC__ASSERT(decoder->private_->length_callback); + FLAC__ASSERT(decoder->private_->eof_callback); + + if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) + return false; + + decoder->private_->is_seeking = true; + + /* turn off md5 checking if a seek is attempted */ + decoder->private_->do_md5_checking = false; + + /* get the file length (currently our algorithm needs to know the length so it's also an error to get FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED) */ + if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__STREAM_DECODER_LENGTH_STATUS_OK) { + decoder->private_->is_seeking = false; + return false; + } + + /* if we haven't finished processing the metadata yet, do that so we have the STREAMINFO, SEEK_TABLE, and first_frame_offset */ + if( + decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA || + decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA + ) { + if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) { + /* above call sets the state for us */ + decoder->private_->is_seeking = false; + return false; + } + /* check this again in case we didn't know total_samples the first time */ + if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) { + decoder->private_->is_seeking = false; + return false; + } + } + + { + const FLAC__bool ok = +#if FLAC__HAS_OGG + decoder->private_->is_ogg? + seek_to_absolute_sample_ogg_(decoder, length, sample) : +#endif + seek_to_absolute_sample_(decoder, length, sample) + ; + decoder->private_->is_seeking = false; + return ok; + } +} + /*********************************************************************** * * Protected class methods @@ -752,7 +1218,9 @@ FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder * unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder) { FLAC__ASSERT(0 != decoder); - return FLAC__bitbuffer_get_input_bytes_unconsumed(decoder->private_->input); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); + FLAC__ASSERT(!(FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) & 7)); + return FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) / 8; } /*********************************************************************** @@ -763,7 +1231,14 @@ unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecod void set_defaults_(FLAC__StreamDecoder *decoder) { +#if FLAC__HAS_OGG + decoder->private_->is_ogg = false; +#endif decoder->private_->read_callback = 0; + decoder->private_->seek_callback = 0; + decoder->private_->tell_callback = 0; + decoder->private_->length_callback = 0; + decoder->private_->eof_callback = 0; decoder->private_->write_callback = 0; decoder->private_->metadata_callback = 0; decoder->private_->error_callback = 0; @@ -772,6 +1247,33 @@ void set_defaults_(FLAC__StreamDecoder *decoder) memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter)); decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] = true; decoder->private_->metadata_filter_ids_count = 0; + + decoder->protected_->md5_checking = false; + +#if FLAC__HAS_OGG + FLAC__ogg_decoder_aspect_set_defaults(&decoder->protected_->ogg_decoder_aspect); +#endif +} + +/* + * This will forcibly set stdin to binary mode (for OSes that require it) + */ +FILE *get_binary_stdin_(void) +{ + /* if something breaks here it is probably due to the presence or + * absence of an underscore before the identifiers 'setmode', + * 'fileno', and/or 'O_BINARY'; check your system header files. + */ +#if defined _MSC_VER || defined __MINGW32__ + _setmode(_fileno(stdin), _O_BINARY); +#elif defined __CYGWIN__ + /* almost certainly not needed for any modern Cygwin, but let's be safe... */ + setmode(_fileno(stdin), _O_BINARY); +#elif defined __EMX__ + setmode(fileno(stdin), O_BINARY); +#endif + + return stdin; } FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels) @@ -802,7 +1304,7 @@ FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigne * (at negative indices) for alignment purposes; we use 4 * to keep the data well-aligned. */ - tmp = (FLAC__int32*)malloc(sizeof(FLAC__int32)*(size+4)); + tmp = safe_malloc_muladd2_(sizeof(FLAC__int32), /*times (*/size, /*+*/4/*)*/); if(tmp == 0) { decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; return false; @@ -810,9 +1312,6 @@ FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigne memset(tmp, 0, sizeof(FLAC__int32)*4); decoder->private_->output[i] = tmp + 4; - /* WATCHOUT: - * minimum of quadword alignment for PPC vector optimizations is REQUIRED: - */ if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) { decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; return false; @@ -827,7 +1326,7 @@ FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigne FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id) { - unsigned i; + size_t i; FLAC__ASSERT(0 != decoder); FLAC__ASSERT(0 != decoder->private_); @@ -845,7 +1344,7 @@ FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder) unsigned i, id; FLAC__bool first = true; - FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); for(i = id = 0; i < 4; ) { if(decoder->private_->cached) { @@ -853,8 +1352,8 @@ FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder) decoder->private_->cached = false; } else { - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ } if(x == FLAC__STREAM_SYNC_STRING[i]) { first = true; @@ -862,19 +1361,24 @@ FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder) id = 0; continue; } + + if(id >= 3) + return false; + if(x == ID3V2_TAG_[id]) { id++; i = 0; if(id == 3) { if(!skip_id3v2_tag_(decoder)) - return false; /* the read_callback_ sets the state for us */ + return false; /* skip_id3v2_tag_ sets the state for us */ } continue; } + id = 0; if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ decoder->private_->header_warmup[0] = (FLAC__byte)x; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */ /* else we have to check if the second byte is the end of a sync code */ @@ -882,7 +1386,7 @@ FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder) decoder->private_->lookahead = (FLAC__byte)x; decoder->private_->cached = true; } - else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */ + else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */ decoder->private_->header_warmup[1] = (FLAC__byte)x; decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME; return true; @@ -890,7 +1394,7 @@ FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder) } i = 0; if(first) { - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data); + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); first = false; } } @@ -904,24 +1408,26 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) FLAC__bool is_last; FLAC__uint32 i, x, type, length; - FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN)) + return false; /* read_callback_ sets the state for us */ is_last = x? true : false; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN)) + return false; /* read_callback_ sets the state for us */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN)) + return false; /* read_callback_ sets the state for us */ if(type == FLAC__METADATA_TYPE_STREAMINFO) { if(!read_metadata_streaminfo_(decoder, is_last, length)) return false; decoder->private_->has_stream_info = true; - if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO]) + if(0 == memcmp(decoder->private_->stream_info.data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) + decoder->private_->do_md5_checking = false; + if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] && decoder->private_->metadata_callback) decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data); } else if(type == FLAC__METADATA_TYPE_SEEKTABLE) { @@ -929,7 +1435,7 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) return false; decoder->private_->has_seek_table = true; - if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE]) + if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE] && decoder->private_->metadata_callback) decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data); } else { @@ -937,13 +1443,19 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) unsigned real_length = length; FLAC__StreamMetadata block; + memset(&block, 0, sizeof(block)); block.is_last = is_last; block.type = (FLAC__MetadataType)type; block.length = length; if(type == FLAC__METADATA_TYPE_APPLICATION) { - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)) + return false; /* read_callback_ sets the state for us */ + + if(real_length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) { /* underflow check */ + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;/*@@@@@@ maybe wrong error? need to resync?*/ + return false; + } real_length -= FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8; @@ -952,36 +1464,41 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) } if(skip_it) { - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, 0, real_length, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length)) + return false; /* read_callback_ sets the state for us */ } else { + FLAC__bool ok = true; switch(type) { case FLAC__METADATA_TYPE_PADDING: /* skip the padding bytes */ - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, 0, real_length, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length)) + ok = false; /* read_callback_ sets the state for us */ break; case FLAC__METADATA_TYPE_APPLICATION: /* remember, we read the ID already */ if(real_length > 0) { - if(0 == (block.data.application.data = (FLAC__byte*)malloc(real_length))) { + if(0 == (block.data.application.data = malloc(real_length))) { decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; + ok = false; } - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length)) + ok = false; /* read_callback_ sets the state for us */ } else block.data.application.data = 0; break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: - if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment)) - return false; + if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment, real_length)) + ok = false; break; case FLAC__METADATA_TYPE_CUESHEET: if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet)) - return false; + ok = false; + break; + case FLAC__METADATA_TYPE_PICTURE: + if(!read_metadata_picture_(decoder, &block.data.picture)) + ok = false; break; case FLAC__METADATA_TYPE_STREAMINFO: case FLAC__METADATA_TYPE_SEEKTABLE: @@ -989,20 +1506,21 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) break; default: if(real_length > 0) { - if(0 == (block.data.unknown.data = (FLAC__byte*)malloc(real_length))) { + if(0 == (block.data.unknown.data = malloc(real_length))) { decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; + ok = false; } - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length)) + ok = false; /* read_callback_ sets the state for us */ } else block.data.unknown.data = 0; break; } - decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data); + if(ok && !decoder->private_->is_seeking && decoder->private_->metadata_callback) + decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data); - /* now we have to free any malloc'ed data in the block */ + /* now we have to free any malloc()ed data in the block */ switch(type) { case FLAC__METADATA_TYPE_PADDING: break; @@ -1028,6 +1546,14 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) if(0 != block.data.cue_sheet.tracks) free(block.data.cue_sheet.tracks); break; + case FLAC__METADATA_TYPE_PICTURE: + if(0 != block.data.picture.mime_type) + free(block.data.picture.mime_type); + if(0 != block.data.picture.description) + free(block.data.picture.description); + if(0 != block.data.picture.data) + free(block.data.picture.data); + break; case FLAC__METADATA_TYPE_STREAMINFO: case FLAC__METADATA_TYPE_SEEKTABLE: FLAC__ASSERT(0); @@ -1036,11 +1562,18 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) free(block.data.unknown.data); break; } + + if(!ok) /* anything that unsets "ok" should also make sure decoder->protected_->state is updated */ + return false; } } - if(is_last) + if(is_last) { + /* if this fails, it's OK, it's just a hint for the seek routine */ + if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->first_frame_offset)) + decoder->private_->first_frame_offset = 0; decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + } return true; } @@ -1050,68 +1583,68 @@ FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is FLAC__uint32 x; unsigned bits, used_bits = 0; - FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); decoder->private_->stream_info.type = FLAC__METADATA_TYPE_STREAMINFO; decoder->private_->stream_info.is_last = is_last; decoder->private_->stream_info.length = length; bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, bits, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, bits)) + return false; /* read_callback_ sets the state for us */ decoder->private_->stream_info.data.stream_info.min_blocksize = x; used_bits += bits; bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)) + return false; /* read_callback_ sets the state for us */ decoder->private_->stream_info.data.stream_info.max_blocksize = x; used_bits += bits; bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) + return false; /* read_callback_ sets the state for us */ decoder->private_->stream_info.data.stream_info.min_framesize = x; used_bits += bits; bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) + return false; /* read_callback_ sets the state for us */ decoder->private_->stream_info.data.stream_info.max_framesize = x; used_bits += bits; bits = FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN)) + return false; /* read_callback_ sets the state for us */ decoder->private_->stream_info.data.stream_info.sample_rate = x; used_bits += bits; bits = FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)) + return false; /* read_callback_ sets the state for us */ decoder->private_->stream_info.data.stream_info.channels = x+1; used_bits += bits; bits = FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)) + return false; /* read_callback_ sets the state for us */ decoder->private_->stream_info.data.stream_info.bits_per_sample = x+1; used_bits += bits; bits = FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; - if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &decoder->private_->stream_info.data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &decoder->private_->stream_info.data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) + return false; /* read_callback_ sets the state for us */ used_bits += bits; - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, decoder->private_->stream_info.data.stream_info.md5sum, 16, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, decoder->private_->stream_info.data.stream_info.md5sum, 16)) + return false; /* read_callback_ sets the state for us */ used_bits += 16*8; /* skip the rest of the block */ FLAC__ASSERT(used_bits % 8 == 0); length -= (used_bits / 8); - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, 0, length, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length)) + return false; /* read_callback_ sets the state for us */ return true; } @@ -1121,7 +1654,7 @@ FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_ FLAC__uint32 i, x; FLAC__uint64 xx; - FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); decoder->private_->seek_table.type = FLAC__METADATA_TYPE_SEEKTABLE; decoder->private_->seek_table.is_last = is_last; @@ -1130,84 +1663,116 @@ FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_ decoder->private_->seek_table.data.seek_table.num_points = length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; /* use realloc since we may pass through here several times (e.g. after seeking) */ - if(0 == (decoder->private_->seek_table.data.seek_table.points = (FLAC__StreamMetadata_SeekPoint*)realloc(decoder->private_->seek_table.data.seek_table.points, decoder->private_->seek_table.data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint)))) { + if(0 == (decoder->private_->seek_table.data.seek_table.points = safe_realloc_mul_2op_(decoder->private_->seek_table.data.seek_table.points, decoder->private_->seek_table.data.seek_table.num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)))) { decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; return false; } for(i = 0; i < decoder->private_->seek_table.data.seek_table.num_points; i++) { - if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN)) + return false; /* read_callback_ sets the state for us */ decoder->private_->seek_table.data.seek_table.points[i].sample_number = xx; - if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN)) + return false; /* read_callback_ sets the state for us */ decoder->private_->seek_table.data.seek_table.points[i].stream_offset = xx; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN)) + return false; /* read_callback_ sets the state for us */ decoder->private_->seek_table.data.seek_table.points[i].frame_samples = x; } length -= (decoder->private_->seek_table.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH); /* if there is a partial point left, skip over it */ if(length > 0) { - /*@@@ do an error_callback() here? there's an argument for either way */ - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, 0, length, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + /*@@@ do a send_error_to_client_() here? there's an argument for either way */ + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length)) + return false; /* read_callback_ sets the state for us */ } return true; } -FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj) +FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, unsigned length) { FLAC__uint32 i; - FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); /* read vendor string */ - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); - if(!FLAC__bitbuffer_read_raw_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ - if(obj->vendor_string.length > 0) { - if(0 == (obj->vendor_string.entry = (FLAC__byte*)malloc(obj->vendor_string.length))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; + if (length >= 8) { + length -= 8; /* vendor string length + num comments entries alone take 8 bytes */ + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); + if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length)) + return false; /* read_callback_ sets the state for us */ + if (obj->vendor_string.length > 0) { + if (length < obj->vendor_string.length) { + obj->vendor_string.length = 0; + obj->vendor_string.entry = 0; + goto skip; + } + else + length -= obj->vendor_string.length; + if (0 == (obj->vendor_string.entry = safe_malloc_add_2op_(obj->vendor_string.length, /*+*/1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length)) + return false; /* read_callback_ sets the state for us */ + obj->vendor_string.entry[obj->vendor_string.length] = '\0'; } - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ - } - else - obj->vendor_string.entry = 0; + else + obj->vendor_string.entry = 0; - /* read num comments */ - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32); - if(!FLAC__bitbuffer_read_raw_uint32_little_endian(decoder->private_->input, &obj->num_comments, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + /* read num comments */ + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32); + if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments)) + return false; /* read_callback_ sets the state for us */ - /* read comments */ - if(obj->num_comments > 0) { - if(0 == (obj->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)malloc(obj->num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - for(i = 0; i < obj->num_comments; i++) { - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); - if(!FLAC__bitbuffer_read_raw_uint32_little_endian(decoder->private_->input, &obj->comments[i].length, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ - if(obj->comments[i].length > 0) { - if(0 == (obj->comments[i].entry = (FLAC__byte*)malloc(obj->comments[i].length))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; + /* read comments */ + if (obj->num_comments > 0) { + if (0 == (obj->comments = safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + for (i = 0; i < obj->num_comments; i++) { + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); + if (length < 4) { + obj->num_comments = i; + goto skip; } - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + else + length -= 4; + if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length)) + return false; /* read_callback_ sets the state for us */ + if (obj->comments[i].length > 0) { + if (length < obj->comments[i].length) { + obj->comments[i].length = 0; + obj->comments[i].entry = 0; + obj->num_comments = i; + goto skip; + } + else + length -= obj->comments[i].length; + if (0 == (obj->comments[i].entry = safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) + return false; /* read_callback_ sets the state for us */ + obj->comments[i].entry[obj->comments[i].length] = '\0'; + } + else + obj->comments[i].entry = 0; } - else - obj->comments[i].entry = 0; } + else + obj->comments = 0; } - else { - obj->comments = 0; + + skip: + if (length > 0) { + /* This will only happen on files with invalid data in comments */ + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length)) + return false; /* read_callback_ sets the state for us */ } return true; @@ -1217,77 +1782,77 @@ FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMet { FLAC__uint32 i, j, x; - FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); memset(obj, 0, sizeof(FLAC__StreamMetadata_CueSheet)); FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8)) + return false; /* read_callback_ sets the state for us */ - if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &obj->lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &obj->lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN)) + return false; /* read_callback_ sets the state for us */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN)) + return false; /* read_callback_ sets the state for us */ obj->is_cd = x? true : false; - if(!FLAC__bitbuffer_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)) + return false; /* read_callback_ sets the state for us */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN)) + return false; /* read_callback_ sets the state for us */ obj->num_tracks = x; if(obj->num_tracks > 0) { - if(0 == (obj->tracks = (FLAC__StreamMetadata_CueSheet_Track*)calloc(obj->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) { + if(0 == (obj->tracks = safe_calloc_(obj->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) { decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; return false; } for(i = 0; i < obj->num_tracks; i++) { FLAC__StreamMetadata_CueSheet_Track *track = &obj->tracks[i]; - if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN)) + return false; /* read_callback_ sets the state for us */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN)) + return false; /* read_callback_ sets the state for us */ track->number = (FLAC__byte)x; FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8)) + return false; /* read_callback_ sets the state for us */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN)) + return false; /* read_callback_ sets the state for us */ track->type = x; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN)) + return false; /* read_callback_ sets the state for us */ track->pre_emphasis = x; - if(!FLAC__bitbuffer_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)) + return false; /* read_callback_ sets the state for us */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN)) + return false; /* read_callback_ sets the state for us */ track->num_indices = (FLAC__byte)x; if(track->num_indices > 0) { - if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) { + if(0 == (track->indices = safe_calloc_(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) { decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; return false; } for(j = 0; j < track->num_indices; j++) { - FLAC__StreamMetadata_CueSheet_Index *index = &track->indices[j]; - if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &index->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + FLAC__StreamMetadata_CueSheet_Index *indx = &track->indices[j]; + if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN)) + return false; /* read_callback_ sets the state for us */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ - index->number = (FLAC__byte)x; + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN)) + return false; /* read_callback_ sets the state for us */ + indx->number = (FLAC__byte)x; - if(!FLAC__bitbuffer_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN)) + return false; /* read_callback_ sets the state for us */ } } } @@ -1296,25 +1861,93 @@ FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMet return true; } +FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj) +{ + FLAC__uint32 x; + + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); + + /* read type */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN)) + return false; /* read_callback_ sets the state for us */ + obj->type = x; + + /* read MIME type */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) + return false; /* read_callback_ sets the state for us */ + if(0 == (obj->mime_type = safe_malloc_add_2op_(x, /*+*/1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(x > 0) { + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->mime_type, x)) + return false; /* read_callback_ sets the state for us */ + } + obj->mime_type[x] = '\0'; + + /* read description */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) + return false; /* read_callback_ sets the state for us */ + if(0 == (obj->description = safe_malloc_add_2op_(x, /*+*/1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(x > 0) { + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->description, x)) + return false; /* read_callback_ sets the state for us */ + } + obj->description[x] = '\0'; + + /* read width */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN)) + return false; /* read_callback_ sets the state for us */ + + /* read height */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN)) + return false; /* read_callback_ sets the state for us */ + + /* read depth */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN)) + return false; /* read_callback_ sets the state for us */ + + /* read colors */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN)) + return false; /* read_callback_ sets the state for us */ + + /* read data */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &(obj->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) + return false; /* read_callback_ sets the state for us */ + if(0 == (obj->data = safe_malloc_(obj->data_length))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(obj->data_length > 0) { + if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->data, obj->data_length)) + return false; /* read_callback_ sets the state for us */ + } + + return true; +} + FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder) { FLAC__uint32 x; unsigned i, skip; /* skip the version and flags bytes */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 24, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 24)) + return false; /* read_callback_ sets the state for us */ /* get the size (in bytes) to skip */ skip = 0; for(i = 0; i < 4; i++) { - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ skip <<= 7; skip |= (x & 0x7f); } /* skip the rest of the tag */ - if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, 0, skip, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, skip)) + return false; /* read_callback_ sets the state for us */ return true; } @@ -1325,17 +1958,17 @@ FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder) /* If we know the total number of samples in the stream, stop if we've read that many. */ /* This will stop us, for example, from wasting time trying to sync on an ID3V1 tag. */ - if(decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.total_samples) { - if(decoder->private_->samples_decoded >= decoder->private_->stream_info.data.stream_info.total_samples) { + if(FLAC__stream_decoder_get_total_samples(decoder) > 0) { + if(decoder->private_->samples_decoded >= FLAC__stream_decoder_get_total_samples(decoder)) { decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; return true; } } /* make sure we're byte aligned */ - if(!FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)) { - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__bitbuffer_bits_left_for_byte_alignment(decoder->private_->input), read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) { + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input))) + return false; /* read_callback_ sets the state for us */ } while(1) { @@ -1344,13 +1977,13 @@ FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder) decoder->private_->cached = false; } else { - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ } if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ decoder->private_->header_warmup[0] = (FLAC__byte)x; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */ /* else we have to check if the second byte is the end of a sync code */ @@ -1358,14 +1991,14 @@ FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder) decoder->private_->lookahead = (FLAC__byte)x; decoder->private_->cached = true; } - else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */ + else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */ decoder->private_->header_warmup[1] = (FLAC__byte)x; decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME; return true; } } if(first) { - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data); + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); first = false; } } @@ -1377,21 +2010,21 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FL { unsigned channel; unsigned i; - FLAC__int32 mid, side, left, right; - FLAC__uint16 frame_crc; /* the one we calculate from the input stream */ + FLAC__int32 mid, side; + unsigned frame_crc; /* the one we calculate from the input stream */ FLAC__uint32 x; *got_a_frame = false; /* init the CRC */ frame_crc = 0; - FLAC__CRC16_UPDATE(decoder->private_->header_warmup[0], frame_crc); - FLAC__CRC16_UPDATE(decoder->private_->header_warmup[1], frame_crc); - FLAC__bitbuffer_reset_read_crc16(decoder->private_->input, frame_crc); + frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[0], frame_crc); + frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[1], frame_crc); + FLAC__bitreader_reset_read_crc16(decoder->private_->input, (FLAC__uint16)frame_crc); if(!read_frame_header_(decoder)) return false; - if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) + if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means we didn't sync on a valid header */ return true; if(!allocate_output_(decoder, decoder->private_->frame.header.blocksize, decoder->private_->frame.header.channels)) return false; @@ -1427,21 +2060,21 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FL */ if(!read_subframe_(decoder, channel, bps, do_full_decode)) return false; - if(decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */ return true; - } } if(!read_zero_padding_(decoder)) return false; + if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption (i.e. "zero bits" were not all zeroes) */ + return true; /* * Read the frame CRC-16 from the footer and check */ - frame_crc = FLAC__bitbuffer_get_read_crc16(decoder->private_->input); - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ - if(frame_crc == (FLAC__uint16)x) { + frame_crc = FLAC__bitreader_get_read_crc16(decoder->private_->input); + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN)) + return false; /* read_callback_ sets the state for us */ + if(frame_crc == x) { if(do_full_decode) { /* Undo any special channel coding */ switch(decoder->private_->frame.header.channel_assignment) { @@ -1461,15 +2094,19 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FL case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: FLAC__ASSERT(decoder->private_->frame.header.channels == 2); for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { +#if 1 mid = decoder->private_->output[0][i]; side = decoder->private_->output[1][i]; mid <<= 1; - if(side & 1) /* i.e. if 'side' is odd... */ - mid++; - left = mid + side; - right = mid - side; - decoder->private_->output[0][i] = left >> 1; - decoder->private_->output[1][i] = right >> 1; + mid |= (side & 1); /* i.e. if 'side' is odd... */ + decoder->private_->output[0][i] = (mid + side) >> 1; + decoder->private_->output[1][i] = (mid - side) >> 1; +#else + /* OPT: without 'side' temp variable */ + mid = (decoder->private_->output[0][i] << 1) | (decoder->private_->output[1][i] & 1); /* i.e. if 'side' is odd... */ + decoder->private_->output[0][i] = (mid + decoder->private_->output[1][i]) >> 1; + decoder->private_->output[1][i] = (mid - decoder->private_->output[1][i]) >> 1; +#endif } break; default: @@ -1480,7 +2117,7 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FL } else { /* Bad frame, emit error and zero the output signal */ - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH, decoder->private_->client_data); + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH); if(do_full_decode) { for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) { memset(decoder->private_->output[channel], 0, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize); @@ -1490,6 +2127,10 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FL *got_a_frame = true; + /* we wait to update fixed_block_size until here, when we're sure we've got a proper frame and hence a correct blocksize */ + if(decoder->private_->next_fixed_block_size) + decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size; + /* put the latest values into the public section of the decoder instance */ decoder->protected_->channels = decoder->private_->frame.header.channels; decoder->protected_->channel_assignment = decoder->private_->frame.header.channel_assignment; @@ -1502,7 +2143,7 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FL /* write it */ if(do_full_decode) { - if(decoder->private_->write_callback(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output, decoder->private_->client_data) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) + if(write_audio_frame_to_client_(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) return false; } @@ -1518,40 +2159,48 @@ FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) FLAC__byte crc8, raw_header[16]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */ unsigned raw_header_len; FLAC__bool is_unparseable = false; - const FLAC__bool is_known_variable_blocksize_stream = (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize != decoder->private_->stream_info.data.stream_info.max_blocksize); - const FLAC__bool is_known_fixed_blocksize_stream = (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize); - FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)); + FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); /* init the raw header with the saved bits from synchronization */ raw_header[0] = decoder->private_->header_warmup[0]; raw_header[1] = decoder->private_->header_warmup[1]; raw_header_len = 2; - /* - * check to make sure that the reserved bits are 0 - */ - if(raw_header[1] & 0x03) { /* MAGIC NUMBER */ + /* check to make sure that reserved bit is 0 */ + if(raw_header[1] & 0x02) /* MAGIC NUMBER */ is_unparseable = true; - } /* * Note that along the way as we read the header, we look for a sync * code inside. If we find one it would indicate that our original * sync was bad since there cannot be a sync code in a valid header. + * + * Three kinds of things can go wrong when reading the frame header: + * 1) We may have sync'ed incorrectly and not landed on a frame header. + * If we don't find a sync code, it can end up looking like we read + * a valid but unparseable header, until getting to the frame header + * CRC. Even then we could get a false positive on the CRC. + * 2) We may have sync'ed correctly but on an unparseable frame (from a + * future encoder). + * 3) We may be on a damaged frame which appears valid but unparseable. + * + * For all these reasons, we try and read a complete frame header as + * long as it seems valid, even if unparseable, up until the frame + * header CRC. */ /* * read in the raw header as bytes so we can CRC it, and parse it on the way */ for(i = 0; i < 2; i++) { - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ /* if we get here it means our original sync was erroneous since the sync code cannot appear in the header */ decoder->private_->lookahead = (FLAC__byte)x; decoder->private_->cached = true; - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data); + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; return true; } @@ -1560,10 +2209,7 @@ FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) switch(x = raw_header[2] >> 4) { case 0: - if(is_known_fixed_blocksize_stream) - decoder->private_->frame.header.blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize; - else - is_unparseable = true; + is_unparseable = true; break; case 1: decoder->private_->frame.header.blocksize = 192; @@ -1601,9 +2247,13 @@ FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) is_unparseable = true; break; case 1: + decoder->private_->frame.header.sample_rate = 88200; + break; case 2: + decoder->private_->frame.header.sample_rate = 176400; + break; case 3: - is_unparseable = true; + decoder->private_->frame.header.sample_rate = 192000; break; case 4: decoder->private_->frame.header.sample_rate = 8000; @@ -1635,7 +2285,7 @@ FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) sample_rate_hint = x; break; case 15: - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data); + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; return true; default: @@ -1696,55 +2346,50 @@ FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) break; } - if(raw_header[3] & 0x01) { /* this should be a zero padding bit */ - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } + /* check to make sure that reserved bit is 0 */ + if(raw_header[3] & 0x01) /* MAGIC NUMBER */ + is_unparseable = true; - if(blocksize_hint && is_known_variable_blocksize_stream) { - if(!FLAC__bitbuffer_read_utf8_uint64(decoder->private_->input, &xx, read_callback_, decoder, raw_header, &raw_header_len)) - return false; /* the read_callback_ sets the state for us */ + /* read the frame's starting sample number (or frame number as the case may be) */ + if( + raw_header[1] & 0x01 || + /*@@@ this clause is a concession to the old way of doing variable blocksize; the only known implementation is flake and can probably be removed without inconveniencing anyone */ + (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize != decoder->private_->stream_info.data.stream_info.max_blocksize) + ) { /* variable blocksize */ + if(!FLAC__bitreader_read_utf8_uint64(decoder->private_->input, &xx, raw_header, &raw_header_len)) + return false; /* read_callback_ sets the state for us */ if(xx == FLAC__U64L(0xffffffffffffffff)) { /* i.e. non-UTF8 code... */ decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */ decoder->private_->cached = true; - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data); + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; return true; } decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER; decoder->private_->frame.header.number.sample_number = xx; } - else { - if(!FLAC__bitbuffer_read_utf8_uint32(decoder->private_->input, &x, read_callback_, decoder, raw_header, &raw_header_len)) - return false; /* the read_callback_ sets the state for us */ + else { /* fixed blocksize */ + if(!FLAC__bitreader_read_utf8_uint32(decoder->private_->input, &x, raw_header, &raw_header_len)) + return false; /* read_callback_ sets the state for us */ if(x == 0xffffffff) { /* i.e. non-UTF8 code... */ decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */ decoder->private_->cached = true; - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data); + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; return true; } - decoder->private_->last_frame_number = x; - decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER; - if(blocksize_hint) { - if(decoder->private_->has_stream_info) - decoder->private_->frame.header.number.sample_number = (FLAC__int64)decoder->private_->stream_info.data.stream_info.min_blocksize * (FLAC__int64)x; - else - is_unparseable = true; - } - else - decoder->private_->frame.header.number.sample_number = (FLAC__int64)decoder->private_->frame.header.blocksize * (FLAC__int64)x; + decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER; + decoder->private_->frame.header.number.frame_number = x; } if(blocksize_hint) { - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ raw_header[raw_header_len++] = (FLAC__byte)x; if(blocksize_hint == 7) { FLAC__uint32 _x; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &_x, 8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8)) + return false; /* read_callback_ sets the state for us */ raw_header[raw_header_len++] = (FLAC__byte)_x; x = (x << 8) | _x; } @@ -1752,13 +2397,13 @@ FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) } if(sample_rate_hint) { - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ raw_header[raw_header_len++] = (FLAC__byte)x; if(sample_rate_hint != 12) { FLAC__uint32 _x; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &_x, 8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8)) + return false; /* read_callback_ sets the state for us */ raw_header[raw_header_len++] = (FLAC__byte)_x; x = (x << 8) | _x; } @@ -1771,19 +2416,45 @@ FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) } /* read the CRC-8 byte */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) + return false; /* read_callback_ sets the state for us */ crc8 = (FLAC__byte)x; if(FLAC__crc8(raw_header, raw_header_len) != crc8) { - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data); + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; return true; } + /* calculate the sample number from the frame number if needed */ + decoder->private_->next_fixed_block_size = 0; + if(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) { + x = decoder->private_->frame.header.number.frame_number; + decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER; + if(decoder->private_->fixed_block_size) + decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->fixed_block_size * (FLAC__uint64)x; + else if(decoder->private_->has_stream_info) { + if(decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize) { + decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->stream_info.data.stream_info.min_blocksize * (FLAC__uint64)x; + decoder->private_->next_fixed_block_size = decoder->private_->stream_info.data.stream_info.max_blocksize; + } + else + is_unparseable = true; + } + else if(x == 0) { + decoder->private_->frame.header.number.sample_number = 0; + decoder->private_->next_fixed_block_size = decoder->private_->frame.header.blocksize; + } + else { + /* can only get here if the stream has invalid frame numbering and no STREAMINFO, so assume it's not the last (possibly short) frame */ + decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->frame.header.blocksize * (FLAC__uint64)x; + } + } + if(is_unparseable) { - decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; - return false; + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; } return true; @@ -1793,17 +2464,18 @@ FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsign { FLAC__uint32 x; FLAC__bool wasted_bits; + unsigned i; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder)) /* MAGIC NUMBER */ - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) /* MAGIC NUMBER */ + return false; /* read_callback_ sets the state for us */ wasted_bits = (x & 1); x &= 0xfe; if(wasted_bits) { unsigned u; - if(!FLAC__bitbuffer_read_unary_unsigned(decoder->private_->input, &u, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_unary_unsigned(decoder->private_->input, &u)) + return false; /* read_callback_ sets the state for us */ decoder->private_->frame.subframes[channel].wasted_bits = u+1; bps -= decoder->private_->frame.subframes[channel].wasted_bits; } @@ -1814,7 +2486,7 @@ FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsign * Lots of magic numbers here */ if(x & 0x80) { - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data); + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; return true; } @@ -1827,24 +2499,29 @@ FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsign return false; } else if(x < 16) { - decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; - return false; + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; } else if(x <= 24) { if(!read_subframe_fixed_(decoder, channel, bps, (x>>1)&7, do_full_decode)) return false; + if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */ + return true; } else if(x < 64) { - decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; - return false; + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; } else { if(!read_subframe_lpc_(decoder, channel, bps, ((x>>1)&31)+1, do_full_decode)) return false; + if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */ + return true; } if(wasted_bits && do_full_decode) { - unsigned i; x = decoder->private_->frame.subframes[channel].wasted_bits; for(i = 0; i < decoder->private_->frame.header.blocksize; i++) decoder->private_->output[channel][i] <<= x; @@ -1862,8 +2539,8 @@ FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channe decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT; - if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &x, bps, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps)) + return false; /* read_callback_ sets the state for us */ subframe->value = x; @@ -1890,31 +2567,34 @@ FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, /* read warm-up samples */ for(u = 0; u < order; u++) { - if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &i32, bps, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps)) + return false; /* read_callback_ sets the state for us */ subframe->warmup[u] = i32; } /* read entropy coding method info */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) + return false; /* read_callback_ sets the state for us */ subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32; switch(subframe->entropy_coding_method.type) { case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) + return false; /* read_callback_ sets the state for us */ subframe->entropy_coding_method.data.partitioned_rice.order = u32; subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel]; break; default: - decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; - return false; + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; } /* read residual */ switch(subframe->entropy_coding_method.type) { case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel])) + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2)) return false; break; default: @@ -1944,53 +2624,56 @@ FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, un /* read warm-up samples */ for(u = 0; u < order; u++) { - if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &i32, bps, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps)) + return false; /* read_callback_ sets the state for us */ subframe->warmup[u] = i32; } /* read qlp coeff precision */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &u32, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN)) + return false; /* read_callback_ sets the state for us */ if(u32 == (1u << FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN) - 1) { - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data); + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; return true; } subframe->qlp_coeff_precision = u32+1; /* read qlp shift */ - if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &i32, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN)) + return false; /* read_callback_ sets the state for us */ subframe->quantization_level = i32; /* read quantized lp coefficiencts */ for(u = 0; u < order; u++) { - if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &i32, subframe->qlp_coeff_precision, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, subframe->qlp_coeff_precision)) + return false; /* read_callback_ sets the state for us */ subframe->qlp_coeff[u] = i32; } /* read entropy coding method info */ - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) + return false; /* read_callback_ sets the state for us */ subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32; switch(subframe->entropy_coding_method.type) { case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) + return false; /* read_callback_ sets the state for us */ subframe->entropy_coding_method.data.partitioned_rice.order = u32; subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel]; break; default: - decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; - return false; + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; } /* read residual */ switch(subframe->entropy_coding_method.type) { case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel])) + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2)) return false; break; default: @@ -2000,13 +2683,12 @@ FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, un /* decode the subframe */ if(do_full_decode) { memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order); + /*@@@@@@ technically not pessimistic enough, should be more like + if( (FLAC__uint64)order * ((((FLAC__uint64)1)<<bps)-1) * ((1<<subframe->qlp_coeff_precision)-1) < (((FLAC__uint64)-1) << 32) ) + */ if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32) - if(bps <= 16 && subframe->qlp_coeff_precision <= 16) { - if(order <= 8) - decoder->private_->local_lpc_restore_signal_16bit_order8(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); - else - decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); - } + if(bps <= 16 && subframe->qlp_coeff_precision <= 16) + decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); else decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); else @@ -2027,8 +2709,8 @@ FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channe subframe->data = residual; for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { - if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &x, bps, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps)) + return false; /* read_callback_ sets the state for us */ residual[i] = x; } @@ -2039,45 +2721,58 @@ FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channe return true; } -FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual) +FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended) { FLAC__uint32 rice_parameter; int i; unsigned partition, sample, u; const unsigned partitions = 1u << partition_order; const unsigned partition_samples = partition_order > 0? decoder->private_->frame.header.blocksize >> partition_order : decoder->private_->frame.header.blocksize - predictor_order; + const unsigned plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; + const unsigned pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; - if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order))) { + /* sanity checks */ + if(partition_order == 0) { + if(decoder->private_->frame.header.blocksize < predictor_order) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + /* We have received a potentially malicious bit stream. All we can do is error out to avoid a heap overflow. */ + return false; + } + } + else { + if(partition_samples < predictor_order) { + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + /* We have received a potentially malicious bit stream. All we can do is error out to avoid a heap overflow. */ + return false; + } + } + + if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, flac_max(6u, partition_order))) { decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; return false; } sample = 0; for(partition = 0; partition < partitions; partition++) { - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, plen)) + return false; /* read_callback_ sets the state for us */ partitioned_rice_contents->parameters[partition] = rice_parameter; - if(rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { -#ifdef FLAC__SYMMETRIC_RICE - for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) { - if(!FLAC__bitbuffer_read_symmetric_rice_signed(decoder->private_->input, &i, rice_parameter, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ - residual[sample] = i; - } -#else + if(rice_parameter < pesc) { + partitioned_rice_contents->raw_bits[partition] = 0; u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order; - if(!FLAC__bitbuffer_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter)) + return false; /* read_callback_ sets the state for us */ sample += u; -#endif } else { - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) + return false; /* read_callback_ sets the state for us */ partitioned_rice_contents->raw_bits[partition] = rice_parameter; for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) { - if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &i, rice_parameter, read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter)) + return false; /* read_callback_ sets the state for us */ residual[sample] = i; } } @@ -2088,27 +2783,607 @@ FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigne FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder) { - if(!FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)) { + if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) { FLAC__uint32 zero = 0; - if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &zero, FLAC__bitbuffer_bits_left_for_byte_alignment(decoder->private_->input), read_callback_, decoder)) - return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &zero, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input))) + return false; /* read_callback_ sets the state for us */ if(zero != 0) { - decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data); + send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; } } return true; } -FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *client_data) +FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data) { FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data; - FLAC__StreamDecoderReadStatus status; - status = decoder->private_->read_callback(decoder, buffer, bytes, decoder->private_->client_data); - if(status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM) + if( +#if FLAC__HAS_OGG + /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */ + !decoder->private_->is_ogg && +#endif + decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data) + ) { + *bytes = 0; decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; - else if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT) + return false; + } + else if(*bytes > 0) { + /* While seeking, it is possible for our seek to land in the + * middle of audio data that looks exactly like a frame header + * from a future version of an encoder. When that happens, our + * error callback will get an + * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM and increment its + * unparseable_frame_count. But there is a remote possibility + * that it is properly synced at such a "future-codec frame", + * so to make sure, we wait to see many "unparseable" errors in + * a row before bailing out. + */ + if(decoder->private_->is_seeking && decoder->private_->unparseable_frame_count > 20) { + decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; + return false; + } + else { + const FLAC__StreamDecoderReadStatus status = +#if FLAC__HAS_OGG + decoder->private_->is_ogg? + read_callback_ogg_aspect_(decoder, buffer, bytes) : +#endif + decoder->private_->read_callback(decoder, buffer, bytes, decoder->private_->client_data) + ; + if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT) { + decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; + return false; + } + else if(*bytes == 0) { + if( + status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM || + ( +#if FLAC__HAS_OGG + /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */ + !decoder->private_->is_ogg && +#endif + decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data) + ) + ) { + decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; + return false; + } + else + return true; + } + else + return true; + } + } + else { + /* abort to avoid a deadlock */ decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; - return status == FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + return false; + } + /* [1] @@@ HACK NOTE: The end-of-stream checking has to be hacked around + * for Ogg FLAC. This is because the ogg decoder aspect can lose sync + * and at the same time hit the end of the stream (for example, seeking + * to a point that is after the beginning of the last Ogg page). There + * is no way to report an Ogg sync loss through the callbacks (see note + * in read_callback_ogg_aspect_()) so it returns CONTINUE with *bytes==0. + * So to keep the decoder from stopping at this point we gate the call + * to the eof_callback and let the Ogg decoder aspect set the + * end-of-stream state when it is needed. + */ +} + +#if FLAC__HAS_OGG +FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes) +{ + switch(FLAC__ogg_decoder_aspect_read_callback_wrapper(&decoder->protected_->ogg_decoder_aspect, buffer, bytes, read_callback_proxy_, decoder, decoder->private_->client_data)) { + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK: + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + /* we don't really have a way to handle lost sync via read + * callback so we'll let it pass and let the underlying + * FLAC decoder catch the error + */ + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC: + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM: + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC: + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION: + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT: + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR: + case FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR: + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + default: + FLAC__ASSERT(0); + /* double protection */ + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } +} + +FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder*)void_decoder; + + switch(decoder->private_->read_callback(decoder, buffer, bytes, client_data)) { + case FLAC__STREAM_DECODER_READ_STATUS_CONTINUE: + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK; + case FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM: + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM; + case FLAC__STREAM_DECODER_READ_STATUS_ABORT: + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT; + default: + /* double protection: */ + FLAC__ASSERT(0); + return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT; + } +} +#endif + +FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) +{ + if(decoder->private_->is_seeking) { + FLAC__uint64 this_frame_sample = frame->header.number.sample_number; + FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize; + FLAC__uint64 target_sample = decoder->private_->target_sample; + + FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + +#if FLAC__HAS_OGG + decoder->private_->got_a_frame = true; +#endif + decoder->private_->last_frame = *frame; /* save the frame */ + if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */ + unsigned delta = (unsigned)(target_sample - this_frame_sample); + /* kick out of seek mode */ + decoder->private_->is_seeking = false; + /* shift out the samples before target_sample */ + if(delta > 0) { + unsigned channel; + const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS]; + for(channel = 0; channel < frame->header.channels; channel++) + newbuffer[channel] = buffer[channel] + delta; + decoder->private_->last_frame.header.blocksize -= delta; + decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta; + /* write the relevant samples */ + return decoder->private_->write_callback(decoder, &decoder->private_->last_frame, newbuffer, decoder->private_->client_data); + } + else { + /* write the relevant samples */ + return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data); + } + } + else { + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + } + } + else { + /* + * If we never got STREAMINFO, turn off MD5 checking to save + * cycles since we don't have a sum to compare to anyway + */ + if(!decoder->private_->has_stream_info) + decoder->private_->do_md5_checking = false; + if(decoder->private_->do_md5_checking) { + if(!FLAC__MD5Accumulate(&decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8)) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data); + } +} + +void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status) +{ + if(!decoder->private_->is_seeking) + decoder->private_->error_callback(decoder, status, decoder->private_->client_data); + else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM) + decoder->private_->unparseable_frame_count++; +} + +FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample) +{ + FLAC__uint64 first_frame_offset = decoder->private_->first_frame_offset, lower_bound, upper_bound, lower_bound_sample, upper_bound_sample, this_frame_sample; + FLAC__int64 pos = -1; + int i; + unsigned approx_bytes_per_frame; + FLAC__bool first_seek = true; + const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder); + const unsigned min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize; + const unsigned max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize; + const unsigned max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize; + const unsigned min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize; + /* take these from the current frame in case they've changed mid-stream */ + unsigned channels = FLAC__stream_decoder_get_channels(decoder); + unsigned bps = FLAC__stream_decoder_get_bits_per_sample(decoder); + const FLAC__StreamMetadata_SeekTable *seek_table = decoder->private_->has_seek_table? &decoder->private_->seek_table.data.seek_table : 0; + + /* use values from stream info if we didn't decode a frame */ + if(channels == 0) + channels = decoder->private_->stream_info.data.stream_info.channels; + if(bps == 0) + bps = decoder->private_->stream_info.data.stream_info.bits_per_sample; + + /* we are just guessing here */ + if(max_framesize > 0) + approx_bytes_per_frame = (max_framesize + min_framesize) / 2 + 1; + /* + * Check if it's a known fixed-blocksize stream. Note that though + * the spec doesn't allow zeroes in the STREAMINFO block, we may + * never get a STREAMINFO block when decoding so the value of + * min_blocksize might be zero. + */ + else if(min_blocksize == max_blocksize && min_blocksize > 0) { + /* note there are no () around 'bps/8' to keep precision up since it's an integer calulation */ + approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64; + } + else + approx_bytes_per_frame = 4096 * channels * bps/8 + 64; + + /* + * First, we set an upper and lower bound on where in the + * stream we will search. For now we assume the worst case + * scenario, which is our best guess at the beginning of + * the first frame and end of the stream. + */ + lower_bound = first_frame_offset; + lower_bound_sample = 0; + upper_bound = stream_length; + upper_bound_sample = total_samples > 0 ? total_samples : target_sample /*estimate it*/; + + /* + * Now we refine the bounds if we have a seektable with + * suitable points. Note that according to the spec they + * must be ordered by ascending sample number. + * + * Note: to protect against invalid seek tables we will ignore points + * that have frame_samples==0 or sample_number>=total_samples + */ + if(seek_table) { + FLAC__uint64 new_lower_bound = lower_bound; + FLAC__uint64 new_upper_bound = upper_bound; + FLAC__uint64 new_lower_bound_sample = lower_bound_sample; + FLAC__uint64 new_upper_bound_sample = upper_bound_sample; + + /* find the closest seek point <= target_sample, if it exists */ + for(i = (int)seek_table->num_points - 1; i >= 0; i--) { + if( + seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && + seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */ + (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */ + seek_table->points[i].sample_number <= target_sample + ) + break; + } + if(i >= 0) { /* i.e. we found a suitable seek point... */ + new_lower_bound = first_frame_offset + seek_table->points[i].stream_offset; + new_lower_bound_sample = seek_table->points[i].sample_number; + } + + /* find the closest seek point > target_sample, if it exists */ + for(i = 0; i < (int)seek_table->num_points; i++) { + if( + seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && + seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */ + (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */ + seek_table->points[i].sample_number > target_sample + ) + break; + } + if(i < (int)seek_table->num_points) { /* i.e. we found a suitable seek point... */ + new_upper_bound = first_frame_offset + seek_table->points[i].stream_offset; + new_upper_bound_sample = seek_table->points[i].sample_number; + } + /* final protection against unsorted seek tables; keep original values if bogus */ + if(new_upper_bound >= new_lower_bound) { + lower_bound = new_lower_bound; + upper_bound = new_upper_bound; + lower_bound_sample = new_lower_bound_sample; + upper_bound_sample = new_upper_bound_sample; + } + } + + FLAC__ASSERT(upper_bound_sample >= lower_bound_sample); + /* there are 2 insidious ways that the following equality occurs, which + * we need to fix: + * 1) total_samples is 0 (unknown) and target_sample is 0 + * 2) total_samples is 0 (unknown) and target_sample happens to be + * exactly equal to the last seek point in the seek table; this + * means there is no seek point above it, and upper_bound_samples + * remains equal to the estimate (of target_samples) we made above + * in either case it does not hurt to move upper_bound_sample up by 1 + */ + if(upper_bound_sample == lower_bound_sample) + upper_bound_sample++; + + decoder->private_->target_sample = target_sample; + while(1) { + /* check if the bounds are still ok */ + if (lower_bound_sample >= upper_bound_sample || lower_bound > upper_bound) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } +#ifndef FLAC__INTEGER_ONLY_LIBRARY + pos = (FLAC__int64)lower_bound + (FLAC__int64)((FLAC__double)(target_sample - lower_bound_sample) / (FLAC__double)(upper_bound_sample - lower_bound_sample) * (FLAC__double)(upper_bound - lower_bound)) - approx_bytes_per_frame; +#else + /* a little less accurate: */ + if(upper_bound - lower_bound < 0xffffffff) + pos = (FLAC__int64)lower_bound + (FLAC__int64)(((target_sample - lower_bound_sample) * (upper_bound - lower_bound)) / (upper_bound_sample - lower_bound_sample)) - approx_bytes_per_frame; + else /* @@@ WATCHOUT, ~2TB limit */ + pos = (FLAC__int64)lower_bound + (FLAC__int64)((((target_sample - lower_bound_sample)>>8) * ((upper_bound - lower_bound)>>8)) / ((upper_bound_sample - lower_bound_sample)>>16)) - approx_bytes_per_frame; +#endif + if(pos >= (FLAC__int64)upper_bound) + pos = (FLAC__int64)upper_bound - 1; + if(pos < (FLAC__int64)lower_bound) + pos = (FLAC__int64)lower_bound; + if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + if(!FLAC__stream_decoder_flush(decoder)) { + /* above call sets the state for us */ + return false; + } + /* Now we need to get a frame. First we need to reset our + * unparseable_frame_count; if we get too many unparseable + * frames in a row, the read callback will return + * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing + * FLAC__stream_decoder_process_single() to return false. + */ + decoder->private_->unparseable_frame_count = 0; + if(!FLAC__stream_decoder_process_single(decoder)) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + /* our write callback will change the state when it gets to the target frame */ + /* actually, we could have got_a_frame if our decoder is at FLAC__STREAM_DECODER_END_OF_STREAM so we need to check for that also */ +#if 0 + /*@@@@@@ used to be the following; not clear if the check for end of stream is needed anymore */ + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING && decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM) + break; +#endif + if(!decoder->private_->is_seeking) + break; + + FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + this_frame_sample = decoder->private_->last_frame.header.number.sample_number; + + if (0 == decoder->private_->samples_decoded || (this_frame_sample + decoder->private_->last_frame.header.blocksize >= upper_bound_sample && !first_seek)) { + if (pos == (FLAC__int64)lower_bound) { + /* can't move back any more than the first frame, something is fatally wrong */ + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + /* our last move backwards wasn't big enough, try again */ + approx_bytes_per_frame = approx_bytes_per_frame? approx_bytes_per_frame * 2 : 16; + continue; + } + /* allow one seek over upper bound, so we can get a correct upper_bound_sample for streams with unknown total_samples */ + first_seek = false; + + /* make sure we are not seeking in corrupted stream */ + if (this_frame_sample < lower_bound_sample) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + + /* we need to narrow the search */ + if(target_sample < this_frame_sample) { + upper_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize; +/*@@@@@@ what will decode position be if at end of stream? */ + if(!FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + approx_bytes_per_frame = (unsigned)(2 * (upper_bound - pos) / 3 + 16); + } + else { /* target_sample >= this_frame_sample + this frame's blocksize */ + lower_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize; + if(!FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + approx_bytes_per_frame = (unsigned)(2 * (lower_bound - pos) / 3 + 16); + } + } + + return true; +} + +#if FLAC__HAS_OGG +FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample) +{ + FLAC__uint64 left_pos = 0, right_pos = stream_length; + FLAC__uint64 left_sample = 0, right_sample = FLAC__stream_decoder_get_total_samples(decoder); + FLAC__uint64 this_frame_sample = (FLAC__uint64)0 - 1; + FLAC__uint64 pos = 0; /* only initialized to avoid compiler warning */ + FLAC__bool did_a_seek; + unsigned iteration = 0; + + /* In the first iterations, we will calculate the target byte position + * by the distance from the target sample to left_sample and + * right_sample (let's call it "proportional search"). After that, we + * will switch to binary search. + */ + unsigned BINARY_SEARCH_AFTER_ITERATION = 2; + + /* We will switch to a linear search once our current sample is less + * than this number of samples ahead of the target sample + */ + static const FLAC__uint64 LINEAR_SEARCH_WITHIN_SAMPLES = FLAC__MAX_BLOCK_SIZE * 2; + + /* If the total number of samples is unknown, use a large value, and + * force binary search immediately. + */ + if(right_sample == 0) { + right_sample = (FLAC__uint64)(-1); + BINARY_SEARCH_AFTER_ITERATION = 0; + } + + decoder->private_->target_sample = target_sample; + for( ; ; iteration++) { + if (iteration == 0 || this_frame_sample > target_sample || target_sample - this_frame_sample > LINEAR_SEARCH_WITHIN_SAMPLES) { + if (iteration >= BINARY_SEARCH_AFTER_ITERATION) { + pos = (right_pos + left_pos) / 2; + } + else { +#ifndef FLAC__INTEGER_ONLY_LIBRARY + pos = (FLAC__uint64)((FLAC__double)(target_sample - left_sample) / (FLAC__double)(right_sample - left_sample) * (FLAC__double)(right_pos - left_pos)); +#else + /* a little less accurate: */ + if ((target_sample-left_sample <= 0xffffffff) && (right_pos-left_pos <= 0xffffffff)) + pos = (FLAC__int64)(((target_sample-left_sample) * (right_pos-left_pos)) / (right_sample-left_sample)); + else /* @@@ WATCHOUT, ~2TB limit */ + pos = (FLAC__int64)((((target_sample-left_sample)>>8) * ((right_pos-left_pos)>>8)) / ((right_sample-left_sample)>>16)); +#endif + /* @@@ TODO: might want to limit pos to some distance + * before EOF, to make sure we land before the last frame, + * thereby getting a this_frame_sample and so having a better + * estimate. + */ + } + + /* physical seek */ + if(decoder->private_->seek_callback((FLAC__StreamDecoder*)decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + if(!FLAC__stream_decoder_flush(decoder)) { + /* above call sets the state for us */ + return false; + } + did_a_seek = true; + } + else + did_a_seek = false; + + decoder->private_->got_a_frame = false; + if(!FLAC__stream_decoder_process_single(decoder)) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + if(!decoder->private_->got_a_frame) { + if(did_a_seek) { + /* this can happen if we seek to a point after the last frame; we drop + * to binary search right away in this case to avoid any wasted + * iterations of proportional search. + */ + right_pos = pos; + BINARY_SEARCH_AFTER_ITERATION = 0; + } + else { + /* this can probably only happen if total_samples is unknown and the + * target_sample is past the end of the stream + */ + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + } + /* our write callback will change the state when it gets to the target frame */ + else if(!decoder->private_->is_seeking) { + break; + } + else { + this_frame_sample = decoder->private_->last_frame.header.number.sample_number; + FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + + if (did_a_seek) { + if (this_frame_sample <= target_sample) { + /* The 'equal' case should not happen, since + * FLAC__stream_decoder_process_single() + * should recognize that it has hit the + * target sample and we would exit through + * the 'break' above. + */ + FLAC__ASSERT(this_frame_sample != target_sample); + + left_sample = this_frame_sample; + /* sanity check to avoid infinite loop */ + if (left_pos == pos) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + left_pos = pos; + } + else if(this_frame_sample > target_sample) { + right_sample = this_frame_sample; + /* sanity check to avoid infinite loop */ + if (right_pos == pos) { + decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; + return false; + } + right_pos = pos; + } + } + } + } + + return true; +} +#endif + +FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + (void)client_data; + + if(*bytes > 0) { + *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, decoder->private_->file); + if(ferror(decoder->private_->file)) + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + else if(*bytes == 0) + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */ +} + +FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + (void)client_data; + + if(decoder->private_->file == stdin) + return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; + else if(fseeko(decoder->private_->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + else + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; +} + +FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + FLAC__off_t pos; + (void)client_data; + + if(decoder->private_->file == stdin) + return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED; + else if((pos = ftello(decoder->private_->file)) < 0) + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + else { + *absolute_byte_offset = (FLAC__uint64)pos; + return FLAC__STREAM_DECODER_TELL_STATUS_OK; + } +} + +FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) +{ + struct flac_stat_s filestats; + (void)client_data; + + if(decoder->private_->file == stdin) + return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; + else if(flac_fstat(fileno(decoder->private_->file), &filestats) != 0) + return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + else { + *stream_length = (FLAC__uint64)filestats.st_size; + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; + } +} + +FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data) +{ + (void)client_data; + + return feof(decoder->private_->file)? true : false; } diff --git a/sys/src/cmd/audio/libFLAC/stream_encoder.c b/sys/src/cmd/audio/libFLAC/stream_encoder.c index 554669650..45bdb252b 100644 --- a/sys/src/cmd/audio/libFLAC/stream_encoder.c +++ b/sys/src/cmd/audio/libFLAC/stream_encoder.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,14 +30,20 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include <limits.h> #include <stdio.h> #include <stdlib.h> /* for malloc() */ #include <string.h> /* for memcpy() */ +#include <sys/types.h> /* for off_t */ +#include "share/compat.h" #include "FLAC/assert.h" #include "FLAC/stream_decoder.h" #include "protected/stream_encoder.h" -#include "private/bitbuffer.h" +#include "private/bitwriter.h" #include "private/bitmath.h" #include "private/crc.h" #include "private/cpu.h" @@ -45,21 +52,30 @@ #include "private/lpc.h" #include "private/md5.h" #include "private/memory.h" +#include "private/macros.h" +#if FLAC__HAS_OGG +#include "private/ogg_helper.h" +#include "private/ogg_mapping.h" +#endif +#include "private/stream_encoder.h" #include "private/stream_encoder_framing.h" +#include "private/window.h" +#include "share/alloc.h" +#include "share/private.h" -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#ifdef min -#undef min -#endif -#define min(x,y) ((x)<(y)?(x):(y)) +/* Exact Rice codeword length calculation is off by default. The simple + * (and fast) estimation (of how many bits a residual value will be + * encoded with) in this encoder is very good, almost always yielding + * compression within 0.1% of exact calculation. + */ +#undef EXACT_RICE_BITS_CALCULATION +/* Rice parameter searching is off by default. The simple (and fast) + * parameter estimation in this encoder is very good, almost always + * yielding compression within 0.1% of the optimal parameters. + */ +#undef ENABLE_RICE_PARAMETER_SEARCH -#ifdef max -#undef max -#endif -#define max(x,y) ((x)>(y)?(x):(y)) typedef struct { FLAC__int32 *data[FLAC__MAX_CHANNELS]; @@ -79,6 +95,32 @@ typedef enum { ENCODER_IN_AUDIO = 2 } EncoderStateHint; +static struct CompressionLevels { + FLAC__bool do_mid_side_stereo; + FLAC__bool loose_mid_side_stereo; + unsigned max_lpc_order; + unsigned qlp_coeff_precision; + FLAC__bool do_qlp_coeff_prec_search; + FLAC__bool do_escape_coding; + FLAC__bool do_exhaustive_model_search; + unsigned min_residual_partition_order; + unsigned max_residual_partition_order; + unsigned rice_parameter_search_dist; + const char *apodization; +} compression_levels_[] = { + { false, false, 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, + { true , true , 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, + { true , false, 0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" }, + { false, false, 6, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" }, + { true , true , 8, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" }, + { true , false, 8, 0, false, false, false, 0, 5, 0, "tukey(5e-1)" }, + { true , false, 8, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2)" }, + { true , false, 12, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2)" }, + { true , false, 12, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2);punchout_tukey(3)" } + /* here we use locale-independent 5e-1 instead of 0.5 or 0,5 */ +}; + + /*********************************************************************** * * Private class method prototypes @@ -87,20 +129,23 @@ typedef enum { static void set_defaults_(FLAC__StreamEncoder *encoder); static void free_(FLAC__StreamEncoder *encoder); -static FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_size); -static FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples); -static FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame); -static FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame); +static FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize); +static FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples, FLAC__bool is_last_block); +static FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, FLAC__bool is_last_block); +static void update_metadata_(const FLAC__StreamEncoder *encoder); +#if FLAC__HAS_OGG +static void update_ogg_metadata_(FLAC__StreamEncoder *encoder); +#endif +static FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block); +static FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block); static FLAC__bool process_subframe_( FLAC__StreamEncoder *encoder, unsigned min_partition_order, unsigned max_partition_order, - FLAC__bool precompute_partition_sums, const FLAC__FrameHeader *frame_header, unsigned subframe_bps, const FLAC__int32 integer_signal[], - const FLAC__real real_signal[], FLAC__Subframe *subframe[2], FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2], FLAC__int32 *residual[2], @@ -110,14 +155,16 @@ static FLAC__bool process_subframe_( static FLAC__bool add_subframe_( FLAC__StreamEncoder *encoder, - const FLAC__FrameHeader *frame_header, + unsigned blocksize, unsigned subframe_bps, const FLAC__Subframe *subframe, - FLAC__BitBuffer *frame + FLAC__BitWriter *frame ); static unsigned evaluate_constant_subframe_( + FLAC__StreamEncoder *encoder, const FLAC__int32 signal, + unsigned blocksize, unsigned subframe_bps, FLAC__Subframe *subframe ); @@ -126,27 +173,26 @@ static unsigned evaluate_fixed_subframe_( FLAC__StreamEncoder *encoder, const FLAC__int32 signal[], FLAC__int32 residual[], - FLAC__uint32 abs_residual[], FLAC__uint64 abs_residual_partition_sums[], unsigned raw_bits_per_partition[], unsigned blocksize, unsigned subframe_bps, unsigned order, unsigned rice_parameter, + unsigned rice_parameter_limit, unsigned min_partition_order, unsigned max_partition_order, - FLAC__bool precompute_partition_sums, FLAC__bool do_escape_coding, unsigned rice_parameter_search_dist, FLAC__Subframe *subframe, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents ); +#ifndef FLAC__INTEGER_ONLY_LIBRARY static unsigned evaluate_lpc_subframe_( FLAC__StreamEncoder *encoder, const FLAC__int32 signal[], FLAC__int32 residual[], - FLAC__uint32 abs_residual[], FLAC__uint64 abs_residual_partition_sums[], unsigned raw_bits_per_partition[], const FLAC__real lp_coeff[], @@ -155,16 +201,18 @@ static unsigned evaluate_lpc_subframe_( unsigned order, unsigned qlp_coeff_precision, unsigned rice_parameter, + unsigned rice_parameter_limit, unsigned min_partition_order, unsigned max_partition_order, - FLAC__bool precompute_partition_sums, FLAC__bool do_escape_coding, unsigned rice_parameter_search_dist, FLAC__Subframe *subframe, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents ); +#endif static unsigned evaluate_verbatim_subframe_( + FLAC__StreamEncoder *encoder, const FLAC__int32 signal[], unsigned blocksize, unsigned subframe_bps, @@ -174,27 +222,28 @@ static unsigned evaluate_verbatim_subframe_( static unsigned find_best_partition_order_( struct FLAC__StreamEncoderPrivate *private_, const FLAC__int32 residual[], - FLAC__uint32 abs_residual[], FLAC__uint64 abs_residual_partition_sums[], unsigned raw_bits_per_partition[], unsigned residual_samples, unsigned predictor_order, unsigned rice_parameter, + unsigned rice_parameter_limit, unsigned min_partition_order, unsigned max_partition_order, - FLAC__bool precompute_partition_sums, + unsigned bps, FLAC__bool do_escape_coding, unsigned rice_parameter_search_dist, - FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice + FLAC__EntropyCodingMethod *best_ecm ); static void precompute_partition_info_sums_( - const FLAC__uint32 abs_residual[], + const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, - unsigned max_partition_order + unsigned max_partition_order, + unsigned bps ); static void precompute_partition_info_escapes_( @@ -206,58 +255,22 @@ static void precompute_partition_info_escapes_( unsigned max_partition_order ); -#ifdef DONT_ESTIMATE_RICE_BITS static FLAC__bool set_partitioned_rice_( - const FLAC__uint32 abs_residual[], +#ifdef EXACT_RICE_BITS_CALCULATION const FLAC__int32 residual[], - const unsigned residual_samples, - const unsigned predictor_order, - const unsigned suggested_rice_parameter, - const unsigned rice_parameter_search_dist, - const unsigned partition_order, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, - unsigned *bits -); - -static FLAC__bool set_partitioned_rice_with_precompute_( - const FLAC__int32 residual[], - const FLAC__uint64 abs_residual_partition_sums[], - const unsigned raw_bits_per_partition[], - const unsigned residual_samples, - const unsigned predictor_order, - const unsigned suggested_rice_parameter, - const unsigned rice_parameter_search_dist, - const unsigned partition_order, - const FLAC__bool search_for_escapes, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, - unsigned *bits -); -#else -static FLAC__bool set_partitioned_rice_( - const FLAC__uint32 abs_residual[], - const unsigned residual_samples, - const unsigned predictor_order, - const unsigned suggested_rice_parameter, - const unsigned rice_parameter_search_dist, - const unsigned partition_order, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, - unsigned *bits -); - -static FLAC__bool set_partitioned_rice_with_precompute_( - const FLAC__uint32 abs_residual[], +#endif const FLAC__uint64 abs_residual_partition_sums[], const unsigned raw_bits_per_partition[], const unsigned residual_samples, const unsigned predictor_order, const unsigned suggested_rice_parameter, + const unsigned rice_parameter_limit, const unsigned rice_parameter_search_dist, const unsigned partition_order, const FLAC__bool search_for_escapes, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, unsigned *bits ); -#endif static unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples); @@ -278,31 +291,16 @@ static void append_to_verify_fifo_interleaved_( unsigned wide_samples ); -static FLAC__StreamDecoderReadStatus verify_read_callback_( - const FLAC__StreamDecoder *decoder, - FLAC__byte buffer[], - unsigned *bytes, - void *client_data -); - -static FLAC__StreamDecoderWriteStatus verify_write_callback_( - const FLAC__StreamDecoder *decoder, - const FLAC__Frame *frame, - const FLAC__int32 * const buffer[], - void *client_data -); - -static void verify_metadata_callback_( - const FLAC__StreamDecoder *decoder, - const FLAC__StreamMetadata *metadata, - void *client_data -); +static FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +static FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +static void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); -static void verify_error_callback_( - const FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderErrorStatus status, - void *client_data -); +static FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +static FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); +static FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); +static FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data); +static FILE *get_binary_stdout_(void); /*********************************************************************** @@ -315,8 +313,12 @@ typedef struct FLAC__StreamEncoderPrivate { unsigned input_capacity; /* current size (in samples) of the signal and residual buffers */ FLAC__int32 *integer_signal[FLAC__MAX_CHANNELS]; /* the integer version of the input signal */ FLAC__int32 *integer_signal_mid_side[2]; /* the integer version of the mid-side input signal (stereo only) */ - FLAC__real *real_signal[FLAC__MAX_CHANNELS]; /* the floating-point version of the input signal */ - FLAC__real *real_signal_mid_side[2]; /* the floating-point version of the mid-side input signal (stereo only) */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY + FLAC__real *real_signal[FLAC__MAX_CHANNELS]; /* (@@@ currently unused) the floating-point version of the input signal */ + FLAC__real *real_signal_mid_side[2]; /* (@@@ currently unused) the floating-point version of the mid-side input signal (stereo only) */ + FLAC__real *window[FLAC__MAX_APODIZATION_FUNCTIONS]; /* the pre-computed floating-point window for each apodization function */ + FLAC__real *windowed_signal; /* the integer_signal[] * current window[] */ +#endif unsigned subframe_bps[FLAC__MAX_CHANNELS]; /* the effective bits per sample of the input signal (stream bps - wasted bits) */ unsigned subframe_bps_mid_side[2]; /* the effective bits per sample of the mid-side input signal (stream bps - wasted bits + 0/1) */ FLAC__int32 *residual_workspace[FLAC__MAX_CHANNELS][2]; /* each channel has a candidate and best workspace where the subframe residual signals will be stored */ @@ -329,53 +331,78 @@ typedef struct FLAC__StreamEncoderPrivate { FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace_mid_side[FLAC__MAX_CHANNELS][2]; FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr[FLAC__MAX_CHANNELS][2]; FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr_mid_side[FLAC__MAX_CHANNELS][2]; - unsigned best_subframe[FLAC__MAX_CHANNELS]; /* index into the above workspaces */ + unsigned best_subframe[FLAC__MAX_CHANNELS]; /* index (0 or 1) into 2nd dimension of the above workspaces */ unsigned best_subframe_mid_side[2]; unsigned best_subframe_bits[FLAC__MAX_CHANNELS]; /* size in bits of the best subframe for each channel */ unsigned best_subframe_bits_mid_side[2]; - FLAC__uint32 *abs_residual; /* workspace where abs(candidate residual) is stored */ FLAC__uint64 *abs_residual_partition_sums; /* workspace where the sum of abs(candidate residual) for each partition is stored */ unsigned *raw_bits_per_partition; /* workspace where the sum of silog2(candidate residual) for each partition is stored */ - FLAC__BitBuffer *frame; /* the current frame being worked on */ - double loose_mid_side_stereo_frames_exact; /* exact number of frames the encoder will use before trying both independent and mid/side frames again */ + FLAC__BitWriter *frame; /* the current frame being worked on */ unsigned loose_mid_side_stereo_frames; /* rounded number of frames the encoder will use before trying both independent and mid/side frames again */ unsigned loose_mid_side_stereo_frame_count; /* number of frames using the current channel assignment */ FLAC__ChannelAssignment last_channel_assignment; - FLAC__StreamMetadata metadata; + FLAC__StreamMetadata streaminfo; /* scratchpad for STREAMINFO as it is built */ + FLAC__StreamMetadata_SeekTable *seek_table; /* pointer into encoder->protected_->metadata_ where the seek table is */ unsigned current_sample_number; unsigned current_frame_number; - struct FLAC__MD5Context md5context; + FLAC__MD5Context md5context; FLAC__CPUInfo cpuinfo; - unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); + void (*local_precompute_partition_info_sums)(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps); +#ifndef FLAC__INTEGER_ONLY_LIBRARY + unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); + unsigned (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +#else + unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); + unsigned (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +#endif +#ifndef FLAC__INTEGER_ONLY_LIBRARY void (*local_lpc_compute_autocorrelation)(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); - void (*local_lpc_compute_residual_from_qlp_coefficients)(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); - void (*local_lpc_compute_residual_from_qlp_coefficients_64bit)(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); - void (*local_lpc_compute_residual_from_qlp_coefficients_16bit)(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); + void (*local_lpc_compute_residual_from_qlp_coefficients)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); + void (*local_lpc_compute_residual_from_qlp_coefficients_64bit)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); + void (*local_lpc_compute_residual_from_qlp_coefficients_16bit)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); +#endif FLAC__bool use_wide_by_block; /* use slow 64-bit versions of some functions because of the block size */ FLAC__bool use_wide_by_partition; /* use slow 64-bit versions of some functions because of the min partition order and blocksize */ FLAC__bool use_wide_by_order; /* use slow 64-bit versions of some functions because of the lpc order */ - FLAC__bool precompute_partition_sums; /* our initial guess as to whether precomputing the partitions sums will be a speed improvement */ FLAC__bool disable_constant_subframes; FLAC__bool disable_fixed_subframes; FLAC__bool disable_verbatim_subframes; +#if FLAC__HAS_OGG + FLAC__bool is_ogg; +#endif + FLAC__StreamEncoderReadCallback read_callback; /* currently only needed for Ogg FLAC */ + FLAC__StreamEncoderSeekCallback seek_callback; + FLAC__StreamEncoderTellCallback tell_callback; FLAC__StreamEncoderWriteCallback write_callback; FLAC__StreamEncoderMetadataCallback metadata_callback; + FLAC__StreamEncoderProgressCallback progress_callback; void *client_data; + unsigned first_seekpoint_to_check; + FILE *file; /* only used when encoding to a file */ + FLAC__uint64 bytes_written; + FLAC__uint64 samples_written; + unsigned frames_written; + unsigned total_frames_estimate; /* unaligned (original) pointers to allocated data */ FLAC__int32 *integer_signal_unaligned[FLAC__MAX_CHANNELS]; FLAC__int32 *integer_signal_mid_side_unaligned[2]; - FLAC__real *real_signal_unaligned[FLAC__MAX_CHANNELS]; - FLAC__real *real_signal_mid_side_unaligned[2]; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + FLAC__real *real_signal_unaligned[FLAC__MAX_CHANNELS]; /* (@@@ currently unused) */ + FLAC__real *real_signal_mid_side_unaligned[2]; /* (@@@ currently unused) */ + FLAC__real *window_unaligned[FLAC__MAX_APODIZATION_FUNCTIONS]; + FLAC__real *windowed_signal_unaligned; +#endif FLAC__int32 *residual_workspace_unaligned[FLAC__MAX_CHANNELS][2]; FLAC__int32 *residual_workspace_mid_side_unaligned[2][2]; - FLAC__uint32 *abs_residual_unaligned; FLAC__uint64 *abs_residual_partition_sums_unaligned; unsigned *raw_bits_per_partition_unaligned; /* * These fields have been moved here from private function local * declarations merely to save stack space during encoding. */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY FLAC__real lp_coeff[FLAC__MAX_LPC_ORDER][FLAC__MAX_LPC_ORDER]; /* from process_subframe_() */ +#endif FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_extra[2]; /* from find_best_partition_order_() */ /* * The data for the verify section @@ -406,27 +433,38 @@ typedef struct FLAC__StreamEncoderPrivate { FLAC_API const char * const FLAC__StreamEncoderStateString[] = { "FLAC__STREAM_ENCODER_OK", + "FLAC__STREAM_ENCODER_UNINITIALIZED", + "FLAC__STREAM_ENCODER_OGG_ERROR", "FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR", "FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA", - "FLAC__STREAM_ENCODER_INVALID_CALLBACK", - "FLAC__STREAM_ENCODER_INVALID_NUMBER_OF_CHANNELS", - "FLAC__STREAM_ENCODER_INVALID_BITS_PER_SAMPLE", - "FLAC__STREAM_ENCODER_INVALID_SAMPLE_RATE", - "FLAC__STREAM_ENCODER_INVALID_BLOCK_SIZE", - "FLAC__STREAM_ENCODER_INVALID_MAX_LPC_ORDER", - "FLAC__STREAM_ENCODER_INVALID_QLP_COEFF_PRECISION", - "FLAC__STREAM_ENCODER_MID_SIDE_CHANNELS_MISMATCH", - "FLAC__STREAM_ENCODER_MID_SIDE_SAMPLE_SIZE_MISMATCH", - "FLAC__STREAM_ENCODER_ILLEGAL_MID_SIDE_FORCE", - "FLAC__STREAM_ENCODER_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER", - "FLAC__STREAM_ENCODER_NOT_STREAMABLE", + "FLAC__STREAM_ENCODER_CLIENT_ERROR", + "FLAC__STREAM_ENCODER_IO_ERROR", "FLAC__STREAM_ENCODER_FRAMING_ERROR", - "FLAC__STREAM_ENCODER_INVALID_METADATA", - "FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING", - "FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_WRITING", - "FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR", - "FLAC__STREAM_ENCODER_ALREADY_INITIALIZED", - "FLAC__STREAM_ENCODER_UNINITIALIZED" + "FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR" +}; + +FLAC_API const char * const FLAC__StreamEncoderInitStatusString[] = { + "FLAC__STREAM_ENCODER_INIT_STATUS_OK", + "FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR", + "FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION", + "FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER", + "FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE", + "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA", + "FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED" +}; + +FLAC_API const char * const FLAC__StreamEncoderReadStatusString[] = { + "FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE", + "FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM", + "FLAC__STREAM_ENCODER_READ_STATUS_ABORT", + "FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED" }; FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[] = { @@ -434,7 +472,30 @@ FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[] = { "FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR" }; -FLAC__BitBuffer *FLAC__bitbuffer_new(void); +FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[] = { + "FLAC__STREAM_ENCODER_SEEK_STATUS_OK", + "FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR", + "FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED" +}; + +FLAC_API const char * const FLAC__StreamEncoderTellStatusString[] = { + "FLAC__STREAM_ENCODER_TELL_STATUS_OK", + "FLAC__STREAM_ENCODER_TELL_STATUS_ERROR", + "FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED" +}; + +/* Number of samples that will be overread to watch for end of stream. By + * 'overread', we mean that the FLAC__stream_encoder_process*() calls will + * always try to read blocksize+1 samples before encoding a block, so that + * even if the stream has a total sample count that is an integral multiple + * of the blocksize, we will still notice when we are encoding the last + * block. This is needed, for example, to correctly set the end-of-stream + * marker in Ogg FLAC. + * + * WATCHOUT: some parts of the code assert that OVERREAD_ == 1 and there's + * not really any reason to change it. + */ +static const unsigned OVERREAD_ = 1; /*********************************************************************** * @@ -448,25 +509,25 @@ FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void) FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ - encoder = (FLAC__StreamEncoder*)calloc(1, sizeof(FLAC__StreamEncoder)); + encoder = calloc(1, sizeof(FLAC__StreamEncoder)); if(encoder == 0) { return 0; } - encoder->protected_ = (FLAC__StreamEncoderProtected*)calloc(1, sizeof(FLAC__StreamEncoderProtected)); + encoder->protected_ = calloc(1, sizeof(FLAC__StreamEncoderProtected)); if(encoder->protected_ == 0) { free(encoder); return 0; } - encoder->private_ = (FLAC__StreamEncoderPrivate*)calloc(1, sizeof(FLAC__StreamEncoderPrivate)); + encoder->private_ = calloc(1, sizeof(FLAC__StreamEncoderPrivate)); if(encoder->private_ == 0) { free(encoder->protected_); free(encoder); return 0; } - encoder->private_->frame = FLAC__bitbuffer_new(); + encoder->private_->frame = FLAC__bitwriter_new(); if(encoder->private_->frame == 0) { free(encoder->private_); free(encoder->protected_); @@ -474,6 +535,8 @@ FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void) return 0; } + encoder->private_->file = 0; + set_defaults_(encoder); encoder->private_->is_being_deleted = false; @@ -515,14 +578,16 @@ FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder) { unsigned i; - FLAC__ASSERT(0 != encoder); + if (encoder == NULL) + return ; + FLAC__ASSERT(0 != encoder->protected_); FLAC__ASSERT(0 != encoder->private_); FLAC__ASSERT(0 != encoder->private_->frame); encoder->private_->is_being_deleted = true; - FLAC__stream_encoder_finish(encoder); + (void)FLAC__stream_encoder_finish(encoder); if(0 != encoder->private_->verify.decoder) FLAC__stream_decoder_delete(encoder->private_->verify.decoder); @@ -538,7 +603,7 @@ FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder) for(i = 0; i < 2; i++) FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_extra[i]); - FLAC__bitbuffer_delete(encoder->private_->frame); + FLAC__bitwriter_delete(encoder->private_->frame); free(encoder->private_); free(encoder->protected_); free(encoder); @@ -550,53 +615,73 @@ FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder) * ***********************************************************************/ -FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder *encoder) +static FLAC__StreamEncoderInitStatus init_stream_internal_( + FLAC__StreamEncoder *encoder, + FLAC__StreamEncoderReadCallback read_callback, + FLAC__StreamEncoderWriteCallback write_callback, + FLAC__StreamEncoderSeekCallback seek_callback, + FLAC__StreamEncoderTellCallback tell_callback, + FLAC__StreamEncoderMetadataCallback metadata_callback, + void *client_data, + FLAC__bool is_ogg +) { unsigned i; - FLAC__bool metadata_has_seektable, metadata_has_vorbis_comment; + FLAC__bool metadata_has_seektable, metadata_has_vorbis_comment, metadata_picture_has_type1, metadata_picture_has_type2; FLAC__ASSERT(0 != encoder); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return encoder->protected_->state = FLAC__STREAM_ENCODER_ALREADY_INITIALIZED; + return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED; - encoder->protected_->state = FLAC__STREAM_ENCODER_OK; +#if !FLAC__HAS_OGG + if(is_ogg) + return FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER; +#endif - if(0 == encoder->private_->write_callback || 0 == encoder->private_->metadata_callback) - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_CALLBACK; + if(0 == write_callback || (seek_callback && 0 == tell_callback)) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS; if(encoder->protected_->channels == 0 || encoder->protected_->channels > FLAC__MAX_CHANNELS) - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_NUMBER_OF_CHANNELS; + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS; - if(encoder->protected_->do_mid_side_stereo && encoder->protected_->channels != 2) - return encoder->protected_->state = FLAC__STREAM_ENCODER_MID_SIDE_CHANNELS_MISMATCH; - - if(encoder->protected_->loose_mid_side_stereo && !encoder->protected_->do_mid_side_stereo) - return encoder->protected_->state = FLAC__STREAM_ENCODER_ILLEGAL_MID_SIDE_FORCE; + if(encoder->protected_->channels != 2) { + encoder->protected_->do_mid_side_stereo = false; + encoder->protected_->loose_mid_side_stereo = false; + } + else if(!encoder->protected_->do_mid_side_stereo) + encoder->protected_->loose_mid_side_stereo = false; if(encoder->protected_->bits_per_sample >= 32) - encoder->protected_->do_mid_side_stereo = false; /* since we do 32-bit math, the side channel would have 33 bps and overflow */ + encoder->protected_->do_mid_side_stereo = false; /* since we currenty do 32-bit math, the side channel would have 33 bps and overflow */ if(encoder->protected_->bits_per_sample < FLAC__MIN_BITS_PER_SAMPLE || encoder->protected_->bits_per_sample > FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE) - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_BITS_PER_SAMPLE; + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE; if(!FLAC__format_sample_rate_is_valid(encoder->protected_->sample_rate)) - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_SAMPLE_RATE; + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE; + + if(encoder->protected_->blocksize == 0) { + if(encoder->protected_->max_lpc_order == 0) + encoder->protected_->blocksize = 1152; + else + encoder->protected_->blocksize = 4096; + } if(encoder->protected_->blocksize < FLAC__MIN_BLOCK_SIZE || encoder->protected_->blocksize > FLAC__MAX_BLOCK_SIZE) - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_BLOCK_SIZE; + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE; if(encoder->protected_->max_lpc_order > FLAC__MAX_LPC_ORDER) - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_MAX_LPC_ORDER; + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER; if(encoder->protected_->blocksize < encoder->protected_->max_lpc_order) - return encoder->protected_->state = FLAC__STREAM_ENCODER_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER; + return FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER; if(encoder->protected_->qlp_coeff_precision == 0) { if(encoder->protected_->bits_per_sample < 16) { /* @@@ need some data about how to set this here w.r.t. blocksize and sample rate */ /* @@@ until then we'll make a guess */ - encoder->protected_->qlp_coeff_precision = max(FLAC__MIN_QLP_COEFF_PRECISION, 2 + encoder->protected_->bits_per_sample / 2); + encoder->protected_->qlp_coeff_precision = flac_max(FLAC__MIN_QLP_COEFF_PRECISION, 2 + encoder->protected_->bits_per_sample / 2); } else if(encoder->protected_->bits_per_sample == 16) { if(encoder->protected_->blocksize <= 192) @@ -625,35 +710,13 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder FLAC__ASSERT(encoder->protected_->qlp_coeff_precision <= FLAC__MAX_QLP_COEFF_PRECISION); } else if(encoder->protected_->qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION || encoder->protected_->qlp_coeff_precision > FLAC__MAX_QLP_COEFF_PRECISION) - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_QLP_COEFF_PRECISION; + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION; if(encoder->protected_->streamable_subset) { - if( - encoder->protected_->blocksize != 192 && - encoder->protected_->blocksize != 576 && - encoder->protected_->blocksize != 1152 && - encoder->protected_->blocksize != 2304 && - encoder->protected_->blocksize != 4608 && - encoder->protected_->blocksize != 256 && - encoder->protected_->blocksize != 512 && - encoder->protected_->blocksize != 1024 && - encoder->protected_->blocksize != 2048 && - encoder->protected_->blocksize != 4096 && - encoder->protected_->blocksize != 8192 && - encoder->protected_->blocksize != 16384 - ) - return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE; - if( - encoder->protected_->sample_rate != 8000 && - encoder->protected_->sample_rate != 16000 && - encoder->protected_->sample_rate != 22050 && - encoder->protected_->sample_rate != 24000 && - encoder->protected_->sample_rate != 32000 && - encoder->protected_->sample_rate != 44100 && - encoder->protected_->sample_rate != 48000 && - encoder->protected_->sample_rate != 96000 - ) - return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE; + if(!FLAC__format_blocksize_is_subset(encoder->protected_->blocksize, encoder->protected_->sample_rate)) + return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; + if(!FLAC__format_sample_rate_is_subset(encoder->protected_->sample_rate)) + return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; if( encoder->protected_->bits_per_sample != 8 && encoder->protected_->bits_per_sample != 12 && @@ -661,9 +724,18 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder encoder->protected_->bits_per_sample != 20 && encoder->protected_->bits_per_sample != 24 ) - return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE; + return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; if(encoder->protected_->max_residual_partition_order > FLAC__SUBSET_MAX_RICE_PARTITION_ORDER) - return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE; + return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; + if( + encoder->protected_->sample_rate <= 48000 && + ( + encoder->protected_->blocksize > FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ || + encoder->protected_->max_lpc_order > FLAC__SUBSET_MAX_LPC_ORDER_48000HZ + ) + ) { + return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE; + } } if(encoder->protected_->max_residual_partition_order >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) @@ -671,41 +743,103 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder if(encoder->protected_->min_residual_partition_order >= encoder->protected_->max_residual_partition_order) encoder->protected_->min_residual_partition_order = encoder->protected_->max_residual_partition_order; +#if FLAC__HAS_OGG + /* reorder metadata if necessary to ensure that any VORBIS_COMMENT is the first, according to the mapping spec */ + if(is_ogg && 0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 1) { + unsigned i1; + for(i1 = 1; i1 < encoder->protected_->num_metadata_blocks; i1++) { + if(0 != encoder->protected_->metadata[i1] && encoder->protected_->metadata[i1]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + FLAC__StreamMetadata *vc = encoder->protected_->metadata[i1]; + for( ; i1 > 0; i1--) + encoder->protected_->metadata[i1] = encoder->protected_->metadata[i1-1]; + encoder->protected_->metadata[0] = vc; + break; + } + } + } +#endif + /* keep track of any SEEKTABLE block */ + if(0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) { + unsigned i2; + for(i2 = 0; i2 < encoder->protected_->num_metadata_blocks; i2++) { + if(0 != encoder->protected_->metadata[i2] && encoder->protected_->metadata[i2]->type == FLAC__METADATA_TYPE_SEEKTABLE) { + encoder->private_->seek_table = &encoder->protected_->metadata[i2]->data.seek_table; + break; /* take only the first one */ + } + } + } + /* validate metadata */ if(0 == encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA; + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; metadata_has_seektable = false; metadata_has_vorbis_comment = false; + metadata_picture_has_type1 = false; + metadata_picture_has_type2 = false; for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) { - if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_STREAMINFO) - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA; - else if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) { + const FLAC__StreamMetadata *m = encoder->protected_->metadata[i]; + if(m->type == FLAC__METADATA_TYPE_STREAMINFO) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + else if(m->type == FLAC__METADATA_TYPE_SEEKTABLE) { if(metadata_has_seektable) /* only one is allowed */ - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA; + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; metadata_has_seektable = true; - if(!FLAC__format_seektable_is_legal(&encoder->protected_->metadata[i]->data.seek_table)) - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA; + if(!FLAC__format_seektable_is_legal(&m->data.seek_table)) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; } - else if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + else if(m->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { if(metadata_has_vorbis_comment) /* only one is allowed */ - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA; + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; metadata_has_vorbis_comment = true; } - else if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_CUESHEET) { - if(!FLAC__format_cuesheet_is_legal(&encoder->protected_->metadata[i]->data.cue_sheet, encoder->protected_->metadata[i]->data.cue_sheet.is_cd, /*violation=*/0)) - return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA; + else if(m->type == FLAC__METADATA_TYPE_CUESHEET) { + if(!FLAC__format_cuesheet_is_legal(&m->data.cue_sheet, m->data.cue_sheet.is_cd, /*violation=*/0)) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + } + else if(m->type == FLAC__METADATA_TYPE_PICTURE) { + if(!FLAC__format_picture_is_legal(&m->data.picture, /*violation=*/0)) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) { + if(metadata_picture_has_type1) /* there should only be 1 per stream */ + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + metadata_picture_has_type1 = true; + /* standard icon must be 32x32 pixel PNG */ + if( + m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD && + ( + (strcmp(m->data.picture.mime_type, "image/png") && strcmp(m->data.picture.mime_type, "-->")) || + m->data.picture.width != 32 || + m->data.picture.height != 32 + ) + ) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + } + else if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) { + if(metadata_picture_has_type2) /* there should only be 1 per stream */ + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + metadata_picture_has_type2 = true; + } } } encoder->private_->input_capacity = 0; for(i = 0; i < encoder->protected_->channels; i++) { encoder->private_->integer_signal_unaligned[i] = encoder->private_->integer_signal[i] = 0; +#ifndef FLAC__INTEGER_ONLY_LIBRARY encoder->private_->real_signal_unaligned[i] = encoder->private_->real_signal[i] = 0; +#endif } for(i = 0; i < 2; i++) { encoder->private_->integer_signal_mid_side_unaligned[i] = encoder->private_->integer_signal_mid_side[i] = 0; +#ifndef FLAC__INTEGER_ONLY_LIBRARY encoder->private_->real_signal_mid_side_unaligned[i] = encoder->private_->real_signal_mid_side[i] = 0; +#endif } +#ifndef FLAC__INTEGER_ONLY_LIBRARY + for(i = 0; i < encoder->protected_->num_apodizations; i++) + encoder->private_->window_unaligned[i] = encoder->private_->window[i] = 0; + encoder->private_->windowed_signal_unaligned = encoder->private_->windowed_signal = 0; +#endif for(i = 0; i < encoder->protected_->channels; i++) { encoder->private_->residual_workspace_unaligned[i][0] = encoder->private_->residual_workspace[i][0] = 0; encoder->private_->residual_workspace_unaligned[i][1] = encoder->private_->residual_workspace[i][1] = 0; @@ -716,11 +850,19 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder encoder->private_->residual_workspace_mid_side_unaligned[i][1] = encoder->private_->residual_workspace_mid_side[i][1] = 0; encoder->private_->best_subframe_mid_side[i] = 0; } - encoder->private_->abs_residual_unaligned = encoder->private_->abs_residual = 0; encoder->private_->abs_residual_partition_sums_unaligned = encoder->private_->abs_residual_partition_sums = 0; encoder->private_->raw_bits_per_partition_unaligned = encoder->private_->raw_bits_per_partition = 0; - encoder->private_->loose_mid_side_stereo_frames_exact = (double)encoder->protected_->sample_rate * 0.4 / (double)encoder->protected_->blocksize; - encoder->private_->loose_mid_side_stereo_frames = (unsigned)(encoder->private_->loose_mid_side_stereo_frames_exact + 0.5); +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->loose_mid_side_stereo_frames = (unsigned)((FLAC__double)encoder->protected_->sample_rate * 0.4 / (FLAC__double)encoder->protected_->blocksize + 0.5); +#else + /* 26214 is the approximate fixed-point equivalent to 0.4 (0.4 * 2^16) */ + /* sample rate can be up to 655350 Hz, and thus use 20 bits, so we do the multiply÷ by hand */ + FLAC__ASSERT(FLAC__MAX_SAMPLE_RATE <= 655350); + FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535); + FLAC__ASSERT(encoder->protected_->sample_rate <= 655350); + FLAC__ASSERT(encoder->protected_->blocksize <= 65535); + encoder->private_->loose_mid_side_stereo_frames = (unsigned)FLAC__fixedpoint_trunc((((FLAC__uint64)(encoder->protected_->sample_rate) * (FLAC__uint64)(26214)) << 16) / (encoder->protected_->blocksize<<16) + FLAC__FP_ONE_HALF); +#endif if(encoder->private_->loose_mid_side_stereo_frames == 0) encoder->private_->loose_mid_side_stereo_frames = 1; encoder->private_->loose_mid_side_stereo_frame_count = 0; @@ -728,7 +870,7 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder encoder->private_->current_frame_number = 0; encoder->private_->use_wide_by_block = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(encoder->protected_->blocksize)+1 > 30); - encoder->private_->use_wide_by_order = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(max(encoder->protected_->max_lpc_order, FLAC__MAX_FIXED_ORDER))+1 > 30); /*@@@ need to use this? */ + encoder->private_->use_wide_by_order = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(flac_max(encoder->protected_->max_lpc_order, FLAC__MAX_FIXED_ORDER))+1 > 30); /*@@@ need to use this? */ encoder->private_->use_wide_by_partition = (false); /*@@@ need to set this */ /* @@ -736,37 +878,41 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder */ FLAC__cpu_info(&encoder->private_->cpuinfo); /* first default to the non-asm routines */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; +#endif + encoder->private_->local_precompute_partition_info_sums = precompute_partition_info_sums_; encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor; + encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide; +#ifndef FLAC__INTEGER_ONLY_LIBRARY encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients; encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide; encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients; +#endif /* now override with asm where appropriate */ -#ifndef FLAC__NO_ASM +#ifndef FLAC__INTEGER_ONLY_LIBRARY +# ifndef FLAC__NO_ASM if(encoder->private_->cpuinfo.use_asm) { -#ifdef FLAC__CPU_IA32 +# ifdef FLAC__CPU_IA32 FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32); -#ifdef FLAC__HAS_NASM -#ifdef FLAC__SSE_OS - if(encoder->private_->cpuinfo.data.ia32.sse) { +# ifdef FLAC__HAS_NASM + if(encoder->private_->cpuinfo.ia32.sse) { if(encoder->protected_->max_lpc_order < 4) encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4; else if(encoder->protected_->max_lpc_order < 8) encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8; else if(encoder->protected_->max_lpc_order < 12) encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12; + else if(encoder->protected_->max_lpc_order < 16) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16; else encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32; } else -#endif - if(encoder->private_->cpuinfo.data.ia32._3dnow) - encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow; - else encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32; - if(encoder->private_->cpuinfo.data.ia32.mmx && encoder->private_->cpuinfo.data.ia32.cmov) - encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov; - if(encoder->private_->cpuinfo.data.ia32.mmx) { + + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32; /* OPT_IA32: was really necessary for GCC < 4.9 */ + if(encoder->private_->cpuinfo.ia32.mmx) { encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32; encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx; } @@ -774,25 +920,166 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32; encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32; } -#endif -#endif + + if(encoder->private_->cpuinfo.ia32.mmx && encoder->private_->cpuinfo.ia32.cmov) + encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov; +# endif /* FLAC__HAS_NASM */ +# ifdef FLAC__HAS_X86INTRIN +# if defined FLAC__SSE_SUPPORTED + if(encoder->private_->cpuinfo.ia32.sse) { + if(encoder->protected_->max_lpc_order < 4) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4; + else if(encoder->protected_->max_lpc_order < 8) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8; + else if(encoder->protected_->max_lpc_order < 12) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12; + else if(encoder->protected_->max_lpc_order < 16) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16; + else + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation; + } +# endif + +# ifdef FLAC__SSE2_SUPPORTED + if(encoder->private_->cpuinfo.ia32.sse2) { + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2; + } +# endif +# ifdef FLAC__SSE4_1_SUPPORTED + if(encoder->private_->cpuinfo.ia32.sse41) { + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41; + } +# endif +# ifdef FLAC__AVX2_SUPPORTED + if(encoder->private_->cpuinfo.ia32.avx2) { + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2; + } +# endif + +# ifdef FLAC__SSE2_SUPPORTED + if (encoder->private_->cpuinfo.ia32.sse2) { + encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_sse2; + encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_sse2; + } +# endif +# ifdef FLAC__SSSE3_SUPPORTED + if (encoder->private_->cpuinfo.ia32.ssse3) { + encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_ssse3; + encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_ssse3; + } +# endif +# endif /* FLAC__HAS_X86INTRIN */ +# elif defined FLAC__CPU_X86_64 + FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_X86_64); +# ifdef FLAC__HAS_X86INTRIN +# ifdef FLAC__SSE_SUPPORTED + if(encoder->protected_->max_lpc_order < 4) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4; + else if(encoder->protected_->max_lpc_order < 8) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8; + else if(encoder->protected_->max_lpc_order < 12) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12; + else if(encoder->protected_->max_lpc_order < 16) + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16; +# endif + +# ifdef FLAC__SSE2_SUPPORTED + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2; +# endif +# ifdef FLAC__SSE4_1_SUPPORTED + if(encoder->private_->cpuinfo.x86.sse41) { + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41; + } +# endif +# ifdef FLAC__AVX2_SUPPORTED + if(encoder->private_->cpuinfo.x86.avx2) { + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2; + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2; + } +# endif + +# ifdef FLAC__SSE2_SUPPORTED + encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_sse2; + encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_sse2; +# endif +# ifdef FLAC__SSSE3_SUPPORTED + if (encoder->private_->cpuinfo.x86.ssse3) { + encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_intrin_ssse3; + encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_ssse3; + } +# endif +# endif /* FLAC__HAS_X86INTRIN */ +# endif /* FLAC__CPU_... */ } -#endif +# endif /* !FLAC__NO_ASM */ +#endif /* !FLAC__INTEGER_ONLY_LIBRARY */ +#if !defined FLAC__NO_ASM && defined FLAC__HAS_X86INTRIN + if(encoder->private_->cpuinfo.use_asm) { +# if defined FLAC__CPU_IA32 +# ifdef FLAC__SSE2_SUPPORTED + if(encoder->private_->cpuinfo.ia32.sse2) + encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_sse2; +# endif +# ifdef FLAC__SSSE3_SUPPORTED + if(encoder->private_->cpuinfo.ia32.ssse3) + encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_ssse3; +# endif +# ifdef FLAC__AVX2_SUPPORTED + if(encoder->private_->cpuinfo.ia32.avx2) + encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_avx2; +# endif +# elif defined FLAC__CPU_X86_64 +# ifdef FLAC__SSE2_SUPPORTED + encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_sse2; +# endif +# ifdef FLAC__SSSE3_SUPPORTED + if(encoder->private_->cpuinfo.x86.ssse3) + encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_ssse3; +# endif +# ifdef FLAC__AVX2_SUPPORTED + if(encoder->private_->cpuinfo.x86.avx2) + encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_avx2; +# endif +# endif /* FLAC__CPU_... */ + } +#endif /* !FLAC__NO_ASM && FLAC__HAS_X86INTRIN */ /* finally override based on wide-ness if necessary */ if(encoder->private_->use_wide_by_block) { - encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_wide; + encoder->private_->local_fixed_compute_best_predictor = encoder->private_->local_fixed_compute_best_predictor_wide; + } + + /* set state to OK; from here on, errors are fatal and we'll override the state then */ + encoder->protected_->state = FLAC__STREAM_ENCODER_OK; + +#if FLAC__HAS_OGG + encoder->private_->is_ogg = is_ogg; + if(is_ogg && !FLAC__ogg_encoder_aspect_init(&encoder->protected_->ogg_encoder_aspect)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; } +#endif - /* we require precompute_partition_sums if do_escape_coding because of their intertwined nature */ - encoder->private_->precompute_partition_sums = (encoder->protected_->max_residual_partition_order > encoder->protected_->min_residual_partition_order) || encoder->protected_->do_escape_coding; + encoder->private_->read_callback = read_callback; + encoder->private_->write_callback = write_callback; + encoder->private_->seek_callback = seek_callback; + encoder->private_->tell_callback = tell_callback; + encoder->private_->metadata_callback = metadata_callback; + encoder->private_->client_data = client_data; if(!resize_buffers_(encoder, encoder->protected_->blocksize)) { /* the above function sets the state for us in case of an error */ - return encoder->protected_->state; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; } - if(!FLAC__bitbuffer_init(encoder->private_->frame)) - return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + if(!FLAC__bitwriter_init(encoder->private_->frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } /* * Set up the verify stuff if necessary @@ -802,27 +1089,30 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder * First, set up the fifo which will hold the * original signal to compare against */ - encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize; + encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize+OVERREAD_; for(i = 0; i < encoder->protected_->channels; i++) { - if(0 == (encoder->private_->verify.input_fifo.data[i] = (FLAC__int32*)malloc(sizeof(FLAC__int32) * encoder->private_->verify.input_fifo.size))) - return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + if(0 == (encoder->private_->verify.input_fifo.data[i] = safe_malloc_mul_2op_p(sizeof(FLAC__int32), /*times*/encoder->private_->verify.input_fifo.size))) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } } encoder->private_->verify.input_fifo.tail = 0; /* * Now set up a stream decoder for verification */ - encoder->private_->verify.decoder = FLAC__stream_decoder_new(); - if(0 == encoder->private_->verify.decoder) - return encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; - - FLAC__stream_decoder_set_read_callback(encoder->private_->verify.decoder, verify_read_callback_); - FLAC__stream_decoder_set_write_callback(encoder->private_->verify.decoder, verify_write_callback_); - FLAC__stream_decoder_set_metadata_callback(encoder->private_->verify.decoder, verify_metadata_callback_); - FLAC__stream_decoder_set_error_callback(encoder->private_->verify.decoder, verify_error_callback_); - FLAC__stream_decoder_set_client_data(encoder->private_->verify.decoder, encoder); - if(FLAC__stream_decoder_init(encoder->private_->verify.decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA) - return encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; + if(0 == encoder->private_->verify.decoder) { + encoder->private_->verify.decoder = FLAC__stream_decoder_new(); + if(0 == encoder->private_->verify.decoder) { + encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + } + + if(FLAC__stream_decoder_init_stream(encoder->private_->verify.decoder, verify_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, verify_write_callback_, verify_metadata_callback_, verify_error_callback_, /*client_data=*/encoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } } encoder->private_->verify.error_stats.absolute_sample = 0; encoder->private_->verify.error_stats.frame_number = 0; @@ -832,15 +1122,27 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder encoder->private_->verify.error_stats.got = 0; /* + * These must be done before we write any metadata, because that + * calls the write_callback, which uses these values. + */ + encoder->private_->first_seekpoint_to_check = 0; + encoder->private_->samples_written = 0; + encoder->protected_->streaminfo_offset = 0; + encoder->protected_->seektable_offset = 0; + encoder->protected_->audio_offset = 0; + + /* * write the stream header */ if(encoder->protected_->verify) encoder->private_->verify.state_hint = ENCODER_IN_MAGIC; - if(!FLAC__bitbuffer_write_raw_uint32(encoder->private_->frame, FLAC__STREAM_SYNC, FLAC__STREAM_SYNC_LEN)) - return encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - if(!write_bitbuffer_(encoder, 0)) { + if(!FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, FLAC__STREAM_SYNC, FLAC__STREAM_SYNC_LEN)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { /* the above function sets the state for us in case of an error */ - return encoder->protected_->state; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; } /* @@ -848,45 +1150,46 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder */ if(encoder->protected_->verify) encoder->private_->verify.state_hint = ENCODER_IN_METADATA; - encoder->private_->metadata.type = FLAC__METADATA_TYPE_STREAMINFO; - encoder->private_->metadata.is_last = false; /* we will have at a minimum a VORBIS_COMMENT afterwards */ - encoder->private_->metadata.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; - encoder->private_->metadata.data.stream_info.min_blocksize = encoder->protected_->blocksize; /* this encoder uses the same blocksize for the whole stream */ - encoder->private_->metadata.data.stream_info.max_blocksize = encoder->protected_->blocksize; - encoder->private_->metadata.data.stream_info.min_framesize = 0; /* we don't know this yet; have to fill it in later */ - encoder->private_->metadata.data.stream_info.max_framesize = 0; /* we don't know this yet; have to fill it in later */ - encoder->private_->metadata.data.stream_info.sample_rate = encoder->protected_->sample_rate; - encoder->private_->metadata.data.stream_info.channels = encoder->protected_->channels; - encoder->private_->metadata.data.stream_info.bits_per_sample = encoder->protected_->bits_per_sample; - encoder->private_->metadata.data.stream_info.total_samples = encoder->protected_->total_samples_estimate; /* we will replace this later with the real total */ - memset(encoder->private_->metadata.data.stream_info.md5sum, 0, 16); /* we don't know this yet; have to fill it in later */ - FLAC__MD5Init(&encoder->private_->md5context); - if(!FLAC__bitbuffer_clear(encoder->private_->frame)) - return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; - if(!FLAC__add_metadata_block(&encoder->private_->metadata, encoder->private_->frame)) - return encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - if(!write_bitbuffer_(encoder, 0)) { + encoder->private_->streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO; + encoder->private_->streaminfo.is_last = false; /* we will have at a minimum a VORBIS_COMMENT afterwards */ + encoder->private_->streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; + encoder->private_->streaminfo.data.stream_info.min_blocksize = encoder->protected_->blocksize; /* this encoder uses the same blocksize for the whole stream */ + encoder->private_->streaminfo.data.stream_info.max_blocksize = encoder->protected_->blocksize; + encoder->private_->streaminfo.data.stream_info.min_framesize = 0; /* we don't know this yet; have to fill it in later */ + encoder->private_->streaminfo.data.stream_info.max_framesize = 0; /* we don't know this yet; have to fill it in later */ + encoder->private_->streaminfo.data.stream_info.sample_rate = encoder->protected_->sample_rate; + encoder->private_->streaminfo.data.stream_info.channels = encoder->protected_->channels; + encoder->private_->streaminfo.data.stream_info.bits_per_sample = encoder->protected_->bits_per_sample; + encoder->private_->streaminfo.data.stream_info.total_samples = encoder->protected_->total_samples_estimate; /* we will replace this later with the real total */ + memset(encoder->private_->streaminfo.data.stream_info.md5sum, 0, 16); /* we don't know this yet; have to fill it in later */ + if(encoder->protected_->do_md5) + FLAC__MD5Init(&encoder->private_->md5context); + if(!FLAC__add_metadata_block(&encoder->private_->streaminfo, encoder->private_->frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { /* the above function sets the state for us in case of an error */ - return encoder->protected_->state; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; } /* * Now that the STREAMINFO block is written, we can init this to an * absurdly-high value... */ - encoder->private_->metadata.data.stream_info.min_framesize = (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN) - 1; + encoder->private_->streaminfo.data.stream_info.min_framesize = (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN) - 1; /* ... and clear this to 0 */ - encoder->private_->metadata.data.stream_info.total_samples = 0; + encoder->private_->streaminfo.data.stream_info.total_samples = 0; /* * Check to see if the supplied metadata contains a VORBIS_COMMENT; * if not, we will write an empty one (FLAC__add_metadata_block() * automatically supplies the vendor string). * - * WATCHOUT: libOggFLAC depends on us to write this block after the - * STREAMINFO since that's what the mapping requires. (In the case - * that metadata_has_vorbis_comment it true it will have already - * insured that the metadata list is properly ordered.) + * WATCHOUT: the Ogg FLAC mapping requires us to write this block after + * the STREAMINFO. (In the case that metadata_has_vorbis_comment is + * true it will have already insured that the metadata list is properly + * ordered.) */ if(!metadata_has_vorbis_comment) { FLAC__StreamMetadata vorbis_comment; @@ -897,13 +1200,13 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder vorbis_comment.data.vorbis_comment.vendor_string.entry = 0; vorbis_comment.data.vorbis_comment.num_comments = 0; vorbis_comment.data.vorbis_comment.comments = 0; - if(!FLAC__bitbuffer_clear(encoder->private_->frame)) - return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; - if(!FLAC__add_metadata_block(&vorbis_comment, encoder->private_->frame)) - return encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - if(!write_bitbuffer_(encoder, 0)) { + if(!FLAC__add_metadata_block(&vorbis_comment, encoder->private_->frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { /* the above function sets the state for us in case of an error */ - return encoder->protected_->state; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; } } @@ -912,90 +1215,335 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder */ for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) { encoder->protected_->metadata[i]->is_last = (i == encoder->protected_->num_metadata_blocks - 1); - if(!FLAC__bitbuffer_clear(encoder->private_->frame)) - return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; - if(!FLAC__add_metadata_block(encoder->protected_->metadata[i], encoder->private_->frame)) - return encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; - if(!write_bitbuffer_(encoder, 0)) { + if(!FLAC__add_metadata_block(encoder->protected_->metadata[i], encoder->private_->frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) { /* the above function sets the state for us in case of an error */ - return encoder->protected_->state; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; } } + /* now that all the metadata is written, we save the stream offset */ + if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) { /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */ + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + if(encoder->protected_->verify) encoder->private_->verify.state_hint = ENCODER_IN_AUDIO; - return encoder->protected_->state; + return FLAC__STREAM_ENCODER_INIT_STATUS_OK; } -FLAC_API void FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder) +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream( + FLAC__StreamEncoder *encoder, + FLAC__StreamEncoderWriteCallback write_callback, + FLAC__StreamEncoderSeekCallback seek_callback, + FLAC__StreamEncoderTellCallback tell_callback, + FLAC__StreamEncoderMetadataCallback metadata_callback, + void *client_data +) { + return init_stream_internal_( + encoder, + /*read_callback=*/0, + write_callback, + seek_callback, + tell_callback, + metadata_callback, + client_data, + /*is_ogg=*/false + ); +} + +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream( + FLAC__StreamEncoder *encoder, + FLAC__StreamEncoderReadCallback read_callback, + FLAC__StreamEncoderWriteCallback write_callback, + FLAC__StreamEncoderSeekCallback seek_callback, + FLAC__StreamEncoderTellCallback tell_callback, + FLAC__StreamEncoderMetadataCallback metadata_callback, + void *client_data +) +{ + return init_stream_internal_( + encoder, + read_callback, + write_callback, + seek_callback, + tell_callback, + metadata_callback, + client_data, + /*is_ogg=*/true + ); +} + +static FLAC__StreamEncoderInitStatus init_FILE_internal_( + FLAC__StreamEncoder *encoder, + FILE *file, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data, + FLAC__bool is_ogg +) +{ + FLAC__StreamEncoderInitStatus init_status; + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != file); + + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED; + + /* double protection */ + if(file == 0) { + encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + + /* + * To make sure that our file does not go unclosed after an error, we + * must assign the FILE pointer before any further error can occur in + * this routine. + */ + if(file == stdout) + file = get_binary_stdout_(); /* just to be safe */ + +#ifdef _WIN32 + /* + * Windows can suffer quite badly from disk fragmentation. This can be + * reduced significantly by setting the output buffer size to be 10MB. + */ + setvbuf(file, NULL, _IOFBF, 10*1024*1024); +#endif + encoder->private_->file = file; + + encoder->private_->progress_callback = progress_callback; + encoder->private_->bytes_written = 0; + encoder->private_->samples_written = 0; + encoder->private_->frames_written = 0; + + init_status = init_stream_internal_( + encoder, + encoder->private_->file == stdout? 0 : is_ogg? file_read_callback_ : 0, + file_write_callback_, + encoder->private_->file == stdout? 0 : file_seek_callback_, + encoder->private_->file == stdout? 0 : file_tell_callback_, + /*metadata_callback=*/0, + client_data, + is_ogg + ); + if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { + /* the above function sets the state for us in case of an error */ + return init_status; + } + + { + unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder); + + FLAC__ASSERT(blocksize != 0); + encoder->private_->total_frames_estimate = (unsigned)((FLAC__stream_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize); + } + + return init_status; +} + +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE( + FLAC__StreamEncoder *encoder, + FILE *file, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data +) +{ + return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/false); +} + +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE( + FLAC__StreamEncoder *encoder, + FILE *file, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data +) +{ + return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/true); +} + +static FLAC__StreamEncoderInitStatus init_file_internal_( + FLAC__StreamEncoder *encoder, + const char *filename, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data, + FLAC__bool is_ogg +) +{ + FILE *file; + + FLAC__ASSERT(0 != encoder); + + /* + * To make sure that our file does not go unclosed after an error, we + * have to do the same entrance checks here that are later performed + * in FLAC__stream_encoder_init_FILE() before the FILE* is assigned. + */ + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED; + + file = filename? flac_fopen(filename, "w+b") : stdout; + + if(file == 0) { + encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR; + return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR; + } + + return init_FILE_internal_(encoder, file, progress_callback, client_data, is_ogg); +} + +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file( + FLAC__StreamEncoder *encoder, + const char *filename, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data +) +{ + return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/false); +} + +FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file( + FLAC__StreamEncoder *encoder, + const char *filename, + FLAC__StreamEncoderProgressCallback progress_callback, + void *client_data +) +{ + return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/true); +} + +FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder) +{ + FLAC__bool error = false; + + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state == FLAC__STREAM_ENCODER_UNINITIALIZED) - return; + return true; if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) { if(encoder->private_->current_sample_number != 0) { + const FLAC__bool is_fractional_block = encoder->protected_->blocksize != encoder->private_->current_sample_number; encoder->protected_->blocksize = encoder->private_->current_sample_number; - process_frame_(encoder, true); /* true => is last frame */ + if(!process_frame_(encoder, is_fractional_block, /*is_last_block=*/true)) + error = true; } } - FLAC__MD5Final(encoder->private_->metadata.data.stream_info.md5sum, &encoder->private_->md5context); + if(encoder->protected_->do_md5) + FLAC__MD5Final(encoder->private_->streaminfo.data.stream_info.md5sum, &encoder->private_->md5context); - if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) { - encoder->private_->metadata_callback(encoder, &encoder->private_->metadata, encoder->private_->client_data); + if(!encoder->private_->is_being_deleted) { + if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK) { + if(encoder->private_->seek_callback) { +#if FLAC__HAS_OGG + if(encoder->private_->is_ogg) + update_ogg_metadata_(encoder); + else +#endif + update_metadata_(encoder); + + /* check if an error occurred while updating metadata */ + if(encoder->protected_->state != FLAC__STREAM_ENCODER_OK) + error = true; + } + if(encoder->private_->metadata_callback) + encoder->private_->metadata_callback(encoder, &encoder->private_->streaminfo, encoder->private_->client_data); + } + + if(encoder->protected_->verify && 0 != encoder->private_->verify.decoder && !FLAC__stream_decoder_finish(encoder->private_->verify.decoder)) { + if(!error) + encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA; + error = true; + } + } + + if(0 != encoder->private_->file) { + if(encoder->private_->file != stdout) + fclose(encoder->private_->file); + encoder->private_->file = 0; } - if(encoder->protected_->verify && 0 != encoder->private_->verify.decoder) - FLAC__stream_decoder_finish(encoder->private_->verify.decoder); +#if FLAC__HAS_OGG + if(encoder->private_->is_ogg) + FLAC__ogg_encoder_aspect_finish(&encoder->protected_->ogg_encoder_aspect); +#endif free_(encoder); set_defaults_(encoder); - encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED; + if(!error) + encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED; + + return !error; } -FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value) +FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; - encoder->protected_->verify = value; +#if FLAC__HAS_OGG + /* can't check encoder->private_->is_ogg since that's not set until init time */ + FLAC__ogg_encoder_aspect_set_serial_number(&encoder->protected_->ogg_encoder_aspect, value); return true; +#else + (void)value; + return false; +#endif } -FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value) +FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; - encoder->protected_->streamable_subset = value; +#ifndef FLAC__MANDATORY_VERIFY_WHILE_ENCODING + encoder->protected_->verify = value; +#endif return true; } -FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value) +FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; - encoder->protected_->do_mid_side_stereo = value; + encoder->protected_->streamable_subset = value; return true; } -FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value) +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; - encoder->protected_->loose_mid_side_stereo = value; + encoder->protected_->do_md5 = value; return true; } FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->protected_->channels = value; @@ -1005,6 +1553,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encod FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->protected_->bits_per_sample = value; @@ -1014,24 +1564,199 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->protected_->sample_rate = value; return true; } +FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__bool ok = true; + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + if(value >= sizeof(compression_levels_)/sizeof(compression_levels_[0])) + value = sizeof(compression_levels_)/sizeof(compression_levels_[0]) - 1; + ok &= FLAC__stream_encoder_set_do_mid_side_stereo (encoder, compression_levels_[value].do_mid_side_stereo); + ok &= FLAC__stream_encoder_set_loose_mid_side_stereo (encoder, compression_levels_[value].loose_mid_side_stereo); +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#if 1 + ok &= FLAC__stream_encoder_set_apodization (encoder, compression_levels_[value].apodization); +#else + /* equivalent to -A tukey(0.5) */ + encoder->protected_->num_apodizations = 1; + encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY; + encoder->protected_->apodizations[0].parameters.tukey.p = 0.5; +#endif +#endif + ok &= FLAC__stream_encoder_set_max_lpc_order (encoder, compression_levels_[value].max_lpc_order); + ok &= FLAC__stream_encoder_set_qlp_coeff_precision (encoder, compression_levels_[value].qlp_coeff_precision); + ok &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search (encoder, compression_levels_[value].do_qlp_coeff_prec_search); + ok &= FLAC__stream_encoder_set_do_escape_coding (encoder, compression_levels_[value].do_escape_coding); + ok &= FLAC__stream_encoder_set_do_exhaustive_model_search (encoder, compression_levels_[value].do_exhaustive_model_search); + ok &= FLAC__stream_encoder_set_min_residual_partition_order(encoder, compression_levels_[value].min_residual_partition_order); + ok &= FLAC__stream_encoder_set_max_residual_partition_order(encoder, compression_levels_[value].max_residual_partition_order); + ok &= FLAC__stream_encoder_set_rice_parameter_search_dist (encoder, compression_levels_[value].rice_parameter_search_dist); + return ok; +} + FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->protected_->blocksize = value; return true; } +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->do_mid_side_stereo = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->loose_mid_side_stereo = value; + return true; +} + +/*@@@@add to tests*/ +FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != specification); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; +#ifdef FLAC__INTEGER_ONLY_LIBRARY + (void)specification; /* silently ignore since we haven't integerized; will always use a rectangular window */ +#else + encoder->protected_->num_apodizations = 0; + while(1) { + const char *s = strchr(specification, ';'); + const size_t n = s? (size_t)(s - specification) : strlen(specification); + if (n==8 && 0 == strncmp("bartlett" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT; + else if(n==13 && 0 == strncmp("bartlett_hann", specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT_HANN; + else if(n==8 && 0 == strncmp("blackman" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN; + else if(n==26 && 0 == strncmp("blackman_harris_4term_92db", specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE; + else if(n==6 && 0 == strncmp("connes" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_CONNES; + else if(n==7 && 0 == strncmp("flattop" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_FLATTOP; + else if(n>7 && 0 == strncmp("gauss(" , specification, 6)) { + FLAC__real stddev = (FLAC__real)strtod(specification+6, 0); + if (stddev > 0.0 && stddev <= 0.5) { + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.gauss.stddev = stddev; + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_GAUSS; + } + } + else if(n==7 && 0 == strncmp("hamming" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HAMMING; + else if(n==4 && 0 == strncmp("hann" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HANN; + else if(n==13 && 0 == strncmp("kaiser_bessel", specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_KAISER_BESSEL; + else if(n==7 && 0 == strncmp("nuttall" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_NUTTALL; + else if(n==9 && 0 == strncmp("rectangle" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_RECTANGLE; + else if(n==8 && 0 == strncmp("triangle" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TRIANGLE; + else if(n>7 && 0 == strncmp("tukey(" , specification, 6)) { + FLAC__real p = (FLAC__real)strtod(specification+6, 0); + if (p >= 0.0 && p <= 1.0) { + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = p; + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; + } + } + else if(n>15 && 0 == strncmp("partial_tukey(" , specification, 14)) { + FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+14, 0); + const char *si_1 = strchr(specification, '/'); + FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.1f; + FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f; + const char *si_2 = strchr((si_1?(si_1+1):specification), '/'); + FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f; + + if (tukey_parts <= 1) { + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p; + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; + }else if (encoder->protected_->num_apodizations + tukey_parts < 32){ + FLAC__int32 m; + for(m = 0; m < tukey_parts; m++){ + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p; + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units); + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units); + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PARTIAL_TUKEY; + } + } + } + else if(n>16 && 0 == strncmp("punchout_tukey(" , specification, 15)) { + FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+15, 0); + const char *si_1 = strchr(specification, '/'); + FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.2f; + FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f; + const char *si_2 = strchr((si_1?(si_1+1):specification), '/'); + FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f; + + if (tukey_parts <= 1) { + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p; + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; + }else if (encoder->protected_->num_apodizations + tukey_parts < 32){ + FLAC__int32 m; + for(m = 0; m < tukey_parts; m++){ + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p; + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units); + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units); + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PUNCHOUT_TUKEY; + } + } + } + else if(n==5 && 0 == strncmp("welch" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_WELCH; + if (encoder->protected_->num_apodizations == 32) + break; + if (s) + specification = s+1; + else + break; + } + if(encoder->protected_->num_apodizations == 0) { + encoder->protected_->num_apodizations = 1; + encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY; + encoder->protected_->apodizations[0].parameters.tukey.p = 0.5; + } +#endif + return true; +} + FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->protected_->max_lpc_order = value; @@ -1041,6 +1766,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder * FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->protected_->qlp_coeff_precision = value; @@ -1050,6 +1777,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEnc FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->protected_->do_qlp_coeff_prec_search = value; @@ -1059,6 +1788,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__Stre FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; #if 0 @@ -1073,6 +1804,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncode FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->protected_->do_exhaustive_model_search = value; @@ -1082,6 +1815,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__St FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->protected_->min_residual_partition_order = value; @@ -1091,6 +1826,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__ FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->protected_->max_residual_partition_order = value; @@ -1100,6 +1837,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__ FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; #if 0 @@ -1114,6 +1853,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__St FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->protected_->total_samples_estimate = value; @@ -1123,39 +1864,32 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__Stream FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; - encoder->protected_->metadata = metadata; - encoder->protected_->num_metadata_blocks = num_blocks; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_write_callback(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteCallback value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != value); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->private_->write_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata_callback(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderMetadataCallback value) -{ - FLAC__ASSERT(0 != encoder); - FLAC__ASSERT(0 != value); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) - return false; - encoder->private_->metadata_callback = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_set_client_data(FLAC__StreamEncoder *encoder, void *value) -{ - FLAC__ASSERT(0 != encoder); - if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + if(0 == metadata) + num_blocks = 0; + if(0 == num_blocks) + metadata = 0; + /* realloc() does not do exactly what we want so... */ + if(encoder->protected_->metadata) { + free(encoder->protected_->metadata); + encoder->protected_->metadata = 0; + encoder->protected_->num_metadata_blocks = 0; + } + if(num_blocks) { + FLAC__StreamMetadata **m; + if(0 == (m = safe_malloc_mul_2op_p(sizeof(m[0]), /*times*/num_blocks))) + return false; + memcpy(m, metadata, sizeof(m[0]) * num_blocks); + encoder->protected_->metadata = m; + encoder->protected_->num_metadata_blocks = num_blocks; + } +#if FLAC__HAS_OGG + if(!FLAC__ogg_encoder_aspect_set_num_metadata(&encoder->protected_->ogg_encoder_aspect, num_blocks)) return false; - encoder->private_->client_data = value; +#endif return true; } @@ -1166,6 +1900,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_client_data(FLAC__StreamEncoder *en FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->private_->disable_constant_subframes = value; @@ -1175,6 +1911,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__Stream FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->private_->disable_fixed_subframes = value; @@ -1184,6 +1922,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEnc FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) return false; encoder->private_->disable_verbatim_subframes = value; @@ -1193,12 +1933,16 @@ FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__Stream FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->state; } FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->verify) return FLAC__stream_decoder_get_state(encoder->private_->verify.decoder); else @@ -1207,6 +1951,9 @@ FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state( FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder) { + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) return FLAC__StreamEncoderStateString[encoder->protected_->state]; else @@ -1216,6 +1963,8 @@ FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__ FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); if(0 != absolute_sample) *absolute_sample = encoder->private_->verify.error_stats.absolute_sample; if(0 != frame_number) @@ -1233,161 +1982,195 @@ FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__St FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->verify; } FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->streamable_subset; } -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder) +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_md5(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); - return encoder->protected_->do_mid_side_stereo; -} - -FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder) -{ - FLAC__ASSERT(0 != encoder); - return encoder->protected_->loose_mid_side_stereo; + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->do_md5; } FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->channels; } FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->bits_per_sample; } FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->sample_rate; } FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->blocksize; } +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->do_mid_side_stereo; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->loose_mid_side_stereo; +} + FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->max_lpc_order; } FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->qlp_coeff_precision; } FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->do_qlp_coeff_prec_search; } FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->do_escape_coding; } FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->do_exhaustive_model_search; } FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->min_residual_partition_order; } FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->max_residual_partition_order; } FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->rice_parameter_search_dist; } FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); return encoder->protected_->total_samples_estimate; } FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples) { - unsigned i, j, channel; - FLAC__int32 x, mid, side; + unsigned i, j = 0, channel; const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize; FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK); - j = 0; - if(encoder->protected_->do_mid_side_stereo && channels == 2) { - do { - if(encoder->protected_->verify) - append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize-encoder->private_->current_sample_number, samples-j)); + do { + const unsigned n = flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j); - for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) { - x = mid = side = buffer[0][j]; - encoder->private_->integer_signal[0][i] = x; - encoder->private_->real_signal[0][i] = (FLAC__real)x; - x = buffer[1][j]; - encoder->private_->integer_signal[1][i] = x; - encoder->private_->real_signal[1][i] = (FLAC__real)x; - mid += x; - side -= x; - mid >>= 1; /* NOTE: not the same as 'mid = (buffer[0][j] + buffer[1][j]) / 2' ! */ - encoder->private_->integer_signal_mid_side[1][i] = side; - encoder->private_->integer_signal_mid_side[0][i] = mid; - encoder->private_->real_signal_mid_side[1][i] = (FLAC__real)side; - encoder->private_->real_signal_mid_side[0][i] = (FLAC__real)mid; - encoder->private_->current_sample_number++; - } - if(i == blocksize) { - if(!process_frame_(encoder, false)) /* false => not last frame */ - return false; - } - } while(j < samples); - } - else { - do { - if(encoder->protected_->verify) - append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize-encoder->private_->current_sample_number, samples-j)); + if(encoder->protected_->verify) + append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, n); - for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) { - for(channel = 0; channel < channels; channel++) { - x = buffer[channel][j]; - encoder->private_->integer_signal[channel][i] = x; - encoder->private_->real_signal[channel][i] = (FLAC__real)x; - } - encoder->private_->current_sample_number++; + for(channel = 0; channel < channels; channel++) + memcpy(&encoder->private_->integer_signal[channel][encoder->private_->current_sample_number], &buffer[channel][j], sizeof(buffer[channel][0]) * n); + + if(encoder->protected_->do_mid_side_stereo) { + FLAC__ASSERT(channels == 2); + /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */ + for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) { + encoder->private_->integer_signal_mid_side[1][i] = buffer[0][j] - buffer[1][j]; + encoder->private_->integer_signal_mid_side[0][i] = (buffer[0][j] + buffer[1][j]) >> 1; /* NOTE: not the same as 'mid = (buffer[0][j] + buffer[1][j]) / 2' ! */ } - if(i == blocksize) { - if(!process_frame_(encoder, false)) /* false => not last frame */ - return false; + } + else + j += n; + + encoder->private_->current_sample_number += n; + + /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */ + if(encoder->private_->current_sample_number > blocksize) { + FLAC__ASSERT(encoder->private_->current_sample_number == blocksize+OVERREAD_); + FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */ + if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false)) + return false; + /* move unprocessed overread samples to beginnings of arrays */ + for(channel = 0; channel < channels; channel++) + encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize]; + if(encoder->protected_->do_mid_side_stereo) { + encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][blocksize]; + encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][blocksize]; } - } while(j < samples); - } + encoder->private_->current_sample_number = 1; + } + } while(j < samples); return true; } @@ -1399,52 +2182,74 @@ FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize; FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK); j = k = 0; + /* + * we have several flavors of the same basic loop, optimized for + * different conditions: + */ if(encoder->protected_->do_mid_side_stereo && channels == 2) { + /* + * stereo coding: unroll channel loop + */ do { if(encoder->protected_->verify) - append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize-encoder->private_->current_sample_number, samples-j)); + append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j)); - for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) { - x = mid = side = buffer[k++]; - encoder->private_->integer_signal[0][i] = x; - encoder->private_->real_signal[0][i] = (FLAC__real)x; + /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */ + for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) { + encoder->private_->integer_signal[0][i] = mid = side = buffer[k++]; x = buffer[k++]; encoder->private_->integer_signal[1][i] = x; - encoder->private_->real_signal[1][i] = (FLAC__real)x; mid += x; side -= x; mid >>= 1; /* NOTE: not the same as 'mid = (left + right) / 2' ! */ encoder->private_->integer_signal_mid_side[1][i] = side; encoder->private_->integer_signal_mid_side[0][i] = mid; - encoder->private_->real_signal_mid_side[1][i] = (FLAC__real)side; - encoder->private_->real_signal_mid_side[0][i] = (FLAC__real)mid; - encoder->private_->current_sample_number++; } - if(i == blocksize) { - if(!process_frame_(encoder, false)) /* false => not last frame */ + encoder->private_->current_sample_number = i; + /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */ + if(i > blocksize) { + if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false)) return false; + /* move unprocessed overread samples to beginnings of arrays */ + FLAC__ASSERT(i == blocksize+OVERREAD_); + FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */ + encoder->private_->integer_signal[0][0] = encoder->private_->integer_signal[0][blocksize]; + encoder->private_->integer_signal[1][0] = encoder->private_->integer_signal[1][blocksize]; + encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][blocksize]; + encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][blocksize]; + encoder->private_->current_sample_number = 1; } } while(j < samples); } else { + /* + * independent channel coding: buffer each channel in inner loop + */ do { if(encoder->protected_->verify) - append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize-encoder->private_->current_sample_number, samples-j)); + append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, flac_min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j)); - for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) { - for(channel = 0; channel < channels; channel++) { - x = buffer[k++]; - encoder->private_->integer_signal[channel][i] = x; - encoder->private_->real_signal[channel][i] = (FLAC__real)x; - } - encoder->private_->current_sample_number++; + /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */ + for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) { + for(channel = 0; channel < channels; channel++) + encoder->private_->integer_signal[channel][i] = buffer[k++]; } - if(i == blocksize) { - if(!process_frame_(encoder, false)) /* false => not last frame */ + encoder->private_->current_sample_number = i; + /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */ + if(i > blocksize) { + if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false)) return false; + /* move unprocessed overread samples to beginnings of arrays */ + FLAC__ASSERT(i == blocksize+OVERREAD_); + FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */ + for(channel = 0; channel < channels; channel++) + encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize]; + encoder->private_->current_sample_number = 1; } } while(j < samples); } @@ -1462,14 +2267,24 @@ void set_defaults_(FLAC__StreamEncoder *encoder) { FLAC__ASSERT(0 != encoder); +#ifdef FLAC__MANDATORY_VERIFY_WHILE_ENCODING + encoder->protected_->verify = true; +#else encoder->protected_->verify = false; +#endif encoder->protected_->streamable_subset = true; + encoder->protected_->do_md5 = true; encoder->protected_->do_mid_side_stereo = false; encoder->protected_->loose_mid_side_stereo = false; encoder->protected_->channels = 2; encoder->protected_->bits_per_sample = 16; encoder->protected_->sample_rate = 44100; - encoder->protected_->blocksize = 1152; + encoder->protected_->blocksize = 0; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->protected_->num_apodizations = 1; + encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY; + encoder->protected_->apodizations[0].parameters.tukey.p = 0.5; +#endif encoder->protected_->max_lpc_order = 0; encoder->protected_->qlp_coeff_precision = 0; encoder->protected_->do_qlp_coeff_prec_search = false; @@ -1482,12 +2297,26 @@ void set_defaults_(FLAC__StreamEncoder *encoder) encoder->protected_->metadata = 0; encoder->protected_->num_metadata_blocks = 0; + encoder->private_->seek_table = 0; encoder->private_->disable_constant_subframes = false; encoder->private_->disable_fixed_subframes = false; encoder->private_->disable_verbatim_subframes = false; +#if FLAC__HAS_OGG + encoder->private_->is_ogg = false; +#endif + encoder->private_->read_callback = 0; encoder->private_->write_callback = 0; + encoder->private_->seek_callback = 0; + encoder->private_->tell_callback = 0; encoder->private_->metadata_callback = 0; + encoder->private_->progress_callback = 0; encoder->private_->client_data = 0; + +#if FLAC__HAS_OGG + FLAC__ogg_encoder_aspect_set_defaults(&encoder->protected_->ogg_encoder_aspect); +#endif + + FLAC__stream_encoder_set_compression_level(encoder, 5); } void free_(FLAC__StreamEncoder *encoder) @@ -1495,26 +2324,47 @@ void free_(FLAC__StreamEncoder *encoder) unsigned i, channel; FLAC__ASSERT(0 != encoder); + if(encoder->protected_->metadata) { + free(encoder->protected_->metadata); + encoder->protected_->metadata = 0; + encoder->protected_->num_metadata_blocks = 0; + } for(i = 0; i < encoder->protected_->channels; i++) { if(0 != encoder->private_->integer_signal_unaligned[i]) { free(encoder->private_->integer_signal_unaligned[i]); encoder->private_->integer_signal_unaligned[i] = 0; } +#ifndef FLAC__INTEGER_ONLY_LIBRARY if(0 != encoder->private_->real_signal_unaligned[i]) { free(encoder->private_->real_signal_unaligned[i]); encoder->private_->real_signal_unaligned[i] = 0; } +#endif } for(i = 0; i < 2; i++) { if(0 != encoder->private_->integer_signal_mid_side_unaligned[i]) { free(encoder->private_->integer_signal_mid_side_unaligned[i]); encoder->private_->integer_signal_mid_side_unaligned[i] = 0; } +#ifndef FLAC__INTEGER_ONLY_LIBRARY if(0 != encoder->private_->real_signal_mid_side_unaligned[i]) { free(encoder->private_->real_signal_mid_side_unaligned[i]); encoder->private_->real_signal_mid_side_unaligned[i] = 0; } +#endif + } +#ifndef FLAC__INTEGER_ONLY_LIBRARY + for(i = 0; i < encoder->protected_->num_apodizations; i++) { + if(0 != encoder->private_->window_unaligned[i]) { + free(encoder->private_->window_unaligned[i]); + encoder->private_->window_unaligned[i] = 0; + } } + if(0 != encoder->private_->windowed_signal_unaligned) { + free(encoder->private_->windowed_signal_unaligned); + encoder->private_->windowed_signal_unaligned = 0; + } +#endif for(channel = 0; channel < encoder->protected_->channels; channel++) { for(i = 0; i < 2; i++) { if(0 != encoder->private_->residual_workspace_unaligned[channel][i]) { @@ -1531,10 +2381,6 @@ void free_(FLAC__StreamEncoder *encoder) } } } - if(0 != encoder->private_->abs_residual_unaligned) { - free(encoder->private_->abs_residual_unaligned); - encoder->private_->abs_residual_unaligned = 0; - } if(0 != encoder->private_->abs_residual_partition_sums_unaligned) { free(encoder->private_->abs_residual_partition_sums_unaligned); encoder->private_->abs_residual_partition_sums_unaligned = 0; @@ -1551,74 +2397,160 @@ void free_(FLAC__StreamEncoder *encoder) } } } - FLAC__bitbuffer_free(encoder->private_->frame); + FLAC__bitwriter_free(encoder->private_->frame); } -FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_size) +FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize) { FLAC__bool ok; unsigned i, channel; - FLAC__ASSERT(new_size > 0); + FLAC__ASSERT(new_blocksize > 0); FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK); FLAC__ASSERT(encoder->private_->current_sample_number == 0); /* To avoid excessive malloc'ing, we only grow the buffer; no shrinking. */ - if(new_size <= encoder->private_->input_capacity) + if(new_blocksize <= encoder->private_->input_capacity) return true; ok = true; - /* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx() - * requires that the input arrays (in our case the integer signals) + /* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx() and ..._intrin_sse2() + * require that the input arrays (in our case the integer signals) * have a buffer of up to 3 zeroes in front (at negative indices) for - * alignment purposes; we use 4 to keep the data well-aligned. + * alignment purposes; we use 4 in front to keep the data well-aligned. */ for(i = 0; ok && i < encoder->protected_->channels; i++) { - ok = ok && FLAC__memory_alloc_aligned_int32_array(new_size+4, &encoder->private_->integer_signal_unaligned[i], &encoder->private_->integer_signal[i]); - ok = ok && FLAC__memory_alloc_aligned_real_array(new_size, &encoder->private_->real_signal_unaligned[i], &encoder->private_->real_signal[i]); + ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_unaligned[i], &encoder->private_->integer_signal[i]); memset(encoder->private_->integer_signal[i], 0, sizeof(FLAC__int32)*4); encoder->private_->integer_signal[i] += 4; +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#if 0 /* @@@ currently unused */ + if(encoder->protected_->max_lpc_order > 0) + ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_unaligned[i], &encoder->private_->real_signal[i]); +#endif +#endif } for(i = 0; ok && i < 2; i++) { - ok = ok && FLAC__memory_alloc_aligned_int32_array(new_size+4, &encoder->private_->integer_signal_mid_side_unaligned[i], &encoder->private_->integer_signal_mid_side[i]); - ok = ok && FLAC__memory_alloc_aligned_real_array(new_size, &encoder->private_->real_signal_mid_side_unaligned[i], &encoder->private_->real_signal_mid_side[i]); + ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_mid_side_unaligned[i], &encoder->private_->integer_signal_mid_side[i]); memset(encoder->private_->integer_signal_mid_side[i], 0, sizeof(FLAC__int32)*4); encoder->private_->integer_signal_mid_side[i] += 4; +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#if 0 /* @@@ currently unused */ + if(encoder->protected_->max_lpc_order > 0) + ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_mid_side_unaligned[i], &encoder->private_->real_signal_mid_side[i]); +#endif +#endif + } +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(ok && encoder->protected_->max_lpc_order > 0) { + for(i = 0; ok && i < encoder->protected_->num_apodizations; i++) + ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->window_unaligned[i], &encoder->private_->window[i]); + ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->windowed_signal_unaligned, &encoder->private_->windowed_signal); } +#endif for(channel = 0; ok && channel < encoder->protected_->channels; channel++) { for(i = 0; ok && i < 2; i++) { - ok = ok && FLAC__memory_alloc_aligned_int32_array(new_size, &encoder->private_->residual_workspace_unaligned[channel][i], &encoder->private_->residual_workspace[channel][i]); + ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_unaligned[channel][i], &encoder->private_->residual_workspace[channel][i]); } } for(channel = 0; ok && channel < 2; channel++) { for(i = 0; ok && i < 2; i++) { - ok = ok && FLAC__memory_alloc_aligned_int32_array(new_size, &encoder->private_->residual_workspace_mid_side_unaligned[channel][i], &encoder->private_->residual_workspace_mid_side[channel][i]); + ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_mid_side_unaligned[channel][i], &encoder->private_->residual_workspace_mid_side[channel][i]); } } - ok = ok && FLAC__memory_alloc_aligned_uint32_array(new_size, &encoder->private_->abs_residual_unaligned, &encoder->private_->abs_residual); - if(encoder->private_->precompute_partition_sums || encoder->protected_->do_escape_coding) /* we require precompute_partition_sums if do_escape_coding because of their intertwined nature */ - ok = ok && FLAC__memory_alloc_aligned_uint64_array(new_size * 2, &encoder->private_->abs_residual_partition_sums_unaligned, &encoder->private_->abs_residual_partition_sums); + /* the *2 is an approximation to the series 1 + 1/2 + 1/4 + ... that sums tree occupies in a flat array */ + /*@@@ new_blocksize*2 is too pessimistic, but to fix, we need smarter logic because a smaller new_blocksize can actually increase the # of partitions; would require moving this out into a separate function, then checking its capacity against the need of the current blocksize&min/max_partition_order (and maybe predictor order) */ + ok = ok && FLAC__memory_alloc_aligned_uint64_array(new_blocksize * 2, &encoder->private_->abs_residual_partition_sums_unaligned, &encoder->private_->abs_residual_partition_sums); if(encoder->protected_->do_escape_coding) - ok = ok && FLAC__memory_alloc_aligned_unsigned_array(new_size * 2, &encoder->private_->raw_bits_per_partition_unaligned, &encoder->private_->raw_bits_per_partition); + ok = ok && FLAC__memory_alloc_aligned_unsigned_array(new_blocksize * 2, &encoder->private_->raw_bits_per_partition_unaligned, &encoder->private_->raw_bits_per_partition); + + /* now adjust the windows if the blocksize has changed */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(ok && new_blocksize != encoder->private_->input_capacity && encoder->protected_->max_lpc_order > 0) { + for(i = 0; ok && i < encoder->protected_->num_apodizations; i++) { + switch(encoder->protected_->apodizations[i].type) { + case FLAC__APODIZATION_BARTLETT: + FLAC__window_bartlett(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_BARTLETT_HANN: + FLAC__window_bartlett_hann(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_BLACKMAN: + FLAC__window_blackman(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE: + FLAC__window_blackman_harris_4term_92db_sidelobe(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_CONNES: + FLAC__window_connes(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_FLATTOP: + FLAC__window_flattop(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_GAUSS: + FLAC__window_gauss(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.gauss.stddev); + break; + case FLAC__APODIZATION_HAMMING: + FLAC__window_hamming(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_HANN: + FLAC__window_hann(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_KAISER_BESSEL: + FLAC__window_kaiser_bessel(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_NUTTALL: + FLAC__window_nuttall(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_RECTANGLE: + FLAC__window_rectangle(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_TRIANGLE: + FLAC__window_triangle(encoder->private_->window[i], new_blocksize); + break; + case FLAC__APODIZATION_TUKEY: + FLAC__window_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.tukey.p); + break; + case FLAC__APODIZATION_PARTIAL_TUKEY: + FLAC__window_partial_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end); + break; + case FLAC__APODIZATION_PUNCHOUT_TUKEY: + FLAC__window_punchout_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end); + break; + case FLAC__APODIZATION_WELCH: + FLAC__window_welch(encoder->private_->window[i], new_blocksize); + break; + default: + FLAC__ASSERT(0); + /* double protection */ + FLAC__window_hann(encoder->private_->window[i], new_blocksize); + break; + } + } + } +#endif if(ok) - encoder->private_->input_capacity = new_size; + encoder->private_->input_capacity = new_blocksize; else encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; return ok; } -FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples) +FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples, FLAC__bool is_last_block) { const FLAC__byte *buffer; - unsigned bytes; + size_t bytes; - FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(encoder->private_->frame)); + FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame)); - FLAC__bitbuffer_get_buffer(encoder->private_->frame, &buffer, &bytes); + if(!FLAC__bitwriter_get_buffer(encoder->private_->frame, &buffer, &bytes)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } if(encoder->protected_->verify) { encoder->private_->verify.output.data = buffer; @@ -1628,7 +2560,8 @@ FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples) } else { if(!FLAC__stream_decoder_process_single(encoder->private_->verify.decoder)) { - FLAC__bitbuffer_release_buffer(encoder->private_->frame); + FLAC__bitwriter_release_buffer(encoder->private_->frame); + FLAC__bitwriter_clear(encoder->private_->frame); if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA) encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; return false; @@ -1636,30 +2569,472 @@ FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples) } } - if(encoder->private_->write_callback(encoder, buffer, bytes, samples, encoder->private_->current_frame_number, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - FLAC__bitbuffer_release_buffer(encoder->private_->frame); - encoder->protected_->state = FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_WRITING; + if(write_frame_(encoder, buffer, bytes, samples, is_last_block) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + FLAC__bitwriter_release_buffer(encoder->private_->frame); + FLAC__bitwriter_clear(encoder->private_->frame); + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; return false; } - FLAC__bitbuffer_release_buffer(encoder->private_->frame); + FLAC__bitwriter_release_buffer(encoder->private_->frame); + FLAC__bitwriter_clear(encoder->private_->frame); if(samples > 0) { - encoder->private_->metadata.data.stream_info.min_framesize = min(bytes, encoder->private_->metadata.data.stream_info.min_framesize); - encoder->private_->metadata.data.stream_info.max_framesize = max(bytes, encoder->private_->metadata.data.stream_info.max_framesize); + encoder->private_->streaminfo.data.stream_info.min_framesize = flac_min(bytes, encoder->private_->streaminfo.data.stream_info.min_framesize); + encoder->private_->streaminfo.data.stream_info.max_framesize = flac_max(bytes, encoder->private_->streaminfo.data.stream_info.max_framesize); } return true; } -FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame) +FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, FLAC__bool is_last_block) +{ + FLAC__StreamEncoderWriteStatus status; + FLAC__uint64 output_position = 0; + +#if FLAC__HAS_OGG == 0 + (void)is_last_block; +#endif + + /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */ + if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &output_position, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + + /* + * Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets. + */ + if(samples == 0) { + FLAC__MetadataType type = (buffer[0] & 0x7f); + if(type == FLAC__METADATA_TYPE_STREAMINFO) + encoder->protected_->streaminfo_offset = output_position; + else if(type == FLAC__METADATA_TYPE_SEEKTABLE && encoder->protected_->seektable_offset == 0) + encoder->protected_->seektable_offset = output_position; + } + + /* + * Mark the current seek point if hit (if audio_offset == 0 that + * means we're still writing metadata and haven't hit the first + * frame yet) + */ + if(0 != encoder->private_->seek_table && encoder->protected_->audio_offset > 0 && encoder->private_->seek_table->num_points > 0) { + const unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder); + const FLAC__uint64 frame_first_sample = encoder->private_->samples_written; + const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1; + FLAC__uint64 test_sample; + unsigned i; + for(i = encoder->private_->first_seekpoint_to_check; i < encoder->private_->seek_table->num_points; i++) { + test_sample = encoder->private_->seek_table->points[i].sample_number; + if(test_sample > frame_last_sample) { + break; + } + else if(test_sample >= frame_first_sample) { + encoder->private_->seek_table->points[i].sample_number = frame_first_sample; + encoder->private_->seek_table->points[i].stream_offset = output_position - encoder->protected_->audio_offset; + encoder->private_->seek_table->points[i].frame_samples = blocksize; + encoder->private_->first_seekpoint_to_check++; + /* DO NOT: "break;" and here's why: + * The seektable template may contain more than one target + * sample for any given frame; we will keep looping, generating + * duplicate seekpoints for them, and we'll clean it up later, + * just before writing the seektable back to the metadata. + */ + } + else { + encoder->private_->first_seekpoint_to_check++; + } + } + } + +#if FLAC__HAS_OGG + if(encoder->private_->is_ogg) { + status = FLAC__ogg_encoder_aspect_write_callback_wrapper( + &encoder->protected_->ogg_encoder_aspect, + buffer, + bytes, + samples, + encoder->private_->current_frame_number, + is_last_block, + (FLAC__OggEncoderAspectWriteCallbackProxy)encoder->private_->write_callback, + encoder, + encoder->private_->client_data + ); + } + else +#endif + status = encoder->private_->write_callback(encoder, buffer, bytes, samples, encoder->private_->current_frame_number, encoder->private_->client_data); + + if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->private_->bytes_written += bytes; + encoder->private_->samples_written += samples; + /* we keep a high watermark on the number of frames written because + * when the encoder goes back to write metadata, 'current_frame' + * will drop back to 0. + */ + encoder->private_->frames_written = flac_max(encoder->private_->frames_written, encoder->private_->current_frame_number+1); + } + else + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + + return status; +} + +/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks. */ +void update_metadata_(const FLAC__StreamEncoder *encoder) +{ + FLAC__byte b[flac_max(6u, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)]; + const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo; + const FLAC__uint64 samples = metadata->data.stream_info.total_samples; + const unsigned min_framesize = metadata->data.stream_info.min_framesize; + const unsigned max_framesize = metadata->data.stream_info.max_framesize; + const unsigned bps = metadata->data.stream_info.bits_per_sample; + FLAC__StreamEncoderSeekStatus seek_status; + + FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); + + /* All this is based on intimate knowledge of the stream header + * layout, but a change to the header format that would break this + * would also break all streams encoded in the previous format. + */ + + /* + * Write MD5 signature + */ + { + const unsigned md5_offset = + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + + FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN + ) / 8; + + if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + md5_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + if(encoder->private_->write_callback(encoder, metadata->data.stream_info.md5sum, 16, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + } + + /* + * Write total samples + */ + { + const unsigned total_samples_byte_offset = + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + + FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + - 4 + ) / 8; + + b[0] = ((FLAC__byte)(bps-1) << 4) | (FLAC__byte)((samples >> 32) & 0x0F); + b[1] = (FLAC__byte)((samples >> 24) & 0xFF); + b[2] = (FLAC__byte)((samples >> 16) & 0xFF); + b[3] = (FLAC__byte)((samples >> 8) & 0xFF); + b[4] = (FLAC__byte)(samples & 0xFF); + if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + total_samples_byte_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + if(encoder->private_->write_callback(encoder, b, 5, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + } + + /* + * Write min/max framesize + */ + { + const unsigned min_framesize_offset = + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + ) / 8; + + b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF); + b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF); + b[2] = (FLAC__byte)(min_framesize & 0xFF); + b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF); + b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF); + b[5] = (FLAC__byte)(max_framesize & 0xFF); + if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + min_framesize_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + if(encoder->private_->write_callback(encoder, b, 6, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + } + + /* + * Write seektable + */ + if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) { + unsigned i; + + FLAC__format_seektable_sort(encoder->private_->seek_table); + + FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table)); + + if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->seektable_offset + FLAC__STREAM_METADATA_HEADER_LENGTH, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) { + if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR) + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + + for(i = 0; i < encoder->private_->seek_table->num_points; i++) { + FLAC__uint64 xx; + unsigned x; + xx = encoder->private_->seek_table->points[i].sample_number; + b[7] = (FLAC__byte)xx; xx >>= 8; + b[6] = (FLAC__byte)xx; xx >>= 8; + b[5] = (FLAC__byte)xx; xx >>= 8; + b[4] = (FLAC__byte)xx; xx >>= 8; + b[3] = (FLAC__byte)xx; xx >>= 8; + b[2] = (FLAC__byte)xx; xx >>= 8; + b[1] = (FLAC__byte)xx; xx >>= 8; + b[0] = (FLAC__byte)xx; xx >>= 8; + xx = encoder->private_->seek_table->points[i].stream_offset; + b[15] = (FLAC__byte)xx; xx >>= 8; + b[14] = (FLAC__byte)xx; xx >>= 8; + b[13] = (FLAC__byte)xx; xx >>= 8; + b[12] = (FLAC__byte)xx; xx >>= 8; + b[11] = (FLAC__byte)xx; xx >>= 8; + b[10] = (FLAC__byte)xx; xx >>= 8; + b[9] = (FLAC__byte)xx; xx >>= 8; + b[8] = (FLAC__byte)xx; xx >>= 8; + x = encoder->private_->seek_table->points[i].frame_samples; + b[17] = (FLAC__byte)x; x >>= 8; + b[16] = (FLAC__byte)x; x >>= 8; + if(encoder->private_->write_callback(encoder, b, 18, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR; + return; + } + } + } +} + +#if FLAC__HAS_OGG +/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks. */ +void update_ogg_metadata_(FLAC__StreamEncoder *encoder) { + /* the # of bytes in the 1st packet that precede the STREAMINFO */ + static const unsigned FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH = + FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH + + FLAC__OGG_MAPPING_MAGIC_LENGTH + + FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH + + FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH + + FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH + + FLAC__STREAM_SYNC_LENGTH + ; + FLAC__byte b[flac_max(6u, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)]; + const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo; + const FLAC__uint64 samples = metadata->data.stream_info.total_samples; + const unsigned min_framesize = metadata->data.stream_info.min_framesize; + const unsigned max_framesize = metadata->data.stream_info.max_framesize; + ogg_page page; + + FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); + FLAC__ASSERT(0 != encoder->private_->seek_callback); + + /* Pre-check that client supports seeking, since we don't want the + * ogg_helper code to ever have to deal with this condition. + */ + if(encoder->private_->seek_callback(encoder, 0, encoder->private_->client_data) == FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED) + return; + + /* All this is based on intimate knowledge of the stream header + * layout, but a change to the header format that would break this + * would also break all streams encoded in the previous format. + */ + + /** + ** Write STREAMINFO stats + **/ + simple_ogg_page__init(&page); + if(!simple_ogg_page__get_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) { + simple_ogg_page__clear(&page); + return; /* state already set */ + } + + /* + * Write MD5 signature + */ + { + const unsigned md5_offset = + FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH + + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + + FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN + ) / 8; + + if(md5_offset + 16 > (unsigned)page.body_len) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + simple_ogg_page__clear(&page); + return; + } + memcpy(page.body + md5_offset, metadata->data.stream_info.md5sum, 16); + } + + /* + * Write total samples + */ + { + const unsigned total_samples_byte_offset = + FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH + + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + + FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + - 4 + ) / 8; + + if(total_samples_byte_offset + 5 > (unsigned)page.body_len) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + simple_ogg_page__clear(&page); + return; + } + b[0] = (FLAC__byte)page.body[total_samples_byte_offset] & 0xF0; + b[0] |= (FLAC__byte)((samples >> 32) & 0x0F); + b[1] = (FLAC__byte)((samples >> 24) & 0xFF); + b[2] = (FLAC__byte)((samples >> 16) & 0xFF); + b[3] = (FLAC__byte)((samples >> 8) & 0xFF); + b[4] = (FLAC__byte)(samples & 0xFF); + memcpy(page.body + total_samples_byte_offset, b, 5); + } + + /* + * Write min/max framesize + */ + { + const unsigned min_framesize_offset = + FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH + + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + ) / 8; + + if(min_framesize_offset + 6 > (unsigned)page.body_len) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + simple_ogg_page__clear(&page); + return; + } + b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF); + b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF); + b[2] = (FLAC__byte)(min_framesize & 0xFF); + b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF); + b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF); + b[5] = (FLAC__byte)(max_framesize & 0xFF); + memcpy(page.body + min_framesize_offset, b, 6); + } + if(!simple_ogg_page__set_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) { + simple_ogg_page__clear(&page); + return; /* state already set */ + } + simple_ogg_page__clear(&page); + + /* + * Write seektable + */ + if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) { + unsigned i; + FLAC__byte *p; + + FLAC__format_seektable_sort(encoder->private_->seek_table); + + FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table)); + + simple_ogg_page__init(&page); + if(!simple_ogg_page__get_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) { + simple_ogg_page__clear(&page); + return; /* state already set */ + } + + if((FLAC__STREAM_METADATA_HEADER_LENGTH + 18*encoder->private_->seek_table->num_points) != (unsigned)page.body_len) { + encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR; + simple_ogg_page__clear(&page); + return; + } + + for(i = 0, p = page.body + FLAC__STREAM_METADATA_HEADER_LENGTH; i < encoder->private_->seek_table->num_points; i++, p += 18) { + FLAC__uint64 xx; + unsigned x; + xx = encoder->private_->seek_table->points[i].sample_number; + b[7] = (FLAC__byte)xx; xx >>= 8; + b[6] = (FLAC__byte)xx; xx >>= 8; + b[5] = (FLAC__byte)xx; xx >>= 8; + b[4] = (FLAC__byte)xx; xx >>= 8; + b[3] = (FLAC__byte)xx; xx >>= 8; + b[2] = (FLAC__byte)xx; xx >>= 8; + b[1] = (FLAC__byte)xx; xx >>= 8; + b[0] = (FLAC__byte)xx; xx >>= 8; + xx = encoder->private_->seek_table->points[i].stream_offset; + b[15] = (FLAC__byte)xx; xx >>= 8; + b[14] = (FLAC__byte)xx; xx >>= 8; + b[13] = (FLAC__byte)xx; xx >>= 8; + b[12] = (FLAC__byte)xx; xx >>= 8; + b[11] = (FLAC__byte)xx; xx >>= 8; + b[10] = (FLAC__byte)xx; xx >>= 8; + b[9] = (FLAC__byte)xx; xx >>= 8; + b[8] = (FLAC__byte)xx; xx >>= 8; + x = encoder->private_->seek_table->points[i].frame_samples; + b[17] = (FLAC__byte)x; x >>= 8; + b[16] = (FLAC__byte)x; x >>= 8; + memcpy(p, b, 18); + } + + if(!simple_ogg_page__set_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) { + simple_ogg_page__clear(&page); + return; /* state already set */ + } + simple_ogg_page__clear(&page); + } +} +#endif + +FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block) +{ + FLAC__uint16 crc; FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK); /* * Accumulate raw signal to the MD5 signature */ - if(!FLAC__MD5Accumulate(&encoder->private_->md5context, (const FLAC__int32 * const *)encoder->private_->integer_signal, encoder->protected_->channels, encoder->protected_->blocksize, (encoder->protected_->bits_per_sample+7) / 8)) { + if(encoder->protected_->do_md5 && !FLAC__MD5Accumulate(&encoder->private_->md5context, (const FLAC__int32 * const *)encoder->private_->integer_signal, encoder->protected_->channels, encoder->protected_->blocksize, (encoder->protected_->bits_per_sample+7) / 8)) { encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; return false; } @@ -1667,7 +3042,7 @@ FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame /* * Process the frame header and subframes into the frame bitbuffer */ - if(!process_subframes_(encoder, is_last_frame)) { + if(!process_subframes_(encoder, is_fractional_block)) { /* the above function sets the state for us in case of an error */ return false; } @@ -1675,7 +3050,7 @@ FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame /* * Zero-pad the frame to a byte_boundary */ - if(!FLAC__bitbuffer_zero_pad_to_byte_boundary(encoder->private_->frame)) { + if(!FLAC__bitwriter_zero_pad_to_byte_boundary(encoder->private_->frame)) { encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; return false; } @@ -1683,13 +3058,19 @@ FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame /* * CRC-16 the whole thing */ - FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(encoder->private_->frame)); - FLAC__bitbuffer_write_raw_uint32(encoder->private_->frame, FLAC__bitbuffer_get_write_crc16(encoder->private_->frame), FLAC__FRAME_FOOTER_CRC_LEN); + FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame)); + if( + !FLAC__bitwriter_get_write_crc16(encoder->private_->frame, &crc) || + !FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, crc, FLAC__FRAME_FOOTER_CRC_LEN) + ) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } /* * Write it */ - if(!write_bitbuffer_(encoder, encoder->protected_->blocksize)) { + if(!write_bitbuffer_(encoder, encoder->protected_->blocksize, is_last_block)) { /* the above function sets the state for us in case of an error */ return false; } @@ -1699,38 +3080,32 @@ FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame */ encoder->private_->current_sample_number = 0; encoder->private_->current_frame_number++; - encoder->private_->metadata.data.stream_info.total_samples += (FLAC__uint64)encoder->protected_->blocksize; + encoder->private_->streaminfo.data.stream_info.total_samples += (FLAC__uint64)encoder->protected_->blocksize; return true; } -FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame) +FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block) { FLAC__FrameHeader frame_header; unsigned channel, min_partition_order = encoder->protected_->min_residual_partition_order, max_partition_order; - FLAC__bool do_independent, do_mid_side, precompute_partition_sums; + FLAC__bool do_independent, do_mid_side; /* * Calculate the min,max Rice partition orders */ - if(is_last_frame) { + if(is_fractional_block) { max_partition_order = 0; } else { max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize(encoder->protected_->blocksize); - max_partition_order = min(max_partition_order, encoder->protected_->max_residual_partition_order); + max_partition_order = flac_min(max_partition_order, encoder->protected_->max_residual_partition_order); } - min_partition_order = min(min_partition_order, max_partition_order); - - precompute_partition_sums = encoder->private_->precompute_partition_sums && ((max_partition_order > min_partition_order) || encoder->protected_->do_escape_coding); + min_partition_order = flac_min(min_partition_order, max_partition_order); /* * Setup the frame */ - if(!FLAC__bitbuffer_clear(encoder->private_->frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; - return false; - } frame_header.blocksize = encoder->protected_->blocksize; frame_header.sample_rate = encoder->protected_->sample_rate; frame_header.channels = encoder->protected_->channels; @@ -1794,11 +3169,9 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_f encoder, min_partition_order, max_partition_order, - precompute_partition_sums, &frame_header, encoder->private_->subframe_bps[channel], encoder->private_->integer_signal[channel], - encoder->private_->real_signal[channel], encoder->private_->subframe_workspace_ptr[channel], encoder->private_->partitioned_rice_contents_workspace_ptr[channel], encoder->private_->residual_workspace[channel], @@ -1822,11 +3195,9 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_f encoder, min_partition_order, max_partition_order, - precompute_partition_sums, &frame_header, encoder->private_->subframe_bps_mid_side[channel], encoder->private_->integer_signal_mid_side[channel], - encoder->private_->real_signal_mid_side[channel], encoder->private_->subframe_workspace_ptr_mid_side[channel], encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[channel], encoder->private_->residual_workspace_mid_side[channel], @@ -1854,8 +3225,12 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_f else { unsigned bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */ unsigned min_bits; - FLAC__ChannelAssignment ca; + int ca; + FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT == 0); + FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE == 1); + FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE == 2); + FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_MID_SIDE == 3); FLAC__ASSERT(do_independent && do_mid_side); /* We have to figure out which channel assignent results in the smallest frame */ @@ -1864,17 +3239,19 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_f bits[FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE ] = encoder->private_->best_subframe_bits [1] + encoder->private_->best_subframe_bits_mid_side[1]; bits[FLAC__CHANNEL_ASSIGNMENT_MID_SIDE ] = encoder->private_->best_subframe_bits_mid_side[0] + encoder->private_->best_subframe_bits_mid_side[1]; - for(channel_assignment = (FLAC__ChannelAssignment)0, min_bits = bits[0], ca = (FLAC__ChannelAssignment)1; (int)ca <= 3; ca = (FLAC__ChannelAssignment)((int)ca + 1)) { + channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; + min_bits = bits[channel_assignment]; + for(ca = 1; ca <= 3; ca++) { if(bits[ca] < min_bits) { min_bits = bits[ca]; - channel_assignment = ca; + channel_assignment = (FLAC__ChannelAssignment)ca; } } } frame_header.channel_assignment = channel_assignment; - if(!FLAC__frame_add_header(&frame_header, encoder->protected_->streamable_subset, encoder->private_->frame)) { + if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) { encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; return false; } @@ -1922,19 +3299,19 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_f } /* note that encoder_add_subframe_ sets the state for us in case of an error */ - if(!add_subframe_(encoder, &frame_header, left_bps , left_subframe , encoder->private_->frame)) + if(!add_subframe_(encoder, frame_header.blocksize, left_bps , left_subframe , encoder->private_->frame)) return false; - if(!add_subframe_(encoder, &frame_header, right_bps, right_subframe, encoder->private_->frame)) + if(!add_subframe_(encoder, frame_header.blocksize, right_bps, right_subframe, encoder->private_->frame)) return false; } else { - if(!FLAC__frame_add_header(&frame_header, encoder->protected_->streamable_subset, encoder->private_->frame)) { + if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) { encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; return false; } for(channel = 0; channel < encoder->protected_->channels; channel++) { - if(!add_subframe_(encoder, &frame_header, encoder->private_->subframe_bps[channel], &encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]], encoder->private_->frame)) { + if(!add_subframe_(encoder, frame_header.blocksize, encoder->private_->subframe_bps[channel], &encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]], encoder->private_->frame)) { /* the above function sets the state for us in case of an error */ return false; } @@ -1956,11 +3333,9 @@ FLAC__bool process_subframe_( FLAC__StreamEncoder *encoder, unsigned min_partition_order, unsigned max_partition_order, - FLAC__bool precompute_partition_sums, const FLAC__FrameHeader *frame_header, unsigned subframe_bps, const FLAC__int32 integer_signal[], - const FLAC__real real_signal[], FLAC__Subframe *subframe[2], FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2], FLAC__int32 *residual[2], @@ -1968,33 +3343,50 @@ FLAC__bool process_subframe_( unsigned *best_bits ) { - FLAC__real fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]; - FLAC__real lpc_residual_bits_per_sample; - FLAC__real autoc[FLAC__MAX_LPC_ORDER+1]; /* WATCHOUT: the size is important even though encoder->protected_->max_lpc_order might be less; some asm routines need all the space */ - FLAC__real lpc_error[FLAC__MAX_LPC_ORDER]; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + FLAC__float fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]; +#else + FLAC__fixedpoint fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]; +#endif +#ifndef FLAC__INTEGER_ONLY_LIBRARY + FLAC__double lpc_residual_bits_per_sample; + FLAC__real autoc[FLAC__MAX_LPC_ORDER+1]; /* WATCHOUT: the size is important even though encoder->protected_->max_lpc_order might be less; some asm and x86 intrinsic routines need all the space */ + FLAC__double lpc_error[FLAC__MAX_LPC_ORDER]; unsigned min_lpc_order, max_lpc_order, lpc_order; - unsigned min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order; unsigned min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision; +#endif + unsigned min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order; unsigned rice_parameter; unsigned _candidate_bits, _best_bits; unsigned _best_subframe; + /* only use RICE2 partitions if stream bps > 16 */ + const unsigned rice_parameter_limit = FLAC__stream_encoder_get_bits_per_sample(encoder) > 16? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; + + FLAC__ASSERT(frame_header->blocksize > 0); /* verbatim subframe is the baseline against which we measure other compressed subframes */ _best_subframe = 0; if(encoder->private_->disable_verbatim_subframes && frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) _best_bits = UINT_MAX; else - _best_bits = evaluate_verbatim_subframe_(integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]); + _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]); if(frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) { unsigned signal_is_constant = false; guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor(integer_signal+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample); /* check for constant subframe */ - if(!encoder->private_->disable_constant_subframes && fixed_residual_bits_per_sample[1] == 0.0) { - /* the above means integer_signal+FLAC__MAX_FIXED_ORDER is constant, now we just have to check the warmup samples */ + if( + !encoder->private_->disable_constant_subframes && +#ifndef FLAC__INTEGER_ONLY_LIBRARY + fixed_residual_bits_per_sample[1] == 0.0 +#else + fixed_residual_bits_per_sample[1] == FLAC__FP_ZERO +#endif + ) { + /* the above means it's possible all samples are the same value; now double-check it: */ unsigned i; signal_is_constant = true; - for(i = 1; i <= FLAC__MAX_FIXED_ORDER; i++) { + for(i = 1; i < frame_header->blocksize; i++) { if(integer_signal[0] != integer_signal[i]) { signal_is_constant = false; break; @@ -2002,7 +3394,7 @@ FLAC__bool process_subframe_( } } if(signal_is_constant) { - _candidate_bits = evaluate_constant_subframe_(integer_signal[0], subframe_bps, subframe[!_best_subframe]); + _candidate_bits = evaluate_constant_subframe_(encoder, integer_signal[0], frame_header->blocksize, subframe_bps, subframe[!_best_subframe]); if(_candidate_bits < _best_bits) { _best_subframe = !_best_subframe; _best_bits = _candidate_bits; @@ -2018,34 +3410,39 @@ FLAC__bool process_subframe_( else { min_fixed_order = max_fixed_order = guess_fixed_order; } + if(max_fixed_order >= frame_header->blocksize) + max_fixed_order = frame_header->blocksize - 1; for(fixed_order = min_fixed_order; fixed_order <= max_fixed_order; fixed_order++) { - if(fixed_residual_bits_per_sample[fixed_order] >= (FLAC__real)subframe_bps) +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(fixed_residual_bits_per_sample[fixed_order] >= (FLAC__float)subframe_bps) continue; /* don't even try */ rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > 0.0)? (unsigned)(fixed_residual_bits_per_sample[fixed_order]+0.5) : 0; /* 0.5 is for rounding */ -#ifndef FLAC__SYMMETRIC_RICE - rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */ +#else + if(FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]) >= (int)subframe_bps) + continue; /* don't even try */ + rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > FLAC__FP_ZERO)? (unsigned)FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]+FLAC__FP_ONE_HALF) : 0; /* 0.5 is for rounding */ #endif - if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { + rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */ + if(rice_parameter >= rice_parameter_limit) { #ifdef DEBUG_VERBOSE - fprintf(stderr, "clipping rice_parameter (%u -> %u) @0\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1); + fprintf(stderr, "clipping rice_parameter (%u -> %u) @0\n", rice_parameter, rice_parameter_limit - 1); #endif - rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1; + rice_parameter = rice_parameter_limit - 1; } _candidate_bits = evaluate_fixed_subframe_( encoder, integer_signal, residual[!_best_subframe], - encoder->private_->abs_residual, encoder->private_->abs_residual_partition_sums, encoder->private_->raw_bits_per_partition, frame_header->blocksize, subframe_bps, fixed_order, rice_parameter, + rice_parameter_limit, min_partition_order, max_partition_order, - precompute_partition_sums, encoder->protected_->do_escape_coding, encoder->protected_->rice_parameter_search_dist, subframe[!_best_subframe], @@ -2058,6 +3455,7 @@ FLAC__bool process_subframe_( } } +#ifndef FLAC__INTEGER_ONLY_LIBRARY /* encode lpc */ if(encoder->protected_->max_lpc_order > 0) { if(encoder->protected_->max_lpc_order >= frame_header->blocksize) @@ -2065,69 +3463,84 @@ FLAC__bool process_subframe_( else max_lpc_order = encoder->protected_->max_lpc_order; if(max_lpc_order > 0) { - encoder->private_->local_lpc_compute_autocorrelation(real_signal, frame_header->blocksize, max_lpc_order+1, autoc); - /* if autoc[0] == 0.0, the signal is constant and we usually won't get here, but it can happen */ - if(autoc[0] != 0.0) { - FLAC__lpc_compute_lp_coefficients(autoc, max_lpc_order, encoder->private_->lp_coeff, lpc_error); - if(encoder->protected_->do_exhaustive_model_search) { - min_lpc_order = 1; - } - else { - unsigned guess_lpc_order = FLAC__lpc_compute_best_order(lpc_error, max_lpc_order, frame_header->blocksize, subframe_bps); - min_lpc_order = max_lpc_order = guess_lpc_order; - } - for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order; lpc_order++) { - lpc_residual_bits_per_sample = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[lpc_order-1], frame_header->blocksize-lpc_order); - if(lpc_residual_bits_per_sample >= (FLAC__real)subframe_bps) - continue; /* don't even try */ - rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (unsigned)(lpc_residual_bits_per_sample+0.5) : 0; /* 0.5 is for rounding */ -#ifndef FLAC__SYMMETRIC_RICE - rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */ -#endif - if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { -#ifdef DEBUG_VERBOSE - fprintf(stderr, "clipping rice_parameter (%u -> %u) @1\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1); -#endif - rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1; - } - if(encoder->protected_->do_qlp_coeff_prec_search) { - min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION; - /* ensure a 32-bit datapath throughout for 16bps or less */ - if(subframe_bps <= 16) - max_qlp_coeff_precision = min(32 - subframe_bps - lpc_order, FLAC__MAX_QLP_COEFF_PRECISION); - else - max_qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION; + unsigned a; + for (a = 0; a < encoder->protected_->num_apodizations; a++) { + FLAC__lpc_window_data(integer_signal, encoder->private_->window[a], encoder->private_->windowed_signal, frame_header->blocksize); + encoder->private_->local_lpc_compute_autocorrelation(encoder->private_->windowed_signal, frame_header->blocksize, max_lpc_order+1, autoc); + /* if autoc[0] == 0.0, the signal is constant and we usually won't get here, but it can happen */ + if(autoc[0] != 0.0) { + FLAC__lpc_compute_lp_coefficients(autoc, &max_lpc_order, encoder->private_->lp_coeff, lpc_error); + if(encoder->protected_->do_exhaustive_model_search) { + min_lpc_order = 1; } else { - min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->protected_->qlp_coeff_precision; - } - for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) { - _candidate_bits = - evaluate_lpc_subframe_( - encoder, - integer_signal, - residual[!_best_subframe], - encoder->private_->abs_residual, - encoder->private_->abs_residual_partition_sums, - encoder->private_->raw_bits_per_partition, - encoder->private_->lp_coeff[lpc_order-1], + const unsigned guess_lpc_order = + FLAC__lpc_compute_best_order( + lpc_error, + max_lpc_order, frame_header->blocksize, - subframe_bps, - lpc_order, - qlp_coeff_precision, - rice_parameter, - min_partition_order, - max_partition_order, - precompute_partition_sums, - encoder->protected_->do_escape_coding, - encoder->protected_->rice_parameter_search_dist, - subframe[!_best_subframe], - partitioned_rice_contents[!_best_subframe] + subframe_bps + ( + encoder->protected_->do_qlp_coeff_prec_search? + FLAC__MIN_QLP_COEFF_PRECISION : /* have to guess; use the min possible size to avoid accidentally favoring lower orders */ + encoder->protected_->qlp_coeff_precision + ) ); - if(_candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */ - if(_candidate_bits < _best_bits) { - _best_subframe = !_best_subframe; - _best_bits = _candidate_bits; + min_lpc_order = max_lpc_order = guess_lpc_order; + } + if(max_lpc_order >= frame_header->blocksize) + max_lpc_order = frame_header->blocksize - 1; + for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order; lpc_order++) { + lpc_residual_bits_per_sample = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[lpc_order-1], frame_header->blocksize-lpc_order); + if(lpc_residual_bits_per_sample >= (FLAC__double)subframe_bps) + continue; /* don't even try */ + rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (unsigned)(lpc_residual_bits_per_sample+0.5) : 0; /* 0.5 is for rounding */ + rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */ + if(rice_parameter >= rice_parameter_limit) { +#ifdef DEBUG_VERBOSE + fprintf(stderr, "clipping rice_parameter (%u -> %u) @1\n", rice_parameter, rice_parameter_limit - 1); +#endif + rice_parameter = rice_parameter_limit - 1; + } + if(encoder->protected_->do_qlp_coeff_prec_search) { + min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION; + /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps streams */ + if(subframe_bps <= 16) { + max_qlp_coeff_precision = flac_min(32 - subframe_bps - FLAC__bitmath_ilog2(lpc_order), FLAC__MAX_QLP_COEFF_PRECISION); + max_qlp_coeff_precision = flac_max(max_qlp_coeff_precision, min_qlp_coeff_precision); + } + else + max_qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION; + } + else { + min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->protected_->qlp_coeff_precision; + } + for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) { + _candidate_bits = + evaluate_lpc_subframe_( + encoder, + integer_signal, + residual[!_best_subframe], + encoder->private_->abs_residual_partition_sums, + encoder->private_->raw_bits_per_partition, + encoder->private_->lp_coeff[lpc_order-1], + frame_header->blocksize, + subframe_bps, + lpc_order, + qlp_coeff_precision, + rice_parameter, + rice_parameter_limit, + min_partition_order, + max_partition_order, + encoder->protected_->do_escape_coding, + encoder->protected_->rice_parameter_search_dist, + subframe[!_best_subframe], + partitioned_rice_contents[!_best_subframe] + ); + if(_candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */ + if(_candidate_bits < _best_bits) { + _best_subframe = !_best_subframe; + _best_bits = _candidate_bits; + } } } } @@ -2135,13 +3548,14 @@ FLAC__bool process_subframe_( } } } +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ } } /* under rare circumstances this can happen when all but lpc subframe types are disabled: */ if(_best_bits == UINT_MAX) { FLAC__ASSERT(_best_subframe == 0); - _best_bits = evaluate_verbatim_subframe_(integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]); + _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]); } *best_subframe = _best_subframe; @@ -2152,34 +3566,34 @@ FLAC__bool process_subframe_( FLAC__bool add_subframe_( FLAC__StreamEncoder *encoder, - const FLAC__FrameHeader *frame_header, + unsigned blocksize, unsigned subframe_bps, const FLAC__Subframe *subframe, - FLAC__BitBuffer *frame + FLAC__BitWriter *frame ) { switch(subframe->type) { case FLAC__SUBFRAME_TYPE_CONSTANT: if(!FLAC__subframe_add_constant(&(subframe->data.constant), subframe_bps, subframe->wasted_bits, frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING; + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; return false; } break; case FLAC__SUBFRAME_TYPE_FIXED: - if(!FLAC__subframe_add_fixed(&(subframe->data.fixed), frame_header->blocksize - subframe->data.fixed.order, subframe_bps, subframe->wasted_bits, frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING; + if(!FLAC__subframe_add_fixed(&(subframe->data.fixed), blocksize - subframe->data.fixed.order, subframe_bps, subframe->wasted_bits, frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; return false; } break; case FLAC__SUBFRAME_TYPE_LPC: - if(!FLAC__subframe_add_lpc(&(subframe->data.lpc), frame_header->blocksize - subframe->data.lpc.order, subframe_bps, subframe->wasted_bits, frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING; + if(!FLAC__subframe_add_lpc(&(subframe->data.lpc), blocksize - subframe->data.lpc.order, subframe_bps, subframe->wasted_bits, frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; return false; } break; case FLAC__SUBFRAME_TYPE_VERBATIM: - if(!FLAC__subframe_add_verbatim(&(subframe->data.verbatim), frame_header->blocksize, subframe_bps, subframe->wasted_bits, frame)) { - encoder->protected_->state = FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING; + if(!FLAC__subframe_add_verbatim(&(subframe->data.verbatim), blocksize, subframe_bps, subframe->wasted_bits, frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; return false; } break; @@ -2190,39 +3604,80 @@ FLAC__bool add_subframe_( return true; } +#define SPOTCHECK_ESTIMATE 0 +#if SPOTCHECK_ESTIMATE +static void spotcheck_subframe_estimate_( + FLAC__StreamEncoder *encoder, + unsigned blocksize, + unsigned subframe_bps, + const FLAC__Subframe *subframe, + unsigned estimate +) +{ + FLAC__bool ret; + FLAC__BitWriter *frame = FLAC__bitwriter_new(); + if(frame == 0) { + fprintf(stderr, "EST: can't allocate frame\n"); + return; + } + if(!FLAC__bitwriter_init(frame)) { + fprintf(stderr, "EST: can't init frame\n"); + return; + } + ret = add_subframe_(encoder, blocksize, subframe_bps, subframe, frame); + FLAC__ASSERT(ret); + { + const unsigned actual = FLAC__bitwriter_get_input_bits_unconsumed(frame); + if(estimate != actual) + fprintf(stderr, "EST: bad, frame#%u sub#%%d type=%8s est=%u, actual=%u, delta=%d\n", encoder->private_->current_frame_number, FLAC__SubframeTypeString[subframe->type], estimate, actual, (int)actual-(int)estimate); + } + FLAC__bitwriter_delete(frame); +} +#endif + unsigned evaluate_constant_subframe_( + FLAC__StreamEncoder *encoder, const FLAC__int32 signal, + unsigned blocksize, unsigned subframe_bps, FLAC__Subframe *subframe ) { + unsigned estimate; subframe->type = FLAC__SUBFRAME_TYPE_CONSTANT; subframe->data.constant.value = signal; - return FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe_bps; + estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + subframe_bps; + +#if SPOTCHECK_ESTIMATE + spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); +#else + (void)encoder, (void)blocksize; +#endif + + return estimate; } unsigned evaluate_fixed_subframe_( FLAC__StreamEncoder *encoder, const FLAC__int32 signal[], FLAC__int32 residual[], - FLAC__uint32 abs_residual[], FLAC__uint64 abs_residual_partition_sums[], unsigned raw_bits_per_partition[], unsigned blocksize, unsigned subframe_bps, unsigned order, unsigned rice_parameter, + unsigned rice_parameter_limit, unsigned min_partition_order, unsigned max_partition_order, - FLAC__bool precompute_partition_sums, FLAC__bool do_escape_coding, unsigned rice_parameter_search_dist, FLAC__Subframe *subframe, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents ) { - unsigned i, residual_bits; + unsigned i, residual_bits, estimate; const unsigned residual_samples = blocksize - order; FLAC__fixed_compute_residual(signal+order, residual_samples, order, residual); @@ -2237,32 +3692,38 @@ unsigned evaluate_fixed_subframe_( find_best_partition_order_( encoder->private_, residual, - abs_residual, abs_residual_partition_sums, raw_bits_per_partition, residual_samples, order, rice_parameter, + rice_parameter_limit, min_partition_order, max_partition_order, - precompute_partition_sums, + subframe_bps, do_escape_coding, rice_parameter_search_dist, - &subframe->data.fixed.entropy_coding_method.data.partitioned_rice + &subframe->data.fixed.entropy_coding_method ); subframe->data.fixed.order = order; for(i = 0; i < order; i++) subframe->data.fixed.warmup[i] = signal[i]; - return FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + (order * subframe_bps) + residual_bits; + estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (order * subframe_bps) + residual_bits; + +#if SPOTCHECK_ESTIMATE + spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); +#endif + + return estimate; } +#ifndef FLAC__INTEGER_ONLY_LIBRARY unsigned evaluate_lpc_subframe_( FLAC__StreamEncoder *encoder, const FLAC__int32 signal[], FLAC__int32 residual[], - FLAC__uint32 abs_residual[], FLAC__uint64 abs_residual_partition_sums[], unsigned raw_bits_per_partition[], const FLAC__real lp_coeff[], @@ -2271,17 +3732,17 @@ unsigned evaluate_lpc_subframe_( unsigned order, unsigned qlp_coeff_precision, unsigned rice_parameter, + unsigned rice_parameter_limit, unsigned min_partition_order, unsigned max_partition_order, - FLAC__bool precompute_partition_sums, FLAC__bool do_escape_coding, unsigned rice_parameter_search_dist, FLAC__Subframe *subframe, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents ) { - FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; - unsigned i, residual_bits; + FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; /* WATCHOUT: the size is important; some x86 intrinsic routines need more than lpc order elements */ + unsigned i, residual_bits, estimate; int quantization, ret; const unsigned residual_samples = blocksize - order; @@ -2289,7 +3750,7 @@ unsigned evaluate_lpc_subframe_( if(subframe_bps <= 16) { FLAC__ASSERT(order > 0); FLAC__ASSERT(order <= FLAC__MAX_LPC_ORDER); - qlp_coeff_precision = min(qlp_coeff_precision, 32 - subframe_bps - FLAC__bitmath_ilog2(order)); + qlp_coeff_precision = flac_min(qlp_coeff_precision, 32 - subframe_bps - FLAC__bitmath_ilog2(order)); } ret = FLAC__lpc_quantize_coefficients(lp_coeff, order, qlp_coeff_precision, qlp_coeff, &quantization); @@ -2314,18 +3775,18 @@ unsigned evaluate_lpc_subframe_( find_best_partition_order_( encoder->private_, residual, - abs_residual, abs_residual_partition_sums, raw_bits_per_partition, residual_samples, order, rice_parameter, + rice_parameter_limit, min_partition_order, max_partition_order, - precompute_partition_sums, + subframe_bps, do_escape_coding, rice_parameter_search_dist, - &subframe->data.fixed.entropy_coding_method.data.partitioned_rice + &subframe->data.lpc.entropy_coding_method ); subframe->data.lpc.order = order; @@ -2335,74 +3796,87 @@ unsigned evaluate_lpc_subframe_( for(i = 0; i < order; i++) subframe->data.lpc.warmup[i] = signal[i]; - return FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN + FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN + (order * (qlp_coeff_precision + subframe_bps)) + residual_bits; + estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN + FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN + (order * (qlp_coeff_precision + subframe_bps)) + residual_bits; + +#if SPOTCHECK_ESTIMATE + spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); +#endif + + return estimate; } +#endif unsigned evaluate_verbatim_subframe_( + FLAC__StreamEncoder *encoder, const FLAC__int32 signal[], unsigned blocksize, unsigned subframe_bps, FLAC__Subframe *subframe ) { + unsigned estimate; + subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM; subframe->data.verbatim.data = signal; - return FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + (blocksize * subframe_bps); + estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (blocksize * subframe_bps); + +#if SPOTCHECK_ESTIMATE + spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate); +#else + (void)encoder; +#endif + + return estimate; } unsigned find_best_partition_order_( FLAC__StreamEncoderPrivate *private_, const FLAC__int32 residual[], - FLAC__uint32 abs_residual[], FLAC__uint64 abs_residual_partition_sums[], unsigned raw_bits_per_partition[], unsigned residual_samples, unsigned predictor_order, unsigned rice_parameter, + unsigned rice_parameter_limit, unsigned min_partition_order, unsigned max_partition_order, - FLAC__bool precompute_partition_sums, + unsigned bps, FLAC__bool do_escape_coding, unsigned rice_parameter_search_dist, - FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice + FLAC__EntropyCodingMethod *best_ecm ) { - FLAC__int32 r; unsigned residual_bits, best_residual_bits = 0; - unsigned residual_sample; unsigned best_parameters_index = 0; + unsigned best_partition_order = 0; const unsigned blocksize = residual_samples + predictor_order; - /* compute abs(residual) for use later */ - for(residual_sample = 0; residual_sample < residual_samples; residual_sample++) { - r = residual[residual_sample]; - abs_residual[residual_sample] = (FLAC__uint32)(r<0? -r : r); - } - max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(max_partition_order, blocksize, predictor_order); - min_partition_order = min(min_partition_order, max_partition_order); + min_partition_order = flac_min(min_partition_order, max_partition_order); - if(precompute_partition_sums) { - int partition_order; - unsigned sum; + private_->local_precompute_partition_info_sums(residual, abs_residual_partition_sums, residual_samples, predictor_order, min_partition_order, max_partition_order, bps); - precompute_partition_info_sums_(abs_residual, abs_residual_partition_sums, residual_samples, predictor_order, min_partition_order, max_partition_order); + if(do_escape_coding) + precompute_partition_info_escapes_(residual, raw_bits_per_partition, residual_samples, predictor_order, min_partition_order, max_partition_order); - if(do_escape_coding) - precompute_partition_info_escapes_(residual, raw_bits_per_partition, residual_samples, predictor_order, min_partition_order, max_partition_order); + { + int partition_order; + unsigned sum; for(partition_order = (int)max_partition_order, sum = 0; partition_order >= (int)min_partition_order; partition_order--) { -#ifdef DONT_ESTIMATE_RICE_BITS if(! - set_partitioned_rice_with_precompute_( + set_partitioned_rice_( +#ifdef EXACT_RICE_BITS_CALCULATION residual, +#endif abs_residual_partition_sums+sum, raw_bits_per_partition+sum, residual_samples, predictor_order, rice_parameter, + rice_parameter_limit, rice_parameter_search_dist, (unsigned)partition_order, do_escape_coding, @@ -2410,23 +3884,6 @@ unsigned find_best_partition_order_( &residual_bits ) ) -#else - if(! - set_partitioned_rice_with_precompute_( - abs_residual, - abs_residual_partition_sums+sum, - raw_bits_per_partition+sum, - residual_samples, - predictor_order, - rice_parameter, - rice_parameter_search_dist, - (unsigned)partition_order, - do_escape_coding, - &private_->partitioned_rice_contents_extra[!best_parameters_index], - &residual_bits - ) - ) -#endif { FLAC__ASSERT(best_residual_bits != 0); break; @@ -2435,117 +3892,99 @@ unsigned find_best_partition_order_( if(best_residual_bits == 0 || residual_bits < best_residual_bits) { best_residual_bits = residual_bits; best_parameters_index = !best_parameters_index; - best_partitioned_rice->order = partition_order; + best_partition_order = partition_order; } } } - else { - unsigned partition_order; - for(partition_order = min_partition_order; partition_order <= max_partition_order; partition_order++) { -#ifdef DONT_ESTIMATE_RICE_BITS - if(! - set_partitioned_rice_( - abs_residual, - residual, - residual_samples, - predictor_order, - rice_parameter, - rice_parameter_search_dist, - partition_order, - &private_->partitioned_rice_contents_extra[!best_parameters_index], - &residual_bits - ) - ) -#else - if(! - set_partitioned_rice_( - abs_residual, - residual_samples, - predictor_order, - rice_parameter, - rice_parameter_search_dist, - partition_order, - &private_->partitioned_rice_contents_extra[!best_parameters_index], - &residual_bits - ) - ) -#endif - { - FLAC__ASSERT(best_residual_bits != 0); + + best_ecm->data.partitioned_rice.order = best_partition_order; + + { + /* + * We are allowed to de-const the pointer based on our special + * knowledge; it is const to the outside world. + */ + FLAC__EntropyCodingMethod_PartitionedRiceContents* prc = (FLAC__EntropyCodingMethod_PartitionedRiceContents*)best_ecm->data.partitioned_rice.contents; + unsigned partition; + + /* save best parameters and raw_bits */ + FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(prc, flac_max(6u, best_partition_order)); + memcpy(prc->parameters, private_->partitioned_rice_contents_extra[best_parameters_index].parameters, sizeof(unsigned)*(1<<(best_partition_order))); + if(do_escape_coding) + memcpy(prc->raw_bits, private_->partitioned_rice_contents_extra[best_parameters_index].raw_bits, sizeof(unsigned)*(1<<(best_partition_order))); + /* + * Now need to check if the type should be changed to + * FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 based on the + * size of the rice parameters. + */ + for(partition = 0; partition < (1u<<best_partition_order); partition++) { + if(prc->parameters[partition] >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { + best_ecm->type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2; break; } - if(best_residual_bits == 0 || residual_bits < best_residual_bits) { - best_residual_bits = residual_bits; - best_parameters_index = !best_parameters_index; - best_partitioned_rice->order = partition_order; - } } } - /* - * We are allowed to de-const the pointer based on our special knowledge; - * it is const to the outside world. - */ - { - FLAC__EntropyCodingMethod_PartitionedRiceContents* best_partitioned_rice_contents = (FLAC__EntropyCodingMethod_PartitionedRiceContents*)best_partitioned_rice->contents; - FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(best_partitioned_rice_contents, max(6, best_partitioned_rice->order)); - memcpy(best_partitioned_rice_contents->parameters, private_->partitioned_rice_contents_extra[best_parameters_index].parameters, sizeof(unsigned)*(1<<(best_partitioned_rice->order))); - memcpy(best_partitioned_rice_contents->raw_bits, private_->partitioned_rice_contents_extra[best_parameters_index].raw_bits, sizeof(unsigned)*(1<<(best_partitioned_rice->order))); - } - return best_residual_bits; } void precompute_partition_info_sums_( - const FLAC__uint32 abs_residual[], + const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, - unsigned max_partition_order + unsigned max_partition_order, + unsigned bps ) { - int partition_order; - unsigned from_partition, to_partition = 0; - const unsigned blocksize = residual_samples + predictor_order; - - /* first do max_partition_order */ - for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) { - FLAC__uint64 abs_residual_partition_sum; - FLAC__uint32 abs_r; - unsigned partition, partition_sample, partition_samples, residual_sample; - const unsigned partitions = 1u << partition_order; - const unsigned default_partition_samples = blocksize >> partition_order; + const unsigned default_partition_samples = (residual_samples + predictor_order) >> max_partition_order; + unsigned partitions = 1u << max_partition_order; - FLAC__ASSERT(default_partition_samples > predictor_order); + FLAC__ASSERT(default_partition_samples > predictor_order); - for(partition = residual_sample = 0; partition < partitions; partition++) { - partition_samples = default_partition_samples; - if(partition == 0) - partition_samples -= predictor_order; - abs_residual_partition_sum = 0; - for(partition_sample = 0; partition_sample < partition_samples; partition_sample++) { - abs_r = abs_residual[residual_sample]; - abs_residual_partition_sum += abs_r; - residual_sample++; + /* first do max_partition_order */ + { + unsigned partition, residual_sample, end = (unsigned)(-(int)predictor_order); + /* WATCHOUT: "+ bps + FLAC__MAX_EXTRA_RESIDUAL_BPS" is the maximum + * assumed size of the average residual magnitude */ + if(FLAC__bitmath_ilog2(default_partition_samples) + bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < 32) { + FLAC__uint32 abs_residual_partition_sum; + + for(partition = residual_sample = 0; partition < partitions; partition++) { + end += default_partition_samples; + abs_residual_partition_sum = 0; + for( ; residual_sample < end; residual_sample++) + abs_residual_partition_sum += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */ + abs_residual_partition_sums[partition] = abs_residual_partition_sum; + } + } + else { /* have to pessimistically use 64 bits for accumulator */ + FLAC__uint64 abs_residual_partition_sum; + + for(partition = residual_sample = 0; partition < partitions; partition++) { + end += default_partition_samples; + abs_residual_partition_sum = 0; + for( ; residual_sample < end; residual_sample++) + abs_residual_partition_sum += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */ + abs_residual_partition_sums[partition] = abs_residual_partition_sum; } - abs_residual_partition_sums[partition] = abs_residual_partition_sum; } - to_partition = partitions; - break; } /* now merge partitions for lower orders */ - for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) { - FLAC__uint64 s; - unsigned i; - const unsigned partitions = 1u << partition_order; - for(i = 0; i < partitions; i++) { - s = abs_residual_partition_sums[from_partition]; - from_partition++; - abs_residual_partition_sums[to_partition] = s + abs_residual_partition_sums[from_partition]; - from_partition++; - to_partition++; + { + unsigned from_partition = 0, to_partition = partitions; + int partition_order; + for(partition_order = (int)max_partition_order - 1; partition_order >= (int)min_partition_order; partition_order--) { + unsigned i; + partitions >>= 1; + for(i = 0; i < partitions; i++) { + abs_residual_partition_sums[to_partition++] = + abs_residual_partition_sums[from_partition ] + + abs_residual_partition_sums[from_partition+1]; + from_partition += 2; + } } } } @@ -2565,8 +4004,8 @@ void precompute_partition_info_escapes_( /* first do max_partition_order */ for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) { - FLAC__int32 r, residual_partition_min, residual_partition_max; - unsigned silog2_min, silog2_max; + FLAC__int32 r; + FLAC__uint32 rmax; unsigned partition, partition_sample, partition_samples, residual_sample; const unsigned partitions = 1u << partition_order; const unsigned default_partition_samples = blocksize >> partition_order; @@ -2577,21 +4016,20 @@ void precompute_partition_info_escapes_( partition_samples = default_partition_samples; if(partition == 0) partition_samples -= predictor_order; - residual_partition_min = residual_partition_max = 0; + rmax = 0; for(partition_sample = 0; partition_sample < partition_samples; partition_sample++) { - r = residual[residual_sample]; - if(r < residual_partition_min) - residual_partition_min = r; - else if(r > residual_partition_max) - residual_partition_max = r; - residual_sample++; + r = residual[residual_sample++]; + /* OPT: maybe faster: rmax |= r ^ (r>>31) */ + if(r < 0) + rmax |= ~r; + else + rmax |= r; } - silog2_min = FLAC__bitmath_silog2(residual_partition_min); - silog2_max = FLAC__bitmath_silog2(residual_partition_max); - raw_bits_per_partition[partition] = max(silog2_min, silog2_max); + /* now we know all residual values are in the range [-rmax-1,rmax] */ + raw_bits_per_partition[partition] = rmax? FLAC__bitmath_ilog2(rmax) + 2 : 1; } to_partition = partitions; - break; + break; /*@@@ yuck, should remove the 'for' loop instead */ } /* now merge partitions for lower orders */ @@ -2602,325 +4040,138 @@ void precompute_partition_info_escapes_( for(i = 0; i < partitions; i++) { m = raw_bits_per_partition[from_partition]; from_partition++; - raw_bits_per_partition[to_partition] = max(m, raw_bits_per_partition[from_partition]); + raw_bits_per_partition[to_partition] = flac_max(m, raw_bits_per_partition[from_partition]); from_partition++; to_partition++; } } } -#ifdef VARIABLE_RICE_BITS -#undef VARIABLE_RICE_BITS -#endif -#ifndef DONT_ESTIMATE_RICE_BITS -#define VARIABLE_RICE_BITS(value, parameter) ((value) >> (parameter)) -#endif - -#ifdef DONT_ESTIMATE_RICE_BITS -FLAC__bool set_partitioned_rice_( - const FLAC__uint32 abs_residual[], - const FLAC__int32 residual[], - const unsigned residual_samples, - const unsigned predictor_order, - const unsigned suggested_rice_parameter, - const unsigned rice_parameter_search_dist, - const unsigned partition_order, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, - unsigned *bits +#ifdef EXACT_RICE_BITS_CALCULATION +static inline unsigned count_rice_bits_in_partition_( + const unsigned rice_parameter, + const unsigned partition_samples, + const FLAC__int32 *residual ) +{ + unsigned i, partition_bits = + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + /* actually could end up being FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN but err on side of 16bps */ + (1+rice_parameter) * partition_samples /* 1 for unary stop bit + rice_parameter for the binary portion */ + ; + for(i = 0; i < partition_samples; i++) + partition_bits += ( (FLAC__uint32)((residual[i]<<1)^(residual[i]>>31)) >> rice_parameter ); + return partition_bits; +} #else -FLAC__bool set_partitioned_rice_( - const FLAC__uint32 abs_residual[], - const unsigned residual_samples, - const unsigned predictor_order, - const unsigned suggested_rice_parameter, - const unsigned rice_parameter_search_dist, - const unsigned partition_order, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, - unsigned *bits +static inline unsigned count_rice_bits_in_partition_( + const unsigned rice_parameter, + const unsigned partition_samples, + const FLAC__uint64 abs_residual_partition_sum ) -#endif { - unsigned rice_parameter, partition_bits; -#ifndef NO_RICE_SEARCH - unsigned best_partition_bits; - unsigned min_rice_parameter, max_rice_parameter, best_rice_parameter = 0; -#endif - unsigned bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; - unsigned *parameters; - - FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER); - - FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order)); - parameters = partitioned_rice_contents->parameters; - - if(partition_order == 0) { - unsigned i; - -#ifndef NO_RICE_SEARCH - if(rice_parameter_search_dist) { - if(suggested_rice_parameter < rice_parameter_search_dist) - min_rice_parameter = 0; - else - min_rice_parameter = suggested_rice_parameter - rice_parameter_search_dist; - max_rice_parameter = suggested_rice_parameter + rice_parameter_search_dist; - if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { -#ifdef DEBUG_VERBOSE - fprintf(stderr, "clipping rice_parameter (%u -> %u) @2\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1); -#endif - max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1; - } - } - else - min_rice_parameter = max_rice_parameter = suggested_rice_parameter; - - best_partition_bits = 0xffffffff; - for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) { -#endif -#ifdef VARIABLE_RICE_BITS -#ifdef FLAC__SYMMETRIC_RICE - partition_bits = (2+rice_parameter) * residual_samples; -#else - const unsigned rice_parameter_estimate = rice_parameter-1; - partition_bits = (1+rice_parameter) * residual_samples; -#endif -#else - partition_bits = 0; -#endif - partition_bits += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; - for(i = 0; i < residual_samples; i++) { -#ifdef VARIABLE_RICE_BITS -#ifdef FLAC__SYMMETRIC_RICE - partition_bits += VARIABLE_RICE_BITS(abs_residual[i], rice_parameter); -#else - partition_bits += VARIABLE_RICE_BITS(abs_residual[i], rice_parameter_estimate); -#endif -#else - partition_bits += FLAC__bitbuffer_rice_bits(residual[i], rice_parameter); /* NOTE: we will need to pass in residual[] in addition to abs_residual[] */ -#endif - } -#ifndef NO_RICE_SEARCH - if(partition_bits < best_partition_bits) { - best_rice_parameter = rice_parameter; - best_partition_bits = partition_bits; - } - } -#endif - parameters[0] = best_rice_parameter; - bits_ += best_partition_bits; - } - else { - unsigned partition, residual_sample, save_residual_sample, partition_sample; - unsigned partition_samples; - FLAC__uint64 mean, k; - const unsigned partitions = 1u << partition_order; - for(partition = residual_sample = 0; partition < partitions; partition++) { - partition_samples = (residual_samples+predictor_order) >> partition_order; - if(partition == 0) { - if(partition_samples <= predictor_order) - return false; - else - partition_samples -= predictor_order; - } - mean = 0; - save_residual_sample = residual_sample; - for(partition_sample = 0; partition_sample < partition_samples; residual_sample++, partition_sample++) - mean += abs_residual[residual_sample]; - residual_sample = save_residual_sample; -#ifdef FLAC__SYMMETRIC_RICE - mean += partition_samples >> 1; /* for rounding effect */ - mean /= partition_samples; - - /* calc rice_parameter = floor(log2(mean)) */ - rice_parameter = 0; - mean>>=1; - while(mean) { - rice_parameter++; - mean >>= 1; - } -#else - /* calc rice_parameter ala LOCO-I */ - for(rice_parameter = 0, k = partition_samples; k < mean; rice_parameter++, k <<= 1) - ; -#endif - if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { -#ifdef DEBUG_VERBOSE - fprintf(stderr, "clipping rice_parameter (%u -> %u) @3\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1); -#endif - rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1; - } - -#ifndef NO_RICE_SEARCH - if(rice_parameter_search_dist) { - if(rice_parameter < rice_parameter_search_dist) - min_rice_parameter = 0; - else - min_rice_parameter = rice_parameter - rice_parameter_search_dist; - max_rice_parameter = rice_parameter + rice_parameter_search_dist; - if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { -#ifdef DEBUG_VERBOSE - fprintf(stderr, "clipping rice_parameter (%u -> %u) @4\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1); -#endif - max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1; - } - } - else - min_rice_parameter = max_rice_parameter = rice_parameter; - - best_partition_bits = 0xffffffff; - for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) { -#endif -#ifdef VARIABLE_RICE_BITS -#ifdef FLAC__SYMMETRIC_RICE - partition_bits = (2+rice_parameter) * partition_samples; -#else - const unsigned rice_parameter_estimate = rice_parameter-1; - partition_bits = (1+rice_parameter) * partition_samples; -#endif -#else - partition_bits = 0; -#endif - partition_bits += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; - save_residual_sample = residual_sample; - for(partition_sample = 0; partition_sample < partition_samples; residual_sample++, partition_sample++) { -#ifdef VARIABLE_RICE_BITS -#ifdef FLAC__SYMMETRIC_RICE - partition_bits += VARIABLE_RICE_BITS(abs_residual[residual_sample], rice_parameter); -#else - partition_bits += VARIABLE_RICE_BITS(abs_residual[residual_sample], rice_parameter_estimate); -#endif -#else - partition_bits += FLAC__bitbuffer_rice_bits(residual[residual_sample], rice_parameter); /* NOTE: we will need to pass in residual[] in addition to abs_residual[] */ -#endif - } -#ifndef NO_RICE_SEARCH - if(rice_parameter != max_rice_parameter) - residual_sample = save_residual_sample; - if(partition_bits < best_partition_bits) { - best_rice_parameter = rice_parameter; - best_partition_bits = partition_bits; - } - } -#endif - parameters[partition] = best_rice_parameter; - bits_ += best_partition_bits; - } - } - - *bits = bits_; - return true; + return + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + /* actually could end up being FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN but err on side of 16bps */ + (1+rice_parameter) * partition_samples + /* 1 for unary stop bit + rice_parameter for the binary portion */ + ( + rice_parameter? + (unsigned)(abs_residual_partition_sum >> (rice_parameter-1)) /* rice_parameter-1 because the real coder sign-folds instead of using a sign bit */ + : (unsigned)(abs_residual_partition_sum << 1) /* can't shift by negative number, so reverse */ + ) + - (partition_samples >> 1) + /* -(partition_samples>>1) to subtract out extra contributions to the abs_residual_partition_sum. + * The actual number of bits used is closer to the sum(for all i in the partition) of abs(residual[i])>>(rice_parameter-1) + * By using the abs_residual_partition sum, we also add in bits in the LSBs that would normally be shifted out. + * So the subtraction term tries to guess how many extra bits were contributed. + * If the LSBs are randomly distributed, this should average to 0.5 extra bits per sample. + */ + ; } +#endif -#ifdef DONT_ESTIMATE_RICE_BITS -FLAC__bool set_partitioned_rice_with_precompute_( +FLAC__bool set_partitioned_rice_( +#ifdef EXACT_RICE_BITS_CALCULATION const FLAC__int32 residual[], +#endif const FLAC__uint64 abs_residual_partition_sums[], const unsigned raw_bits_per_partition[], const unsigned residual_samples, const unsigned predictor_order, const unsigned suggested_rice_parameter, + const unsigned rice_parameter_limit, const unsigned rice_parameter_search_dist, const unsigned partition_order, const FLAC__bool search_for_escapes, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, unsigned *bits ) -#else -FLAC__bool set_partitioned_rice_with_precompute_( - const FLAC__uint32 abs_residual[], - const FLAC__uint64 abs_residual_partition_sums[], - const unsigned raw_bits_per_partition[], - const unsigned residual_samples, - const unsigned predictor_order, - const unsigned suggested_rice_parameter, - const unsigned rice_parameter_search_dist, - const unsigned partition_order, - const FLAC__bool search_for_escapes, - FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, - unsigned *bits -) -#endif { unsigned rice_parameter, partition_bits; -#ifndef NO_RICE_SEARCH - unsigned best_partition_bits; - unsigned min_rice_parameter, max_rice_parameter, best_rice_parameter = 0; -#endif - unsigned flat_bits; + unsigned best_partition_bits, best_rice_parameter = 0; unsigned bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; unsigned *parameters, *raw_bits; +#ifdef ENABLE_RICE_PARAMETER_SEARCH + unsigned min_rice_parameter, max_rice_parameter; +#else + (void)rice_parameter_search_dist; +#endif - FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER); + FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER); + FLAC__ASSERT(rice_parameter_limit <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER); - FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order)); + FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, flac_max(6u, partition_order)); parameters = partitioned_rice_contents->parameters; raw_bits = partitioned_rice_contents->raw_bits; if(partition_order == 0) { - unsigned i; - -#ifndef NO_RICE_SEARCH + best_partition_bits = (unsigned)(-1); +#ifdef ENABLE_RICE_PARAMETER_SEARCH if(rice_parameter_search_dist) { if(suggested_rice_parameter < rice_parameter_search_dist) min_rice_parameter = 0; else min_rice_parameter = suggested_rice_parameter - rice_parameter_search_dist; max_rice_parameter = suggested_rice_parameter + rice_parameter_search_dist; - if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { + if(max_rice_parameter >= rice_parameter_limit) { #ifdef DEBUG_VERBOSE - fprintf(stderr, "clipping rice_parameter (%u -> %u) @5\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1); + fprintf(stderr, "clipping rice_parameter (%u -> %u) @5\n", max_rice_parameter, rice_parameter_limit - 1); #endif - max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1; + max_rice_parameter = rice_parameter_limit - 1; } } else min_rice_parameter = max_rice_parameter = suggested_rice_parameter; - best_partition_bits = 0xffffffff; for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) { -#endif -#ifdef VARIABLE_RICE_BITS -#ifdef FLAC__SYMMETRIC_RICE - partition_bits = (2+rice_parameter) * residual_samples; #else - const unsigned rice_parameter_estimate = rice_parameter-1; - partition_bits = (1+rice_parameter) * residual_samples; + rice_parameter = suggested_rice_parameter; #endif +#ifdef EXACT_RICE_BITS_CALCULATION + partition_bits = count_rice_bits_in_partition_(rice_parameter, residual_samples, residual); #else - partition_bits = 0; + partition_bits = count_rice_bits_in_partition_(rice_parameter, residual_samples, abs_residual_partition_sums[0]); #endif - partition_bits += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; - for(i = 0; i < residual_samples; i++) { -#ifdef VARIABLE_RICE_BITS -#ifdef FLAC__SYMMETRIC_RICE - partition_bits += VARIABLE_RICE_BITS(abs_residual[i], rice_parameter); -#else - partition_bits += VARIABLE_RICE_BITS(abs_residual[i], rice_parameter_estimate); -#endif -#else - partition_bits += FLAC__bitbuffer_rice_bits(residual[i], rice_parameter); /* NOTE: we will need to pass in residual[] instead of abs_residual[] */ -#endif - } -#ifndef NO_RICE_SEARCH if(partition_bits < best_partition_bits) { best_rice_parameter = rice_parameter; best_partition_bits = partition_bits; } +#ifdef ENABLE_RICE_PARAMETER_SEARCH } #endif if(search_for_escapes) { - flat_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[0] * residual_samples; - if(flat_bits <= best_partition_bits) { + partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[0] * residual_samples; + if(partition_bits <= best_partition_bits) { raw_bits[0] = raw_bits_per_partition[0]; - best_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; - best_partition_bits = flat_bits; + best_rice_parameter = 0; /* will be converted to appropriate escape parameter later */ + best_partition_bits = partition_bits; } + else + raw_bits[0] = 0; } parameters[0] = best_rice_parameter; bits_ += best_partition_bits; } else { - unsigned partition, residual_sample, save_residual_sample, partition_sample; + unsigned partition, residual_sample; unsigned partition_samples; FLAC__uint64 mean, k; const unsigned partitions = 1u << partition_order; @@ -2933,91 +4184,95 @@ FLAC__bool set_partitioned_rice_with_precompute_( partition_samples -= predictor_order; } mean = abs_residual_partition_sums[partition]; -#ifdef FLAC__SYMMETRIC_RICE - mean += partition_samples >> 1; /* for rounding effect */ - mean /= partition_samples; - - /* calc rice_parameter = floor(log2(mean)) */ - rice_parameter = 0; - mean>>=1; - while(mean) { - rice_parameter++; - mean >>= 1; - } -#else - /* calc rice_parameter ala LOCO-I */ + /* we are basically calculating the size in bits of the + * average residual magnitude in the partition: + * rice_parameter = floor(log2(mean/partition_samples)) + * 'mean' is not a good name for the variable, it is + * actually the sum of magnitudes of all residual values + * in the partition, so the actual mean is + * mean/partition_samples + */ +#if 0 /* old simple code */ for(rice_parameter = 0, k = partition_samples; k < mean; rice_parameter++, k <<= 1) ; +#else +#if defined FLAC__CPU_X86_64 /* and other 64-bit arch, too */ + if(mean <= 0x80000000/512) { /* 512: more or less optimal for both 16- and 24-bit input */ +#else + if(mean <= 0x80000000/8) { /* 32-bit arch: use 32-bit math if possible */ #endif - if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { + FLAC__uint32 k2, mean2 = (FLAC__uint32) mean; + rice_parameter = 0; k2 = partition_samples; + while(k2*8 < mean2) { /* requires: mean <= (2^31)/8 */ + rice_parameter += 4; k2 <<= 4; /* tuned for 16-bit input */ + } + while(k2 < mean2) { /* requires: mean <= 2^31 */ + rice_parameter++; k2 <<= 1; + } + } + else { + rice_parameter = 0; k = partition_samples; + if(mean <= FLAC__U64L(0x8000000000000000)/128) /* usually mean is _much_ smaller than this value */ + while(k*128 < mean) { /* requires: mean <= (2^63)/128 */ + rice_parameter += 8; k <<= 8; /* tuned for 24-bit input */ + } + while(k < mean) { /* requires: mean <= 2^63 */ + rice_parameter++; k <<= 1; + } + } +#endif + if(rice_parameter >= rice_parameter_limit) { #ifdef DEBUG_VERBOSE - fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1); + fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, rice_parameter_limit - 1); #endif - rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1; + rice_parameter = rice_parameter_limit - 1; } -#ifndef NO_RICE_SEARCH + best_partition_bits = (unsigned)(-1); +#ifdef ENABLE_RICE_PARAMETER_SEARCH if(rice_parameter_search_dist) { if(rice_parameter < rice_parameter_search_dist) min_rice_parameter = 0; else min_rice_parameter = rice_parameter - rice_parameter_search_dist; max_rice_parameter = rice_parameter + rice_parameter_search_dist; - if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { + if(max_rice_parameter >= rice_parameter_limit) { #ifdef DEBUG_VERBOSE - fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1); + fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, rice_parameter_limit - 1); #endif - max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1; + max_rice_parameter = rice_parameter_limit - 1; } } else min_rice_parameter = max_rice_parameter = rice_parameter; - best_partition_bits = 0xffffffff; for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) { #endif -#ifdef VARIABLE_RICE_BITS -#ifdef FLAC__SYMMETRIC_RICE - partition_bits = (2+rice_parameter) * partition_samples; -#else - const unsigned rice_parameter_estimate = rice_parameter-1; - partition_bits = (1+rice_parameter) * partition_samples; -#endif -#else - partition_bits = 0; -#endif - partition_bits += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; - save_residual_sample = residual_sample; - for(partition_sample = 0; partition_sample < partition_samples; residual_sample++, partition_sample++) { -#ifdef VARIABLE_RICE_BITS -#ifdef FLAC__SYMMETRIC_RICE - partition_bits += VARIABLE_RICE_BITS(abs_residual[residual_sample], rice_parameter); -#else - partition_bits += VARIABLE_RICE_BITS(abs_residual[residual_sample], rice_parameter_estimate); -#endif +#ifdef EXACT_RICE_BITS_CALCULATION + partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, residual+residual_sample); #else - partition_bits += FLAC__bitbuffer_rice_bits(residual[residual_sample], rice_parameter); /* NOTE: we will need to pass in residual[] instead of abs_residual[] */ + partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, abs_residual_partition_sums[partition]); #endif - } -#ifndef NO_RICE_SEARCH - if(rice_parameter != max_rice_parameter) - residual_sample = save_residual_sample; if(partition_bits < best_partition_bits) { best_rice_parameter = rice_parameter; best_partition_bits = partition_bits; } +#ifdef ENABLE_RICE_PARAMETER_SEARCH } #endif if(search_for_escapes) { - flat_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[partition] * partition_samples; - if(flat_bits <= best_partition_bits) { + partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[partition] * partition_samples; + if(partition_bits <= best_partition_bits) { raw_bits[partition] = raw_bits_per_partition[partition]; - best_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; - best_partition_bits = flat_bits; + best_rice_parameter = 0; /* will be converted to appropriate escape parameter later */ + best_partition_bits = partition_bits; } + else + raw_bits[partition] = 0; } parameters[partition] = best_rice_parameter; bits_ += best_partition_bits; + residual_sample += partition_samples; } } @@ -3078,10 +4333,10 @@ void append_to_verify_fifo_interleaved_(verify_input_fifo *fifo, const FLAC__int FLAC__ASSERT(fifo->tail <= fifo->size); } -FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) +FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) { FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data; - const unsigned encoded_bytes = encoder->private_->verify.output.bytes; + const size_t encoded_bytes = encoder->private_->verify.output.bytes; (void)decoder; if(encoder->private_->verify.needs_magic_hack) { @@ -3113,10 +4368,12 @@ FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder { FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder *)client_data; unsigned channel; - const unsigned channels = FLAC__stream_decoder_get_channels(decoder); + const unsigned channels = frame->header.channels; const unsigned blocksize = frame->header.blocksize; const unsigned bytes_per_block = sizeof(FLAC__int32) * blocksize; + (void)decoder; + for(channel = 0; channel < channels; channel++) { if(0 != memcmp(buffer[channel], encoder->private_->verify.input_fifo.data[channel], bytes_per_block)) { unsigned i, sample = 0; @@ -3143,10 +4400,10 @@ FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder } } /* dequeue the frame from the fifo */ - for(channel = 0; channel < channels; channel++) { - memmove(&encoder->private_->verify.input_fifo.data[channel][0], &encoder->private_->verify.input_fifo.data[channel][blocksize], encoder->private_->verify.input_fifo.tail - blocksize); - } encoder->private_->verify.input_fifo.tail -= blocksize; + FLAC__ASSERT(encoder->private_->verify.input_fifo.tail <= OVERREAD_); + for(channel = 0; channel < channels; channel++) + memmove(&encoder->private_->verify.input_fifo.data[channel][0], &encoder->private_->verify.input_fifo.data[channel][blocksize], encoder->private_->verify.input_fifo.tail * sizeof(encoder->private_->verify.input_fifo.data[0][0])); return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } @@ -3161,3 +4418,108 @@ void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDeco (void)decoder, (void)status; encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; } + +FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + (void)client_data; + + *bytes = fread(buffer, 1, *bytes, encoder->private_->file); + if (*bytes == 0) { + if (feof(encoder->private_->file)) + return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM; + else if (ferror(encoder->private_->file)) + return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; + } + return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE; +} + +FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + (void)client_data; + + if(fseeko(encoder->private_->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) + return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; + else + return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; +} + +FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + FLAC__off_t offset; + + (void)client_data; + + offset = ftello(encoder->private_->file); + + if(offset < 0) { + return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; + } + else { + *absolute_byte_offset = (FLAC__uint64)offset; + return FLAC__STREAM_ENCODER_TELL_STATUS_OK; + } +} + +#ifdef FLAC__VALGRIND_TESTING +static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t ret = fwrite(ptr, size, nmemb, stream); + if(!ferror(stream)) + fflush(stream); + return ret; +} +#else +#define local__fwrite fwrite +#endif + +FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data) +{ + (void)client_data, (void)current_frame; + + if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, encoder->private_->file) == bytes) { + FLAC__bool call_it = 0 != encoder->private_->progress_callback && ( +#if FLAC__HAS_OGG + /* We would like to be able to use 'samples > 0' in the + * clause here but currently because of the nature of our + * Ogg writing implementation, 'samples' is always 0 (see + * ogg_encoder_aspect.c). The downside is extra progress + * callbacks. + */ + encoder->private_->is_ogg? true : +#endif + samples > 0 + ); + if(call_it) { + /* NOTE: We have to add +bytes, +samples, and +1 to the stats + * because at this point in the callback chain, the stats + * have not been updated. Only after we return and control + * gets back to write_frame_() are the stats updated + */ + encoder->private_->progress_callback(encoder, encoder->private_->bytes_written+bytes, encoder->private_->samples_written+samples, encoder->private_->frames_written+(samples?1:0), encoder->private_->total_frames_estimate, encoder->private_->client_data); + } + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; + } + else + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; +} + +/* + * This will forcibly set stdout to binary mode (for OSes that require it) + */ +FILE *get_binary_stdout_(void) +{ + /* if something breaks here it is probably due to the presence or + * absence of an underscore before the identifiers 'setmode', + * 'fileno', and/or 'O_BINARY'; check your system header files. + */ +#if defined _MSC_VER || defined __MINGW32__ + _setmode(_fileno(stdout), _O_BINARY); +#elif defined __CYGWIN__ + /* almost certainly not needed for any modern Cygwin, but let's be safe... */ + setmode(_fileno(stdout), _O_BINARY); +#elif defined __EMX__ + setmode(fileno(stdout), O_BINARY); +#endif + + return stdout; +} diff --git a/sys/src/cmd/audio/libFLAC/stream_encoder_framing.c b/sys/src/cmd/audio/libFLAC/stream_encoder_framing.c index 5eb4a0cb1..959eca0a7 100644 --- a/sys/src/cmd/audio/libFLAC/stream_encoder_framing.c +++ b/sys/src/cmd/audio/libFLAC/stream_encoder_framing.c @@ -1,5 +1,6 @@ /* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000,2001,2002,2003,2004 Josh Coalson + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,29 +30,28 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + #include <stdio.h> #include <string.h> /* for strlen() */ #include "private/stream_encoder_framing.h" #include "private/crc.h" #include "FLAC/assert.h" -#ifdef max -#undef max -#endif -#define max(x,y) ((x)>(y)?(x):(y)) - -static FLAC__bool add_entropy_coding_method_(FLAC__BitBuffer *bb, const FLAC__EntropyCodingMethod *method); -static FLAC__bool add_residual_partitioned_rice_(FLAC__BitBuffer *bb, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order); +static FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method); +static FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order, const FLAC__bool is_extended); -FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitBuffer *bb) +FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw) { unsigned i, j; const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING); - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN)) return false; /* @@ -64,135 +64,168 @@ FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__ i += vendor_string_length; } FLAC__ASSERT(i < (1u << FLAC__STREAM_METADATA_LENGTH_LEN)); - if(!FLAC__bitbuffer_write_raw_uint32(bb, i, FLAC__STREAM_METADATA_LENGTH_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, i, FLAC__STREAM_METADATA_LENGTH_LEN)) return false; switch(metadata->type) { case FLAC__METADATA_TYPE_STREAMINFO: FLAC__ASSERT(metadata->data.stream_info.min_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN)); - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.min_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN)) return false; FLAC__ASSERT(metadata->data.stream_info.max_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)); - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.max_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)) return false; FLAC__ASSERT(metadata->data.stream_info.min_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)); - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.min_framesize, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_framesize, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) return false; FLAC__ASSERT(metadata->data.stream_info.max_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)); - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.max_framesize, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_framesize, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) return false; FLAC__ASSERT(FLAC__format_sample_rate_is_valid(metadata->data.stream_info.sample_rate)); - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.sample_rate, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.sample_rate, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN)) return false; FLAC__ASSERT(metadata->data.stream_info.channels > 0); FLAC__ASSERT(metadata->data.stream_info.channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)); - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.channels-1, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.channels-1, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)) return false; FLAC__ASSERT(metadata->data.stream_info.bits_per_sample > 0); FLAC__ASSERT(metadata->data.stream_info.bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)); - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.bits_per_sample-1, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.bits_per_sample-1, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint64(bb, metadata->data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) + if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) return false; - if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.stream_info.md5sum, 16)) + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.stream_info.md5sum, 16)) return false; break; case FLAC__METADATA_TYPE_PADDING: - if(!FLAC__bitbuffer_write_zeroes(bb, metadata->length * 8)) + if(!FLAC__bitwriter_write_zeroes(bw, metadata->length * 8)) return false; break; case FLAC__METADATA_TYPE_APPLICATION: - if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) return false; - if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.application.data, metadata->length - (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8))) + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.data, metadata->length - (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8))) return false; break; case FLAC__METADATA_TYPE_SEEKTABLE: for(i = 0; i < metadata->data.seek_table.num_points; i++) { - if(!FLAC__bitbuffer_write_raw_uint64(bb, metadata->data.seek_table.points[i].sample_number, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN)) + if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].sample_number, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint64(bb, metadata->data.seek_table.points[i].stream_offset, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN)) + if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].stream_offset, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.seek_table.points[i].frame_samples, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.seek_table.points[i].frame_samples, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN)) return false; } break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: - if(!FLAC__bitbuffer_write_raw_uint32_little_endian(bb, vendor_string_length)) + if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, vendor_string_length)) return false; - if(!FLAC__bitbuffer_write_byte_block(bb, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length)) + if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length)) return false; - if(!FLAC__bitbuffer_write_raw_uint32_little_endian(bb, metadata->data.vorbis_comment.num_comments)) + if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.num_comments)) return false; for(i = 0; i < metadata->data.vorbis_comment.num_comments; i++) { - if(!FLAC__bitbuffer_write_raw_uint32_little_endian(bb, metadata->data.vorbis_comment.comments[i].length)) + if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.comments[i].length)) return false; - if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.vorbis_comment.comments[i].entry, metadata->data.vorbis_comment.comments[i].length)) + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.vorbis_comment.comments[i].entry, metadata->data.vorbis_comment.comments[i].length)) return false; } break; case FLAC__METADATA_TYPE_CUESHEET: FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); - if(!FLAC__bitbuffer_write_byte_block(bb, (const FLAC__byte*)metadata->data.cue_sheet.media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8)) + if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.cue_sheet.media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8)) return false; - if(!FLAC__bitbuffer_write_raw_uint64(bb, metadata->data.cue_sheet.lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN)) + if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.cue_sheet.lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.cue_sheet.is_cd? 1 : 0, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.is_cd? 1 : 0, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN)) return false; - if(!FLAC__bitbuffer_write_zeroes(bb, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)) + if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.cue_sheet.num_tracks, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.num_tracks, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN)) return false; for(i = 0; i < metadata->data.cue_sheet.num_tracks; i++) { const FLAC__StreamMetadata_CueSheet_Track *track = metadata->data.cue_sheet.tracks + i; - if(!FLAC__bitbuffer_write_raw_uint64(bb, track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN)) + if(!FLAC__bitwriter_write_raw_uint64(bw, track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, track->number, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, track->number, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN)) return false; FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); - if(!FLAC__bitbuffer_write_byte_block(bb, (const FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8)) + if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, track->type, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, track->type, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, track->pre_emphasis, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, track->pre_emphasis, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN)) return false; - if(!FLAC__bitbuffer_write_zeroes(bb, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)) + if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, track->num_indices, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, track->num_indices, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN)) return false; for(j = 0; j < track->num_indices; j++) { - const FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j; + const FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + j; - if(!FLAC__bitbuffer_write_raw_uint64(bb, index->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN)) + if(!FLAC__bitwriter_write_raw_uint64(bw, indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, index->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, indx->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN)) return false; - if(!FLAC__bitbuffer_write_zeroes(bb, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN)) + if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN)) return false; } } break; + case FLAC__METADATA_TYPE_PICTURE: + { + size_t len; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN)) + return false; + len = strlen(metadata->data.picture.mime_type); + if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) + return false; + if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.picture.mime_type, len)) + return false; + len = strlen((const char *)metadata->data.picture.description); + if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) + return false; + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.description, len)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.data_length, FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) + return false; + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.data, metadata->data.picture.data_length)) + return false; + } + break; default: - if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.unknown.data, metadata->length)) + if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.unknown.data, metadata->length)) return false; break; } - FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(bb)); + FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw)); return true; } -FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__bool streamable_subset, FLAC__BitBuffer *bb) +FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw) { unsigned u, blocksize_hint, sample_rate_hint; + FLAC__byte crc; - FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(bb)); + FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw)); - if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, 0, FLAC__FRAME_HEADER_RESERVED_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_RESERVED_LEN)) + return false; + + if(!FLAC__bitwriter_write_raw_uint32(bw, (header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER)? 0 : 1, FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN)) return false; FLAC__ASSERT(header->blocksize > 0 && header->blocksize <= FLAC__MAX_BLOCK_SIZE); @@ -216,28 +249,27 @@ FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__bool st default: if(header->blocksize <= 0x100) blocksize_hint = u = 6; - else if(header->blocksize <= 0x10000) + else blocksize_hint = u = 7; - else { - FLAC__ASSERT(0); - return false; - } break; } - if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_BLOCK_SIZE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BLOCK_SIZE_LEN)) return false; FLAC__ASSERT(FLAC__format_sample_rate_is_valid(header->sample_rate)); sample_rate_hint = 0; switch(header->sample_rate) { - case 8000: u = 4; break; - case 16000: u = 5; break; - case 22050: u = 6; break; - case 24000: u = 7; break; - case 32000: u = 8; break; - case 44100: u = 9; break; - case 48000: u = 10; break; - case 96000: u = 11; break; + case 88200: u = 1; break; + case 176400: u = 2; break; + case 192000: u = 3; break; + case 8000: u = 4; break; + case 16000: u = 5; break; + case 22050: u = 6; break; + case 24000: u = 7; break; + case 32000: u = 8; break; + case 44100: u = 9; break; + case 48000: u = 10; break; + case 96000: u = 11; break; default: if(header->sample_rate <= 255000 && header->sample_rate % 1000 == 0) sample_rate_hint = u = 12; @@ -245,15 +277,11 @@ FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__bool st sample_rate_hint = u = 14; else if(header->sample_rate <= 0xffff) sample_rate_hint = u = 13; - else if(streamable_subset) { - FLAC__ASSERT(0); - return false; - } else u = 0; break; } - if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_SAMPLE_RATE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_SAMPLE_RATE_LEN)) return false; FLAC__ASSERT(header->channels > 0 && header->channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN) && header->channels <= FLAC__MAX_CHANNELS); @@ -276,7 +304,7 @@ FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__bool st default: FLAC__ASSERT(0); } - if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN)) return false; FLAC__ASSERT(header->bits_per_sample > 0 && header->bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)); @@ -288,74 +316,91 @@ FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__bool st case 24: u = 6; break; default: u = 0; break; } - if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN)) return false; - FLAC__ASSERT(header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER); - if(!FLAC__bitbuffer_write_utf8_uint32(bb, header->number.frame_number)) - return false; + if(header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) { + if(!FLAC__bitwriter_write_utf8_uint32(bw, header->number.frame_number)) + return false; + } + else { + if(!FLAC__bitwriter_write_utf8_uint64(bw, header->number.sample_number)) + return false; + } if(blocksize_hint) - if(!FLAC__bitbuffer_write_raw_uint32(bb, header->blocksize-1, (blocksize_hint==6)? 8:16)) + if(!FLAC__bitwriter_write_raw_uint32(bw, header->blocksize-1, (blocksize_hint==6)? 8:16)) return false; switch(sample_rate_hint) { case 12: - if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate / 1000, 8)) + if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 1000, 8)) return false; break; case 13: - if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate, 16)) + if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate, 16)) return false; break; case 14: - if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate / 10, 16)) + if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 10, 16)) return false; break; } /* write the CRC */ - if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__bitbuffer_get_write_crc8(bb), FLAC__FRAME_HEADER_CRC_LEN)) + if(!FLAC__bitwriter_get_write_crc8(bw, &crc)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, crc, FLAC__FRAME_HEADER_CRC_LEN)) return false; return true; } -FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb) +FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw) { FLAC__bool ok; ok = - FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN) && - (wasted_bits? FLAC__bitbuffer_write_unary_unsigned(bb, wasted_bits-1) : true) && - FLAC__bitbuffer_write_raw_int32(bb, subframe->value, subframe_bps) + FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN) && + (wasted_bits? FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1) : true) && + FLAC__bitwriter_write_raw_int32(bw, subframe->value, subframe_bps) ; return ok; } -FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb) +FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw) { unsigned i; - if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK | (subframe->order<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK | (subframe->order<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) return false; if(wasted_bits) - if(!FLAC__bitbuffer_write_unary_unsigned(bb, wasted_bits-1)) + if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) return false; for(i = 0; i < subframe->order; i++) - if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->warmup[i], subframe_bps)) + if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps)) return false; - if(!add_entropy_coding_method_(bb, &subframe->entropy_coding_method)) + if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method)) return false; switch(subframe->entropy_coding_method.type) { case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - if(!add_residual_partitioned_rice_(bb, subframe->residual, residual_samples, subframe->order, subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, subframe->entropy_coding_method.data.partitioned_rice.order)) + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!add_residual_partitioned_rice_( + bw, + subframe->residual, + residual_samples, + subframe->order, + subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, + subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, + subframe->entropy_coding_method.data.partitioned_rice.order, + /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 + )) return false; break; default: @@ -365,33 +410,43 @@ FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsign return true; } -FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb) +FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw) { unsigned i; - if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK | ((subframe->order-1)<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK | ((subframe->order-1)<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) return false; if(wasted_bits) - if(!FLAC__bitbuffer_write_unary_unsigned(bb, wasted_bits-1)) + if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) return false; for(i = 0; i < subframe->order; i++) - if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->warmup[i], subframe_bps)) + if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps)) return false; - if(!FLAC__bitbuffer_write_raw_uint32(bb, subframe->qlp_coeff_precision-1, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, subframe->qlp_coeff_precision-1, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN)) return false; - if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->quantization_level, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN)) + if(!FLAC__bitwriter_write_raw_int32(bw, subframe->quantization_level, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN)) return false; for(i = 0; i < subframe->order; i++) - if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->qlp_coeff[i], subframe->qlp_coeff_precision)) + if(!FLAC__bitwriter_write_raw_int32(bw, subframe->qlp_coeff[i], subframe->qlp_coeff_precision)) return false; - if(!add_entropy_coding_method_(bb, &subframe->entropy_coding_method)) + if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method)) return false; switch(subframe->entropy_coding_method.type) { case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - if(!add_residual_partitioned_rice_(bb, subframe->residual, residual_samples, subframe->order, subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, subframe->entropy_coding_method.data.partitioned_rice.order)) + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!add_residual_partitioned_rice_( + bw, + subframe->residual, + residual_samples, + subframe->order, + subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, + subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, + subframe->entropy_coding_method.data.partitioned_rice.order, + /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 + )) return false; break; default: @@ -401,31 +456,32 @@ FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned r return true; } -FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb) +FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw) { unsigned i; const FLAC__int32 *signal = subframe->data; - if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) return false; if(wasted_bits) - if(!FLAC__bitbuffer_write_unary_unsigned(bb, wasted_bits-1)) + if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) return false; for(i = 0; i < samples; i++) - if(!FLAC__bitbuffer_write_raw_int32(bb, signal[i], subframe_bps)) + if(!FLAC__bitwriter_write_raw_int32(bw, signal[i], subframe_bps)) return false; return true; } -FLAC__bool add_entropy_coding_method_(FLAC__BitBuffer *bb, const FLAC__EntropyCodingMethod *method) +FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method) { - if(!FLAC__bitbuffer_write_raw_uint32(bb, method->type, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, method->type, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) return false; switch(method->type) { case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - if(!FLAC__bitbuffer_write_raw_uint32(bb, method->data.partitioned_rice.order, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: + if(!FLAC__bitwriter_write_raw_uint32(bw, method->data.partitioned_rice.order, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) return false; break; default: @@ -434,29 +490,28 @@ FLAC__bool add_entropy_coding_method_(FLAC__BitBuffer *bb, const FLAC__EntropyCo return true; } -FLAC__bool add_residual_partitioned_rice_(FLAC__BitBuffer *bb, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order) +FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order, const FLAC__bool is_extended) { + const unsigned plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; + const unsigned pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; + if(partition_order == 0) { unsigned i; - if(!FLAC__bitbuffer_write_raw_uint32(bb, rice_parameters[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)) - return false; - if(rice_parameters[0] < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { - for(i = 0; i < residual_samples; i++) { -#ifdef FLAC__SYMMETRIC_RICE - if(!FLAC__bitbuffer_write_symmetric_rice_signed(bb, residual[i], rice_parameters[0])) - return false; -#else - if(!FLAC__bitbuffer_write_rice_signed(bb, residual[i], rice_parameters[0])) - return false; -#endif - } + if(raw_bits[0] == 0) { + if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[0], plen)) + return false; + if(!FLAC__bitwriter_write_rice_signed_block(bw, residual, residual_samples, rice_parameters[0])) + return false; } else { - if(!FLAC__bitbuffer_write_raw_uint32(bb, raw_bits[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) + FLAC__ASSERT(rice_parameters[0] == 0); + if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) return false; for(i = 0; i < residual_samples; i++) { - if(!FLAC__bitbuffer_write_raw_int32(bb, residual[i], raw_bits[0])) + if(!FLAC__bitwriter_write_raw_int32(bw, residual[i], raw_bits[0])) return false; } } @@ -467,28 +522,23 @@ FLAC__bool add_residual_partitioned_rice_(FLAC__BitBuffer *bb, const FLAC__int32 unsigned partition_samples; const unsigned default_partition_samples = (residual_samples+predictor_order) >> partition_order; for(i = 0; i < (1u<<partition_order); i++) { - if(!FLAC__bitbuffer_write_raw_uint32(bb, rice_parameters[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)) - return false; partition_samples = default_partition_samples; if(i == 0) partition_samples -= predictor_order; k += partition_samples; - if(rice_parameters[i] < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { - for(j = k_last; j < k; j++) { -#ifdef FLAC__SYMMETRIC_RICE - if(!FLAC__bitbuffer_write_symmetric_rice_signed(bb, residual[j], rice_parameters[i])) - return false; -#else - if(!FLAC__bitbuffer_write_rice_signed(bb, residual[j], rice_parameters[i])) - return false; -#endif - } + if(raw_bits[i] == 0) { + if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[i], plen)) + return false; + if(!FLAC__bitwriter_write_rice_signed_block(bw, residual+k_last, k-k_last, rice_parameters[i])) + return false; } else { - if(!FLAC__bitbuffer_write_raw_uint32(bb, raw_bits[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) + if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen)) + return false; + if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) return false; for(j = k_last; j < k; j++) { - if(!FLAC__bitbuffer_write_raw_int32(bb, residual[j], raw_bits[i])) + if(!FLAC__bitwriter_write_raw_int32(bw, residual[j], raw_bits[i])) return false; } } diff --git a/sys/src/cmd/audio/libFLAC/window.c b/sys/src/cmd/audio/libFLAC/window.c new file mode 100644 index 000000000..4387ef727 --- /dev/null +++ b/sys/src/cmd/audio/libFLAC/window.c @@ -0,0 +1,282 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2006-2009 Josh Coalson + * Copyright (C) 2011-2014 Xiph.Org Foundation + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <math.h> +#include "share/compat.h" +#include "FLAC/assert.h" +#include "FLAC/format.h" +#include "private/window.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + + +void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + if (L & 1) { + for (n = 0; n <= N/2; n++) + window[n] = 2.0f * n / (float)N; + for (; n <= N; n++) + window[n] = 2.0f - 2.0f * n / (float)N; + } + else { + for (n = 0; n <= L/2-1; n++) + window[n] = 2.0f * n / (float)N; + for (; n <= N; n++) + window[n] = 2.0f - 2.0f * n / (float)N; + } +} + +void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N-0.5f) - 0.38f * cos(2.0f * M_PI * ((float)n/(float)N))); +} + +void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.42f - 0.5f * cos(2.0f * M_PI * n / N) + 0.08f * cos(4.0f * M_PI * n / N)); +} + +/* 4-term -92dB side-lobe */ +void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n <= N; n++) + window[n] = (FLAC__real)(0.35875f - 0.48829f * cos(2.0f * M_PI * n / N) + 0.14128f * cos(4.0f * M_PI * n / N) - 0.01168f * cos(6.0f * M_PI * n / N)); +} + +void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + const double N2 = (double)N / 2.; + FLAC__int32 n; + + for (n = 0; n <= N; n++) { + double k = ((double)n - N2) / N2; + k = 1.0f - k * k; + window[n] = (FLAC__real)(k * k); + } +} + +void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(1.0f - 1.93f * cos(2.0f * M_PI * n / N) + 1.29f * cos(4.0f * M_PI * n / N) - 0.388f * cos(6.0f * M_PI * n / N) + 0.0322f * cos(8.0f * M_PI * n / N)); +} + +void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev) +{ + const FLAC__int32 N = L - 1; + const double N2 = (double)N / 2.; + FLAC__int32 n; + + for (n = 0; n <= N; n++) { + const double k = ((double)n - N2) / (stddev * N2); + window[n] = (FLAC__real)exp(-0.5f * k * k); + } +} + +void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.54f - 0.46f * cos(2.0f * M_PI * n / N)); +} + +void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.5f - 0.5f * cos(2.0f * M_PI * n / N)); +} + +void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.402f - 0.498f * cos(2.0f * M_PI * n / N) + 0.098f * cos(4.0f * M_PI * n / N) - 0.001f * cos(6.0f * M_PI * n / N)); +} + +void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = (FLAC__real)(0.3635819f - 0.4891775f*cos(2.0f*M_PI*n/N) + 0.1365995f*cos(4.0f*M_PI*n/N) - 0.0106411f*cos(6.0f*M_PI*n/N)); +} + +void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L) +{ + FLAC__int32 n; + + for (n = 0; n < L; n++) + window[n] = 1.0f; +} + +void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L) +{ + FLAC__int32 n; + + if (L & 1) { + for (n = 1; n <= (L+1)/2; n++) + window[n-1] = 2.0f * n / ((float)L + 1.0f); + for (; n <= L; n++) + window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f); + } + else { + for (n = 1; n <= L/2; n++) + window[n-1] = 2.0f * n / ((float)L + 1.0f); + for (; n <= L; n++) + window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f); + } +} + +void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p) +{ + if (p <= 0.0) + FLAC__window_rectangle(window, L); + else if (p >= 1.0) + FLAC__window_hann(window, L); + else { + const FLAC__int32 Np = (FLAC__int32)(p / 2.0f * L) - 1; + FLAC__int32 n; + /* start with rectangle... */ + FLAC__window_rectangle(window, L); + /* ...replace ends with hann */ + if (Np > 0) { + for (n = 0; n <= Np; n++) { + window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * n / Np)); + window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * (n+Np) / Np)); + } + } + } +} + +void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end) +{ + const FLAC__int32 start_n = (FLAC__int32)(start * L); + const FLAC__int32 end_n = (FLAC__int32)(end * L); + const FLAC__int32 N = end_n - start_n; + FLAC__int32 Np, n, i; + + if (p <= 0.0f) + FLAC__window_partial_tukey(window, L, 0.05f, start, end); + else if (p >= 1.0f) + FLAC__window_partial_tukey(window, L, 0.95f, start, end); + else { + + Np = (FLAC__int32)(p / 2.0f * N); + + for (n = 0; n < start_n && n < L; n++) + window[n] = 0.0f; + for (i = 1; n < (start_n+Np) && n < L; n++, i++) + window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np)); + for (; n < (end_n-Np) && n < L; n++) + window[n] = 1.0f; + for (i = Np; n < end_n && n < L; n++, i--) + window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np)); + for (; n < L; n++) + window[n] = 0.0f; + } +} + +void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end) +{ + const FLAC__int32 start_n = (FLAC__int32)(start * L); + const FLAC__int32 end_n = (FLAC__int32)(end * L); + FLAC__int32 Ns, Ne, n, i; + + if (p <= 0.0f) + FLAC__window_punchout_tukey(window, L, 0.05f, start, end); + else if (p >= 1.0f) + FLAC__window_punchout_tukey(window, L, 0.95f, start, end); + else { + + Ns = (FLAC__int32)(p / 2.0f * start_n); + Ne = (FLAC__int32)(p / 2.0f * (L - end_n)); + + for (n = 0, i = 1; n < Ns && n < L; n++, i++) + window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns)); + for (; n < start_n-Ns && n < L; n++) + window[n] = 1.0f; + for (i = Ns; n < start_n && n < L; n++, i--) + window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns)); + for (; n < end_n && n < L; n++) + window[n] = 0.0f; + for (i = 1; n < end_n+Ne && n < L; n++, i++) + window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne)); + for (; n < L - (Ne) && n < L; n++) + window[n] = 1.0f; + for (i = Ne; n < L; n++, i--) + window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne)); + } +} + +void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L) +{ + const FLAC__int32 N = L - 1; + const double N2 = (double)N / 2.; + FLAC__int32 n; + + for (n = 0; n <= N; n++) { + const double k = ((double)n - N2) / N2; + window[n] = (FLAC__real)(1.0f - k * k); + } +} + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ |