From aa97e4d4981d61808a558c5ab36be6d3bcc2c4f6 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Wed, 16 Feb 2005 19:33:19 +0000 Subject: Initial import of libFLAC from flac-1.1.2.tar.gz git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5983 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/libFLAC/AUTHORS | 41 + apps/codecs/libFLAC/COPYING.Xiph | 28 + apps/codecs/libFLAC/README | 257 ++ apps/codecs/libFLAC/README.rockbox | 25 + apps/codecs/libFLAC/bitbuffer.c | 2690 ++++++++++++++++ apps/codecs/libFLAC/bitmath.c | 145 + apps/codecs/libFLAC/cpu.c | 179 ++ apps/codecs/libFLAC/crc.c | 149 + apps/codecs/libFLAC/file_decoder.c | 673 ++++ apps/codecs/libFLAC/file_encoder.c | 776 +++++ apps/codecs/libFLAC/fixed.c | 422 +++ apps/codecs/libFLAC/float.c | 304 ++ apps/codecs/libFLAC/format.c | 474 +++ apps/codecs/libFLAC/include/FLAC/all.h | 158 + apps/codecs/libFLAC/include/FLAC/assert.h | 45 + apps/codecs/libFLAC/include/FLAC/callback.h | 181 ++ apps/codecs/libFLAC/include/FLAC/export.h | 47 + apps/codecs/libFLAC/include/FLAC/file_decoder.h | 660 ++++ apps/codecs/libFLAC/include/FLAC/file_encoder.h | 871 +++++ apps/codecs/libFLAC/include/FLAC/format.h | 861 +++++ apps/codecs/libFLAC/include/FLAC/metadata.h | 1858 +++++++++++ apps/codecs/libFLAC/include/FLAC/ordinals.h | 73 + .../libFLAC/include/FLAC/seekable_stream_decoder.h | 931 ++++++ .../libFLAC/include/FLAC/seekable_stream_encoder.h | 992 ++++++ apps/codecs/libFLAC/include/FLAC/stream_decoder.h | 873 +++++ apps/codecs/libFLAC/include/FLAC/stream_encoder.h | 1064 ++++++ apps/codecs/libFLAC/include/private/all.h | 48 + apps/codecs/libFLAC/include/private/bitbuffer.h | 159 + apps/codecs/libFLAC/include/private/bitmath.h | 42 + apps/codecs/libFLAC/include/private/cpu.h | 94 + apps/codecs/libFLAC/include/private/crc.h | 57 + apps/codecs/libFLAC/include/private/fixed.h | 97 + apps/codecs/libFLAC/include/private/float.h | 97 + apps/codecs/libFLAC/include/private/format.h | 44 + apps/codecs/libFLAC/include/private/lpc.h | 197 ++ apps/codecs/libFLAC/include/private/md5.h | 54 + apps/codecs/libFLAC/include/private/memory.h | 56 + apps/codecs/libFLAC/include/private/metadata.h | 40 + .../include/private/stream_encoder_framing.h | 45 + apps/codecs/libFLAC/include/protected/all.h | 42 + .../libFLAC/include/protected/file_decoder.h | 41 + .../libFLAC/include/protected/file_encoder.h | 41 + .../include/protected/seekable_stream_decoder.h | 42 + .../include/protected/seekable_stream_encoder.h | 42 + .../libFLAC/include/protected/stream_decoder.h | 51 + .../libFLAC/include/protected/stream_encoder.h | 60 + apps/codecs/libFLAC/lpc.c | 430 +++ apps/codecs/libFLAC/md5.c | 315 ++ apps/codecs/libFLAC/memory.c | 188 ++ apps/codecs/libFLAC/metadata_iterators.c | 2964 +++++++++++++++++ apps/codecs/libFLAC/metadata_object.c | 1472 +++++++++ apps/codecs/libFLAC/seekable_stream_decoder.c | 1111 +++++++ apps/codecs/libFLAC/seekable_stream_encoder.c | 943 ++++++ apps/codecs/libFLAC/stream_decoder.c | 2157 +++++++++++++ apps/codecs/libFLAC/stream_encoder.c | 3394 ++++++++++++++++++++ apps/codecs/libFLAC/stream_encoder_framing.c | 499 +++ 56 files changed, 29599 insertions(+) create mode 100644 apps/codecs/libFLAC/AUTHORS create mode 100644 apps/codecs/libFLAC/COPYING.Xiph create mode 100644 apps/codecs/libFLAC/README create mode 100644 apps/codecs/libFLAC/README.rockbox create mode 100644 apps/codecs/libFLAC/bitbuffer.c create mode 100644 apps/codecs/libFLAC/bitmath.c create mode 100644 apps/codecs/libFLAC/cpu.c create mode 100644 apps/codecs/libFLAC/crc.c create mode 100644 apps/codecs/libFLAC/file_decoder.c create mode 100644 apps/codecs/libFLAC/file_encoder.c create mode 100644 apps/codecs/libFLAC/fixed.c create mode 100644 apps/codecs/libFLAC/float.c create mode 100644 apps/codecs/libFLAC/format.c create mode 100644 apps/codecs/libFLAC/include/FLAC/all.h create mode 100644 apps/codecs/libFLAC/include/FLAC/assert.h create mode 100644 apps/codecs/libFLAC/include/FLAC/callback.h create mode 100644 apps/codecs/libFLAC/include/FLAC/export.h create mode 100644 apps/codecs/libFLAC/include/FLAC/file_decoder.h create mode 100644 apps/codecs/libFLAC/include/FLAC/file_encoder.h create mode 100644 apps/codecs/libFLAC/include/FLAC/format.h create mode 100644 apps/codecs/libFLAC/include/FLAC/metadata.h create mode 100644 apps/codecs/libFLAC/include/FLAC/ordinals.h create mode 100644 apps/codecs/libFLAC/include/FLAC/seekable_stream_decoder.h create mode 100644 apps/codecs/libFLAC/include/FLAC/seekable_stream_encoder.h create mode 100644 apps/codecs/libFLAC/include/FLAC/stream_decoder.h create mode 100644 apps/codecs/libFLAC/include/FLAC/stream_encoder.h create mode 100644 apps/codecs/libFLAC/include/private/all.h create mode 100644 apps/codecs/libFLAC/include/private/bitbuffer.h create mode 100644 apps/codecs/libFLAC/include/private/bitmath.h create mode 100644 apps/codecs/libFLAC/include/private/cpu.h create mode 100644 apps/codecs/libFLAC/include/private/crc.h create mode 100644 apps/codecs/libFLAC/include/private/fixed.h create mode 100644 apps/codecs/libFLAC/include/private/float.h create mode 100644 apps/codecs/libFLAC/include/private/format.h create mode 100644 apps/codecs/libFLAC/include/private/lpc.h create mode 100644 apps/codecs/libFLAC/include/private/md5.h create mode 100644 apps/codecs/libFLAC/include/private/memory.h create mode 100644 apps/codecs/libFLAC/include/private/metadata.h create mode 100644 apps/codecs/libFLAC/include/private/stream_encoder_framing.h create mode 100644 apps/codecs/libFLAC/include/protected/all.h create mode 100644 apps/codecs/libFLAC/include/protected/file_decoder.h create mode 100644 apps/codecs/libFLAC/include/protected/file_encoder.h create mode 100644 apps/codecs/libFLAC/include/protected/seekable_stream_decoder.h create mode 100644 apps/codecs/libFLAC/include/protected/seekable_stream_encoder.h create mode 100644 apps/codecs/libFLAC/include/protected/stream_decoder.h create mode 100644 apps/codecs/libFLAC/include/protected/stream_encoder.h create mode 100644 apps/codecs/libFLAC/lpc.c create mode 100644 apps/codecs/libFLAC/md5.c create mode 100644 apps/codecs/libFLAC/memory.c create mode 100644 apps/codecs/libFLAC/metadata_iterators.c create mode 100644 apps/codecs/libFLAC/metadata_object.c create mode 100644 apps/codecs/libFLAC/seekable_stream_decoder.c create mode 100644 apps/codecs/libFLAC/seekable_stream_encoder.c create mode 100644 apps/codecs/libFLAC/stream_decoder.c create mode 100644 apps/codecs/libFLAC/stream_encoder.c create mode 100644 apps/codecs/libFLAC/stream_encoder_framing.c (limited to 'apps/codecs/libFLAC') diff --git a/apps/codecs/libFLAC/AUTHORS b/apps/codecs/libFLAC/AUTHORS new file mode 100644 index 0000000000..49ddae8466 --- /dev/null +++ b/apps/codecs/libFLAC/AUTHORS @@ -0,0 +1,41 @@ +/* FLAC - Free Lossless Audio Codec + * Copyright (C) 2001,2002,2003,2004,2005 Josh Coalson + * + * This file is part the FLAC project. FLAC is comprised of several + * components distributed under difference licenses. The codec libraries + * are distributed under Xiph.Org's BSD-like license (see the file + * COPYING.Xiph in this distribution). All other programs, libraries, and + * plugins are distributed under the GPL (see COPYING.GPL). The documentation + * is distributed under the Gnu FDL (see COPYING.FDL). Each file in the + * FLAC distribution contains at the top the terms under which it may be + * distributed. + * + * Since this particular file is relevant to all components of FLAC, + * it may be distributed under the Xiph.Org license, which is the least + * restrictive of those mentioned above. See the file COPYING.Xiph in this + * distribution. + */ + + +FLAC (http://flac.sourceforge.net/) is an Open Source lossless audio +codec developed by Josh Coalson . + +Other major contributors and their contributions: +"Andrey Astafiev" +* Russian translation of the HTML documentation + +"Miroslav Lichvar" +* IA-32 assembly versions of several libFLAC routines + +"Brady Patterson" +* AIFF file support, PPC assembly versions of libFLAC routines + +"Daisuke Shimamura" +* i18n support in the XMMS plugin + +"X-Fixer" +* Configuration system, tag editing, and file info in the Winamp2 plugin + +"Matt Zimmerman" +* Libtool/autoconf/automake make system, flac man page + diff --git a/apps/codecs/libFLAC/COPYING.Xiph b/apps/codecs/libFLAC/COPYING.Xiph new file mode 100644 index 0000000000..610a3ba144 --- /dev/null +++ b/apps/codecs/libFLAC/COPYING.Xiph @@ -0,0 +1,28 @@ +Copyright (C) 2000,2001,2002,2003,2004,2005 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. diff --git a/apps/codecs/libFLAC/README b/apps/codecs/libFLAC/README new file mode 100644 index 0000000000..e135601037 --- /dev/null +++ b/apps/codecs/libFLAC/README @@ -0,0 +1,257 @@ +/* FLAC - Free Lossless Audio Codec + * Copyright (C) 2001,2002,2003,2004,2005 Josh Coalson + * + * This file is part the FLAC project. FLAC is comprised of several + * components distributed under difference licenses. The codec libraries + * are distributed under Xiph.Org's BSD-like license (see the file + * COPYING.Xiph in this distribution). All other programs, libraries, and + * plugins are distributed under the GPL (see COPYING.GPL). The documentation + * is distributed under the Gnu FDL (see COPYING.FDL). Each file in the + * FLAC distribution contains at the top the terms under which it may be + * distributed. + * + * Since this particular file is relevant to all components of FLAC, + * it may be distributed under the Xiph.Org license, which is the least + * restrictive of those mentioned above. See the file COPYING.Xiph in this + * distribution. + */ + + +FLAC (http://flac.sourceforge.net/) is an Open Source lossless audio +codec developed by Josh Coalson. + +FLAC is comprised of + * `libFLAC', a library which implements reference encoders and + decoders, and a metadata interface + * `libFLAC++', a C++ object wrapper library around libFLAC + * `libOggFLAC' and `libOggFLAC++', which provide encoders and + decoders for FLAC streams in an Ogg container + * `flac', a command-line program for encoding and decoding files + * `metaflac', a command-line program for viewing and editing FLAC + metadata + * player plugins for XMMS and Winamp + * user and API documentation + +The libraries (libFLAC, libFLAC++, libOggFLAC, and libOggFLAC++) are +licensed under Xiph.org's BSD-like license (see COPYING.Xiph). All other +programs and plugins are licensed under the GNU General Public License +(see COPYING.GPL). The documentation is licensed under the GNU Free +Documentation License (see COPYING.FDL). + + +=============================================================================== +FLAC - 1.1.2 - Contents +=============================================================================== + +- Introduction +- Prerequisites +- Building in a GNU environment +- Building with Makefile.lite +- Building with MSVC +- Building on Mac OS X +- Note to embedded developers + + +=============================================================================== +Introduction +=============================================================================== + +This is the source release for the FLAC project. See + + doc/html/index.html + +for full documentation. + +A brief description of the directory tree: + + doc/ the HTML documentation + flac.pbproj/ the Mac OS X Project Builder project + include/ public include files for libFLAC and libFLAC++ + man/ the man page for `flac' + src/ the source code and private headers + test/ the test scripts + + +=============================================================================== +Prerequisites +=============================================================================== + +To build FLAC with support for Ogg FLAC you must have built and installed +libogg according to the specific instructions below. You must have +libogg 1.1.2 or greater, or there will be seeking problems with Ogg FLAC. + +If you are building on x86 and want the assembly optimizations, you will +need to have NASM >= 0.98.30 installed according to the specific instructions +below. + + +=============================================================================== +Building in a GNU environment +=============================================================================== + +FLAC uses autoconf and libtool for configuring and building. +Better documentation for these will be forthcoming, but in +general, this should work: + +./configure && make && make check && make install + +The 'make check' step is optional; omit it to skip all the tests, +which can take several hours and use around 70-80 megs of disk space. +Even though it will stop with an explicit message on any failure, it +does print out a lot of stuff so you might want to capture the output +to a file if you're having a problem. Also, don't run 'make check' +as root because it confuses some of the tests. + +NOTE: Despite our best efforts it's entirely possible to have +problems when using older versions of autoconf, automake, or +libtool. If you have the latest versions and still can't get it +to work, see the next section on Makefile.lite. + +There are a few FLAC-specific arguments you can give to +`configure': + +--enable-debug : Builds everything with debug symbols and some +extra (and more verbose) error checking. + +--disable-asm-optimizations : Disables the compilation of the +assembly routines. Many routines have assembly versions for +speed and `configure' is pretty good about knowing what is +supported, but you can use this option to build only from the +C sources. + +--enable-sse : If you are building for an x86 CPU that supports +SSE instructions, you can enable some of the faster routines +if your operating system also supports SSE instructions. flac +can tell if the CPU supports the instructions but currently has +no way to test if the OS does, so if it does, you must pass +this argument to configure to use the SSE routines. If flac +crashes when built with this option you will have to go back and +configure without --enable-sse. Note that +--disable-asm-optimizations implies --disable-sse. + +--enable-local-xmms-plugin : Installs the FLAC XMMS plugin in +$HOME/.xmms/Plugins, instead of the global XMMS plugin area +(usually /usr/lib/xmms/Input). + +--with-ogg= +--with-xmms-prefix= +--with-libiconv-prefix= +Use these if you have these packages but configure can't find them. + +If you want to build completely from scratch (i.e. starting with just +configure.in and Makefile.am) you should be able to just run 'autogen.sh' +but make sure and read the comments in that file first. + + +=============================================================================== +Building with Makefile.lite +=============================================================================== + +There is a more lightweight build system for do-it-yourself-ers. +It is also useful if configure isn't working, which may be the +case since lately we've had some problems with different versions +of automake and libtool. The Makefile.lite system should work +on GNU systems with few or no adjustments. + +From the top level just 'make -f Makefile.lite'. You can +specify zero or one optional target from 'release', 'debug', +'test', or 'clean'. The default is 'release'. There is no +'install' target but everything you need will end up in the +obj/ directory. + +If you are not on an x86 system or you don't have nasm, you +may have to change the DEFINES in src/libFLAC/Makefile.lite. If +you don't have nasm, remove -DFLAC__HAS_NASM. If your target is +not an x86, change -DFLAC__CPU_IA32 to -DFLAC__CPU_UNKNOWN. + + +=============================================================================== +Building with MSVC +=============================================================================== + +There are now .dsp projects and a master FLAC.dsw workspace to build +all the libraries and executables. + +Prerequisite: you must have the Ogg libraries installed as described +later. + +Prerequisite: you must have nasm installed, and nasmw.exe must be in +your PATH, or the path to nasmw.exe must be added to the list of +directories for executable files in the MSVC global options. + +To build everything, run Developer Studio, do File|Open Workspace, +and open FLAC.dsw. Select "Build | Set active configuration..." +from the menu, then in the dialog, select "All - Win32 Release" (or +Debug if you prefer). Click "Ok" then hit F7 to build. This will build +all libraries both statically (e.g. obj\release\lib\libFLAC_static.lib) +and as DLLs (e.g. obj\release\bin\libFLAC.dll), and it will build all +binaries, statically linked (e.g. obj\release\bin\flac.exe). + +Everything will end up in the "obj" directory. DLLs and .exe files +are all that are needed and can be copied to an installation area and +added to the PATH. The plugins have to be copied to their appropriate +place in the player area. For Winamp2 this is \Plugins. + +By default the code is configured with Ogg support. Before building FLAC +you will need to get the Ogg source distribution +(see http://xiph.org/ogg/vorbis/download/), build ogg_static.lib (load and +build win32\ogg_static.dsp), copy ogg_static.lib into FLAC's +'obj\release\lib' directory, and copy the entire include\ogg tree into +FLAC's 'include' directory (so that there is an 'ogg' directory in FLAC's +'include' directory with the files ogg.h, os_types.h and config_types.h). + + +=============================================================================== +Building on Mac OS X +=============================================================================== + +If you have Fink, the GNU flow above should work. Otherwise, +there is a Project Builder project in the top-level source +directory to build libFLAC and the command-line utilities on +Mac OS X. In a terminal, cd to the top-level directory (the +one that contains this README file) and type: + + pbxbuild -alltargets + +This will create everything and leave it in the build/ directory. +Don't worry about the rest of the stuff that is in build/ or +the stuff that was already there before building. + +The Project Builder project requires that you have libiconv and +libogg in /sw, ala fink. If you don't, you'll need to install +them somewhere and change the path to them in the Library Paths +section of several targets. + +It also assumes the CPU supports Altivec instructions. If it does +not, you will also have to add -DFLAC__NO_ASM to the CFLAGS in the +libFLAC target. + +There currently is no install procedure; you will have to +manually copy the tools to wherever you need them. + + +=============================================================================== +Note to embedded developers +=============================================================================== + +libFLAC has grown larger over time as more functionality has been +included, but much of it may be unnecessary for a particular embedded +implementation. Unused parts may be pruned by some simple editing of +configure.in and src/libFLAC/Makefile.am; the following dependency +graph shows which modules may be pruned without breaking things +further down: + +file_encoder.h + stream_encoder.h + format.h + +file_decoder.h + seekable_stream_decoder.h + stream_decoder.h + format.h + +metadata.h + format.h + +There is a section dedicated to embedded use in the libFLAC API +HTML documentation (see doc/html/api/index.html). diff --git a/apps/codecs/libFLAC/README.rockbox b/apps/codecs/libFLAC/README.rockbox new file mode 100644 index 0000000000..5c0c5ecc2c --- /dev/null +++ b/apps/codecs/libFLAC/README.rockbox @@ -0,0 +1,25 @@ +Library: libFLAC-1.1.2 (Released 2005-02-05) +Imported: 2005-02-16 by Dave Chapman + + +This directory contains a local version of libFLAC for use by Rockbox +for software decoding and encoding of FLAC files. + + +LICENSING INFORMATION + +libFLAC (which is only one part of the FLAC distribution) is +distributed under Xiph.Org's BSD-like license - see the files AUTHORS +and COPYING.Xiph in this directory for details. + + +IMPORT DETAILS + +The base version first imported into Rockbox was the libFLAC included +in the flac-1.1.2.tar.gz distribution, downloaded on 2005-02-06 from +Sourceforge. + +The contents of the flac-1.1.2/src/libFLAC directory (minus the +autoconf/automake files and ia32/ppc specific subdirectories) was +imported, along with the contents of the flac-1.2.2/include/FLAC +directory, which was moved into existing libFLAC/include directory. diff --git a/apps/codecs/libFLAC/bitbuffer.c b/apps/codecs/libFLAC/bitbuffer.c new file mode 100644 index 0000000000..8f5aefa67b --- /dev/null +++ b/apps/codecs/libFLAC/bitbuffer.c @@ -0,0 +1,2690 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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 /* for malloc() */ +#include /* 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. + * + */ + +/* + * Some optimization strategies are slower with older versions of MSVC + */ +#if defined _MSC_VER && _MSC_VER <= 1200 +#define FLAC__OLD_MSVC_FLAVOR +#endif + +/* + * 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 */ + +#ifndef FLAC__OLD_MSVC_FLAVOR +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 +}; +#endif + +#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)); +#ifndef FLAC__OLD_MSVC_FLAVOR +#define FLAC__ALIGNED_BLURB_UNARY(blurb) (byte_to_unary_table[blurb]) +#endif +#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)); +#ifndef FLAC__OLD_MSVC_FLAVOR +#define FLAC__ALIGNED_BLURB_UNARY(blurb) ((blurb) <= 0xff ? byte_to_unary_table[blurb] + 24 : ((blurb) <= 0xffff ? byte_to_unary_table[(blurb) >> 8] + 16 : ((blurb) <= 0xffffff ? byte_to_unary_table[(blurb) >> 16] + 8 : byte_to_unary_table[(blurb) >> 24]))) +#endif +#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) { +#if FLAC__BITS_PER_BLURB == 8 + /* + * memset and memcpy are usually implemented in assembly language + * by the system libc, and they can be much faster + */ + const unsigned r_end = bb->blurbs + (bb->bits? 1:0); + const unsigned r = bb->consumed_blurbs, l = r_end - r; + memmove(&bb->buffer[0], &bb->buffer[r], l); + memset(&bb->buffer[l], 0, r); +#elif FLAC__BITS_PER_BLURB == 32 + /* still needs optimization */ + const unsigned r_end = bb->blurbs + (bb->bits? 1:0); + unsigned l = 0, r = bb->consumed_blurbs; + for( ; r < r_end; l++, r++) + bb->buffer[l] = bb->buffer[r]; + for( ; l < r_end; l++) + bb->buffer[l] = 0; +#else + FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */ +#endif /* FLAC__BITS_PER_BLURB == 32 or 8 */ + + 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() +{ + 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; + 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; + 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<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< 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<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< 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; + total_bits = 1 + k + msbs; + pattern = 1 << k; /* the unary end bit */ + pattern |= (uval & ((1u<= 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; + total_bits = 1 + k + msbs; + pattern = 1 << k; /* the unary end bit */ + pattern |= (uval & ((1u<= 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) +#ifdef FLAC__OLD_MSVC_FLAVOR +{ + 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; +} +#else +{ + const FLAC__blurb *buffer = bb->buffer; + + unsigned i, j, val_i = nvals; + 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; + + cbits = bb->consumed_bits; + i = bb->consumed_blurbs; + while(val_i != 0) { + for( ; i < bb->blurbs; i++) { + blurb = (save_blurb = buffer[i]) << cbits; + while(1) { + if(state == 0) { + if(blurb) { + j = FLAC__ALIGNED_BLURB_UNARY(blurb); + msbs += j; + 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; + } + blurb <<= j; + } + 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); + *vals = (int)(uval >> 1 ^ -(int)(uval & 1)); + --val_i; + if(val_i == 0) { + i++; + goto break2; + } + ++vals; + + msbs = 0; + state = 0; + } + + lsbs_left -= available_bits; + break; + } + else { + cbits += lsbs_left; + uval <<= lsbs_left; + uval |= (blurb >> (FLAC__BITS_PER_BLURB - lsbs_left)); + blurb <<= lsbs_left; + + /* compose the value */ + uval |= (msbs << parameter); + *vals = (int)(uval >> 1 ^ -(int)(uval & 1)); + --val_i; + if(val_i == 0) + goto break2; + ++vals; + + msbs = 0; + state = 0; + } + } + } + } +break2: + bb->consumed_blurbs = i; + bb->consumed_bits = cbits; + bb->total_consumed_bits = (i << FLAC__BITS_PER_BLURB_LOG2) | cbits; + if(val_i != 0) { + 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; +} +#endif + +#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<= 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<= 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/apps/codecs/libFLAC/bitmath.c b/apps/codecs/libFLAC/bitmath.c new file mode 100644 index 0000000000..2bc509b414 --- /dev/null +++ b/apps/codecs/libFLAC/bitmath.c @@ -0,0 +1,145 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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 "private/bitmath.h" +#include "FLAC/assert.h" + +/* 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(FLAC__uint32 v) +{ + unsigned l = 0; + FLAC__ASSERT(v > 0); + while(v >>= 1) + l++; + return l; +} + +unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v) +{ + unsigned l = 0; + FLAC__ASSERT(v > 0); + while(v >>= 1) + l++; + return l; +} + +/* An example of what FLAC__bitmath_silog2() computes: + * + * silog2(-10) = 5 + * silog2(- 9) = 5 + * silog2(- 8) = 4 + * silog2(- 7) = 4 + * silog2(- 6) = 4 + * silog2(- 5) = 4 + * silog2(- 4) = 3 + * silog2(- 3) = 3 + * silog2(- 2) = 2 + * silog2(- 1) = 2 + * silog2( 0) = 0 + * silog2( 1) = 2 + * silog2( 2) = 3 + * silog2( 3) = 3 + * silog2( 4) = 4 + * silog2( 5) = 4 + * silog2( 6) = 4 + * silog2( 7) = 4 + * silog2( 8) = 5 + * silog2( 9) = 5 + * silog2( 10) = 5 + */ +unsigned FLAC__bitmath_silog2(int v) +{ + while(1) { + if(v == 0) { + return 0; + } + else if(v > 0) { + unsigned l = 0; + while(v) { + l++; + v >>= 1; + } + return l+1; + } + else if(v == -1) { + return 2; + } + else { + v++; + v = -v; + } + } +} + +unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v) +{ + while(1) { + if(v == 0) { + return 0; + } + else if(v > 0) { + unsigned l = 0; + while(v) { + l++; + v >>= 1; + } + return l+1; + } + else if(v == -1) { + return 2; + } + else { + v++; + v = -v; + } + } +} diff --git a/apps/codecs/libFLAC/cpu.c b/apps/codecs/libFLAC/cpu.c new file mode 100644 index 0000000000..1e6b27994f --- /dev/null +++ b/apps/codecs/libFLAC/cpu.c @@ -0,0 +1,179 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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 "private/cpu.h" +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined FLAC__CPU_PPC +#if !defined FLAC__NO_ASM +#if defined FLAC__SYS_DARWIN +#include +#include +#include +#include +#include +#ifndef CPU_SUBTYPE_POWERPC_970 +#define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100) +#endif +#else /* FLAC__SYS_DARWIN */ +#include +#include + +static sigjmp_buf jmpbuf; +static volatile sig_atomic_t canjump = 0; + +static void sigill_handler (int sig) +{ + if (!canjump) { + signal (sig, SIG_DFL); + raise (sig); + } + canjump = 0; + siglongjmp (jmpbuf, 1); +} +#endif /* FLAC__SYS_DARWIN */ +#endif /* FLAC__NO_ASM */ +#endif /* FLAC__CPU_PPC */ + +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; + +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; + + +void FLAC__cpu_info(FLAC__CPUInfo *info) +{ +#ifdef FLAC__CPU_IA32 + info->type = FLAC__CPUINFO_TYPE_IA32; +#if !defined FLAC__NO_ASM && defined FLAC__HAS_NASM + info->use_asm = true; + { + 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; +#else + info->data.ia32._3dnow = info->data.ia32.ext3dnow = info->data.ia32.extmmx = false; +#endif + } +#else + info->use_asm = false; +#endif +#elif defined FLAC__CPU_PPC + info->type = FLAC__CPUINFO_TYPE_PPC; +#if !defined FLAC__NO_ASM + info->use_asm = true; +#ifdef FLAC__USE_ALTIVEC +#if defined FLAC__SYS_DARWIN + { + int selectors[2] = { CTL_HW, HW_VECTORUNIT }; + int result = 0; + size_t length = sizeof(result); + int error = sysctl(selectors, 2, &result, &length, 0, 0); + + info->data.ppc.altivec = error==0 ? result!=0 : 0; + } + { + host_basic_info_data_t hostInfo; + mach_msg_type_number_t infoCount; + + infoCount = HOST_BASIC_INFO_COUNT; + host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount); + + info->data.ppc.ppc64 = (hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970); + } +#else /* FLAC__SYS_DARWIN */ + { + /* no Darwin, do it the brute-force way */ + /* this is borrowed from MPlayer from the libmpeg2 library */ + info->data.ppc.altivec = 0; + info->data.ppc.ppc64 = 0; + + signal (SIGILL, sigill_handler); + if (!sigsetjmp (jmpbuf, 1)) { + canjump = 1; + + asm volatile ( + "mtspr 256, %0\n\t" + "vand %%v0, %%v0, %%v0" + : + : "r" (-1) + ); + + info->data.ppc.altivec = 1; + } + canjump = 0; + if (!sigsetjmp (jmpbuf, 1)) { + int x = 0; + canjump = 1; + + /* PPC64 hardware implements the cntlzd instruction */ + asm volatile ("cntlzd %0, %1" : "=r" (x) : "r" (x) ); + + info->data.ppc.ppc64 = 1; + } + signal (SIGILL, SIG_DFL); + } +#endif /* FLAC__SYS_DARWIN */ +#else /* FLAC__USE_ALTIVEC */ + info->data.ppc.altivec = 0; + info->data.ppc.ppc64 = 0; +#endif /* FLAC__USE_ALTIVEC */ +#else /* FLAC__NO_ASM */ + info->use_asm = false; +#endif /* FLAC__NO_ASM */ +#else + info->type = FLAC__CPUINFO_TYPE_UNKNOWN; + info->use_asm = false; +#endif +} diff --git a/apps/codecs/libFLAC/crc.c b/apps/codecs/libFLAC/crc.c new file mode 100644 index 0000000000..52e1b600ea --- /dev/null +++ b/apps/codecs/libFLAC/crc.c @@ -0,0 +1,149 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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 "private/crc.h" + +/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */ + +FLAC__byte const FLAC__crc8_table[256] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, + 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, + 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, + 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, + 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, + 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, + 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, + 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, + 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, + 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, + 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, + 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 +}; + +/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */ + +FLAC__uint16 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, + 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, + 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, + 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, + 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, + 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, + 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, + 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, + 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, + 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, + 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, + 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, + 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, + 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, + 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, + 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, + 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, + 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, + 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, + 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, + 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, + 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, + 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, + 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, + 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, + 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, + 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, + 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, + 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 +}; + + +void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc) +{ + *crc = FLAC__crc8_table[*crc ^ data]; +} + +void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc) +{ + while(len--) + *crc = FLAC__crc8_table[*crc ^ *data++]; +} + +FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len) +{ + FLAC__uint8 crc = 0; + + while(len--) + crc = FLAC__crc8_table[crc ^ *data++]; + + 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) +{ + FLAC__uint16 crc = 0; + + while(len--) + crc = (crc<<8) ^ FLAC__crc16_table[(crc>>8) ^ *data++]; + + return crc; +} diff --git a/apps/codecs/libFLAC/file_decoder.c b/apps/codecs/libFLAC/file_decoder.c new file mode 100644 index 0000000000..29d489587a --- /dev/null +++ b/apps/codecs/libFLAC/file_decoder.c @@ -0,0 +1,673 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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 +#include /* for malloc() */ +#include /* for strcmp() */ +#include /* for stat() */ +#if defined _MSC_VER || defined __MINGW32__ +#include /* for _setmode() */ +#include /* for _O_BINARY */ +#elif defined __CYGWIN__ +#include /* for setmode(), O_BINARY */ +#include /* 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_(); +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" +}; + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +FLAC_API FLAC__FileDecoder *FLAC__file_decoder_new() +{ + 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_() +{ + /* 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/apps/codecs/libFLAC/file_encoder.c b/apps/codecs/libFLAC/file_encoder.c new file mode 100644 index 0000000000..db4c421f98 --- /dev/null +++ b/apps/codecs/libFLAC/file_encoder.c @@ -0,0 +1,776 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2002,2003,2004,2005 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 +#include /* for malloc() */ +#include /* 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" +}; + + +/*********************************************************************** + * + * 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/apps/codecs/libFLAC/fixed.c b/apps/codecs/libFLAC/fixed.c new file mode 100644 index 0000000000..c1d4a52baa --- /dev/null +++ b/apps/codecs/libFLAC/fixed.c @@ -0,0 +1,422 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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 +#include "private/bitmath.h" +#include "private/fixed.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))) + +#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< 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< 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]; + FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]); + FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]); + FLAC__int32 error, save; + FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; + unsigned i, order; + + for(i = 0; i < data_len; i++) { + error = data[i] ; total_error_0 += local_abs(error); save = error; + error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error; + error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error; + error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error; + 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)) + order = 0; + else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4)) + order = 1; + else if(total_error_2 < min(total_error_3, total_error_4)) + order = 2; + else if(total_error_3 < total_error_4) + order = 3; + else + order = 4; + + /* Estimate the expected number of bits per residual signal sample. */ + /* 'total_error*' is linearly related to the variance of the residual */ + /* signal, so we use it directly to compute E(|x|) */ + FLAC__ASSERT(data_len > 0 || total_error_0 == 0); + FLAC__ASSERT(data_len > 0 || total_error_1 == 0); + 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); +#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; +} + +#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]; + FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]); + FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]); + FLAC__int32 error, save; + /* total_error_* are 64-bits to avoid overflow when encoding + * erratic signals when the bits-per-sample and blocksize are + * large. + */ + FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; + unsigned i, order; + + for(i = 0; i < data_len; i++) { + error = data[i] ; total_error_0 += local_abs(error); save = error; + error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error; + error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error; + error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error; + 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)) + order = 0; + else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4)) + order = 1; + else if(total_error_2 < min(total_error_3, total_error_4)) + order = 2; + else if(total_error_3 < total_error_4) + order = 3; + else + order = 4; + + /* Estimate the expected number of bits per residual signal sample. */ + /* 'total_error*' is linearly related to the variance of the residual */ + /* signal, so we use it directly to compute E(|x|) */ + FLAC__ASSERT(data_len > 0 || total_error_0 == 0); + FLAC__ASSERT(data_len > 0 || total_error_1 == 0); + 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); +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#if defined _MSC_VER || defined __MINGW32__ + /* with MSVC you have to spoon feed it the casting */ + residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)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)(FLAC__int64)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)(FLAC__int64)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)(FLAC__int64)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)(FLAC__int64)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0); +#else + 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); +#endif +#else + 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; +} + +void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]) +{ + const int idata_len = (int)data_len; + int i; + + switch(order) { + case 0: + for(i = 0; i < idata_len; i++) { + residual[i] = data[i]; + } + break; + case 1: + 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] */ + residual[i] = data[i] - (data[i-1] << 1) + data[i-2]; + } + break; + case 3: + for(i = 0; i < idata_len; i++) { + /* == data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3] */ + residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3]; + } + 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] */ + residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4]; + } + break; + default: + FLAC__ASSERT(0); + } +} + +void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[]) +{ + int i, idata_len = (int)data_len; + + switch(order) { + case 0: + for(i = 0; i < idata_len; i++) { + data[i] = residual[i]; + } + break; + case 1: + 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] */ + data[i] = residual[i] + (data[i-1]<<1) - data[i-2]; + } + break; + case 3: + for(i = 0; i < idata_len; i++) { + /* residual[i] + 3*data[i-1] - 3*data[i-2]) + data[i-3] */ + data[i] = residual[i] + (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) + data[i-3]; + } + 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] */ + data[i] = residual[i] + ((data[i-1]+data[i-3])<<2) - ((data[i-2]<<2) + (data[i-2]<<1)) - data[i-4]; + } + break; + default: + FLAC__ASSERT(0); + } +} diff --git a/apps/codecs/libFLAC/float.c b/apps/codecs/libFLAC/float.c new file mode 100644 index 0000000000..cbb381d431 --- /dev/null +++ b/apps/codecs/libFLAC/float.c @@ -0,0 +1,304 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2004,2005 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 "FLAC/assert.h" + +#include "private/float.h" + +#ifdef FLAC__INTEGER_ONLY_LIBRARY + +/* 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 + +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/apps/codecs/libFLAC/format.c b/apps/codecs/libFLAC/format.c new file mode 100644 index 0000000000..25ec7d98b6 --- /dev/null +++ b/apps/codecs/libFLAC/format.c @@ -0,0 +1,474 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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 +#include /* for qsort() */ +#include "FLAC/assert.h" +#include "FLAC/format.h" +#include "private/format.h" + +#ifdef HAVE_CONFIG_H +#include +#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 + +/* 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.2 20050205"; +#else +FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20050205"; +#endif + +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_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */ + +FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */ + +FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */ + +FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff); + +FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */ + +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */ + +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */ +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */ +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */ + +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */ +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_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_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 */ +FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */ +FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */ +FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */ + +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_RICE_RAW_LEN = 5; /* bits */ + +FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1< FLAC__MAX_SAMPLE_RATE || + ( + sample_rate >= (1u << 16) && + !(sample_rate % 1000 == 0 || sample_rate % 10 == 0) + ) + ) { + return false; + } + else + return true; +} + +FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table) +{ + unsigned i; + FLAC__uint64 prev_sample_number = 0; + FLAC__bool got_prev = false; + + FLAC__ASSERT(0 != seek_table); + + for(i = 0; i < seek_table->num_points; i++) { + if(got_prev) { + if( + seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && + seek_table->points[i].sample_number <= prev_sample_number + ) + return false; + } + prev_sample_number = seek_table->points[i].sample_number; + got_prev = true; + } + + return true; +} + +/* used as the sort predicate for qsort() */ +static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r) +{ + /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */ + if(l->sample_number == r->sample_number) + return 0; + else if(l->sample_number < r->sample_number) + return -1; + else + return 1; +} + +FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table) +{ + unsigned i, j; + FLAC__bool first; + + FLAC__ASSERT(0 != seek_table); + + /* sort the seekpoints */ + qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_); + + /* uniquify the seekpoints */ + first = true; + for(i = j = 0; i < seek_table->num_points; i++) { + if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) { + if(!first) { + if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number) + continue; + } + } + first = false; + seek_table->points[j++] = seek_table->points[i]; + } + + for(i = j; i < seek_table->num_points; i++) { + seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + seek_table->points[i].stream_offset = 0; + seek_table->points[i].frame_samples = 0; + } + + return j; +} + +static __inline 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) + return 2; + else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) + return 3; + 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; +} + +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; + + if(check_cd_da_subset) { + if(cue_sheet->lead_in < 2 * 44100) { + if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds"; + return false; + } + if(cue_sheet->lead_in % 588 != 0) { + if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples"; + return false; + } + } + + if(cue_sheet->num_tracks == 0) { + if(violation) *violation = "cue sheet must have at least one track (the lead-out)"; + return false; + } + + if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) { + if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)"; + return false; + } + + for(i = 0; i < cue_sheet->num_tracks; i++) { + if(cue_sheet->tracks[i].number == 0) { + if(violation) *violation = "cue sheet may not have a track number 0"; + return false; + } + + if(check_cd_da_subset) { + if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) { + if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170"; + return false; + } + } + + 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"; + return false; + } + + if(i < cue_sheet->num_tracks - 1) { + if(cue_sheet->tracks[i].num_indices == 0) { + if(violation) *violation = "cue sheet track must have at least one index point"; + return false; + } + + if(cue_sheet->tracks[i].indices[0].number > 1) { + if(violation) *violation = "cue sheet track's first index number must be 0 or 1"; + return false; + } + } + + for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) { + if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) { + if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples"; + return false; + } + + if(j > 0) { + if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) { + if(violation) *violation = "cue sheet track index numbers must increase by 1"; + return false; + } + } + } + } + + return true; +} + +/* + * These routines are private to libFLAC + */ +unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order) +{ + return + FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order( + FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize), + blocksize, + predictor_order + ); +} + +unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize) +{ + unsigned max_rice_partition_order = 0; + while(!(blocksize & 1)) { + max_rice_partition_order++; + blocksize >>= 1; + } + return 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) +{ + unsigned max_rice_partition_order = limit; + + while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order) + max_rice_partition_order--; + + FLAC__ASSERT( + (max_rice_partition_order == 0 && blocksize >= predictor_order) || + (max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order) + ); + + return max_rice_partition_order; +} + +void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object) +{ + FLAC__ASSERT(0 != object); + + object->parameters = 0; + object->raw_bits = 0; + object->capacity_by_order = 0; +} + +void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object) +{ + FLAC__ASSERT(0 != object); + + if(0 != object->parameters) + free(object->parameters); + if(0 != object->raw_bits) + free(object->raw_bits); + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object); +} + +FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order) +{ + FLAC__ASSERT(0 != object); + + 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)))) + return false; + if(0 == (object->raw_bits = (unsigned*)realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order)))) + return false; + object->capacity_by_order = max_partition_order; + } + + return true; +} diff --git a/apps/codecs/libFLAC/include/FLAC/all.h b/apps/codecs/libFLAC/include/FLAC/all.h new file mode 100644 index 0000000000..0fd49af6e4 --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/all.h @@ -0,0 +1,158 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__ALL_H +#define FLAC__ALL_H + +#include "export.h" + +#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" + +/** \mainpage + * + * \section intro Introduction + * + * This is the documentation for the FLAC C and C++ APIs. It is + * highly interconnected; this introduction should give you a top + * level idea of the structure and how to find the information you + * need. As a prerequisite you should have at least a basic + * knowledge of the FLAC format, documented + * here. + * + * \section c_api FLAC C API + * + * The FLAC C API is the interface to libFLAC, a set of structures + * 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 /FLAC/... + * + * By writing a little code and linking against libFLAC, it is + * relatively easy to add FLAC support to another program. The + * library is licensed under Xiph's BSD license. + * Complete source code of libFLAC as well as the command-line + * encoder and plugins is available and is a useful source of + * examples. + * + * Aside from encoders and decoders, libFLAC provides a powerful + * metadata interface for manipulating metadata in FLAC files. It + * allows the user to add, delete, and modify FLAC metadata blocks + * and it can automatically take advantage of PADDING blocks to avoid + * rewriting the entire FLAC file when changing the size of the + * metadata. + * + * libFLAC usually only requires the standard C library and C math + * library. In particular, threading is not used so there is no + * 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 + * Xiph's BSD license. + * + * \section cpp_api FLAC C++ API + * + * The FLAC C++ API is a set of classes that encapsulate the + * structures and functions in libFLAC. They provide slightly more + * functionality with respect to metadata but are otherwise + * 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 + * /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++. + * + * Both libFLAC++ libOggFLAC++ are also licensed under + * Xiph's BSD license. + * + * \section getting_started Getting Started + * + * A good starting point for learning the API is to browse through + * the modules. Modules are logical + * groupings of related functions or classes, which correspond roughly + * to header files or sections of header files. Each module includes a + * detailed description of the general usage of its functions or + * classes. + * + * From there you can go on to look at the documentation of + * individual functions. You can see different views of the individual + * functions through the links in top bar across this page. + * + * \section embedded_developers Embedded Developers + * + * libFLAC has grown larger over time as more functionality has been + * included, but much of it may be unnecessary for a particular embedded + * implementation. Unused parts may be pruned by some simple editing of + * src/libFLAC/Makefile.am. In general, the decoders, encoders, and + * metadata interface are all independent from each other. + * + * 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 + * + * 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. + */ + +/** \defgroup flac FLAC C API + * + * The FLAC C API is the interface to libFLAC, a set of structures + * describing the components of FLAC streams, and functions for + * encoding and decoding streams, as well as manipulating FLAC + * metadata in files. + * + * You should start with the format components as all other modules + * are dependent on it. + */ + +#endif diff --git a/apps/codecs/libFLAC/include/FLAC/assert.h b/apps/codecs/libFLAC/include/FLAC/assert.h new file mode 100644 index 0000000000..99e3381fd1 --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/assert.h @@ -0,0 +1,45 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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__ASSERT_H +#define FLAC__ASSERT_H + +/* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */ +#ifdef DEBUG +#include +#define FLAC__ASSERT(x) assert(x) +#define FLAC__ASSERT_DECLARATION(x) x +#else +#define FLAC__ASSERT(x) +#define FLAC__ASSERT_DECLARATION(x) +#endif + +#endif diff --git a/apps/codecs/libFLAC/include/FLAC/callback.h b/apps/codecs/libFLAC/include/FLAC/callback.h new file mode 100644 index 0000000000..c6f94c0cf4 --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/callback.h @@ -0,0 +1,181 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2004,2005 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__CALLBACK_H +#define FLAC__CALLBACK_H + +#include "ordinals.h" +#include /* for size_t */ + +/** \file include/FLAC/callback.h + * + * \brief + * This module defines the structures for describing I/O callbacks + * to the other FLAC interfaces. + * + * See the detailed documentation for callbacks in the + * \link flac_callbacks callbacks \endlink module. + */ + +/** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures + * \ingroup flac + * + * \brief + * This module defines the structures for describing I/O callbacks + * to the other FLAC interfaces. + * + * The purpose of the I/O callback functions is to create a common way + * for the metadata interfaces to handle I/O. + * + * Originally the metadata interfaces required filenames as the way of + * specifying FLAC files to operate on. This is problematic in some + * environments so there is an additional option to specify a set of + * callbacks for doing I/O on the FLAC file, instead of the filename. + * + * In addition to the callbacks, a FLAC__IOHandle type is defined as an + * opaque structure for a data source. + * + * The callback function prototypes are similar (but not identical) to the + * stdio functions fread, fwrite, fseek, ftell, feof, and fclose. If you use + * 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 + * 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), + * or write a wrapper. The same is true for feof() since this is usually + * implemented as a macro, not as a function whose address can be taken. + * + * \{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* FLAC__IOHandle; + +/** Signature for the read callback. + * The signature and semantics match POSIX fread() implementations + * and can generally be used interchangeably. + * + * \param ptr The address of the read buffer. + * \param size The size of the records to be read. + * \param nmemb The number of records to be read. + * \param handle The handle to the data source. + * \retval size_t + * The number of records read. + */ +typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); + +/** Signature for the write callback. + * The signature and semantics match POSIX fwrite() implementations + * and can generally be used interchangeably. + * + * \param ptr The address of the write buffer. + * \param size The size of the records to be written. + * \param nmemb The number of records to be written. + * \param handle The handle to the data source. + * \retval size_t + * The number of records written. + */ +typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); + +/** Signature for the seek callback. + * The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT + * EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long' + * and 32-bits wide. + * + * \param handle The handle to the data source. + * \param offset The new position, relative to \a whence + * \param whence \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END + * \retval int + * \c 0 on success, \c -1 on error. + */ +typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence); + +/** Signature for the tell callback. + * The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT + * EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long' + * and 32-bits wide. + * + * \param handle The handle to the data source. + * \retval FLAC__int64 + * The current position on success, \c -1 on error. + */ +typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle); + +/** Signature for the EOF callback. + * The signature and semantics mostly match POSIX feof() but WATCHOUT: + * on many systems, feof() is a macro, so in this case a wrapper function + * must be provided instead. + * + * \param handle The handle to the data source. + * \retval int + * \c 0 if not at end of file, nonzero if at end of file. + */ +typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle); + +/** Signature for the close callback. + * The signature and semantics match POSIX fclose() implementations + * and can generally be used interchangeably. + * + * \param handle The handle to the data source. + * \retval int + * \c 0 on success, \c EOF on error. + */ +typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle); + +/** A structure for holding a set of callbacks. + * Each FLAC interface that requires a FLAC__IOCallbacks structure will + * describe which of the callbacks are required. The ones that are not + * required may be set to NULL. + * + * If the seek requirement for an interface is optional, you can signify that + * a data sorce is not seekable by setting the \a seek field to \c NULL. + */ +typedef struct { + FLAC__IOCallback_Read read; + FLAC__IOCallback_Write write; + FLAC__IOCallback_Seek seek; + FLAC__IOCallback_Tell tell; + FLAC__IOCallback_Eof eof; + FLAC__IOCallback_Close close; +} FLAC__IOCallbacks; + +/* \} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/apps/codecs/libFLAC/include/FLAC/export.h b/apps/codecs/libFLAC/include/FLAC/export.h new file mode 100644 index 0000000000..db4ec59d2f --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/export.h @@ -0,0 +1,47 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__EXPORT_H +#define FLAC__EXPORT_H + +#if defined(FLAC__NO_DLL) || !defined(_MSC_VER) +#define FLAC_API + +#else + +#ifdef FLAC_API_EXPORTS +#define FLAC_API _declspec(dllexport) +#else +#define FLAC_API _declspec(dllimport) + +#endif +#endif +#endif diff --git a/apps/codecs/libFLAC/include/FLAC/file_decoder.h b/apps/codecs/libFLAC/include/FLAC/file_decoder.h new file mode 100644 index 0000000000..c4b1c6cdb7 --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/file_decoder.h @@ -0,0 +1,660 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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/apps/codecs/libFLAC/include/FLAC/file_encoder.h b/apps/codecs/libFLAC/include/FLAC/file_encoder.h new file mode 100644 index 0000000000..fbbfadb303 --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/file_encoder.h @@ -0,0 +1,871 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2002,2003,2004,2005 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/apps/codecs/libFLAC/include/FLAC/format.h b/apps/codecs/libFLAC/include/FLAC/format.h new file mode 100644 index 0000000000..26080cbf72 --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/format.h @@ -0,0 +1,861 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__FORMAT_H +#define FLAC__FORMAT_H + +#include "export.h" +#include "ordinals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file include/FLAC/format.h + * + * \brief + * This module contains structure definitions for the representation + * of FLAC format components in memory. These are the basic + * structures used by the rest of the interfaces. + * + * See the detailed documentation in the + * \link flac_format format \endlink module. + */ + +/** \defgroup flac_format FLAC/format.h: format components + * \ingroup flac + * + * \brief + * This module contains structure definitions for the representation + * of FLAC format components in memory. These are the basic + * structures used by the rest of the interfaces. + * + * First, you should be familiar with the + * FLAC format. Many of the values here + * follow directly from the specification. As a user of libFLAC, the + * interesting parts really are the structures that describe the frame + * header and metadata blocks. + * + * The format structures here are very primitive, designed to store + * information in an efficient way. Reading information from the + * structures is easy but creating or modifying them directly is + * more complex. For the most part, as a user of a library, editing + * is not necessary; however, for metadata blocks it is, so there are + * convenience functions provided in the \link flac_metadata metadata + * module \endlink to simplify the manipulation of metadata blocks. + * + * \note + * It's not the best convention, but symbols ending in _LEN are in bits + * and _LENGTH are in bytes. _LENGTH symbols are \#defines instead of + * global variables because they are usually used when declaring byte + * arrays and some compilers require compile-time knowledge of array + * sizes when declared on the stack. + * + * \{ + */ + + +/* + Most of the values described in this file are defined by the FLAC + format specification. There is nothing to tune here. +*/ + +/** The largest legal metadata type code. */ +#define FLAC__MAX_METADATA_TYPE_CODE (126u) + +/** The minimum block size, in samples, permitted by the format. */ +#define FLAC__MIN_BLOCK_SIZE (16u) + +/** The maximum block size, in samples, permitted by the format. */ +#define FLAC__MAX_BLOCK_SIZE (65535u) + +/** The maximum number of channels permitted by the format. */ +#define FLAC__MAX_CHANNELS (8u) + +/** The minimum sample resolution permitted by the format. */ +#define FLAC__MIN_BITS_PER_SAMPLE (4u) + +/** The maximum sample resolution permitted by the format. */ +#define FLAC__MAX_BITS_PER_SAMPLE (32u) + +/** The maximum sample resolution permitted by libFLAC. + * + * \warning + * FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format. However, + * the reference encoder/decoder is currently limited to 24 bits because + * of prevalent 32-bit math, so make sure and use this value when + * appropriate. + */ +#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (24u) + +/** The maximum sample rate permitted by the format. The value is + * ((2 ^ 16) - 1) * 10; see FLAC format + * as to why. + */ +#define FLAC__MAX_SAMPLE_RATE (655350u) + +/** The maximum LPC order permitted by the format. */ +#define FLAC__MAX_LPC_ORDER (32u) + +/** The minimum quantized linear predictor coefficient precision + * permitted by the format. + */ +#define FLAC__MIN_QLP_COEFF_PRECISION (5u) + +/** The maximum quantized linear predictor coefficient precision + * permitted by the format. + */ +#define FLAC__MAX_QLP_COEFF_PRECISION (15u) + +/** The maximum order of the fixed predictors permitted by the format. */ +#define FLAC__MAX_FIXED_ORDER (4u) + +/** The maximum Rice partition order permitted by the format. */ +#define FLAC__MAX_RICE_PARTITION_ORDER (15u) + +/** The maximum Rice partition order permitted by the FLAC Subset. */ +#define FLAC__SUBSET_MAX_RICE_PARTITION_ORDER (8u) + +/** The version string of the release, stamped onto the libraries and binaries. + * + * \note + * This does not correspond to the shared library version number, which + * is used to determine binary compatibility. + */ +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 + * VORBIS_COMMENT the trailing null is stripped. + */ +extern FLAC_API const char *FLAC__VENDOR_STRING; + +/** The byte string representation of the beginning of a FLAC stream. */ +extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */ + +/** The 32-bit integer big-endian representation of the beginning of + * a FLAC stream. + */ +extern FLAC_API const unsigned FLAC__STREAM_SYNC; /* = 0x664C6143 */ + +/** The length of the FLAC signature in bits. */ +extern FLAC_API const unsigned FLAC__STREAM_SYNC_LEN; /* = 32 bits */ + +/** The length of the FLAC signature in bytes. */ +#define FLAC__STREAM_SYNC_LENGTH (4u) + + +/***************************************************************************** + * + * Subframe structures + * + *****************************************************************************/ + +/*****************************************************************************/ + +/** An enumeration of the available entropy coding methods. */ +typedef enum { + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0 + /**< Residual is coded by partitioning into contexts, each with it's own + * Rice parameter. */ +} FLAC__EntropyCodingMethodType; + +/** Maps a FLAC__EntropyCodingMethodType to a C string. + * + * Using a FLAC__EntropyCodingMethodType as the index to this array will + * give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[]; + + +/** Contents of a Rice partitioned residual + */ +typedef struct { + + unsigned *parameters; + /**< The Rice parameters for each context. */ + + unsigned *raw_bits; + /**< Widths for escape-coded partitions. */ + + unsigned capacity_by_order; + /**< The capacity of the \a parameters and \a raw_bits arrays + * specified as an order, i.e. the number of array elements + * allocated is 2 ^ \a capacity_by_order. + */ +} FLAC__EntropyCodingMethod_PartitionedRiceContents; + +/** Header for a Rice partitioned residual. (c.f. format specification) + */ +typedef struct { + + unsigned order; + /**< The partition order, i.e. # of contexts = 2 ^ \a order. */ + + const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents; + /**< The context's Rice parameters and/or raw bits. */ + +} FLAC__EntropyCodingMethod_PartitionedRice; + +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_RICE_RAW_LEN; /**< == 5 (bits) */ + +extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; +/**< == (1<format specification) + */ +typedef struct { + FLAC__EntropyCodingMethodType type; + union { + FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice; + } data; +} FLAC__EntropyCodingMethod; + +extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */ + +/*****************************************************************************/ + +/** An enumeration of the available subframe types. */ +typedef enum { + FLAC__SUBFRAME_TYPE_CONSTANT = 0, /**< constant signal */ + FLAC__SUBFRAME_TYPE_VERBATIM = 1, /**< uncompressed signal */ + FLAC__SUBFRAME_TYPE_FIXED = 2, /**< fixed polynomial prediction */ + FLAC__SUBFRAME_TYPE_LPC = 3 /**< linear prediction */ +} FLAC__SubframeType; + +/** Maps a FLAC__SubframeType to a C string. + * + * Using a FLAC__SubframeType as the index to this array will + * give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__SubframeTypeString[]; + + +/** CONSTANT subframe. (c.f. format specification) + */ +typedef struct { + FLAC__int32 value; /**< The constant signal value. */ +} FLAC__Subframe_Constant; + + +/** VERBATIM subframe. (c.f. format specification) + */ +typedef struct { + const FLAC__int32 *data; /**< A pointer to verbatim signal. */ +} FLAC__Subframe_Verbatim; + + +/** FIXED subframe. (c.f. format specification) + */ +typedef struct { + FLAC__EntropyCodingMethod entropy_coding_method; + /**< The residual coding method. */ + + unsigned order; + /**< The polynomial order. */ + + FLAC__int32 warmup[FLAC__MAX_FIXED_ORDER]; + /**< Warmup samples to prime the predictor, length == order. */ + + const FLAC__int32 *residual; + /**< The residual signal, length == (blocksize minus order) samples. */ +} FLAC__Subframe_Fixed; + + +/** LPC subframe. (c.f. format specification) + */ +typedef struct { + FLAC__EntropyCodingMethod entropy_coding_method; + /**< The residual coding method. */ + + unsigned order; + /**< The FIR order. */ + + unsigned qlp_coeff_precision; + /**< Quantized FIR filter coefficient precision in bits. */ + + int quantization_level; + /**< The qlp coeff shift needed. */ + + FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; + /**< FIR filter coefficients. */ + + FLAC__int32 warmup[FLAC__MAX_LPC_ORDER]; + /**< Warmup samples to prime the predictor, length == order. */ + + const FLAC__int32 *residual; + /**< The residual signal, length == (blocksize minus order) samples. */ +} FLAC__Subframe_LPC; + +extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */ +extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */ + + +/** FLAC subframe structure. (c.f. format specification) + */ +typedef struct { + FLAC__SubframeType type; + union { + FLAC__Subframe_Constant constant; + FLAC__Subframe_Fixed fixed; + FLAC__Subframe_LPC lpc; + FLAC__Subframe_Verbatim verbatim; + } data; + unsigned wasted_bits; +} FLAC__Subframe; + +extern FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN; /**< == 1 (bit) */ +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 */ + +/*****************************************************************************/ + + +/***************************************************************************** + * + * Frame structures + * + *****************************************************************************/ + +/** An enumeration of the available channel assignments. */ +typedef enum { + FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, /**< independent channels */ + FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, /**< left+side stereo */ + FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, /**< right+side stereo */ + FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 /**< mid+side stereo */ +} FLAC__ChannelAssignment; + +/** Maps a FLAC__ChannelAssignment to a C string. + * + * Using a FLAC__ChannelAssignment as the index to this array will + * give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__ChannelAssignmentString[]; + +/** An enumeration of the possible frame numbering methods. */ +typedef enum { + FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER, /**< number contains the frame number */ + FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER /**< number contains the sample number of first sample in frame */ +} FLAC__FrameNumberType; + +/** Maps a FLAC__FrameNumberType to a C string. + * + * Using a FLAC__FrameNumberType as the index to this array will + * give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__FrameNumberTypeString[]; + + +/** FLAC frame header structure. (c.f. format specification) + */ +typedef struct { + unsigned blocksize; + /**< The number of samples per subframe. */ + + unsigned sample_rate; + /**< The sample rate in Hz. */ + + unsigned channels; + /**< The number of channels (== number of subframes). */ + + FLAC__ChannelAssignment channel_assignment; + /**< The channel assignment for the frame. */ + + unsigned bits_per_sample; + /**< The sample resolution. */ + + FLAC__FrameNumberType number_type; + /**< The numbering scheme used for the frame. */ + + union { + FLAC__uint32 frame_number; + FLAC__uint64 sample_number; + } number; + /**< The frame number or sample number of first sample in frame; + * use the \a number_type value to determine which to use. */ + + FLAC__uint8 crc; + /**< CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0) + * of the raw frame header bytes, meaning everything before the CRC byte + * including the sync code. + */ +} FLAC__FrameHeader; + +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_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) */ +extern FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */ +extern FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */ +extern FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */ + + +/** FLAC frame footer structure. (c.f. format specification) + */ +typedef struct { + FLAC__uint16 crc; + /**< CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with + * 0) of the bytes before the crc, back to and including the frame header + * sync code. + */ +} FLAC__FrameFooter; + +extern FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */ + + +/** FLAC frame structure. (c.f. format specification) + */ +typedef struct { + FLAC__FrameHeader header; + FLAC__Subframe subframes[FLAC__MAX_CHANNELS]; + FLAC__FrameFooter footer; +} FLAC__Frame; + +/*****************************************************************************/ + + +/***************************************************************************** + * + * Meta-data structures + * + *****************************************************************************/ + +/** An enumeration of the available metadata block types. */ +typedef enum { + + FLAC__METADATA_TYPE_STREAMINFO = 0, + /**< STREAMINFO block */ + + FLAC__METADATA_TYPE_PADDING = 1, + /**< PADDING block */ + + FLAC__METADATA_TYPE_APPLICATION = 2, + /**< APPLICATION block */ + + FLAC__METADATA_TYPE_SEEKTABLE = 3, + /**< SEEKTABLE block */ + + FLAC__METADATA_TYPE_VORBIS_COMMENT = 4, + /**< VORBISCOMMENT block */ + + FLAC__METADATA_TYPE_CUESHEET = 5, + /**< CUESHEET block */ + + FLAC__METADATA_TYPE_UNDEFINED = 6 + /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */ + +} FLAC__MetadataType; + +/** Maps a FLAC__MetadataType to a C string. + * + * Using a FLAC__MetadataType as the index to this array will + * give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__MetadataTypeString[]; + + +/** FLAC STREAMINFO structure. (c.f. format specification) + */ +typedef struct { + unsigned min_blocksize, max_blocksize; + unsigned min_framesize, max_framesize; + unsigned sample_rate; + unsigned channels; + unsigned bits_per_sample; + FLAC__uint64 total_samples; + FLAC__byte md5sum[16]; +} FLAC__StreamMetadata_StreamInfo; + +extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */ + +/** The total stream length of the STREAMINFO block in bytes. */ +#define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u) + +/** FLAC PADDING structure. (c.f. format specification) + */ +typedef struct { + int dummy; + /**< Conceptually this is an empty struct since we don't store the + * padding bytes. Empty structs are not allowed by some C compilers, + * hence the dummy. + */ +} FLAC__StreamMetadata_Padding; + + +/** FLAC APPLICATION structure. (c.f. format specification) + */ +typedef struct { + FLAC__byte id[4]; + FLAC__byte *data; +} FLAC__StreamMetadata_Application; + +extern FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */ + +/** SeekPoint structure used in SEEKTABLE blocks. (c.f. format specification) + */ +typedef struct { + FLAC__uint64 sample_number; + /**< The sample number of the target frame. */ + + FLAC__uint64 stream_offset; + /**< The offset, in bytes, of the target frame with respect to + * beginning of the first frame. */ + + unsigned frame_samples; + /**< The number of samples in the target frame. */ +} FLAC__StreamMetadata_SeekPoint; + +extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */ + +/** The total stream length of a seek point in bytes. */ +#define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u) + +/** The value used in the \a sample_number field of + * FLAC__StreamMetadataSeekPoint used to indicate a placeholder + * point (== 0xffffffffffffffff). + */ +extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + + +/** FLAC SEEKTABLE structure. (c.f. format specification) + * + * \note From the format specification: + * - The seek points must be sorted by ascending sample number. + * - Each seek point's sample number must be the first sample of the + * target frame. + * - Each seek point's sample number must be unique within the table. + * - Existence of a SEEKTABLE block implies a correct setting of + * total_samples in the stream_info block. + * - Behavior is undefined when more than one SEEKTABLE block is + * present in a stream. + */ +typedef struct { + unsigned num_points; + FLAC__StreamMetadata_SeekPoint *points; +} FLAC__StreamMetadata_SeekTable; + + +/** Vorbis comment entry structure used in VORBIS_COMMENT blocks. (c.f. format specification) + * + * 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; + FLAC__byte *entry; +} FLAC__StreamMetadata_VorbisComment_Entry; + +extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */ + + +/** FLAC VORBIS_COMMENT structure. (c.f. format specification) + */ +typedef struct { + FLAC__StreamMetadata_VorbisComment_Entry vendor_string; + FLAC__uint32 num_comments; + FLAC__StreamMetadata_VorbisComment_Entry *comments; +} FLAC__StreamMetadata_VorbisComment; + +extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */ + + +/** FLAC CUESHEET track index structure. (See the + * format specification for + * the full description of each field.) + */ +typedef struct { + FLAC__uint64 offset; + /**< Offset in samples, relative to the track offset, of the index + * point. + */ + + FLAC__byte number; + /**< The index point number. */ +} FLAC__StreamMetadata_CueSheet_Index; + +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */ + + +/** FLAC CUESHEET track structure. (See the + * format specification for + * the full description of each field.) + */ +typedef struct { + FLAC__uint64 offset; + /**< Track offset in samples, relative to the beginning of the FLAC audio stream. */ + + FLAC__byte number; + /**< The track number. */ + + char isrc[13]; + /**< Track ISRC. This is a 12-digit alphanumeric code plus a trailing '\0' */ + + unsigned type:1; + /**< The track type: 0 for audio, 1 for non-audio. */ + + unsigned pre_emphasis:1; + /**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */ + + FLAC__byte num_indices; + /**< The number of track index points. */ + + FLAC__StreamMetadata_CueSheet_Index *indices; + /**< NULL if num_indices == 0, else pointer to array of index points. */ + +} FLAC__StreamMetadata_CueSheet_Track; + +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */ + + +/** FLAC CUESHEET structure. (See the + * format specification + * for the full description of each field.) + */ +typedef struct { + char media_catalog_number[129]; + /**< Media catalog number, in ASCII printable characters 0x20-0x7e. In + * general, the media catalog number may be 0 to 128 bytes long; any + * unused characters should be right-padded with NUL characters. + */ + + FLAC__uint64 lead_in; + /**< The number of lead-in samples. */ + + FLAC__bool is_cd; + /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false */ + + unsigned num_tracks; + /**< The number of tracks. */ + + FLAC__StreamMetadata_CueSheet_Track *tracks; + /**< NULL if num_tracks == 0, else pointer to array of tracks. */ + +} FLAC__StreamMetadata_CueSheet; + +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (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. + */ +typedef struct { + FLAC__byte *data; +} FLAC__StreamMetadata_Unknown; + + +/** FLAC metadata block structure. (c.f. format specification) + */ +typedef struct { + FLAC__MetadataType type; + /**< The type of the metadata block; used determine which member of the + * \a data union to dereference. If type >= FLAC__METADATA_TYPE_UNDEFINED + * then \a data.unknown must be used. */ + + FLAC__bool is_last; + /**< \c true if this metadata block is the last, else \a false */ + + unsigned length; + /**< Length, in bytes, of the block data as it appears in the stream. */ + + union { + FLAC__StreamMetadata_StreamInfo stream_info; + FLAC__StreamMetadata_Padding padding; + FLAC__StreamMetadata_Application application; + FLAC__StreamMetadata_SeekTable seek_table; + FLAC__StreamMetadata_VorbisComment vorbis_comment; + FLAC__StreamMetadata_CueSheet cue_sheet; + FLAC__StreamMetadata_Unknown unknown; + } data; + /**< Polymorphic block data; use the \a type value to determine which + * to use. */ +} FLAC__StreamMetadata; + +extern FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */ + +/** The total stream length of a metadata block header in bytes. */ +#define FLAC__STREAM_METADATA_HEADER_LENGTH (4u) + +/*****************************************************************************/ + + +/***************************************************************************** + * + * Utility functions + * + *****************************************************************************/ + +/** 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. + * + * \param sample_rate The sample rate to test for compliance. + * \retval FLAC__bool + * \c true if the given sample rate conforms to the specification, else + * \c false. + */ +FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(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 value A string to be checked. + * \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); + +/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ +/** 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. + * + * \param seek_table A pointer to a seek table to be checked. + * \assert + * \code seek_table != NULL \endcode + * \retval FLAC__bool + * \c false if seek table is illegal, else \c true. + */ +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 + * points are converted into placeholder points and sorted to the end of + * the table. + * + * \param seek_table A pointer to a seek table to be sorted. + * \assert + * \code seek_table != NULL \endcode + * \retval unsigned + * The number of duplicate seek points converted into placeholders. + */ +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. + * + * \param cue_sheet A pointer to an existing cue sheet to be checked. + * \param check_cd_da_subset If \c true, check CUESHEET against more + * stringent requirements for a CD-DA (audio) disc. + * \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 cue_sheet != NULL \endcode + * \retval FLAC__bool + * \c false if cue sheet is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation); + +/* \} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/apps/codecs/libFLAC/include/FLAC/metadata.h b/apps/codecs/libFLAC/include/FLAC/metadata.h new file mode 100644 index 0000000000..ff40e6d5ed --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/metadata.h @@ -0,0 +1,1858 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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__METADATA_H +#define FLAC__METADATA_H + +#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/) +******************************************************************************/ + +/** \file include/FLAC/metadata.h + * + * \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. + * + * See the detailed documentation for each interface in the + * \link flac_metadata metadata \endlink module. + */ + +/** \defgroup flac_metadata FLAC/metadata.h: metadata interfaces + * \ingroup flac + * + * \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. + * + * There are three metadata interfaces of increasing complexity: + * + * Level 0: + * Read-only access to the STREAMINFO and VORBIS_COMMENT blocks. + * + * Level 1: + * Read-write access to all metadata blocks. This level is write- + * efficient in most cases (more on this below), and uses less memory + * than level 2. + * + * Level 2: + * Read-write access to all metadata blocks. This level is write- + * efficient in all cases, but uses more memory since all metadata for + * the whole file is read into memory and manipulated before writing + * out again. + * + * What do we mean by efficient? Since FLAC metadata appears at the + * beginning of the file, when writing metadata back to a FLAC file + * it is possible to grow or shrink the metadata such that the entire + * file must be rewritten. However, if the size remains the same during + * changes or PADDING blocks are utilized, only the metadata needs to be + * overwritten, which is much faster. + * + * Efficient means the whole file is rewritten at most one time, and only + * when necessary. Level 1 is not efficient only in the case that you + * cause more than one metadata block to grow or shrink beyond what can + * be accomodated by padding. In this case you should probably use level + * 2, which allows you to edit all the metadata for a file in memory and + * write it out all at once. + * + * All levels know how to skip over and not disturb an ID3v2 tag at the + * front of the file. + * + * 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. + * + * In addition to the three interfaces, this module defines functions for + * creating and manipulating various metadata objects in memory. As we see + * from the Format module, FLAC metadata blocks in memory are very primitive + * structures for storing information in an efficient way. Reading + * information from the structures is easy but creating or modifying them + * directly is more complex. The metadata object routines here facilitate + * this by taking care of the consistency and memory management drudgery. + * + * Unless you will be using the level 1 or 2 interfaces to modify existing + * metadata however, you will not probably not need these. + * + * From a dependency standpoint, none of the encoders or decoders require + * the metadata module. This is so that embedded users can strip out the + * metadata module from libFLAC to reduce the size and complexity. + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup flac_metadata_level0 FLAC/metadata.h: metadata level 0 interface + * \ingroup flac_metadata + * + * \brief + * The level 0 interface consists of individual routines to read the + * STREAMINFO and VORBIS_COMMENT blocks, requiring only a filename. + * + * It skips 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. + * + * \param filename The path to the FLAC file to read. + * \param streaminfo A pointer to space for the STREAMINFO block. Since + * FLAC__StreamMetadata is a simple structure with no + * memory allocation involved, you pass the address of + * an existing structure. It need not be initialized. + * \assert + * \code filename != NULL \endcode + * \code streaminfo != NULL \endcode + * \retval FLAC__bool + * \c true if a valid STREAMINFO block was read from \a filename. Returns + * \c false if there was a memory allocation error, a file decoder error, + * or the file contained no STREAMINFO block. (A memory allocation error + * is possible because this function must set up a file decoder.) + */ +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. + * + * \param filename The path to the FLAC file to read. + * \param tags The address where the returned pointer will be + * stored. The \a tags object must be deleted by + * the caller using FLAC__metadata_object_delete(). + * \assert + * \code filename != NULL \endcode + * \code streaminfo != 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. + * 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); + +/* \} */ + + +/** \defgroup flac_metadata_level1 FLAC/metadata.h: metadata level 1 interface + * \ingroup flac_metadata + * + * \brief + * The level 1 interface provides read-write access to FLAC file metadata and + * operates directly on the FLAC file. + * + * The general usage of this interface is: + * + * - 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. + * - Use FLAC__metadata_simple_iterator_next() and + * FLAC__metadata_simple_iterator_prev() to move around 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 + * forward from the front of the file. + * - Use FLAC__metadata_simple_iterator_get_block_type() or + * FLAC__metadata_simple_iterator_get_block() to access the actual data at + * the current iterator position. The returned object is yours to modify + * and free. + * - Use FLAC__metadata_simple_iterator_set_block() to write a modified block + * back. You must have write permission to the original file. Make sure to + * read the whole comment to FLAC__metadata_simple_iterator_set_block() + * below. + * - Use FLAC__metadata_simple_iterator_insert_block_after() to add new blocks. + * Use the object creation functions from + * \link flac_metadata_object here \endlink to generate new objects. + * - Use FLAC__metadata_simple_iterator_delete_block() to remove the block + * currently referred to by the iterator, or replace it with padding. + * - Destroy the iterator with FLAC__metadata_simple_iterator_delete() when + * finished. + * + * \note + * The FLAC file remains open the whole time between + * FLAC__metadata_simple_iterator_init() and + * FLAC__metadata_simple_iterator_delete(), so make sure you are not altering + * the file during this time. + * + * \note + * Do not modify the \a is_last, \a length, or \a type fields of returned + * FLAC__StreamMetadata objects. These are managed automatically. + * + * \note + * If any of the modification functions + * (FLAC__metadata_simple_iterator_set_block(), + * FLAC__metadata_simple_iterator_delete_block(), + * FLAC__metadata_simple_iterator_insert_block_after(), etc.) return \c false, + * you should delete the iterator as it may no longer be valid. + * + * \{ + */ + +struct FLAC__Metadata_SimpleIterator; +/** The opaque structure definition for the level 1 iterator type. + * See the + * \link flac_metadata_level1 metadata level 1 module \endlink + * for a detailed description. + */ +typedef struct FLAC__Metadata_SimpleIterator FLAC__Metadata_SimpleIterator; + +/** Status type for FLAC__Metadata_SimpleIterator. + * + * The iterator's current status can be obtained by calling FLAC__metadata_simple_iterator_status(). + */ +typedef enum { + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK = 0, + /**< The iterator is in the normal OK state */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, + /**< The data passed into a function violated the function's usage criteria */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE, + /**< The iterator could not open the target file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE, + /**< The iterator could not find the FLAC signature at the start of the file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE, + /**< The iterator tried to write to a file that was not writable */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA, + /**< The iterator encountered input that does not conform to the FLAC metadata specification */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR, + /**< The iterator encountered an error while reading the FLAC file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, + /**< The iterator encountered an error while seeking in the FLAC file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR, + /**< The iterator encountered an error while writing the FLAC file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR, + /**< The iterator encountered an error renaming the FLAC file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR, + /**< The iterator encountered an error removing the temporary file */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR, + /**< Memory allocation failed */ + + FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR + /**< The caller violated an assertion or an unexpected error occurred */ + +} FLAC__Metadata_SimpleIteratorStatus; + +/** Maps a FLAC__Metadata_SimpleIteratorStatus to a C string. + * + * Using a FLAC__Metadata_SimpleIteratorStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[]; + + +/** Create a new iterator instance. + * + * \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(); + +/** Free an iterator instance. Deletes the object pointed to by \a iterator. + * + * \param iterator A pointer to an existing iterator. + * \assert + * \code iterator != NULL \endcode + */ +FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator); + +/** Get the current status of the iterator. Call this after a function + * returns \c false to get the reason for the error. Also resets the status + * to FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK. + * + * \param iterator A pointer to an existing iterator. + * \assert + * \code iterator != NULL \endcode + * \retval FLAC__Metadata_SimpleIteratorStatus + * The current status of the iterator. + */ +FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator); + +/** Initialize the iterator to point to the first metadata block in the + * given FLAC file. + * + * \param iterator A pointer to an existing iterator. + * \param filename The path to the FLAC file. + * \param read_only If \c true, the FLAC file will be opened + * in read-only mode; if \c false, the FLAC + * file will be opened for edit even if no + * edits are performed. + * \param preserve_file_stats If \c true, the owner and modification + * time will be preserved even if the FLAC + * file is written to. + * \assert + * \code iterator != NULL \endcode + * \code filename != NULL \endcode + * \retval FLAC__bool + * \c false if a memory allocation error occurs, the file can't be + * opened, or another error occurs, else \c true. + */ +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); + +/** Returns \c true if the FLAC file is writable. If \c false, calls to + * FLAC__metadata_simple_iterator_set_block() and + * FLAC__metadata_simple_iterator_insert_block_after() will fail. + * + * \param iterator A pointer to an existing iterator. + * \assert + * \code iterator != NULL \endcode + * \retval FLAC__bool + * See above. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator); + +/** Moves the iterator forward one metadata block, returning \c false if + * already at the end. + * + * \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 false if already at the last metadata block of the chain, else + * \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator); + +/** Moves the iterator backward one metadata block, returning \c false if + * already at the beginning. + * + * \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 false if already at the first metadata block of the chain, else + * \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(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. + * + * \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__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 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. + * + * You must call FLAC__metadata_object_delete() on the returned object + * when you are finished with it. + * + * \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__StreamMetadata* + * The current metadata block. + */ +FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator); + +/** Write a block back to the FLAC file. This function tries to be + * as efficient as possible; how the block is actually written is + * shown by the following: + * + * Existing block is a STREAMINFO block and the new block is a + * STREAMINFO block: the new block is written in place. Make sure + * you know what you're doing when changing the values of a + * STREAMINFO block. + * + * Existing block is a STREAMINFO block and the new block is a + * not a STREAMINFO block: this is an error since the first block + * must be a STREAMINFO block. Returns \c false without altering the + * file. + * + * Existing block is not a STREAMINFO block and the new block is a + * STREAMINFO block: this is an error since there may be only one + * STREAMINFO block. Returns \c false without altering the file. + * + * Existing block and new block are the same length: the existing + * block will be replaced by the new block, written in place. + * + * Existing block is longer than new block: if use_padding is \c true, + * the existing block will be overwritten in place with the new + * block followed by a PADDING block, if possible, to make the total + * size the same as the existing block. Remember that a padding + * block requires at least four bytes so if the difference in size + * between the new block and existing block is less than that, the + * entire file will have to be rewritten, using the new block's + * exact size. If use_padding is \c false, the entire file will be + * rewritten, replacing the existing block by the new block. + * + * Existing block is shorter than new block: if use_padding is \c true, + * the function will try and expand the new block into the following + * PADDING block, if it exists and doing so won't shrink the PADDING + * block to less than 4 bytes. If there is no following PADDING + * block, or it will shrink to less than 4 bytes, or use_padding is + * \c false, the entire file is rewritten, replacing the existing block + * with the new block. Note that in this case any following PADDING + * block is preserved as is. + * + * After writing the block, the iterator will remain in the same + * place, i.e. pointing to the new block. + * + * \param iterator A pointer to an existing initialized iterator. + * \param block The block to set. + * \param use_padding See above. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \code block != NULL \endcode + * \retval FLAC__bool + * \c true if successful, else \c false. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding); + +/** This is similar to FLAC__metadata_simple_iterator_set_block() + * except that instead of writing over an existing block, it appends + * a block after the existing block. \a use_padding is again used to + * tell the function to try an expand into following padding in an + * attempt to avoid rewriting the entire file. + * + * This function will fail and return \c false if given a STREAMINFO + * block. + * + * After writing the block, the iterator will be pointing to the + * new block. + * + * \param iterator A pointer to an existing initialized iterator. + * \param block The block to set. + * \param use_padding See above. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \code block != NULL \endcode + * \retval FLAC__bool + * \c true if successful, else \c false. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding); + +/** Deletes the block at the current position. This will cause the + * entire FLAC file to be rewritten, unless \a use_padding is \c true, + * in which case the block will be replaced by an equal-sized PADDING + * block. The iterator will be left pointing to the block before the + * one just deleted. + * + * You may not delete the STREAMINFO block. + * + * \param iterator A pointer to an existing initialized iterator. + * \param use_padding See above. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_simple_iterator_init() + * \retval FLAC__bool + * \c true if successful, else \c false. + */ +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding); + +/* \} */ + + +/** \defgroup flac_metadata_level2 FLAC/metadata.h: metadata level 2 interface + * \ingroup flac_metadata + * + * \brief + * The level 2 interface provides read-write access to FLAC file metadata; + * 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. + * + * 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. + * - Optionally, consolidate the padding using + * FLAC__metadata_chain_merge_padding() or + * FLAC__metadata_chain_sort_padding(). + * - Create a new iterator using FLAC__metadata_iterator_new() + * - Initialize the iterator to point to the first element in the chain + * using FLAC__metadata_iterator_init() + * - Traverse the chain using FLAC__metadata_iterator_next and + * FLAC__metadata_iterator_prev(). + * - Get a block for reading or modification using + * FLAC__metadata_iterator_get_block(). The pointer to the object + * inside the chain is returned, so the block is yours to modify. + * Changes will be reflected in the FLAC file when you write the + * chain. You can also add and delete blocks (see functions below). + * - When done, write out the chain using FLAC__metadata_chain_write(). + * Make sure to read the whole comment to the function below. + * - Delete the chain using FLAC__metadata_chain_delete(). + * + * \note + * 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(). + * + * \note + * Do not modify the is_last, length, or type fields of returned + * FLAC__StreamMetadata objects. These are managed automatically. + * + * \note + * The metadata objects returned by FLAC__metadata_iterator_get_block() + * are owned by the chain; do not FLAC__metadata_object_delete() them. + * In the same way, blocks passed to FLAC__metadata_iterator_set_block() + * become owned by the chain and they will be deleted when the chain is + * deleted. + * + * \{ + */ + +struct FLAC__Metadata_Chain; +/** The opaque structure definition for the level 2 chain type. + */ +typedef struct FLAC__Metadata_Chain FLAC__Metadata_Chain; + +struct FLAC__Metadata_Iterator; +/** The opaque structure definition for the level 2 iterator type. + */ +typedef struct FLAC__Metadata_Iterator FLAC__Metadata_Iterator; + +typedef enum { + FLAC__METADATA_CHAIN_STATUS_OK = 0, + /**< The chain is in the normal OK state */ + + FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT, + /**< The data passed into a function violated the function's usage criteria */ + + FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE, + /**< The chain could not open the target file */ + + FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE, + /**< The chain could not find the FLAC signature at the start of the file */ + + FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE, + /**< The chain tried to write to a file that was not writable */ + + FLAC__METADATA_CHAIN_STATUS_BAD_METADATA, + /**< The chain encountered input that does not conform to the FLAC metadata specification */ + + FLAC__METADATA_CHAIN_STATUS_READ_ERROR, + /**< The chain encountered an error while reading the FLAC file */ + + FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR, + /**< The chain encountered an error while seeking in the FLAC file */ + + FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR, + /**< The chain encountered an error while writing the FLAC file */ + + FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR, + /**< The chain encountered an error renaming the FLAC file */ + + FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR, + /**< The chain encountered an error removing the temporary file */ + + FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR, + /**< Memory allocation failed */ + + FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR, + /**< The caller violated an assertion or an unexpected error occurred */ + + FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS, + /**< One or more of the required callbacks was NULL */ + + 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_STATUS_WRONG_WRITE_CALL + /**< FLAC__metadata_chain_write_with_callbacks() was called when the + * chain write requires a tempfile; use + * FLAC__metadata_chain_write_with_callbacks_and_tempfile() instead. + * Or, FLAC__metadata_chain_write_with_callbacks_and_tempfile() was + * called when the chain write does not require a tempfile; use + * FLAC__metadata_chain_write_with_callbacks() instead. + * Always check FLAC__metadata_chain_check_if_tempfile_needed() + * before writing via callbacks. */ + +} FLAC__Metadata_ChainStatus; + +/** Maps a FLAC__Metadata_ChainStatus to a C string. + * + * Using a FLAC__Metadata_ChainStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__Metadata_ChainStatusString[]; + +/*********** FLAC__Metadata_Chain ***********/ + +/** Create a new chain instance. + * + * \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(); + +/** Free a chain instance. Deletes the object pointed to by \a chain. + * + * \param chain A pointer to an existing chain. + * \assert + * \code chain != NULL \endcode + */ +FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain); + +/** Get the current status of the chain. Call this after a function + * returns \c false to get the reason for the error. Also resets the + * status to FLAC__METADATA_CHAIN_STATUS_OK. + * + * \param chain A pointer to an existing chain. + * \assert + * \code chain != NULL \endcode + * \retval FLAC__Metadata_ChainStatus + * The current status of the chain. + */ +FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain); + +/** Read all metadata from a FLAC file into the chain. + * + * \param chain A pointer to an existing chain. + * \param filename The path to the 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(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. + * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" + * for Windows). + * + * \param chain A pointer to an existing chain. + * \param handle The I/O handle of the 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_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. + * + * Under certain conditions, padding can be utilized so that writing + * edited metadata back to the FLAC file does not require rewriting the + * entire file. If rewriting is required, then a temporary workfile is + * required. When writing metadata using callbacks, you must check + * this function to know whether to call + * FLAC__metadata_chain_write_with_callbacks() or + * FLAC__metadata_chain_write_with_callbacks_and_tempfile(). When + * writing with FLAC__metadata_chain_write(), the temporary file is + * handled internally. + * + * \param chain A pointer to an existing chain. + * \param use_padding + * Whether or not padding will be allowed to be used + * during the write. The value of \a use_padding given + * here must match the value later passed to + * FLAC__metadata_chain_write_with_callbacks() or + * FLAC__metadata_chain_write_with_callbacks_with_tempfile(). + * \assert + * \code chain != NULL \endcode + * \retval FLAC__bool + * \c true if writing the current chain would require a tempfile, or + * \c false if metadata can be written in place. + */ +FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding); + +/** Write all metadata out to the FLAC file. This function tries to be as + * efficient as possible; how the metadata is actually written is shown by + * the following: + * + * If the current chain is the same size as the existing metadata, the new + * data is written in place. + * + * If the current chain is longer than the existing metadata, and + * \a use_padding is \c true, and the last block is a PADDING block of + * sufficient length, the function will truncate the final padding block + * so that the overall size of the metadata is the same as the existing + * metadata, and then just rewrite the metadata. Otherwise, if not all of + * the above conditions are met, the entire FLAC file must be rewritten. + * If you want to use padding this way it is a good idea to call + * FLAC__metadata_chain_sort_padding() first so that you have the maximum + * amount of padding to work with, unless you need to preserve ordering + * of the PADDING blocks for some reason. + * + * If the current chain is shorter than the existing metadata, and + * \a use_padding is \c true, and the final block is a PADDING block, the padding + * is extended to make the overall size the same as the existing data. If + * \a use_padding is \c true and the last block is not a PADDING block, a new + * PADDING block is added to the end of the new data to make it the same + * size as the existing data (if possible, see the note to + * FLAC__metadata_simple_iterator_set_block() about the four byte limit) + * and the new data is written in place. If none of the above apply or + * \a use_padding is \c false, the entire FLAC file is rewritten. + * + * If \a preserve_file_stats is \c true, the owner and modification time will + * 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(). + * + * \param chain A pointer to an existing chain. + * \param use_padding See above. + * \param preserve_file_stats See above. + * \assert + * \code chain != NULL \endcode + * \retval FLAC__bool + * \c true if the write succeeded, else \c false. On failure, + * check the status with FLAC__metadata_chain_status(). + */ +FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats); + +/** Write all metadata out to a FLAC stream via callbacks. + * + * (See FLAC__metadata_chain_write() for the details on how padding is + * used to write metadata in place if possible.) + * + * The \a handle must be open for updating and be seekable. The + * equivalent minimum stdio fopen() file mode is \c "r+" (or \c "r+b" + * 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(). + * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned + * \c false. + * + * \param chain A pointer to an existing chain. + * \param use_padding See FLAC__metadata_chain_write() + * \param handle The I/O handle of the FLAC stream to write. The + * handle will NOT be closed after the metadata is + * written; that is the duty of the caller. + * \param callbacks A set of callbacks to use for I/O. The mandatory + * callbacks are \a write and \a seek. + * \assert + * \code chain != NULL \endcode + * \retval FLAC__bool + * \c true if the write succeeded, else \c false. On failure, + * check the status with FLAC__metadata_chain_status(). + */ +FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); + +/** Write all metadata out to a FLAC stream via callbacks. + * + * (See FLAC__metadata_chain_write() for the details on how padding is + * used to write metadata in place if possible.) + * + * This version of the write-with-callbacks function must be used when + * FLAC__metadata_chain_check_if_tempfile_needed() returns true. In + * this function, you must supply an I/O handle corresponding to the + * FLAC file to edit, and a temporary handle to which the new FLAC + * file will be written. It is the caller's job to move this temporary + * FLAC file on top of the original FLAC file to complete the metadata + * edit. + * + * The \a handle must be open for reading and be seekable. The + * equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" + * for Windows). + * + * The \a temp_handle must be open for writing. The + * equivalent minimum stdio fopen() file mode is \c "w" (or \c "wb" + * for Windows). It should be an empty stream, or at least positioned + * at the start-of-file (in which case it is the caller's duty to + * 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(). + * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned + * \c true. + * + * \param chain A pointer to an existing chain. + * \param use_padding See FLAC__metadata_chain_write() + * \param handle The I/O handle of the original FLAC stream to read. + * The handle will NOT be closed after the metadata is + * written; that is the duty of the caller. + * \param callbacks A set of callbacks to use for I/O on \a handle. + * The mandatory callbacks are \a read, \a seek, and + * \a eof. + * \param temp_handle The I/O handle of the FLAC stream to write. The + * handle will NOT be closed after the metadata is + * written; that is the duty of the caller. + * \param temp_callbacks + * A set of callbacks to use for I/O on temp_handle. + * The only mandatory callback is \a write. + * \assert + * \code chain != NULL \endcode + * \retval FLAC__bool + * \c true if the write succeeded, else \c false. On failure, + * check the status with FLAC__metadata_chain_status(). + */ +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); + +/** Merge adjacent PADDING blocks into a single block. + * + * \note This function does not write to the FLAC file, it only + * modifies the chain. + * + * \warning Any iterator on the current chain will become invalid after this + * call. You should delete the iterator and get a new one. + * + * \param chain A pointer to an existing chain. + * \assert + * \code chain != NULL \endcode + */ +FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain); + +/** This function will move all PADDING blocks to the end on the metadata, + * then merge them into a single block. + * + * \note This function does not write to the FLAC file, it only + * modifies the chain. + * + * \warning Any iterator on the current chain will become invalid after this + * call. You should delete the iterator and get a new one. + * + * \param chain A pointer to an existing chain. + * \assert + * \code chain != NULL \endcode + */ +FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain); + + +/*********** FLAC__Metadata_Iterator ***********/ + +/** Create a new iterator instance. + * + * \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(); + +/** Free an iterator instance. Deletes the object pointed to by \a iterator. + * + * \param iterator A pointer to an existing iterator. + * \assert + * \code iterator != NULL \endcode + */ +FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator); + +/** Initialize the iterator to point to the first metadata block in the + * given chain. + * + * \param iterator A pointer to an existing iterator. + * \param chain A pointer to an existing and initialized (read) chain. + * \assert + * \code iterator != NULL \endcode + * \code chain != NULL \endcode + */ +FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain); + +/** Moves the iterator forward one metadata block, returning \c false if + * already at the end. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__bool + * \c false if already at the last metadata block of the chain, else + * \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator); + +/** Moves the iterator backward one metadata block, returning \c false if + * already at the beginning. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__bool + * \c false if already at the first metadata block of the chain, else + * \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator); + +/** Get the type of the metadata block at the current position. + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__MetadataType + * The type of the metadata block at the current iterator position. + */ +FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator); + +/** Get the metadata block at the current position. You can modify + * the block in place but must write the chain before the changes + * are reflected to the FLAC file. You do not need to call + * FLAC__metadata_iterator_set_block() to reflect the changes; + * the pointer returned by FLAC__metadata_iterator_get_block() + * points directly into the chain. + * + * \warning + * Do not call FLAC__metadata_object_delete() on the returned object; + * to delete a block use FLAC__metadata_iterator_delete_block(). + * + * \param iterator A pointer to an existing initialized iterator. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__StreamMetadata* + * The current metadata block. + */ +FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator); + +/** Set the metadata block at the current position, replacing the existing + * block. The new block passed in becomes owned by the chain and it will be + * deleted when the chain is deleted. + * + * \param iterator A pointer to an existing initialized iterator. + * \param block A pointer to a metadata block. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \code block != NULL \endcode + * \retval FLAC__bool + * \c false if the conditions in the above description are not met, or + * a memory allocation error occurs, otherwise \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); + +/** Removes the current block from the chain. If \a replace_with_padding is + * \c true, the block will instead be replaced with a padding block of equal + * size. You can not delete the STREAMINFO block. The iterator will be + * left pointing to the block before the one just "deleted", even if + * \a replace_with_padding is \c true. + * + * \param iterator A pointer to an existing initialized iterator. + * \param replace_with_padding See above. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__bool + * \c false if the conditions in the above description are not met, + * otherwise \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding); + +/** Insert a new block before the current block. You cannot insert a block + * before the first STREAMINFO block. You cannot insert a STREAMINFO block + * as there can be only one, the one that already exists at the head when you + * read in a chain. The chain takes ownership of the new block and it will be + * deleted when the chain is deleted. The iterator will be left pointing to + * the new block. + * + * \param iterator A pointer to an existing initialized iterator. + * \param block A pointer to a metadata block to insert. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__bool + * \c false if the conditions in the above description are not met, or + * a memory allocation error occurs, otherwise \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); + +/** Insert a new block after the current block. You cannot insert a STREAMINFO + * block as there can be only one, the one that already exists at the head when + * you read in a chain. The chain takes ownership of the new block and it will + * be deleted when the chain is deleted. The iterator will be left pointing to + * the new block. + * + * \param iterator A pointer to an existing initialized iterator. + * \param block A pointer to a metadata block to insert. + * \assert + * \code iterator != NULL \endcode + * \a iterator has been successfully initialized with + * FLAC__metadata_iterator_init() + * \retval FLAC__bool + * \c false if the conditions in the above description are not met, or + * a memory allocation error occurs, otherwise \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); + +/* \} */ + + +/** \defgroup flac_metadata_object FLAC/metadata.h: metadata object methods + * \ingroup flac_metadata + * + * \brief + * This module contains methods for manipulating FLAC metadata objects. + * + * Since many are variable length we have to be careful about the memory + * management. We decree that all pointers to data in the object are + * owned by the object and memory-managed by the object. + * + * Use the FLAC__metadata_object_new() and FLAC__metadata_object_delete() + * functions to create all instances. When using the + * FLAC__metadata_object_set_*() functions to set pointers to data, set + * \a copy to \c true to have the function make it's own copy of the data, or + * to \c false to give the object ownership of your data. In the latter case + * your pointer must be freeable by free() and will be free()d when the object + * is FLAC__metadata_object_delete()d. It is legal to pass a null pointer as + * the data pointer to a FLAC__metadata_object_set_*() function as long as + * the length argument is 0 and the \a copy argument is \c false. + * + * The FLAC__metadata_object_new() and FLAC__metadata_object_clone() function + * will return \c NULL in the case of a memory allocation error, otherwise a new + * object. The FLAC__metadata_object_set_*() functions return \c false in the + * case of a memory allocation error. + * + * We don't have the convenience of C++ here, so note that the library relies + * on you to keep the types straight. In other words, if you pass, for + * example, a FLAC__StreamMetadata* that represents a STREAMINFO block to + * 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. + * + * \{ + */ + + +/** Create a new metadata object instance of the given type. + * + * The object will be "empty"; i.e. values and data pointers will be \c 0, + * with the exception of FLAC__METADATA_TYPE_VORBIS_COMMENT, which will have + * the vendor string set (but zero comments). + * + * Do not pass in a value greater than or equal to + * \a FLAC__METADATA_TYPE_UNDEFINED unless you really know what you're + * doing. + * + * \param type Type of object to create + * \retval FLAC__StreamMetadata* + * \c NULL if there was an error allocating memory or the type code is + * greater than FLAC__MAX_METADATA_TYPE_CODE, else the new instance. + */ +FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type); + +/** Create a copy of an existing metadata object. + * + * The copy is a "deep" copy, i.e. dynamically allocated data within the + * object is also copied. The caller takes ownership of the new block and + * is responsible for freeing it with FLAC__metadata_object_delete(). + * + * \param object Pointer to object to copy. + * \assert + * \code object != NULL \endcode + * \retval FLAC__StreamMetadata* + * \c NULL if there was an error allocating memory, else the new instance. + */ +FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object); + +/** Free a metadata object. Deletes the object pointed to by \a object. + * + * The delete is a "deep" delete, i.e. dynamically allocated data within the + * object is also deleted. + * + * \param object A pointer to an existing object. + * \assert + * \code object != NULL \endcode + */ +FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object); + +/** Compares two metadata objects. + * + * The compare is "deep", i.e. dynamically allocated data within the + * object is also compared. + * + * \param block1 A pointer to an existing object. + * \param block2 A pointer to an existing object. + * \assert + * \code block1 != NULL \endcode + * \code block2 != NULL \endcode + * \retval FLAC__bool + * \c true if objects are identical, else \c false. + */ +FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2); + +/** 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. + * + * \param object A pointer to an existing APPLICATION 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_APPLICATION \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_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy); + +/** Resize the seekpoint array. + * + * If the size shrinks, elements will truncated; if it grows, new placeholder + * points will be added to the end. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param new_num_points The desired length of the array; may be \c 0. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code (object->data.seek_table.points == NULL && object->data.seek_table.num_points == 0) || + * (object->data.seek_table.points != NULL && object->data.seek_table.num_points > 0) \endcode + * \retval FLAC__bool + * \c false if memory allocation error, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points); + +/** Set a seekpoint in a seektable. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param point_num Index into seekpoint array to set. + * \param point The point to set. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code object->data.seek_table.num_points > point_num \endcode + */ +FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point); + +/** Insert a seekpoint into a seektable. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param point_num Index into seekpoint array to set. + * \param point The point to set. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code object->data.seek_table.num_points >= point_num \endcode + * \retval FLAC__bool + * \c false if memory allocation error, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point); + +/** Delete a seekpoint from a seektable. + * + * \param object A pointer to an existing SEEKTABLE object. + * \param point_num Index into seekpoint array to set. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \code object->data.seek_table.num_points > point_num \endcode + * \retval FLAC__bool + * \c false if memory allocation error, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num); + +/** Check a seektable to see if it conforms to the FLAC specification. + * See the format specification for limits on the contents of the + * seektable. + * + * \param object A pointer to an existing SEEKTABLE object. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \retval FLAC__bool + * \c false if seek table is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object); + +/** Append a number of placeholder points 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 num The number of placeholder points to append. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \retval FLAC__bool + * \c false if memory allocation fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num); + +/** Append a specific seek point template 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 sample_number The sample number of the seek point template. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \retval FLAC__bool + * \c false if memory allocation fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number); + +/** Append specific 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 sample_numbers An array of sample numbers for the seek points. + * \param num The number of seek point templates to append. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \retval FLAC__bool + * \c false if memory allocation fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num); + +/** 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 num The number of placeholder points to append. + * \param total_samples The total number of samples to be encoded; + * the seekpoints will be spaced approximately + * \a total_samples / \a num samples apart. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \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); + +/** Sort a seek table's seek points according to the format specification, + * removing duplicates. + * + * \param object A pointer to a seek table to be sorted. + * \param compact If \c false, behaves like FLAC__format_seektable_sort(). + * If \c true, duplicates are deleted and the seek table is + * shrunk appropriately; the number of placeholder points + * present in the seek table will be the same after the call + * as before. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode + * \retval FLAC__bool + * \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. + * + * \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. + * \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) \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_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); + +/** Resize the comment array. + * + * If the size shrinks, elements will truncated; if it grows, new empty + * fields will be added to the end. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param new_num_comments The desired length of the array; may be \c 0. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \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 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. + * + * \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. + * \param entry The entry to set the comment to. + * \param copy See above. + * \assert + * \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 + * \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_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. + * + * \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 + * at and after \a comment_num move right one position. + * To append a comment to the end, set \a comment_num to + * \c object->data.vorbis_comment.num_comments . + * \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 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 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. + * \param comment_num The index of the comment to delete. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \code object->data.vorbis_comment.num_comments > comment_num \endcode + * \retval FLAC__bool + * \c false if realloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num); + +/** 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 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 NUL. + * \assert + * \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); + +/** Find a Vorbis comment with the given field name. + * + * The search begins at entry number \a offset; use an offset of 0 to + * search from the beginning of the comment array. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param offset The offset into the comment array from where to start + * the search. + * \param field_name The field name of the comment to find. + * \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); + +/** Remove first Vorbis comment matching the given field name. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param field_name The field name of comment to delete. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \retval int + * \c -1 for memory allocation error, \c 0 for no matching entries, + * \c 1 for one matching entry deleted. + */ +FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name); + +/** Remove all Vorbis comments matching the given field name. + * + * \param object A pointer to an existing VORBIS_COMMENT object. + * \param field_name The field name of comments to delete. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode + * \retval int + * \c -1 for memory allocation error, \c 0 for no matching entries, + * else the number of matching entries deleted. + */ +FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name); + +/** Create a new CUESHEET track instance. + * + * The object will be "empty"; i.e. values and data pointers will be \c 0. + * + * \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(); + +/** Create a copy of an existing CUESHEET track object. + * + * The copy is a "deep" copy, i.e. dynamically allocated data within the + * object is also copied. The caller takes ownership of the new object and + * is responsible for freeing it with + * FLAC__metadata_object_cuesheet_track_delete(). + * + * \param object Pointer to object to copy. + * \assert + * \code object != NULL \endcode + * \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_clone(const FLAC__StreamMetadata_CueSheet_Track *object); + +/** Delete a CUESHEET track object + * + * \param object A pointer to an existing CUESHEET track object. + * \assert + * \code object != NULL \endcode + */ +FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object); + +/** Resize a track's index point array. + * + * If the size shrinks, elements will truncated; if it grows, new blank + * indices will be added to the end. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index of the track to modify. NOTE: this is not + * necessarily the same as the track's \a number field. + * \param new_num_indices The desired length of the array; may be \c 0. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \code object->data.cue_sheet.num_tracks > track_num \endcode + * \code (object->data.cue_sheet.tracks[track_num].indices == NULL && object->data.cue_sheet.tracks[track_num].num_indices == 0) || + * (object->data.cue_sheet.tracks[track_num].indices != NULL && object->data.cue_sheet.tracks[track_num].num_indices > 0) \endcode + * \retval FLAC__bool + * \c false if memory allocation error, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices); + +/** Insert an index point in a CUESHEET track at the given index. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index of the track to modify. NOTE: this is not + * necessarily the same as the track's \a number field. + * \param index_num The index into the track's index array at which to + * insert the index point. NOTE: this is not necessarily + * the same as the index point's \a number field. The + * indices at and after \a index_num move right one + * position. To append an index point to the end, set + * \a index_num to + * \c object->data.cue_sheet.tracks[track_num].num_indices . + * \param index The index point to insert. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \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. + */ +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); + +/** Insert a blank index point in a CUESHEET track at the given index. + * + * A blank index point is one in which all field values are zero. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index of the track to modify. NOTE: this is not + * necessarily the same as the track's \a number field. + * \param index_num The index into the track's index array at which to + * insert the index point. NOTE: this is not necessarily + * the same as the index point's \a number field. The + * indices at and after \a index_num move right one + * position. To append an index point to the end, set + * \a index_num to + * \c object->data.cue_sheet.tracks[track_num].num_indices . + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \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. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num); + +/** Delete an index point in a CUESHEET track at the given index. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index into the track array of the track to + * modify. NOTE: this is not necessarily the same + * as the track's \a number field. + * \param index_num The index into the track's index array of the index + * to delete. NOTE: this is not necessarily the same + * as the index's \a number field. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \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. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num); + +/** Resize the track array. + * + * If the size shrinks, elements will truncated; if it grows, new blank + * tracks will be added to the end. + * + * \param object A pointer to an existing CUESHEET object. + * \param new_num_tracks The desired length of the array; may be \c 0. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode + * \code (object->data.cue_sheet.tracks == NULL && object->data.cue_sheet.num_tracks == 0) || + * (object->data.cue_sheet.tracks != NULL && object->data.cue_sheet.num_tracks > 0) \endcode + * \retval FLAC__bool + * \c false if memory allocation error, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks); + +/** 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. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num Index into track array to set. NOTE: this is not + * necessarily the same as the track's \a number field. + * \param track The track to set the track to. You may safely pass in + * a const pointer if \a copy is \c true. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \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) + * \retval FLAC__bool + * \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. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index at which to insert the track. NOTE: this + * is not necessarily the same as the track's \a number + * field. The tracks at and after \a track_num move right + * one position. To append a track to the end, set + * \a track_num to \c object->data.cue_sheet.num_tracks . + * \param track The track to insert. You may safely pass in a const + * pointer if \a copy is \c true. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \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. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy); + +/** Insert a blank track in a CUESHEET block at the given index. + * + * A blank track is one in which all field values are zero. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index at which to insert the track. NOTE: this + * is not necessarily the same as the track's \a number + * field. The tracks at and after \a track_num move right + * one position. To append a track to the end, set + * \a track_num to \c object->data.cue_sheet.num_tracks . + * \assert + * \code object != NULL \endcode + * \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. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num); + +/** Delete a track in a CUESHEET block at the given index. + * + * \param object A pointer to an existing CUESHEET object. + * \param track_num The index into the track array of the track to + * delete. NOTE: this is not necessarily the same + * as the track's \a number field. + * \assert + * \code object != NULL \endcode + * \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. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num); + +/** 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. + * + * \param object A pointer to an existing CUESHEET object. + * \param check_cd_da_subset If \c true, check CUESHEET against more + * stringent requirements for a CD-DA (audio) disc. + * \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_CUESHEET \endcode + * \retval FLAC__bool + * \c false if cue sheet is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation); + +/* \} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/apps/codecs/libFLAC/include/FLAC/ordinals.h b/apps/codecs/libFLAC/include/FLAC/ordinals.h new file mode 100644 index 0000000000..10bc25d5f1 --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/ordinals.h @@ -0,0 +1,73 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__ORDINALS_H +#define FLAC__ORDINALS_H + +#ifndef _MSC_VER +#include +#endif + +typedef signed char FLAC__int8; +typedef unsigned char 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; +#else +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; + +#ifdef true +#undef true +#endif +#ifdef false +#undef false +#endif +#ifndef __cplusplus +#define true 1 +#define false 0 +#endif + +#endif diff --git a/apps/codecs/libFLAC/include/FLAC/seekable_stream_decoder.h b/apps/codecs/libFLAC/include/FLAC/seekable_stream_decoder.h new file mode 100644 index 0000000000..dee5a89cef --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/seekable_stream_decoder.h @@ -0,0 +1,931 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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/apps/codecs/libFLAC/include/FLAC/seekable_stream_encoder.h b/apps/codecs/libFLAC/include/FLAC/seekable_stream_encoder.h new file mode 100644 index 0000000000..4efeb427be --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/seekable_stream_encoder.h @@ -0,0 +1,992 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2002,2003,2004,2005 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/apps/codecs/libFLAC/include/FLAC/stream_decoder.h b/apps/codecs/libFLAC/include/FLAC/stream_decoder.h new file mode 100644 index 0000000000..6cd59d42a9 --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/stream_decoder.h @@ -0,0 +1,873 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__STREAM_DECODER_H +#define FLAC__STREAM_DECODER_H + +#include "export.h" +#include "format.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \file include/FLAC/stream_decoder.h + * + * \brief + * This module contains the functions which implement the stream + * decoder. + * + * See the detailed documentation in the + * \link flac_stream_decoder stream decoder \endlink module. + */ + +/** \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. + */ + +/** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface + * \ingroup flac_decoder + * + * \brief + * This module contains the functions which implement the stream + * decoder. + * + * 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 + * FLAC__stream_decoder_set_*() functions. + * - The program initializes the instance to validate the settings and + * prepare for decoding using FLAC__stream_decoder_init(). + * - 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(), + * which flushes the input and output and resets the decoder to the + * uninitialized state. + * - The instance may be used again or deleted with + * FLAC__stream_decoder_delete(). + * + * 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. + * + * Once the decoder is initialized, your program will call one of several + * functions to start the decoding process: + * + * - FLAC__stream_decoder_process_single() - Tells the decoder to process at + * most one metadata block or audio frame and return, calling either the + * metadata callback or write callback, respectively, once. If the decoder + * 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 + * 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, + * write, or error callback per metadata block, audio frame, or sync error, + * respectively. + * + * When the decoder has finished decoding (normally or through an abort), + * the instance is finished by calling FLAC__stream_decoder_finish(), which + * ensures the decoder is in the correct state and frees memory. Then the + * 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. + * + * The FLAC__stream_decoder_set_metadata_*() functions deserve special + * attention. By default, the decoder only calls the metadata_callback for + * the STREAMINFO block. These functions allow you to tell the decoder + * 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. + * + * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but + * they still can legally be filtered from the metadata_callback. + * + * \note + * 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 + * 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__StreamDecoder + * + * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state(). + */ +typedef enum { + + FLAC__STREAM_DECODER_SEARCH_FOR_METADATA = 0, + /**< The decoder is ready to search for metadata. */ + + FLAC__STREAM_DECODER_READ_METADATA, + /**< 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. */ + + FLAC__STREAM_DECODER_READ_FRAME, + /**< The decoder is ready to or is in the process of reading a frame. */ + + FLAC__STREAM_DECODER_END_OF_STREAM, + /**< The decoder has reached the end of the stream. */ + + 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. + */ + + 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. */ + +} FLAC__StreamDecoderState; + +/** Maps a FLAC__StreamDecoderState to a C string. + * + * Using a FLAC__StreamDecoderState as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderStateString[]; + + +/** Return values for the FLAC__StreamDecoder read callback. + */ +typedef enum { + + FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, + /**< 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. */ + + FLAC__STREAM_DECODER_READ_STATUS_ABORT + /**< An unrecoverable error occurred. The decoder will return from the process call. */ + +} FLAC__StreamDecoderReadStatus; + +/** Maps a FLAC__StreamDecoderReadStatus to a C string. + * + * Using a FLAC__StreamDecoderReadStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[]; + + +/** Return values for the FLAC__StreamDecoder write callback. + */ +typedef enum { + + FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE, + /**< The write was OK and decoding can continue. */ + + FLAC__STREAM_DECODER_WRITE_STATUS_ABORT + /**< An unrecoverable error occurred. The decoder will return from the process call. */ + +} FLAC__StreamDecoderWriteStatus; + +/** Maps a FLAC__StreamDecoderWriteStatus to a C string. + * + * Using a FLAC__StreamDecoderWriteStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[]; + + +/** Possible values passed in to the FLAC__StreamDecoder error callback. + */ +typedef enum { + + FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, + /**< An error in the stream caused the decoder to lose synchronization. */ + + FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, + /**< The decoder encountered a corrupted frame header. */ + + FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH + /**< The frame's data did not match the CRC in the footer. */ + +} FLAC__StreamDecoderErrorStatus; + +/** Maps a FLAC__StreamDecoderErrorStatus to a C string. + * + * Using a FLAC__StreamDecoderErrorStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[]; + + +/*********************************************************************** + * + * class FLAC__StreamDecoder + * + ***********************************************************************/ + +struct FLAC__StreamDecoderProtected; +struct FLAC__StreamDecoderPrivate; +/** The opaque structure definition for the stream decoder type. + * See the \link flac_stream_decoder stream decoder module \endlink + * for a detailed description. + */ +typedef struct { + struct FLAC__StreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */ + struct FLAC__StreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */ +} FLAC__StreamDecoder; + +/** Signature for the read callback. + * See FLAC__stream_decoder_set_read_callback() 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. 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_decoder_set_client_data(). + * \retval FLAC__StreamDecoderReadStatus + * The callee's return status. + */ +typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data); + +/** Signature for the write callback. + * See FLAC__stream_decoder_set_write_callback() for more info. + * + * \param decoder The decoder instance calling the callback. + * \param frame The description of the decoded frame. See + * FLAC__Frame. + * \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. + * \param client_data The callee's client data set through + * FLAC__stream_decoder_set_client_data(). + * \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. + * + * \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(). + */ +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. + * + * \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(). + */ +typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +/** Create a new stream decoder instance. The instance is created with + * default settings; see the individual FLAC__stream_decoder_set_*() + * functions for each setting's default. + * + * \retval FLAC__StreamDecoder* + * \c NULL if there was an error allocating memory, else the new instance. + */ +FLAC_API FLAC__StreamDecoder *FLAC__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__stream_decoder_delete(FLAC__StreamDecoder *decoder); + + +/*********************************************************************** + * + * Public class method prototypes + * + ***********************************************************************/ + +/** 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. + * + * \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_metadata_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderMetadataCallback value); + +/** Set the error callback. + * The supplied function will be called whenever an error occurs during + * decoding. + * + * \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_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. + * + * \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__stream_decoder_set_client_data(FLAC__StreamDecoder *decoder, void *value); + +/** Direct the decoder to pass on all metadata blocks of type \a type. + * + * \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__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type); + +/** Direct the decoder to pass on all APPLICATION metadata blocks of the + * given \a id. + * + * \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__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]); + +/** Direct the decoder to pass on all metadata blocks of any type. + * + * \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__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder); + +/** Direct the decoder to filter out all metadata blocks of type \a type. + * + * \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__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type); + +/** Direct the decoder to filter out all APPLICATION metadata blocks of + * the given \a id. + * + * \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__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]); + +/** Direct the decoder to filter out all metadata blocks of any type. + * + * \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__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder); + +/** Get the current decoder state. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__StreamDecoderState + * The current decoder state. + */ +FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder); + +/** Get the current decoder state as a C string. + * + * \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__stream_decoder_get_resolved_state_string(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. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval unsigned + * See above. + */ +FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder); + +/** Get the current channel assignment 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. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval FLAC__ChannelAssignment + * See above. + */ +FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder); + +/** Get the current sample resolution 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. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval unsigned + * See above. + */ +FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder); + +/** Get the current sample rate in Hz of the stream being decoded. + * Will only be valid after decoding has started and will contain the + * value from the most recently decoded frame header. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval unsigned + * See above. + */ +FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder); + +/** Get the current blocksize of the stream being decoded. + * Will only be valid after decoding has started and will contain the + * value from the most recently decoded frame header. + * + * \param decoder A decoder instance to query. + * \assert + * \code decoder != NULL \endcode + * \retval unsigned + * See above. + */ +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 + * 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. + * \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. + */ +FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *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__STREAM_DECODER_UNINITIALIZED. + * + * 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() + * with a FLAC__stream_decoder_finish(). + * + * \param decoder An uninitialized decoder instance. + * \assert + * \code decoder != NULL \endcode + */ +FLAC_API void 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. + * + * \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. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder); + +/** Reset the decoding process. + * 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. + * + * \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. + */ +FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder); + +/** Decode one metadata block or audio frame. + * This version instructs the decoder to decode a either a single metadata + * block or a single frame and stop, unless the callbacks return a fatal + * error or the read callback returns + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. + * + * 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. + * + * 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 + * 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 + * corrupt, frame. (Such corrupted frames are sent as silence of the + * correct length to the write callback.) + * + * \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). + */ +FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder); + +/** Decode until the end of the metadata. + * This version instructs the decoder to decode from the current position + * and continue until all the metadata has been read, or until the + * callbacks return a fatal error or the read callback returns + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. + * + * 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. + * + * \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). + */ +FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder); + +/** Decode until the end of the stream. + * This version instructs the decoder to decode from the current position + * and continue until the end of stream (the read callback returns + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM), or until the + * callbacks return a fatal error. + * + * 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. + * + * \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). + */ +FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder); + +/** Skip one audio frame. + * This version instructs the decoder to 'skip' a single frame and stop, + * unless the callbacks return a fatal error or the read callback returns + * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. + * + * The decoding flow is the same as what occurs when + * FLAC__stream_decoder_process_single() is called to process an audio + * frame, except that this function does not decode the parsed data into + * PCM or call the write callback. The integrity of the frame is still + * checked the same way as in the other process functions. + * + * This function will return once one whole frame is skipped, in the + * 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 an + * 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 + * to the next frame, then use + * FLAC__seekable_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. + * + * \param decoder An initialized decoder instance not in a metadata + * state. + * \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 + * 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_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder); + +/* \} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/apps/codecs/libFLAC/include/FLAC/stream_encoder.h b/apps/codecs/libFLAC/include/FLAC/stream_encoder.h new file mode 100644 index 0000000000..0ac18a365d --- /dev/null +++ b/apps/codecs/libFLAC/include/FLAC/stream_encoder.h @@ -0,0 +1,1064 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__STREAM_ENCODER_H +#define FLAC__STREAM_ENCODER_H + +#include "export.h" +#include "format.h" +#include "stream_decoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \file include/FLAC/stream_encoder.h + * + * \brief + * This module contains the functions which implement the stream + * encoder. + * + * See the detailed documentation in the + * \link flac_stream_encoder stream encoder \endlink module. + */ + +/** \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. + */ + +/** \defgroup flac_stream_encoder FLAC/stream_encoder.h: stream encoder interface + * \ingroup flac_encoder + * + * \brief + * This module contains the functions which implement the stream + * encoder. + * + * 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 initializes the instance to validate the settings and + * prepare for encoding using FLAC__stream_encoder_init(). + * - 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. + * - 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 + * 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(). + * + * 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 + * user-level documentation + * or the formal description). 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 + * call the write callback several times, once with the \c fLaC signature, + * and once for each encoded metadata block. + * + * After initializing the instance, the user may feed audio data to the + * encoder in one of two ways: + * + * - Channel separate, through FLAC__stream_encoder_process() - The user + * 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. + * - Channel interleaved, through + * FLAC__stream_encoder_process_interleaved() - The user 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 + * 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 + * FLAC__stream_encoder_delete() or initialized again to encode another + * stream. + * + * For programs that write their own metadata, but that do not know the + * actual metadata until after encoding, it is advantageous to instruct + * the encoder to write a PADDING block of the correct size, so that + * instead of rewriting the whole stream after encoding, the program can + * just overwrite the PADDING block. If only the maximum size of the + * metadata is known, the program can write a slightly larger padding + * block, then split it after encoding. + * + * Make sure you understand how lengths are calculated. All FLAC metadata + * blocks have a 4 byte header which contains the type and length. This + * length does not include the 4 bytes of the header. See the format page + * for the specification of metadata blocks and their lengths. + * + * \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 + * return \c true, otherwise \c false. + * + * \note + * FLAC__stream_encoder_finish() resets all settings to the constructor + * defaults, including the callbacks. + * + * \{ + */ + + +/** State values for a FLAC__StreamEncoder + * + * The encoder's state can be obtained by calling FLAC__stream_encoder_get_state(). + */ +typedef enum { + + FLAC__STREAM_ENCODER_OK = 0, + /**< The encoder is in the normal OK state. */ + + FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR, + /**< An error occurred in the underlying verify stream decoder; + * check FLAC__stream_encoder_get_verify_decoder_state(). + */ + + FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA, + /**< The verify decoder detected a mismatch between the original + * 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_INVALID_NUMBER_OF_CHANNELS, + /**< The encoder has an invalid setting for number of channels. */ + + FLAC__STREAM_ENCODER_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, + /**< The encoder has an invalid setting for the input sample rate. */ + + FLAC__STREAM_ENCODER_INVALID_BLOCK_SIZE, + /**< The encoder has an invalid setting for the block size. */ + + FLAC__STREAM_ENCODER_INVALID_MAX_LPC_ORDER, + /**< The encoder has an invalid setting for the maximum LPC order. */ + + FLAC__STREAM_ENCODER_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, + /**< 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_FRAMING_ERROR, + /**< An error occurred while writing the stream; usually, the write_callback returned an error. */ + + FLAC__STREAM_ENCODER_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 + * - It contains an illegal CUESHEET as checked by FLAC__format_cuesheet_is_legal() + * - It contains an illegal SEEKTABLE as checked by FLAC__format_seektable_is_legal() + * - 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 + * already initialized, usually because + * FLAC__stream_encoder_finish() was not called. + */ + + FLAC__STREAM_ENCODER_UNINITIALIZED + /**< The encoder is in the uninitialized state. */ + +} 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[]; + +/** Return values for the FLAC__StreamEncoder write callback. + */ +typedef enum { + + FLAC__STREAM_ENCODER_WRITE_STATUS_OK = 0, + /**< The write was OK and encoding can continue. */ + + FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR + /**< An unrecoverable error occurred. The encoder will return from the process call. */ + +} FLAC__StreamEncoderWriteStatus; + +/** Maps a FLAC__StreamEncoderWriteStatus to a C string. + * + * Using a FLAC__StreamEncoderWriteStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[]; + + +/*********************************************************************** + * + * class FLAC__StreamEncoder + * + ***********************************************************************/ + +struct FLAC__StreamEncoderProtected; +struct FLAC__StreamEncoderPrivate; +/** The opaque structure definition for the stream encoder type. + * See the \link flac_stream_encoder stream encoder module \endlink + * for a detailed description. + */ +typedef struct { + struct FLAC__StreamEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */ + struct FLAC__StreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */ +} FLAC__StreamEncoder; + +/** Signature for the write callback. + * See FLAC__stream_encoder_set_write_callback() 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 the current frame being encoded. + * \param client_data The callee's client data set through + * FLAC__stream_encoder_set_client_data(). + * \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); + +/** Signature for the metadata callback. + * See FLAC__stream_encoder_set_metadata_callback() for more info. + * + * \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(). + */ +typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data); + + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +/** Create a new stream encoder instance. The instance is created with + * default settings; see the individual FLAC__stream_encoder_set_*() + * functions for each setting's default. + * + * \retval FLAC__StreamEncoder* + * \c NULL if there was an error allocating memory, else the new instance. + */ +FLAC_API FLAC__StreamEncoder *FLAC__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__stream_encoder_delete(FLAC__StreamEncoder *encoder); + + +/*********************************************************************** + * + * Public class method prototypes + * + ***********************************************************************/ + +/** 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, + * the process call will return \c false. Note that this will slow the + * encoding process by the extra time required for decoding and comparison. + * + * \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_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 + * comply. If \c false, the settings may take advantage of the full + * range that the format allows. + * + * Make sure you know what it entails before setting this to \c false. + * + * \default \c true + * \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_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 + * \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_channels(FLAC__StreamEncoder *encoder, unsigned value); + +/** Set the sample resolution of the input to be encoded. + * + * \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__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value); + +/** Set the sample rate (in Hz) of the input to be encoded. + * + * \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__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value); + +/** Set the blocksize to use while encoding. + * + * \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__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value); + +/** Set the maximum LPC order, or \c 0 to use only the fixed predictors. + * + * \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__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value); + +/** Set the precision, in bits, of the quantized linear predictor + * coefficients, or \c 0 to let the encoder select it based on the + * blocksize. + * + * \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__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value); + +/** Set to \c false to use only the specified quantized linear predictor + * coefficient precision, or \c true to search neighboring precision + * values and use the best one. + * + * \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__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value); + +/** Deprecated. Setting this value has no effect. + * + * \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__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value); + +/** Set to \c false to let the encoder estimate the best model order + * based on the residual signal energy, or \c true to force the + * encoder to evaluate all order models and select the best. + * + * \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__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value); + +/** Set the minimum partition order to search when coding the residual. + * This is used in tandem with + * FLAC__stream_encoder_set_max_residual_partition_order(). + * + * The partition order determines the context size in the residual. + * The context size will be approximately blocksize / (2 ^ order). + * + * Set both min and max values to \c 0 to force a single context, + * whose Rice parameter is based on the residual signal variance. + * Otherwise, set a min and max order, and the encoder will search + * all orders, using the mean of each context for its Rice parameter, + * and use the best. + * + * \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__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value); + +/** Set the maximum partition order to search when coding the residual. + * This is used in tandem with + * FLAC__stream_encoder_set_min_residual_partition_order(). + * + * The partition order determines the context size in the residual. + * The context size will be approximately blocksize / (2 ^ order). + * + * Set both min and max values to \c 0 to force a single context, + * whose Rice parameter is based on the residual signal variance. + * Otherwise, set a min and max order, and the encoder will search + * all orders, using the mean of each context for its Rice parameter, + * and use the best. + * + * \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__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value); + +/** Deprecated. Setting this value has no effect. + * + * \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__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value); + +/** Set an estimate of the total samples that will be encoded. + * This is merely an estimate and may be set to \c 0 if unknown. + * This value will be written to the STREAMINFO block before encoding, + * and can remove the need for the caller to rewrite the value later + * if the value is known before encoding. + * + * \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__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value); + +/** 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. + * + * \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. + * + * \note + * The STREAMINFO block is always written and no STREAMINFO block may + * occur in the supplied array. + * + * \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()) + * + * \note + * A VORBIS_COMMENT block may be supplied. The vendor string in it + * will be ignored. libFLAC will use it's own vendor string. libFLAC + * will not modify the passed-in VORBIS_COMMENT's vendor string, it + * will simply write it's own into the stream. If no VORBIS_COMMENT + * block is present in the \a metadata array, libFLAC will write an + * empty one, containing only the vendor string. + * + * \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__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. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__StreamEncoderState + * The current encoder state. + */ +FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder); + +/** Get the state of the verify stream decoder. + * Useful when 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 verify stream decoder state. + */ +FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder); + +/** Get the current encoder state as a C string. + * This version automatically resolves + * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR by getting the + * verify decoder'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__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder); + +/** Get relevant values about the nature of a verify decoder error. + * Useful when the stream encoder state is + * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. The arguments should + * be addresses in which the stats will be returned, or NULL if value + * is not desired. + * + * \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__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); + +/** Get the "verify" flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_verify(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder); + +/** Get the "streamable subset" flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_streamable_subset(). + */ +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. + * \assert + * \code encoder != NULL \endcode + * \retval unsigned + * See FLAC__stream_encoder_set_channels(). + */ +FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder); + +/** Get the input sample resolution setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval unsigned + * See FLAC__stream_encoder_set_bits_per_sample(). + */ +FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder); + +/** Get the input sample rate setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval unsigned + * See FLAC__stream_encoder_set_sample_rate(). + */ +FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder); + +/** Get the blocksize setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval unsigned + * See FLAC__stream_encoder_set_blocksize(). + */ +FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder); + +/** Get the maximum LPC order setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval unsigned + * See FLAC__stream_encoder_set_max_lpc_order(). + */ +FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder); + +/** Get the quantized linear predictor coefficient precision setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval unsigned + * See FLAC__stream_encoder_set_qlp_coeff_precision(). + */ +FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder); + +/** Get the qlp coefficient precision search flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_do_qlp_coeff_prec_search(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder); + +/** Get the "escape coding" flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_do_escape_coding(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder); + +/** Get the exhaustive model search flag. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__bool + * See FLAC__stream_encoder_set_do_exhaustive_model_search(). + */ +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder); + +/** Get the minimum residual partition order setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval unsigned + * See FLAC__stream_encoder_set_min_residual_partition_order(). + */ +FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder); + +/** Get maximum residual partition order setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval unsigned + * See FLAC__stream_encoder_set_max_residual_partition_order(). + */ +FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder); + +/** Get the Rice parameter search distance setting. + * + * \param encoder An encoder instance to query. + * \assert + * \code encoder != NULL \endcode + * \retval unsigned + * See FLAC__stream_encoder_set_rice_parameter_search_dist(). + */ +FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder); + +/** 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. + * + * \param encoder An encoder instance to set. + * \assert + * \code encoder != NULL \endcode + * \retval FLAC__uint64 + * See FLAC__stream_encoder_get_total_samples_estimate(). + */ +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 + * 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 + * 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. + * + * \param encoder An uninitialized encoder instance. + * \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. + */ +FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder *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__STREAM_ENCODER_UNINITIALIZED. Note that this can generate + * one or more write callbacks before returning, and will generate + * a metadata callback. + * + * 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() + * with a FLAC__stream_encoder_finish(). + * + * \param encoder An uninitialized encoder instance. + * \assert + * \code encoder != NULL \endcode + */ +FLAC_API void 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. + * + * \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__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode + * \retval FLAC__bool + * \c true if successful, else \c false; in this case, check the + * encoder state with FLAC__stream_encoder_get_state() to see what + * went wrong. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples); + +/** Submit data for encoding. + * This version allows you to supply the input data where the channels + * are interleaved into a single array (i.e. channel0_sample0, + * 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. + * + * \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__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__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode + * \retval FLAC__bool + * \c true if successful, else \c false; in this case, check the + * encoder state with FLAC__stream_encoder_get_state() to see what + * went wrong. + */ +FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples); + +/* \} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/apps/codecs/libFLAC/include/private/all.h b/apps/codecs/libFLAC/include/private/all.h new file mode 100644 index 0000000000..5c9e9842e1 --- /dev/null +++ b/apps/codecs/libFLAC/include/private/all.h @@ -0,0 +1,48 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__ALL_H +#define FLAC__PRIVATE__ALL_H + +#include "bitbuffer.h" +#include "bitmath.h" +#include "cpu.h" +#include "crc.h" +#include "fixed.h" +#include "float.h" +#include "format.h" +#include "lpc.h" +#include "md5.h" +#include "memory.h" +#include "metadata.h" +#include "stream_encoder_framing.h" + +#endif diff --git a/apps/codecs/libFLAC/include/private/bitbuffer.h b/apps/codecs/libFLAC/include/private/bitbuffer.h new file mode 100644 index 0000000000..4ce5957fde --- /dev/null +++ b/apps/codecs/libFLAC/include/private/bitbuffer.h @@ -0,0 +1,159 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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 /* 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/apps/codecs/libFLAC/include/private/bitmath.h b/apps/codecs/libFLAC/include/private/bitmath.h new file mode 100644 index 0000000000..1615c338c8 --- /dev/null +++ b/apps/codecs/libFLAC/include/private/bitmath.h @@ -0,0 +1,42 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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__BITMATH_H +#define FLAC__PRIVATE__BITMATH_H + +#include "FLAC/ordinals.h" + +unsigned FLAC__bitmath_ilog2(FLAC__uint32 v); +unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v); +unsigned FLAC__bitmath_silog2(int v); +unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v); + +#endif diff --git a/apps/codecs/libFLAC/include/private/cpu.h b/apps/codecs/libFLAC/include/private/cpu.h new file mode 100644 index 0000000000..a57936051f --- /dev/null +++ b/apps/codecs/libFLAC/include/private/cpu.h @@ -0,0 +1,94 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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__CPU_H +#define FLAC__PRIVATE__CPU_H + +#include "FLAC/ordinals.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +typedef enum { + FLAC__CPUINFO_TYPE_IA32, + FLAC__CPUINFO_TYPE_PPC, + FLAC__CPUINFO_TYPE_UNKNOWN +} FLAC__CPUInfo_Type; + +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; + +typedef struct { + FLAC__bool altivec; + FLAC__bool ppc64; +} 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; + +typedef struct { + FLAC__bool use_asm; + FLAC__CPUInfo_Type type; + union { + FLAC__CPUInfo_IA32 ia32; + FLAC__CPUInfo_PPC ppc; + } data; +} 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 +#endif + +#endif diff --git a/apps/codecs/libFLAC/include/private/crc.h b/apps/codecs/libFLAC/include/private/crc.h new file mode 100644 index 0000000000..487ed04010 --- /dev/null +++ b/apps/codecs/libFLAC/include/private/crc.h @@ -0,0 +1,57 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__CRC_H +#define FLAC__PRIVATE__CRC_H + +#include "FLAC/ordinals.h" + +/* 8 bit CRC generator, MSB shifted first +** polynomial = x^8 + x^2 + x^1 + x^0 +** init = 0 +*/ +extern FLAC__byte const FLAC__crc8_table[256]; +#define FLAC__CRC8_UPDATE(data, crc) (crc) = FLAC__crc8_table[(crc) ^ (data)]; +void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc); +void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc); +FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len); + +/* 16 bit CRC generator, MSB shifted first +** 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); + +#endif diff --git a/apps/codecs/libFLAC/include/private/fixed.h b/apps/codecs/libFLAC/include/private/fixed.h new file mode 100644 index 0000000000..8401ffa8ee --- /dev/null +++ b/apps/codecs/libFLAC/include/private/fixed.h @@ -0,0 +1,97 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__FIXED_H +#define FLAC__PRIVATE__FIXED_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "private/float.h" +#include "FLAC/format.h" + +/* + * FLAC__fixed_compute_best_predictor() + * -------------------------------------------------------------------- + * Compute the best fixed predictor and the expected bits-per-sample + * of the residual signal for each order. The _wide() version uses + * 64-bit integers which is statistically necessary when bits-per- + * sample + log2(blocksize) > 30 + * + * IN data[0,data_len-1] + * IN data_len + * OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER] + */ +#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]); +# 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__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); +# endif +# endif +# endif +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(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 + +/* + * FLAC__fixed_compute_residual() + * -------------------------------------------------------------------- + * Compute the residual signal obtained from sutracting the predicted + * signal from the original. + * + * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) + * IN data_len length of original signal + * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order + * OUT residual[0,data_len-1] residual signal + */ +void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]); + +/* + * FLAC__fixed_restore_signal() + * -------------------------------------------------------------------- + * Restore the original signal by summing the residual and the + * predictor. + * + * IN residual[0,data_len-1] residual signal + * IN data_len length of original signal + * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order + * *** IMPORTANT: the caller must pass in the historical samples: + * IN data[-order,-1] previously-reconstructed historical samples + * OUT data[0,data_len-1] original signal + */ +void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[]); + +#endif diff --git a/apps/codecs/libFLAC/include/private/float.h b/apps/codecs/libFLAC/include/private/float.h new file mode 100644 index 0000000000..67a5f266e8 --- /dev/null +++ b/apps/codecs/libFLAC/include/private/float.h @@ -0,0 +1,97 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2004,2005 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__FLOAT_H +#define FLAC__PRIVATE__FLOAT_H + +#ifdef HAVE_CONFIG_H +#include +#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< +#endif + +#include "private/float.h" +#include "FLAC/format.h" + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +/* + * FLAC__lpc_compute_autocorrelation() + * -------------------------------------------------------------------- + * Compute the autocorrelation for lags between 0 and lag-1. + * Assumes data[] outside of [0,data_len-1] == 0. + * Asserts that lag > 0. + * + * IN data[0,data_len-1] + * IN data_len + * IN 0 < lag <= data_len + * OUT autoc[0,lag-1] + */ +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 +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 +# endif +#endif + +/* + * FLAC__lpc_compute_lp_coefficients() + * -------------------------------------------------------------------- + * Computes LP coefficients for orders 1..max_order. + * Do not call if autoc[0] == 0.0. This means the signal is zero + * and there is no point in calculating a predictor. + * + * IN autoc[0,max_order] autocorrelation values + * IN 0 < max_order <= FLAC__MAX_LPC_ORDER max LP order to compute + * 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 + * + * 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__double error[]); + +/* + * FLAC__lpc_quantize_coefficients() + * -------------------------------------------------------------------- + * Quantizes the LP coefficients. NOTE: precision + bits_per_sample + * must be less than 32 (sizeof(FLAC__int32)*8). + * + * IN lp_coeff[0,order-1] LP coefficients + * IN order LP order + * IN FLAC__MIN_QLP_COEFF_PRECISION < precision + * desired precision (in bits, including sign + * bit) of largest coefficient + * OUT qlp_coeff[0,order-1] quantized coefficients + * OUT shift # of bits to shift right to get approximated + * LP coefficients. NOTE: could be negative. + * RETURN 0 => quantization OK + * 1 => coefficients require too much shifting for *shift to + * fit in the LPC subframe header. 'shift' is unset. + * 2 => coefficients are all zero, which is bad. 'shift' is + * unset. + */ +int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift); + +/* + * FLAC__lpc_compute_residual_from_qlp_coefficients() + * -------------------------------------------------------------------- + * Compute the residual signal obtained from sutracting the predicted + * signal from the original. + * + * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) + * IN data_len length of original signal + * IN qlp_coeff[0,order-1] quantized LP coefficients + * IN order > 0 LP 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[]); +#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 +#endif + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ + +/* + * FLAC__lpc_restore_signal() + * -------------------------------------------------------------------- + * Restore the original signal by summing the residual and the + * predictor. + * + * IN residual[0,data_len-1] residual signal + * IN data_len length of original signal + * IN qlp_coeff[0,order-1] quantized LP coefficients + * IN order > 0 LP order + * IN lp_quantization quantization of LP coefficients in bits + * *** IMPORTANT: the caller must pass in the historical samples: + * IN data[-order,-1] previously-reconstructed historical samples + * OUT data[0,data_len-1] original signal + */ +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 +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 /* FLAC__HAS_NASM */ +# 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/* FLAC__CPU_IA32 || FLAC__CPU_PPC */ +#endif /* FLAC__NO_ASM */ + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +/* + * FLAC__lpc_compute_expected_bits_per_residual_sample() + * -------------------------------------------------------------------- + * Compute the expected number of bits per residual signal sample + * based on the LP error (which is related to the residual variance). + * + * IN lpc_error >= 0.0 error returned from calculating LP coefficients + * IN total_samples > 0 # of samples in residual signal + * RETURN expected bits per sample + */ +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() + * -------------------------------------------------------------------- + * Compute the best order from the array of signal errors returned + * during coefficient computation. + * + * 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 + * RETURN [1,max_order] best order + */ +unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample); + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ + +#endif diff --git a/apps/codecs/libFLAC/include/private/md5.h b/apps/codecs/libFLAC/include/private/md5.h new file mode 100644 index 0000000000..e85326015f --- /dev/null +++ b/apps/codecs/libFLAC/include/private/md5.h @@ -0,0 +1,54 @@ +/* + * This is the header file for the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' + * header definitions; now uses stuff from dpkg's config.h + * - Ian Jackson . + * Still in the public domain. + * + * Josh Coalson: made some changes to integrate with libFLAC. + * Still in the public domain. + */ + +#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 { + FLAC__uint32 buf[4]; + FLAC__uint32 bytes[2]; + FLAC__uint32 in[16]; + FLAC__byte *internal_buf; + unsigned capacity; +}; + +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]); + +FLAC_API FLAC__bool FLAC__MD5Accumulate(struct FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample); + +#endif /* !MD5_H */ diff --git a/apps/codecs/libFLAC/include/private/memory.h b/apps/codecs/libFLAC/include/private/memory.h new file mode 100644 index 0000000000..fca808155b --- /dev/null +++ b/apps/codecs/libFLAC/include/private/memory.h @@ -0,0 +1,56 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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__MEMORY_H +#define FLAC__PRIVATE__MEMORY_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include /* 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); +#ifndef FLAC__INTEGER_ONLY_LIBRARY +FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer); +#endif + +#endif diff --git a/apps/codecs/libFLAC/include/private/metadata.h b/apps/codecs/libFLAC/include/private/metadata.h new file mode 100644 index 0000000000..f95e2deab5 --- /dev/null +++ b/apps/codecs/libFLAC/include/private/metadata.h @@ -0,0 +1,40 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2002,2003,2004,2005 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__METADATA_H +#define FLAC__PRIVATE__METADATA_H + +#include "FLAC/metadata.h" + +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/apps/codecs/libFLAC/include/private/stream_encoder_framing.h b/apps/codecs/libFLAC/include/private/stream_encoder_framing.h new file mode 100644 index 0000000000..5b5426a3e1 --- /dev/null +++ b/apps/codecs/libFLAC/include/private/stream_encoder_framing.h @@ -0,0 +1,45 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__STREAM_ENCODER_FRAMING_H +#define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H + +#include "FLAC/format.h" +#include "bitbuffer.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); + +#endif diff --git a/apps/codecs/libFLAC/include/protected/all.h b/apps/codecs/libFLAC/include/protected/all.h new file mode 100644 index 0000000000..12e7ae2a5e --- /dev/null +++ b/apps/codecs/libFLAC/include/protected/all.h @@ -0,0 +1,42 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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__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" + +#endif diff --git a/apps/codecs/libFLAC/include/protected/file_decoder.h b/apps/codecs/libFLAC/include/protected/file_decoder.h new file mode 100644 index 0000000000..88662bb34d --- /dev/null +++ b/apps/codecs/libFLAC/include/protected/file_decoder.h @@ -0,0 +1,41 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__PROTECTED__FILE_DECODER_H +#define FLAC__PROTECTED__FILE_DECODER_H + +#include "FLAC/file_decoder.h" + +typedef struct FLAC__FileDecoderProtected { + FLAC__FileDecoderState state; +} FLAC__FileDecoderProtected; + +#endif diff --git a/apps/codecs/libFLAC/include/protected/file_encoder.h b/apps/codecs/libFLAC/include/protected/file_encoder.h new file mode 100644 index 0000000000..1d516d1da8 --- /dev/null +++ b/apps/codecs/libFLAC/include/protected/file_encoder.h @@ -0,0 +1,41 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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__PROTECTED__FILE_ENCODER_H +#define FLAC__PROTECTED__FILE_ENCODER_H + +#include "FLAC/file_encoder.h" + +typedef struct FLAC__FileEncoderProtected { + FLAC__FileEncoderState state; +} FLAC__FileEncoderProtected; + +#endif diff --git a/apps/codecs/libFLAC/include/protected/seekable_stream_decoder.h b/apps/codecs/libFLAC/include/protected/seekable_stream_decoder.h new file mode 100644 index 0000000000..71123da898 --- /dev/null +++ b/apps/codecs/libFLAC/include/protected/seekable_stream_decoder.h @@ -0,0 +1,42 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__PROTECTED__SEEKABLE_STREAM_DECODER_H +#define FLAC__PROTECTED__SEEKABLE_STREAM_DECODER_H + +#include "FLAC/seekable_stream_decoder.h" + +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; + +#endif diff --git a/apps/codecs/libFLAC/include/protected/seekable_stream_encoder.h b/apps/codecs/libFLAC/include/protected/seekable_stream_encoder.h new file mode 100644 index 0000000000..3341d9a5aa --- /dev/null +++ b/apps/codecs/libFLAC/include/protected/seekable_stream_encoder.h @@ -0,0 +1,42 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2002,2003,2004,2005 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__PROTECTED__SEEKABLE_STREAM_ENCODER_H +#define FLAC__PROTECTED__SEEKABLE_STREAM_ENCODER_H + +#include "FLAC/seekable_stream_encoder.h" + +typedef struct FLAC__SeekableStreamEncoderProtected { + FLAC__SeekableStreamEncoderState state; + FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset; +} FLAC__SeekableStreamEncoderProtected; + +#endif diff --git a/apps/codecs/libFLAC/include/protected/stream_decoder.h b/apps/codecs/libFLAC/include/protected/stream_decoder.h new file mode 100644 index 0000000000..15eaf28d71 --- /dev/null +++ b/apps/codecs/libFLAC/include/protected/stream_decoder.h @@ -0,0 +1,51 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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__PROTECTED__STREAM_DECODER_H +#define FLAC__PROTECTED__STREAM_DECODER_H + +#include "FLAC/stream_decoder.h" + +typedef struct FLAC__StreamDecoderProtected { + FLAC__StreamDecoderState state; + unsigned channels; + FLAC__ChannelAssignment channel_assignment; + unsigned bits_per_sample; + unsigned sample_rate; /* in Hz */ + unsigned blocksize; /* in samples (per channel) */ +} FLAC__StreamDecoderProtected; + +/* + * return the number of input bytes consumed + */ +unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder); + +#endif diff --git a/apps/codecs/libFLAC/include/protected/stream_encoder.h b/apps/codecs/libFLAC/include/protected/stream_encoder.h new file mode 100644 index 0000000000..86495cc9ae --- /dev/null +++ b/apps/codecs/libFLAC/include/protected/stream_encoder.h @@ -0,0 +1,60 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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__PROTECTED__STREAM_ENCODER_H +#define FLAC__PROTECTED__STREAM_ENCODER_H + +#include "FLAC/stream_encoder.h" + +typedef struct FLAC__StreamEncoderProtected { + FLAC__StreamEncoderState state; + FLAC__bool verify; + FLAC__bool streamable_subset; + FLAC__bool do_mid_side_stereo; + FLAC__bool loose_mid_side_stereo; + unsigned channels; + unsigned bits_per_sample; + unsigned sample_rate; + unsigned blocksize; + unsigned max_lpc_order; + unsigned qlp_coeff_precision; + FLAC__bool do_qlp_coeff_prec_search; + FLAC__bool do_exhaustive_model_search; + FLAC__bool do_escape_coding; + unsigned min_residual_partition_order; + unsigned max_residual_partition_order; + unsigned rice_parameter_search_dist; + FLAC__uint64 total_samples_estimate; + FLAC__StreamMetadata **metadata; + unsigned num_metadata_blocks; +} FLAC__StreamEncoderProtected; + +#endif diff --git a/apps/codecs/libFLAC/lpc.c b/apps/codecs/libFLAC/lpc.c new file mode 100644 index 0000000000..b846db5cb1 --- /dev/null +++ b/apps/codecs/libFLAC/lpc.c @@ -0,0 +1,430 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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 +#include "FLAC/assert.h" +#include "FLAC/format.h" +#include "private/bitmath.h" +#include "private/lpc.h" +#if defined DEBUG || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE +#include +#endif + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +#ifndef M_LN2 +/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */ +#define M_LN2 0.69314718055994530942 +#endif + +void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]) +{ + /* a readable, but slower, version */ +#if 0 + FLAC__real d; + unsigned i; + + FLAC__ASSERT(lag > 0); + FLAC__ASSERT(lag <= data_len); + + while(lag--) { + for(i = lag, d = 0.0; i < data_len; i++) + d += data[i] * data[i - lag]; + autoc[lag] = d; + } +#endif + + /* + * this version tends to run faster because of better data locality + * ('data_len' is usually much larger than 'lag') + */ + FLAC__real d; + unsigned sample, coeff; + const unsigned limit = data_len - lag; + + FLAC__ASSERT(lag > 0); + FLAC__ASSERT(lag <= data_len); + + for(coeff = 0; coeff < lag; coeff++) + autoc[coeff] = 0.0; + for(sample = 0; sample <= limit; sample++) { + d = data[sample]; + for(coeff = 0; coeff < lag; coeff++) + autoc[coeff] += d * data[sample+coeff]; + } + for(; sample < data_len; sample++) { + d = data[sample]; + for(coeff = 0; coeff < data_len - sample; coeff++) + autoc[coeff] += d * data[sample+coeff]; + } +} + +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; + FLAC__double r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_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++) { + /* 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); + + /* Update LPC coefficients and total error. */ + lpc[i]=r; + for(j = 0; j < (i>>1); j++) { + FLAC__double tmp = lpc[j]; + lpc[j] += r * lpc[i-1-j]; + lpc[i-1-j] += r * tmp; + } + if(i & 1) + lpc[j] += lpc[j] * r; + + err *= (1.0 - r * r); + + /* 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] = err; + } +} + +int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift) +{ + unsigned i; + FLAC__double d, cmax = -1e32; + 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); + + /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */ + precision--; + qmax = 1 << precision; + qmin = -qmax; + qmax--; + + for(i = 0; i < order; i++) { + if(lp_coeff[i] == 0.0) + continue; + 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 { + 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 >= 0) { + for(i = 0; i < order; i++) { + qlp_coeff[i] = (FLAC__int32)floor((FLAC__double)lp_coeff[i] * (FLAC__double)(1 << *shift)); + + /* 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, (FLAC__double)lp_coeff[i] * (FLAC__double)(1 << *shift), floor((FLAC__double)lp_coeff[i] * (FLAC__double)(1 << *shift))); +#endif + cmax *= 2.0; + goto redo_it; + } + } + } + else { /* (*shift < 0) */ + const int nshift = -(*shift); +#ifdef DEBUG + fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift = %d\n", *shift); +#endif + for(i = 0; i < order; i++) { + qlp_coeff[i] = (FLAC__int32)floor((FLAC__double)lp_coeff[i] / (FLAC__double)(1 << nshift)); + + /* 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, (FLAC__double)lp_coeff[i] / (FLAC__double)(1 << nshift), floor((FLAC__double)lp_coeff[i] / (FLAC__double)(1 << nshift))); +#endif + cmax *= 2.0; + goto redo_it; + } + } + } + + 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[]) +{ +#ifdef FLAC__OVERFLOW_DETECT + FLAC__int64 sumo; +#endif + unsigned i, j; + FLAC__int32 sum; + const FLAC__int32 *history; + +#ifdef FLAC__OVERFLOW_DETECT_VERBOSE + fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); + for(i=0;i 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 + } + *(residual++) = *(data++) - (sum >> lp_quantization); + } + + /* Here's a slower but clearer version: + for(i = 0; i < data_len; i++) { + sum = 0; + for(j = 0; j < order; j++) + sum += qlp_coeff[j] * data[i-j-1]; + residual[i] = data[i] - (sum >> lp_quantization); + } + */ +} + +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[]) +{ + unsigned i, j; + FLAC__int64 sum; + const FLAC__int32 *history; + +#ifdef FLAC__OVERFLOW_DETECT_VERBOSE + fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); + for(i=0;i 0); + + for(i = 0; i < data_len; i++) { + sum = 0; + 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); + 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)); + break; + } +#endif + *(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization); + } +} + +#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[]) +{ +#ifdef FLAC__OVERFLOW_DETECT + FLAC__int64 sumo; +#endif + unsigned i, j; + FLAC__int32 sum; + const FLAC__int32 *history; + +#ifdef FLAC__OVERFLOW_DETECT_VERBOSE + fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); + for(i=0;i 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 + } + *(data++) = *(residual++) + (sum >> lp_quantization); + } + + /* Here's a slower but clearer version: + for(i = 0; i < data_len; i++) { + sum = 0; + for(j = 0; j < order; j++) + sum += qlp_coeff[j] * data[i-j-1]; + data[i] = residual[i] + (sum >> lp_quantization); + } + */ +} + +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[]) +{ + unsigned i, j; + FLAC__int64 sum; + const FLAC__int32 *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); + for(i=0;i 0); + + for(i = 0; i < data_len; i++) { + sum = 0; + 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); + 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)); + break; + } +#endif + *(data++) = *(residual++) + (FLAC__int32)(sum >> lp_quantization); + } +} + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples) +{ + FLAC__double error_scale; + + FLAC__ASSERT(total_samples > 0); + + 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__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__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 floating-point resolution */ + return 1e32; + } + else { + return 0.0; + } +} + +unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample) +{ + unsigned order, best_order; + FLAC__double best_bits, tmp_bits, error_scale; + + FLAC__ASSERT(max_order > 0); + FLAC__ASSERT(total_samples > 0); + + 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__double)total_samples; + + 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__double)(total_samples - order) + (FLAC__double)(order * bits_per_signal_sample); + if(tmp_bits < best_bits) { + best_order = order; + best_bits = tmp_bits; + } + } + + return best_order+1; /* +1 since index of lpc_error[] is order-1 */ +} + +#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/apps/codecs/libFLAC/md5.c b/apps/codecs/libFLAC/md5.c new file mode 100644 index 0000000000..9679387db9 --- /dev/null +++ b/apps/codecs/libFLAC/md5.c @@ -0,0 +1,315 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + * + * Josh Coalson: made some changes to integrate with libFLAC. + * Still in the public domain. + */ + +#include /* for malloc() */ +#include /* for memcpy() */ + +#include "private/md5.h" + +#ifdef HAVE_CONFIG_H +#include +#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) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * 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]) +{ + register FLAC__uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +FLaC__INLINE +void +byteSwap(FLAC__uint32 *buf, unsigned words) +{ + md5byte *p = (md5byte *)buf; + + if(!is_big_endian_host_) + return; + do { + *buf++ = (FLAC__uint32)((unsigned)p[3] << 8 | p[2]) << 16 | ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +FLAC__MD5Init(struct FLAC__MD5Context *ctx) +{ + 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; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +FLAC__MD5Update(struct FLAC__MD5Context *ctx, md5byte const *buf, unsigned len) +{ + FLAC__uint32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)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); + FLAC__MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + FLAC__MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it. + */ +FLAC__bool +FLAC__MD5Accumulate(struct FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample) +{ + 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; + } + } + } + + FLAC__MD5Update(ctx, ctx->internal_buf, bytes_needed); + + return true; +} + +/* + * 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) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + FLAC__MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + FLAC__MD5Transform(ctx->buf, ctx->in); + + 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; + ctx->capacity = 0; + } +} diff --git a/apps/codecs/libFLAC/memory.c b/apps/codecs/libFLAC/memory.c new file mode 100644 index 0000000000..9718b261b8 --- /dev/null +++ b/apps/codecs/libFLAC/memory.c @@ -0,0 +1,188 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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 "private/memory.h" +#include "FLAC/assert.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address) +{ + void *x; + + FLAC__ASSERT(0 != 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); +#else + x = 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__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, &u.pv); + if(0 == pu) { + return false; + } + else { + if(*unaligned_pointer != 0) + free(*unaligned_pointer); + *unaligned_pointer = pu; + *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__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, &u.pv); + if(0 == pu) { + return false; + } + else { + if(*unaligned_pointer != 0) + free(*unaligned_pointer); + *unaligned_pointer = pu; + *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__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, &u.pv); + if(0 == pu) { + return false; + } + else { + if(*unaligned_pointer != 0) + free(*unaligned_pointer); + *unaligned_pointer = pu; + *aligned_pointer = u.pa; + return true; + } +} + +FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_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, &u.pv); + if(0 == pu) { + return false; + } + else { + if(*unaligned_pointer != 0) + free(*unaligned_pointer); + *unaligned_pointer = pu; + *aligned_pointer = u.pa; + return true; + } +} + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_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, &u.pv); + if(0 == pu) { + return false; + } + else { + if(*unaligned_pointer != 0) + free(*unaligned_pointer); + *unaligned_pointer = pu; + *aligned_pointer = u.pa; + return true; + } +} + +#endif diff --git a/apps/codecs/libFLAC/metadata_iterators.c b/apps/codecs/libFLAC/metadata_iterators.c new file mode 100644 index 0000000000..2d50dd2bdb --- /dev/null +++ b/apps/codecs/libFLAC/metadata_iterators.c @@ -0,0 +1,2964 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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 +#include +#include +#include + +#if defined _MSC_VER || defined __MINGW32__ +#include /* for utime() */ +#include /* for chmod() */ +#else +#include /* some flavors of BSD (like OS X) require this to get time_t */ +#include /* for utime() */ +#include /* for chown(), unlink() */ +#endif +#include /* 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)) + + +/**************************************************************************** + * + * Local function declarations + * + ***************************************************************************/ + +static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes); +static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes); +static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes); +static FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes); +static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes); +static FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes); + +static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator); +static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block); +static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block); +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_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_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); +static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block); +static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block); +static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block); +static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block); +static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length); +static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length); +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_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); +static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last); +static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append); + +static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator); +static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator); + +static unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb); +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 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_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); + +static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status); +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 int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence); +static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle); + +static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status); + + +#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 + +/**************************************************************************** + * + * Level 0 implementation + * + ***************************************************************************/ + +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); + +typedef struct { + FLAC__bool got_error; + FLAC__bool got_object; + FLAC__StreamMetadata *object; +} level0_client_data; + +FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo) +{ + level0_client_data cd; + FLAC__FileDecoder *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); + + 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; + } + + 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); + } + + if(0 != cd.object) + FLAC__metadata_object_delete(cd.object); + + return cd.got_object; +} + +FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags) +{ + level0_client_data cd; + FLAC__FileDecoder *decoder; + + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != tags); + + decoder = FLAC__file_decoder_new(); + + if(0 == decoder) + return false; + + *tags = 0; + + 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_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); + + 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; + } + + FLAC__file_decoder_finish(decoder); + FLAC__file_decoder_delete(decoder); + + if(cd.got_object) + *tags = cd.object; + + return cd.got_object; +} + +FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *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) +{ + level0_client_data *cd = (level0_client_data *)client_data; + (void)decoder; + + /* + * we assume we only get here when the one metadata block we were + * looking for was passed to us + */ + if(!cd->got_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) +{ + level0_client_data *cd = (level0_client_data *)client_data; + (void)decoder; + + if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) + cd->got_error = true; +} + + +/**************************************************************************** + * + * Level 1 implementation + * + ***************************************************************************/ + +#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4) +/* 1 for initial offset, +4 for our own personal use */ + +struct FLAC__Metadata_SimpleIterator { + FILE *file; + char *filename, *tempfile_path_prefix; + struct stat 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 */ + unsigned depth; + /* this is the metadata block header of the current block we are pointing to: */ + FLAC__bool is_last; + FLAC__MetadataType type; + unsigned length; +}; + +FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = { + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR", + "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR" +}; + + +FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new() +{ + FLAC__Metadata_SimpleIterator *iterator = (FLAC__Metadata_SimpleIterator*)calloc(1, sizeof(FLAC__Metadata_SimpleIterator)); + + if(0 != iterator) { + iterator->file = 0; + iterator->filename = 0; + iterator->tempfile_path_prefix = 0; + iterator->has_stats = false; + iterator->is_writable = false; + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; + iterator->first_offset = iterator->offset[0] = -1; + iterator->depth = 0; + } + + return iterator; +} + +static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + + if(0 != iterator->file) { + fclose(iterator->file); + iterator->file = 0; + if(iterator->has_stats) + set_file_stats_(iterator->filename, &iterator->stats); + } + if(0 != iterator->filename) { + free(iterator->filename); + iterator->filename = 0; + } + if(0 != iterator->tempfile_path_prefix) { + free(iterator->tempfile_path_prefix); + iterator->tempfile_path_prefix = 0; + } +} + +FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + + simple_iterator_free_guts_(iterator); + free(iterator); +} + +FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__Metadata_SimpleIteratorStatus status; + + FLAC__ASSERT(0 != iterator); + + status = iterator->status; + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; + return status; +} + +static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only) +{ + unsigned ret; + + FLAC__ASSERT(0 != iterator); + + if(read_only || 0 == (iterator->file = fopen(iterator->filename, "r+b"))) { + iterator->is_writable = false; + if(read_only || errno == EACCES) { + if(0 == (iterator->file = fopen(iterator->filename, "rb"))) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; + return false; + } + } + else { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; + return false; + } + } + else { + iterator->is_writable = true; + } + + ret = seek_to_first_metadata_block_(iterator->file); + switch(ret) { + case 0: + iterator->depth = 0; + iterator->first_offset = iterator->offset[iterator->depth] = ftell(iterator->file); + return read_metadata_block_header_(iterator); + case 1: + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + case 2: + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + case 3: + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE; + return false; + default: + FLAC__ASSERT(0); + return false; + } +} + +#if 0 +@@@ If we decide to finish implementing this, put this comment back in metadata.h +/* + * The 'tempfile_path_prefix' allows you to specify a directory where + * tempfiles should go. Remember that if your metadata edits cause the + * FLAC file to grow, the entire file will have to be rewritten. If + * 'tempfile_path_prefix' is NULL, the temp file will be written in the + * same directory as the original FLAC file. This makes replacing the + * original with the tempfile fast but requires extra space in the same + * partition for the tempfile. If space is a problem, you can pass a + * directory name belonging to a different partition in + * 'tempfile_path_prefix'. Note that you should use the forward slash + * '/' as the directory separator. A trailing slash is not needed; it + * will be added automatically. + */ +FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfile_path_prefix); +#endif + +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 */ + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != filename); + + simple_iterator_free_guts_(iterator); + + if(!read_only && preserve_file_stats) + iterator->has_stats = get_file_stats_(filename, &iterator->stats); + + if(0 == (iterator->filename = strdup(filename))) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + + return simple_iterator_prime_input_(iterator, read_only); +} + +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + return iterator->is_writable; +} + +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + if(iterator->is_last) + return false; + + if(0 != fseek(iterator->file, iterator->length, SEEK_CUR)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + iterator->offset[iterator->depth] = ftell(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__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + if(iterator->offset[iterator->depth] == iterator->first_offset) + return false; + + if(0 != fseek(iterator->file, iterator->first_offset, SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + this_offset = iterator->first_offset; + 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)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + this_offset = ftell(iterator->file); + if(!read_metadata_block_header_(iterator)) + return false; + } + + iterator->offset[iterator->depth] = this_offset; + + return true; +} + +FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + return iterator->type; +} + +FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type); + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + if(0 != block) { + block->is_last = iterator->is_last; + block->length = iterator->length; + + if(!read_metadata_block_data_(iterator, block)) { + FLAC__metadata_object_delete(block); + return 0; + } + + /* 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)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + FLAC__metadata_object_delete(block); + return 0; + } + } + else + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + return block; +} + +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__bool ret; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(0 != block); + + if(!iterator->is_writable) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE; + return false; + } + + if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) { + if(iterator->type != block->type) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; + return false; + } + } + + block->is_last = iterator->is_last; + + if(iterator->length == block->length) + return write_metadata_block_stationary_(iterator, block); + else if(iterator->length > block->length) { + 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); + 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); + return ret; + } + } + else /* iterator->length < block->length */ { + unsigned padding_leftover = 0; + FLAC__bool padding_is_last = false; + if(use_padding) { + /* first see if we can even use padding */ + if(iterator->is_last) { + use_padding = false; + } + else { + const unsigned extra_padding_bytes_required = block->length - iterator->length; + simple_iterator_push_(iterator); + if(!FLAC__metadata_simple_iterator_next(iterator)) { + (void)simple_iterator_pop_(iterator); + return false; + } + if(iterator->type != FLAC__METADATA_TYPE_PADDING) { + use_padding = false; + } + else { + if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) { + padding_leftover = 0; + block->is_last = iterator->is_last; + } + else if(iterator->length < extra_padding_bytes_required) + use_padding = false; + else { + padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required; + padding_is_last = iterator->is_last; + block->is_last = false; + } + } + if(!simple_iterator_pop_(iterator)) + return false; + } + } + if(use_padding) { + 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); + 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); + 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); + return ret; + } + } +} + +FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding) +{ + 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__bool ret; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + FLAC__ASSERT(0 != block); + + if(!iterator->is_writable) + return false; + + if(block->type == FLAC__METADATA_TYPE_STREAMINFO) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; + return false; + } + + block->is_last = iterator->is_last; + + if(use_padding) { + /* first see if we can even use padding */ + if(iterator->is_last) { + use_padding = false; + } + else { + simple_iterator_push_(iterator); + if(!FLAC__metadata_simple_iterator_next(iterator)) { + (void)simple_iterator_pop_(iterator); + return false; + } + if(iterator->type != FLAC__METADATA_TYPE_PADDING) { + use_padding = false; + } + else { + if(iterator->length == block->length) { + padding_leftover = 0; + block->is_last = iterator->is_last; + } + else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) + use_padding = false; + else { + padding_leftover = iterator->length - block->length; + padding_is_last = iterator->is_last; + block->is_last = false; + } + } + if(!simple_iterator_pop_(iterator)) + return false; + } + } + if(use_padding) { + /* move to the next block, which is suitable padding */ + if(!FLAC__metadata_simple_iterator_next(iterator)) + return false; + 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); + 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); + 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); + 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__bool ret; + + if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT; + return false; + } + + if(use_padding) { + FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING); + if(0 == padding) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + padding->length = iterator->length; + if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) { + FLAC__metadata_object_delete(padding); + return false; + } + 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); + 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); + return ret; + } +} + + + +/**************************************************************************** + * + * Level 2 implementation + * + ***************************************************************************/ + + +typedef struct FLAC__Metadata_Node { + FLAC__StreamMetadata *data; + struct FLAC__Metadata_Node *prev, *next; +} FLAC__Metadata_Node; + +struct FLAC__Metadata_Chain { + char *filename; /* will be NULL if using callbacks */ + FLAC__Metadata_Node *head; + FLAC__Metadata_Node *tail; + unsigned nodes; + FLAC__Metadata_ChainStatus status; + long first_offset, last_offset; /*@@@ 2G limit */ + /* + * 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 */ +}; + +struct FLAC__Metadata_Iterator { + FLAC__Metadata_Chain *chain; + FLAC__Metadata_Node *current; +}; + +FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = { + "FLAC__METADATA_CHAIN_STATUS_OK", + "FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT", + "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE", + "FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE", + "FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE", + "FLAC__METADATA_CHAIN_STATUS_BAD_METADATA", + "FLAC__METADATA_CHAIN_STATUS_READ_ERROR", + "FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR", + "FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR", + "FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR", + "FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR", + "FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR", + "FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR", + "FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS", + "FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", + "FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL" +}; + + +static FLAC__Metadata_Node *node_new_() +{ + return (FLAC__Metadata_Node*)calloc(1, sizeof(FLAC__Metadata_Node)); +} + +static void node_delete_(FLAC__Metadata_Node *node) +{ + FLAC__ASSERT(0 != node); + if(0 != node->data) + FLAC__metadata_object_delete(node->data); + free(node); +} + +static void chain_init_(FLAC__Metadata_Chain *chain) +{ + FLAC__ASSERT(0 != chain); + + chain->filename = 0; + chain->head = chain->tail = 0; + chain->nodes = 0; + chain->status = FLAC__METADATA_CHAIN_STATUS_OK; + chain->initial_length = 0; +} + +static void chain_clear_(FLAC__Metadata_Chain *chain) +{ + FLAC__Metadata_Node *node, *next; + + FLAC__ASSERT(0 != chain); + + for(node = chain->head; node; ) { + next = node->next; + node_delete_(node); + node = next; + } + + if(0 != chain->filename) + free(chain->filename); + + chain_init_(chain); +} + +static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) +{ + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != node); + FLAC__ASSERT(0 != node->data); + + node->next = node->prev = 0; + node->data->is_last = true; + if(0 != chain->tail) + chain->tail->data->is_last = false; + + if(0 == chain->head) + chain->head = node; + else { + FLAC__ASSERT(0 != chain->tail); + chain->tail->next = node; + node->prev = chain->tail; + } + chain->tail = node; + chain->nodes++; +} + +static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) +{ + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != node); + + if(node == chain->head) + chain->head = node->next; + else + node->prev->next = node->next; + + if(node == chain->tail) + chain->tail = node->prev; + else + node->next->prev = node->prev; + + if(0 != chain->tail) + chain->tail->data->is_last = true; + + chain->nodes--; +} + +static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) +{ + chain_remove_node_(chain, node); + node_delete_(node); +} + +static unsigned chain_calculate_length_(FLAC__Metadata_Chain *chain) +{ + const FLAC__Metadata_Node *node; + unsigned length = 0; + for(node = chain->head; node; node = node->next) + length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length); + return length; +} + +static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node) +{ + FLAC__ASSERT(0 != node); + FLAC__ASSERT(0 != node->data); + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + FLAC__ASSERT(0 != iterator->chain); + FLAC__ASSERT(0 != iterator->chain->head); + FLAC__ASSERT(0 != iterator->chain->tail); + + node->data->is_last = false; + + node->prev = iterator->current->prev; + node->next = iterator->current; + + if(0 == node->prev) + iterator->chain->head = node; + else + node->prev->next = node; + + iterator->current->prev = node; + + iterator->chain->nodes++; +} + +static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node) +{ + FLAC__ASSERT(0 != node); + FLAC__ASSERT(0 != node->data); + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + FLAC__ASSERT(0 != iterator->chain); + FLAC__ASSERT(0 != iterator->chain->head); + FLAC__ASSERT(0 != iterator->chain->tail); + + iterator->current->data->is_last = false; + + node->prev = iterator->current; + node->next = iterator->current->next; + + if(0 == node->next) + iterator->chain->tail = node; + else + node->next->prev = node; + + node->prev->next = node; + + iterator->chain->tail->data->is_last = true; + + iterator->chain->nodes++; +} + +/* return true iff node and node->next are both padding */ +static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node) +{ + if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) { + const unsigned growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length; + node->data->length += growth; + + chain_delete_node_(chain, node->next); + return true; + } + else + return false; +} + +/* Returns the new length of the chain, or 0 if there was an error. */ +/* WATCHOUT: This can get called multiple times before a write, so + * it should still work when this happens. + */ +/* 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) +{ + unsigned 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; + 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) { + FLAC__StreamMetadata *padding; + FLAC__Metadata_Node *node; + if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) { + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return 0; + } + padding->length = chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length); + if(0 == (node = node_new_())) { + FLAC__metadata_object_delete(padding); + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return 0; + } + node->data = padding; + chain_append_node_(chain, node); + current_length = chain_calculate_length_(chain); + FLAC__ASSERT(current_length == chain->initial_length); + } + /* 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; + 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) { + 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) { + chain->tail->data->length -= delta; + current_length -= delta; + FLAC__ASSERT(current_length == chain->initial_length); + } + } + } + } + + return current_length; +} + +static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Tell tell_cb) +{ + FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != chain); + + /* we assume we're already at the beginning of the file */ + + switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) { + case 0: + break; + case 1: + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; + return false; + case 2: + chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + return false; + case 3: + chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE; + return false; + default: + FLAC__ASSERT(0); + return false; + } + + { + FLAC__int64 pos = tell_cb(handle); + if(pos < 0) { + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; + return false; + } + chain->first_offset = (long)pos; + } + + { + FLAC__bool is_last; + FLAC__MetadataType type; + unsigned length; + + do { + node = node_new_(); + if(0 == node) { + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + + if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; + return false; + } + + node->data = FLAC__metadata_object_new(type); + if(0 == node->data) { + node_delete_(node); + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + + node->data->is_last = is_last; + node->data->length = length; + + chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data)); + if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) { + node_delete_(node); + return false; + } + chain_append_node_(chain, node); + } while(!is_last); + } + + { + FLAC__int64 pos = tell_cb(handle); + if(pos < 0) { + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR; + return false; + } + chain->last_offset = (long)pos; + } + + 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; + + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != chain->head); + + if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + return false; + } + + for(node = chain->head; node; node = node->next) { + if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; + return false; + } + if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; + return false; + } + } + + /*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/ + + chain->status = FLAC__METADATA_CHAIN_STATUS_OK; + return true; +} + +static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain) +{ + FILE *file; + FLAC__bool ret; + + FLAC__ASSERT(0 != chain->filename); + + if(0 == (file = fopen(chain->filename, "r+b"))) { + chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; + return false; + } + + /* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */ + ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_); + + fclose(file); + + return ret; +} + +static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix) +{ + FILE *f, *tempfile; + char *tempfilename; + FLAC__Metadata_SimpleIteratorStatus status; + const FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != chain->filename); + FLAC__ASSERT(0 != chain->head); + + /* copy the file prefix (data up to first metadata block */ + if(0 == (f = 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; + } + if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) { + chain->status = get_equivalent_status_(status); + cleanup_tempfile_(&tempfile, &tempfilename); + return false; + } + + /* 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; + } + if(!write_metadata_block_data_(tempfile, &status, node->data)) { + chain->status = get_equivalent_status_(status); + return false; + } + } + /*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/ + + /* copy the file postfix (everything after the metadata) */ + if(0 != fseek(f, chain->last_offset, SEEK_SET)) { + cleanup_tempfile_(&tempfile, &tempfilename); + chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + return false; + } + if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) { + cleanup_tempfile_(&tempfile, &tempfilename); + chain->status = get_equivalent_status_(status); + return false; + } + + /* move the tempfile on top of the original */ + (void)fclose(f); + if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status)) + return false; + + return true; +} + +/* assumes 'handle' is already at beginning of file */ +static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb) +{ + FLAC__Metadata_SimpleIteratorStatus status; + const FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 == chain->filename); + FLAC__ASSERT(0 != chain->head); + + /* copy the file prefix (data up to first metadata block */ + if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) { + chain->status = get_equivalent_status_(status); + return false; + } + + /* write the metadata */ + for(node = chain->head; node; node = node->next) { + if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; + return false; + } + if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; + return false; + } + } + /*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/ + + /* copy the file postfix (everything after the metadata) */ + if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + return false; + } + if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) { + chain->status = get_equivalent_status_(status); + return false; + } + + return true; +} + +FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new() +{ + FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)calloc(1, sizeof(FLAC__Metadata_Chain)); + + if(0 != chain) + chain_init_(chain); + + return chain; +} + +FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain) +{ + FLAC__ASSERT(0 != chain); + + chain_clear_(chain); + + free(chain); +} + +FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain) +{ + FLAC__Metadata_ChainStatus status; + + FLAC__ASSERT(0 != chain); + + status = chain->status; + chain->status = FLAC__METADATA_CHAIN_STATUS_OK; + return status; +} + +FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename) +{ + FILE *file; + FLAC__bool ret; + + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != filename); + + chain_clear_(chain); + + if(0 == (chain->filename = strdup(filename))) { + chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + + if(0 == (file = 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_); + + 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__ASSERT(0 != chain); + + chain_clear_(chain); + + if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) { + chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; + return false; + } + + /* 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_ */ + + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding) +{ + /* This does all the same checks that are in chain_prepare_for_write_() + * 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); + + FLAC__ASSERT(0 != 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) + 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) + 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; + 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) + return false; + /* if there is at least 'delta' bytes of padding, trim the padding down */ + else if(chain->tail->data->length >= delta) + return false; + } + } + } + + return (current_length != chain->initial_length); +} + +FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats) +{ + struct stat stats; + const char *tempfile_path_prefix = 0; + unsigned current_length; + + FLAC__ASSERT(0 != chain); + + if (0 == chain->filename) { + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; + return false; + } + + current_length = chain_prepare_for_write_(chain, use_padding); + + /* a return value of 0 means there was an error; chain->status is already set */ + if (0 == current_length) + return false; + + if(preserve_file_stats) + get_file_stats_(chain->filename, &stats); + + if(current_length == chain->initial_length) { + if(!chain_rewrite_metadata_in_place_(chain)) + return false; + } + else { + if(!chain_rewrite_file_(chain, tempfile_path_prefix)) + return false; + + /* recompute lengths and offsets */ + { + const FLAC__Metadata_Node *node; + chain->initial_length = current_length; + chain->last_offset = chain->first_offset; + for(node = chain->head; node; node = node->next) + chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length); + } + } + + if(preserve_file_stats) + set_file_stats_(chain->filename, &stats); + + return true; +} + +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__ASSERT(0 != chain); + + if (0 != chain->filename) { + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; + return false; + } + + if (0 == callbacks.write || 0 == callbacks.seek) { + chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; + return false; + } + + if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL; + return false; + } + + current_length = chain_prepare_for_write_(chain, use_padding); + + /* a return value of 0 means there was an error; chain->status is already set */ + if (0 == current_length) + return false; + + FLAC__ASSERT(current_length == chain->initial_length); + + return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek); +} + +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__ASSERT(0 != chain); + + if (0 != chain->filename) { + chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH; + return false; + } + + if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) { + chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; + return false; + } + if (0 == temp_callbacks.write) { + chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS; + return false; + } + + if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL; + return false; + } + + current_length = chain_prepare_for_write_(chain, use_padding); + + /* a return value of 0 means there was an error; chain->status is already set */ + if (0 == current_length) + return false; + + FLAC__ASSERT(current_length != chain->initial_length); + + /* rewind */ + if(0 != callbacks.seek(handle, 0, SEEK_SET)) { + chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + return false; + } + + if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write)) + return false; + + /* recompute lengths and offsets */ + { + const FLAC__Metadata_Node *node; + chain->initial_length = current_length; + chain->last_offset = chain->first_offset; + for(node = chain->head; node; node = node->next) + chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length); + } + + return true; +} + +FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain) +{ + FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != chain); + + for(node = chain->head; node; ) { + if(!chain_merge_adjacent_padding_(chain, node)) + node = node->next; + } +} + +FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain) +{ + FLAC__Metadata_Node *node, *save; + unsigned i; + + FLAC__ASSERT(0 != chain); + + /* + * Don't try and be too smart... this simple algo is good enough for + * the small number of nodes that we deal with. + */ + for(i = 0, node = chain->head; i < chain->nodes; i++) { + if(node->data->type == FLAC__METADATA_TYPE_PADDING) { + save = node->next; + chain_remove_node_(chain, node); + chain_append_node_(chain, node); + node = save; + } + else { + node = node->next; + } + } + + FLAC__metadata_chain_merge_padding(chain); +} + + +FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new() +{ + FLAC__Metadata_Iterator *iterator = (FLAC__Metadata_Iterator*)calloc(1, sizeof(FLAC__Metadata_Iterator)); + + /* calloc() implies: + iterator->current = 0; + iterator->chain = 0; + */ + + return iterator; +} + +FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + + free(iterator); +} + +FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != chain); + FLAC__ASSERT(0 != chain->head); + + iterator->chain = chain; + iterator->current = chain->head; +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + + if(0 == iterator->current || 0 == iterator->current->next) + return false; + + iterator->current = iterator->current->next; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + + if(0 == iterator->current || 0 == iterator->current->prev) + return false; + + iterator->current = iterator->current->prev; + return true; +} + +FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + FLAC__ASSERT(0 != iterator->current->data); + + return iterator->current->data->type; +} + +FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + + return iterator->current->data; +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != block); + return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block); +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding) +{ + FLAC__Metadata_Node *save; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + + if(0 == iterator->current->prev) { + FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO); + return false; + } + + save = iterator->current->prev; + + if(replace_with_padding) { + FLAC__metadata_object_delete_data(iterator->current->data); + iterator->current->data->type = FLAC__METADATA_TYPE_PADDING; + } + else { + chain_delete_node_(iterator->chain, iterator->current); + } + + iterator->current = save; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block) +{ + FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + FLAC__ASSERT(0 != block); + + if(block->type == FLAC__METADATA_TYPE_STREAMINFO) + return false; + + if(0 == iterator->current->prev) { + FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO); + return false; + } + + if(0 == (node = node_new_())) + return false; + + node->data = block; + iterator_insert_node_(iterator, node); + iterator->current = node; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block) +{ + FLAC__Metadata_Node *node; + + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->current); + FLAC__ASSERT(0 != block); + + if(block->type == FLAC__METADATA_TYPE_STREAMINFO) + return false; + + if(0 == (node = node_new_())) + return false; + + node->data = block; + iterator_insert_node_after_(iterator, node); + iterator->current = node; + return true; +} + + +/**************************************************************************** + * + * Local function definitions + * + ***************************************************************************/ + +void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes) +{ + unsigned i; + + b += bytes; + + for(i = 0; i < bytes; i++) { + *(--b) = (FLAC__byte)(val & 0xff); + val >>= 8; + } +} + +void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes) +{ + unsigned i; + + for(i = 0; i < bytes; i++) { + *(b++) = (FLAC__byte)(val & 0xff); + val >>= 8; + } +} + +void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes) +{ + unsigned i; + + b += bytes; + + for(i = 0; i < bytes; i++) { + *(--b) = (FLAC__byte)(val & 0xff); + val >>= 8; + } +} + +FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes) +{ + FLAC__uint32 ret = 0; + unsigned i; + + for(i = 0; i < bytes; i++) + ret = (ret << 8) | (FLAC__uint32)(*b++); + + return ret; +} + +FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes) +{ + FLAC__uint32 ret = 0; + unsigned i; + + b += bytes; + + for(i = 0; i < bytes; i++) + ret = (ret << 8) | (FLAC__uint32)(*--b); + + return ret; +} + +FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes) +{ + FLAC__uint64 ret = 0; + unsigned i; + + for(i = 0; i < bytes; i++) + ret = (ret << 8) | (FLAC__uint64)(*b++); + + return ret; +} + +FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + + return true; +} + +FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block) +{ + FLAC__ASSERT(0 != iterator); + FLAC__ASSERT(0 != iterator->file); + + iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block); + + return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK); +} + +FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length) +{ + FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH]; + + if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH) + return false; + + *is_last = raw_header[0] & 0x80? true : false; + *type = (FLAC__MetadataType)(raw_header[0] & 0x7f); + *length = unpack_uint32_(raw_header + 1, 3); + + /* Note that we don't check: + * if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED) + * we just will read in an opaque block + */ + + return true; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block) +{ + switch(block->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + return read_metadata_block_data_streaminfo_cb_(handle, read_cb, &block->data.stream_info); + case FLAC__METADATA_TYPE_PADDING: + return read_metadata_block_data_padding_cb_(handle, seek_cb, &block->data.padding, block->length); + case FLAC__METADATA_TYPE_APPLICATION: + return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length); + 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); + case FLAC__METADATA_TYPE_CUESHEET: + return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet); + default: + return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length); + } +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block) +{ + FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b; + + if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + + b = buffer; + + /* we are using hardcoded numbers for simplicity but we should + * probably eventually write a bit-level unpacker and use the + * _STREAMINFO_ constants. + */ + block->min_blocksize = unpack_uint32_(b, 2); b += 2; + block->max_blocksize = unpack_uint32_(b, 2); b += 2; + block->min_framesize = unpack_uint32_(b, 3); b += 3; + block->max_framesize = unpack_uint32_(b, 3); b += 3; + block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((unsigned)(b[2] & 0xf0) >> 4); + block->channels = (unsigned)((b[2] & 0x0e) >> 1) + 1; + block->bits_per_sample = ((((unsigned)(b[2] & 0x01)) << 4) | (((unsigned)(b[3] & 0xf0)) >> 4)) + 1; + block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4); + memcpy(block->md5sum, b+8, 16); + + 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 */ + + if(0 != seek_cb(handle, block_length, SEEK_CUR)) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length) +{ + const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; + + if(read_cb(block->id, 1, id_bytes, handle) != 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))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + if(read_cb(block->data, 1, block_length, handle) != block_length) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + } + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length) +{ + unsigned i; + FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH]; + + FLAC__ASSERT(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH == 0); + + block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; + + if(block->num_points == 0) + block->points = 0; + else if(0 == (block->points = (FLAC__StreamMetadata_SeekPoint*)malloc(block->num_points * sizeof(FLAC__StreamMetadata_SeekPoint)))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + for(i = 0; i < block->num_points; i++) { + if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + /* some MAGIC NUMBERs here */ + block->points[i].sample_number = unpack_uint64_(buffer, 8); + block->points[i].stream_offset = unpack_uint64_(buffer+8, 8); + block->points[i].frame_samples = unpack_uint32_(buffer+16, 2); + } + + 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) +{ + 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); + + 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(0 != entry->entry) + free(entry->entry); + + if(entry->length == 0) { + entry->entry = 0; + } + else { + if(0 == (entry->entry = (FLAC__byte*)malloc(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) +{ + 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); + + if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string)))) + return status; + + 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); + + 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)))) + 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; + } + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track) +{ + unsigned i, len; + FLAC__byte buffer[32]; /* asserted below that this is big enough */ + + FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64)); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + track->offset = unpack_uint64_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + track->number = (FLAC__byte)unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8; + if(read_cb(track->isrc, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + + FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0); + len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN == 1); + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN == 1); + track->type = buffer[0] >> 7; + track->pre_emphasis = (buffer[0] >> 6) & 1; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len); + + 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)))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + for(i = 0; i < track->num_indices; i++) { + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + track->indices[i].offset = unpack_uint64_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + } + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block) +{ + unsigned i, len; + FLAC__Metadata_SimpleIteratorStatus status; + FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */ + + FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)/8 <= sizeof(buffer)); + FLAC__ASSERT(sizeof(FLAC__uint64) <= sizeof(buffer)); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8; + if(read_cb(block->media_catalog_number, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->lead_in = unpack_uint64_(buffer, len); + + FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0); + len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->is_cd = buffer[0]&0x80? true : false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->num_tracks = unpack_uint32_(buffer, len); + + 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)))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + for(i = 0; i < block->num_tracks; i++) { + if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i))) + 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))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + if(read_cb(block->data, 1, block_length, handle) != block_length) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + } + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block) +{ + FLAC__ASSERT(0 != file); + FLAC__ASSERT(0 != status); + + if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + + return true; +} + +FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block) +{ + FLAC__ASSERT(0 != file); + FLAC__ASSERT(0 != status); + + if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; + return true; + } + else { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } +} + +FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block) +{ + FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH]; + + FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN)); + + buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type; + pack_uint32_(block->length, buffer + 1, 3); + + if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH) + return false; + + return true; +} + +FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block) +{ + FLAC__ASSERT(0 != block); + + switch(block->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info); + case FLAC__METADATA_TYPE_PADDING: + return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length); + case FLAC__METADATA_TYPE_APPLICATION: + return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length); + case FLAC__METADATA_TYPE_SEEKTABLE: + return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table); + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + 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); + default: + return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length); + } +} + +FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block) +{ + FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH]; + const unsigned channels1 = block->channels - 1; + const unsigned bps1 = block->bits_per_sample - 1; + + /* we are using hardcoded numbers for simplicity but we should + * probably eventually write a bit-level packer and use the + * _STREAMINFO_ constants. + */ + pack_uint32_(block->min_blocksize, buffer, 2); + pack_uint32_(block->max_blocksize, buffer+2, 2); + pack_uint32_(block->min_framesize, buffer+4, 3); + pack_uint32_(block->max_framesize, buffer+7, 3); + buffer[10] = (block->sample_rate >> 12) & 0xff; + buffer[11] = (block->sample_rate >> 4) & 0xff; + buffer[12] = ((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4); + buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f)); + pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4); + memcpy(buffer+18, block->md5sum, 16); + + if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH) + return false; + + return true; +} + +FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length) +{ + unsigned i, n = block_length; + FLAC__byte buffer[1024]; + + (void)block; + + memset(buffer, 0, 1024); + + for(i = 0; i < n/1024; i++) + if(write_cb(buffer, 1, 1024, handle) != 1024) + return false; + + n %= 1024; + + if(write_cb(buffer, 1, n, handle) != n) + return false; + + return true; +} + +FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length) +{ + const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; + + if(write_cb(block->id, 1, id_bytes, handle) != id_bytes) + return false; + + block_length -= id_bytes; + + if(write_cb(block->data, 1, block_length, handle) != block_length) + return false; + + return true; +} + +FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block) +{ + unsigned i; + FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH]; + + for(i = 0; i < block->num_points; i++) { + /* some MAGIC NUMBERs here */ + pack_uint64_(block->points[i].sample_number, buffer, 8); + pack_uint64_(block->points[i].stream_offset, buffer+8, 8); + pack_uint32_(block->points[i].frame_samples, buffer+16, 2); + if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH) + return false; + } + + return true; +} + +FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block) +{ + unsigned i; + const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8; + 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); + + pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len); + if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len) + return false; + if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length) + return false; + + pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len); + if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len) + return false; + + for(i = 0; i < block->num_comments; i++) { + pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len); + if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len) + return false; + if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length) + return false; + } + + return true; +} + +FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block) +{ + unsigned i, j, len; + FLAC__byte buffer[1024]; /* asserted below that this is big enough */ + + FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64)); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8); + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8; + if(write_cb(block->media_catalog_number, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8; + pack_uint64_(block->lead_in, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0); + len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8; + memset(buffer, 0, len); + if(block->is_cd) + buffer[0] |= 0x80; + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8; + pack_uint32_(block->num_tracks, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + for(i = 0; i < block->num_tracks; i++) { + FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8; + pack_uint64_(track->offset, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8; + pack_uint32_(track->number, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8; + if(write_cb(track->isrc, 1, len, handle) != len) + return false; + + FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0); + len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8; + memset(buffer, 0, len); + buffer[0] = (track->type << 7) | (track->pre_emphasis << 6); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8; + pack_uint32_(track->num_indices, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + for(j = 0; j < track->num_indices; j++) { + FLAC__StreamMetadata_CueSheet_Index *index = 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); + 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); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8; + memset(buffer, 0, len); + if(write_cb(buffer, 1, len, handle) != len) + 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) + return false; + + return true; +} + +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)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + if(!write_metadata_block_header_(iterator->file, &iterator->status, block)) + return false; + + if(!write_metadata_block_data_(iterator->file, &iterator->status, block)) + return false; + + if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + return read_metadata_block_header_(iterator); +} + +FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last) +{ + FLAC__StreamMetadata *padding; + + if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + block->is_last = false; + + if(!write_metadata_block_header_(iterator->file, &iterator->status, block)) + return false; + + if(!write_metadata_block_data_(iterator->file, &iterator->status, block)) + return false; + + if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + padding->is_last = padding_is_last; + padding->length = padding_length; + + if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) { + FLAC__metadata_object_delete(padding); + return false; + } + + if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) { + FLAC__metadata_object_delete(padding); + return false; + } + + FLAC__metadata_object_delete(padding); + + if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + return read_metadata_block_header_(iterator); +} + +FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append) +{ + FILE *tempfile; + char *tempfilename; + int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */ + long fixup_is_last_flag_offset = -1; + + FLAC__ASSERT(0 != block || append == false); + + if(iterator->is_last) { + if(append) { + fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */ + fixup_is_last_flag_offset = iterator->offset[iterator->depth]; + } + else if(0 == block) { + simple_iterator_push_(iterator); + if(!FLAC__metadata_simple_iterator_prev(iterator)) { + (void)simple_iterator_pop_(iterator); + return false; + } + fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */ + fixup_is_last_flag_offset = iterator->offset[iterator->depth]; + if(!simple_iterator_pop_(iterator)) + return false; + } + } + + if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append)) + return false; + + if(0 != block) { + if(!write_metadata_block_header_(tempfile, &iterator->status, block)) { + cleanup_tempfile_(&tempfile, &tempfilename); + return false; + } + + if(!write_metadata_block_data_(tempfile, &iterator->status, block)) { + cleanup_tempfile_(&tempfile, &tempfilename); + return false; + } + } + + if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0)) + return false; + + if(append) + return FLAC__metadata_simple_iterator_next(iterator); + + return true; +} + +void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator) +{ + FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH); + iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth]; + iterator->depth++; +} + +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)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + + return read_metadata_block_header_(iterator); +} + +/* return meanings: + * 0: ok + * 1: read error + * 2: seek error + * 3: not a FLAC file + */ +unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb) +{ + FLAC__byte buffer[4]; + size_t n; + unsigned i; + + FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == 4); + + /* skip any id3v2 tag */ + errno = 0; + n = read_cb(buffer, 1, 4, handle); + if(errno) + return 1; + else if(n != 4) + return 3; + else if(0 == memcmp(buffer, "ID3", 3)) { + unsigned tag_length = 0; + + /* skip to the tag length */ + if(seek_cb(handle, 2, SEEK_CUR) < 0) + return 2; + + /* read the length */ + for(i = 0; i < 4; i++) { + if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80) + return 1; + tag_length <<= 7; + tag_length |= (buffer[0] & 0x7f); + } + + /* skip the rest of the tag */ + if(seek_cb(handle, tag_length, SEEK_CUR) < 0) + return 2; + + /* read the stream sync code */ + errno = 0; + n = read_cb(buffer, 1, 4, handle); + if(errno) + return 1; + else if(n != 4) + return 3; + } + + /* check for the fLaC signature */ + if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH)) + return 0; + else + return 3; +} + +unsigned seek_to_first_metadata_block_(FILE *f) +{ + return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCallback_Read)fread, fseek_wrapper_); +} + +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]; + + if(0 != fseek(iterator->file, 0, SEEK_SET)) { + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) { + cleanup_tempfile_(tempfile, tempfilename); + return false; + } + if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) { + cleanup_tempfile_(tempfile, tempfilename); + return false; + } + + 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) +{ + long save_offset = iterator->offset[iterator->depth]; /*@@@ 2G limit */ + FLAC__ASSERT(0 != *tempfile); + + if(0 != fseek(iterator->file, save_offset + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length, SEEK_SET)) { + cleanup_tempfile_(tempfile, tempfilename); + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) { + cleanup_tempfile_(tempfile, tempfilename); + return false; + } + + if(fixup_is_last_code != 0) { + /* + * if code == 1, it means a block was appended to the end so + * we have to clear the is_last flag of the previous block + * if code == -1, it means the last block was deleted so + * we have to set the is_last flag of the previous block + */ + /* 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)) { + cleanup_tempfile_(tempfile, tempfilename); + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + if(fread(&x, 1, 1, *tempfile) != 1) { + cleanup_tempfile_(tempfile, tempfilename); + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + if(fixup_is_last_code > 0) { + FLAC__ASSERT(x & 0x80); + x &= 0x7f; + } + else { + FLAC__ASSERT(!(x & 0x80)); + x |= 0x80; + } + if(0 != fseek(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) { + cleanup_tempfile_(tempfile, tempfilename); + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR; + return false; + } + if(local__fwrite(&x, 1, 1, *tempfile) != 1) { + cleanup_tempfile_(tempfile, tempfilename); + iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + } + + (void)fclose(iterator->file); + + if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status)) + return false; + + if(iterator->has_stats) + set_file_stats_(iterator->filename, &iterator->stats); + + 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) + if(!FLAC__metadata_simple_iterator_next(iterator)) + return false; + return true; + } + else { + /* move the iterator to it's original block faster by faking a push, then doing a pop_ */ + FLAC__ASSERT(iterator->depth == 0); + iterator->offset[0] = save_offset; + iterator->depth++; + return simple_iterator_pop_(iterator); + } +} + +FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status) +{ + FLAC__byte buffer[8192]; + unsigned n; + + while(bytes > 0) { + n = min(sizeof(buffer), bytes); + if(fread(buffer, 1, n, file) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + if(local__fwrite(buffer, 1, n, tempfile) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + bytes -= n; + } + + 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__byte buffer[8192]; + unsigned n; + + while(bytes > 0) { + n = min(sizeof(buffer), bytes); + if(read_cb(buffer, 1, n, handle) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + if(temp_write_cb(buffer, 1, n, temp_handle) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + bytes -= n; + } + + return true; +} + +FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status) +{ + FLAC__byte buffer[8192]; + size_t n; + + while(!feof(file)) { + n = fread(buffer, 1, sizeof(buffer), file); + if(n == 0 && !feof(file)) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + } + + return true; +} + +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) +{ + FLAC__byte buffer[8192]; + size_t n; + + while(!eof_cb(handle)) { + n = read_cb(buffer, 1, sizeof(buffer), handle); + if(n == 0 && !eof_cb(handle)) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + return false; + } + if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR; + return false; + } + } + + return true; +} + +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))) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + return false; + } + strcpy(*tempfilename, filename); + strcat(*tempfilename, tempfile_suffix); + } + else { + const char *p = strrchr(filename, '/'); + if(0 == p) + p = filename; + else + p++; + + if(0 == (*tempfilename = (char*)malloc(strlen(tempfile_path_prefix) + 1 + strlen(p) + strlen(tempfile_suffix) + 1))) { + *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); + } + + if(0 == (*tempfile = fopen(*tempfilename, "w+b"))) { + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE; + return false; + } + + return true; +} + +FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != tempfile); + FLAC__ASSERT(0 != *tempfile); + FLAC__ASSERT(0 != tempfilename); + FLAC__ASSERT(0 != *tempfilename); + FLAC__ASSERT(0 != status); + + (void)fclose(*tempfile); + *tempfile = 0; + +#if defined _MSC_VER || defined __MINGW32__ + if(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)) { + cleanup_tempfile_(tempfile, tempfilename); + *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR; + return false; + } + + cleanup_tempfile_(tempfile, tempfilename); + + return true; +} + +void cleanup_tempfile_(FILE **tempfile, char **tempfilename) +{ + if(0 != *tempfile) { + (void)fclose(*tempfile); + *tempfile = 0; + } + + if(0 != *tempfilename) { + (void)unlink(*tempfilename); + free(*tempfilename); + *tempfilename = 0; + } +} + +FLAC__bool get_file_stats_(const char *filename, struct stat *stats) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != stats); + return (0 == stat(filename, stats)); +} + +void set_file_stats_(const char *filename, struct stat *stats) +{ + struct utimbuf srctime; + + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != 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); +#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); +} + +FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle) +{ + return (long)ftell((FILE*)handle); +} + +FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status) +{ + switch(status) { + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK: + return FLAC__METADATA_CHAIN_STATUS_OK; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT: + return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE: + return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE: + return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE: + return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA: + return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR: + return FLAC__METADATA_CHAIN_STATUS_READ_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR: + return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR: + return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR: + return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR: + return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR: + return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR; + case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR: + default: + return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; + } +} diff --git a/apps/codecs/libFLAC/metadata_object.c b/apps/codecs/libFLAC/metadata_object.c new file mode 100644 index 0000000000..290036ce26 --- /dev/null +++ b/apps/codecs/libFLAC/metadata_object.c @@ -0,0 +1,1472 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2001,2002,2003,2004,2005 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 +#include + +#include "private/metadata.h" + +#include "FLAC/assert.h" + + +/**************************************************************************** + * + * Local routines + * + ***************************************************************************/ + +static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes) +{ + if(bytes > 0 && 0 != from) { + FLAC__byte *x; + if(0 == (x = (FLAC__byte*)malloc(bytes))) + return false; + memcpy(x, from, bytes); + *to = x; + } + else { + FLAC__ASSERT(0 == from); + FLAC__ASSERT(bytes == 0); + *to = 0; + } + return true; +} + +static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length) +{ + FLAC__byte *x = (FLAC__byte*)realloc(*entry, length+1); + if(0 != x) { + x[length] = '\0'; + *entry = x; + 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; + if(0 == from->entry) { + FLAC__ASSERT(from->length == 0); + to->entry = 0; + } + else { + FLAC__byte *x; + FLAC__ASSERT(from->length > 0); + if(0 == (x = (FLAC__byte*)malloc(from->length+1))) + return false; + memcpy(x, from->entry, from->length); + x[from->length] = '\0'; + to->entry = x; + } + return true; +} + +static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from) +{ + memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track)); + if(0 == from->indices) { + FLAC__ASSERT(from->num_indices == 0); + } + 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)))) + return false; + memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); + to->indices = x; + } + return true; +} + +static void seektable_calculate_length_(FLAC__StreamMetadata *object) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; +} + +static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(unsigned num_points) +{ + FLAC__StreamMetadata_SeekPoint *object_array; + + FLAC__ASSERT(num_points > 0); + + object_array = (FLAC__StreamMetadata_SeekPoint*)malloc(num_points * sizeof(FLAC__StreamMetadata_SeekPoint)); + + if(0 != object_array) { + unsigned i; + for(i = 0; i < num_points; i++) { + object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + object_array[i].stream_offset = 0; + object_array[i].frame_samples = 0; + } + } + + return object_array; +} + +static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object) +{ + unsigned i; + + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8; + object->length += object->data.vorbis_comment.vendor_string.length; + object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8; + for(i = 0; i < object->data.vorbis_comment.num_comments; i++) { + object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8); + object->length += object->data.vorbis_comment.comments[i].length; + } +} + +static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(unsigned num_comments) +{ + FLAC__ASSERT(num_comments > 0); + + return (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)); +} + +static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments) +{ + unsigned i; + + FLAC__ASSERT(0 != object_array && num_comments > 0); + + for(i = 0; i < num_comments; i++) + if(0 != object_array[i].entry) + free(object_array[i].entry); + + if(0 != object_array) + free(object_array); +} + +static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments) +{ + FLAC__StreamMetadata_VorbisComment_Entry *return_array; + + FLAC__ASSERT(0 != object_array); + FLAC__ASSERT(num_comments > 0); + + return_array = vorbiscomment_entry_array_new_(num_comments); + + if(0 != return_array) { + unsigned i; + + for(i = 0; i < num_comments; i++) { + if(!copy_vcentry_(return_array+i, object_array+i)) { + vorbiscomment_entry_array_delete_(return_array, num_comments); + return 0; + } + } + } + + return return_array; +} + +static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy) +{ + FLAC__byte *save; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(0 != dest); + FLAC__ASSERT(0 != src); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT((0 != src->entry && src->length > 0) || (0 == src->entry && src->length == 0)); + + save = dest->entry; + + if(0 != src->entry && src->length > 0) { + 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 { + /* the src is null */ + *dest = *src; + } + + if(0 != save) + free(save); + + vorbiscomment_calculate_length_(object); + 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; + + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + + object->length = ( + FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN + + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN + ) / 8; + + object->length += object->data.cue_sheet.num_tracks * ( + FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN + + FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN + ) / 8; + + for(i = 0; i < object->data.cue_sheet.num_tracks; i++) { + object->length += object->data.cue_sheet.tracks[i].num_indices * ( + FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN + + FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN + + FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN + ) / 8; + } +} + +static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(unsigned num_indices) +{ + FLAC__ASSERT(num_indices > 0); + + return (FLAC__StreamMetadata_CueSheet_Index*)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)); +} + +static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks) +{ + unsigned i; + + FLAC__ASSERT(0 != object_array && num_tracks > 0); + + for(i = 0; i < num_tracks; i++) { + if(0 != object_array[i].indices) { + FLAC__ASSERT(object_array[i].num_indices > 0); + free(object_array[i].indices); + } + } + + if(0 != object_array) + free(object_array); +} + +static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks) +{ + FLAC__StreamMetadata_CueSheet_Track *return_array; + + FLAC__ASSERT(0 != object_array); + FLAC__ASSERT(num_tracks > 0); + + return_array = cuesheet_track_array_new_(num_tracks); + + if(0 != return_array) { + unsigned i; + + for(i = 0; i < num_tracks; i++) { + if(!copy_track_(return_array+i, object_array+i)) { + cuesheet_track_array_delete_(return_array, num_tracks); + return 0; + } + } + } + + return return_array; +} + +static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy) +{ + FLAC__StreamMetadata_CueSheet_Index *save; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(0 != dest); + FLAC__ASSERT(0 != src); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT((0 != src->indices && src->num_indices > 0) || (0 == src->indices && src->num_indices == 0)); + + save = dest->indices; + + /* do the copy first so that if we fail we leave the object untouched */ + if(copy) { + if(!copy_track_(dest, src)) + return false; + } + else { + *dest = *src; + } + + if(0 != save) + free(save); + + cuesheet_calculate_length_(object); + return true; +} + + +/**************************************************************************** + * + * Metadata object routines + * + ***************************************************************************/ + +FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type) +{ + FLAC__StreamMetadata *object; + + if(type > FLAC__MAX_METADATA_TYPE_CODE) + return 0; + + object = (FLAC__StreamMetadata*)calloc(1, sizeof(FLAC__StreamMetadata)); + if(0 != object) { + object->is_last = false; + object->type = type; + switch(type) { + case FLAC__METADATA_TYPE_STREAMINFO: + object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH; + break; + case FLAC__METADATA_TYPE_PADDING: + /* calloc() took care of this for us: + object->length = 0; + */ + break; + case FLAC__METADATA_TYPE_APPLICATION: + object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8; + /* calloc() took care of this for us: + object->data.application.data = 0; + */ + break; + case FLAC__METADATA_TYPE_SEEKTABLE: + /* calloc() took care of this for us: + object->length = 0; + object->data.seek_table.num_points = 0; + object->data.seek_table.points = 0; + */ + 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+1)) { + free(object); + return 0; + } + vorbiscomment_calculate_length_(object); + } + break; + case FLAC__METADATA_TYPE_CUESHEET: + cuesheet_calculate_length_(object); + break; + default: + /* calloc() took care of this for us: + object->length = 0; + object->data.unknown.data = 0; + */ + break; + } + } + + return object; +} + +FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object) +{ + FLAC__StreamMetadata *to; + + FLAC__ASSERT(0 != object); + + if(0 != (to = FLAC__metadata_object_new(object->type))) { + to->is_last = object->is_last; + to->type = object->type; + to->length = object->length; + switch(to->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo)); + break; + case FLAC__METADATA_TYPE_PADDING: + break; + case FLAC__METADATA_TYPE_APPLICATION: + 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); + return 0; + } + break; + case FLAC__METADATA_TYPE_SEEKTABLE: + to->data.seek_table.num_points = object->data.seek_table.num_points; + 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; + } + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + if(0 != to->data.vorbis_comment.vendor_string.entry) { + free(to->data.vorbis_comment.vendor_string.entry); + to->data.vorbis_comment.vendor_string.entry = 0; + } + if(!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) { + FLAC__metadata_object_delete(to); + return 0; + } + if(object->data.vorbis_comment.num_comments == 0) { + FLAC__ASSERT(0 == object->data.vorbis_comment.comments); + to->data.vorbis_comment.comments = 0; + } + else { + FLAC__ASSERT(0 != object->data.vorbis_comment.comments); + to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments); + if(0 == to->data.vorbis_comment.comments) { + FLAC__metadata_object_delete(to); + return 0; + } + } + to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments; + break; + case FLAC__METADATA_TYPE_CUESHEET: + memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet)); + if(object->data.cue_sheet.num_tracks == 0) { + FLAC__ASSERT(0 == object->data.cue_sheet.tracks); + } + else { + FLAC__ASSERT(0 != object->data.cue_sheet.tracks); + to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); + if(0 == to->data.cue_sheet.tracks) { + 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); + return 0; + } + break; + } + } + + return to; +} + +void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object) +{ + FLAC__ASSERT(0 != object); + + switch(object->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + case FLAC__METADATA_TYPE_PADDING: + break; + case FLAC__METADATA_TYPE_APPLICATION: + if(0 != object->data.application.data) { + free(object->data.application.data); + object->data.application.data = 0; + } + break; + case FLAC__METADATA_TYPE_SEEKTABLE: + if(0 != object->data.seek_table.points) { + free(object->data.seek_table.points); + object->data.seek_table.points = 0; + } + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + if(0 != object->data.vorbis_comment.vendor_string.entry) { + free(object->data.vorbis_comment.vendor_string.entry); + object->data.vorbis_comment.vendor_string.entry = 0; + } + if(0 != object->data.vorbis_comment.comments) { + FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0); + vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments); + } + break; + case FLAC__METADATA_TYPE_CUESHEET: + if(0 != object->data.cue_sheet.tracks) { + FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0); + cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); + } + break; + default: + if(0 != object->data.unknown.data) { + free(object->data.unknown.data); + object->data.unknown.data = 0; + } + break; + } +} + +FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object) +{ + FLAC__metadata_object_delete_data(object); + free(object); +} + +static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2) +{ + if(block1->min_blocksize != block2->min_blocksize) + return false; + if(block1->max_blocksize != block2->max_blocksize) + return false; + if(block1->min_framesize != block2->min_framesize) + return false; + if(block1->max_framesize != block2->max_framesize) + return false; + if(block1->sample_rate != block2->sample_rate) + return false; + if(block1->channels != block2->channels) + return false; + if(block1->bits_per_sample != block2->bits_per_sample) + return false; + if(block1->total_samples != block2->total_samples) + return false; + if(0 != memcmp(block1->md5sum, block2->md5sum, 16)) + return false; + return true; +} + +static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, unsigned block_length) +{ + FLAC__ASSERT(0 != block1); + FLAC__ASSERT(0 != block2); + FLAC__ASSERT(block_length >= sizeof(block1->id)); + + if(0 != memcmp(block1->id, block2->id, sizeof(block1->id))) + return false; + if(0 != block1->data && 0 != block2->data) + return 0 == memcmp(block1->data, block2->data, block_length - sizeof(block1->id)); + else + return block1->data == block2->data; +} + +static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2) +{ + unsigned i; + + FLAC__ASSERT(0 != block1); + FLAC__ASSERT(0 != block2); + + if(block1->num_points != block2->num_points) + return false; + + if(0 != block1->points && 0 != block2->points) { + for(i = 0; i < block1->num_points; i++) { + if(block1->points[i].sample_number != block2->points[i].sample_number) + return false; + if(block1->points[i].stream_offset != block2->points[i].stream_offset) + return false; + if(block1->points[i].frame_samples != block2->points[i].frame_samples) + return false; + } + return true; + } + else + return block1->points == block2->points; +} + +static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2) +{ + unsigned i; + + if(block1->vendor_string.length != block2->vendor_string.length) + return false; + + if(0 != block1->vendor_string.entry && 0 != block2->vendor_string.entry) { + if(0 != memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length)) + return false; + } + else if(block1->vendor_string.entry != block2->vendor_string.entry) + return false; + + if(block1->num_comments != block2->num_comments) + return false; + + for(i = 0; i < block1->num_comments; i++) { + if(0 != block1->comments[i].entry && 0 != block2->comments[i].entry) { + if(0 != memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length)) + return false; + } + else if(block1->comments[i].entry != block2->comments[i].entry) + return false; + } + return true; +} + +static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2) +{ + unsigned i, j; + + if(0 != strcmp(block1->media_catalog_number, block2->media_catalog_number)) + return false; + + if(block1->lead_in != block2->lead_in) + return false; + + if(block1->is_cd != block2->is_cd) + return false; + + if(block1->num_tracks != block2->num_tracks) + return false; + + if(0 != block1->tracks && 0 != block2->tracks) { + FLAC__ASSERT(block1->num_tracks > 0); + for(i = 0; i < block1->num_tracks; i++) { + if(block1->tracks[i].offset != block2->tracks[i].offset) + return false; + if(block1->tracks[i].number != block2->tracks[i].number) + return false; + if(0 != memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc))) + return false; + if(block1->tracks[i].type != block2->tracks[i].type) + return false; + if(block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis) + return false; + if(block1->tracks[i].num_indices != block2->tracks[i].num_indices) + return false; + if(0 != block1->tracks[i].indices && 0 != block2->tracks[i].indices) { + FLAC__ASSERT(block1->tracks[i].num_indices > 0); + for(j = 0; j < block1->tracks[i].num_indices; j++) { + if(block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset) + return false; + if(block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number) + return false; + } + } + else if(block1->tracks[i].indices != block2->tracks[i].indices) + return false; + } + } + else if(block1->tracks != block2->tracks) + 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); + FLAC__ASSERT(0 != block2); + + if(0 != block1->data && 0 != block2->data) + return 0 == memcmp(block1->data, block2->data, block_length); + else + return block1->data == block2->data; +} + +FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2) +{ + FLAC__ASSERT(0 != block1); + FLAC__ASSERT(0 != block2); + + if(block1->type != block2->type) { + return false; + } + if(block1->is_last != block2->is_last) { + return false; + } + if(block1->length != block2->length) { + return false; + } + switch(block1->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info); + case FLAC__METADATA_TYPE_PADDING: + return true; /* we don't compare the padding guts */ + case FLAC__METADATA_TYPE_APPLICATION: + return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length); + case FLAC__METADATA_TYPE_SEEKTABLE: + return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table); + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + 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); + default: + return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length); + } +} + +FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy) +{ + FLAC__byte *save; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION); + FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false)); + + save = object->data.application.data; + + /* do the copy first so that if we fail we leave the object untouched */ + if(copy) { + if(!copy_bytes_(&object->data.application.data, data, length)) + return false; + } + else { + object->data.application.data = data; + } + + if(0 != save) + free(save); + + object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + if(0 == object->data.seek_table.points) { + FLAC__ASSERT(object->data.seek_table.num_points == 0); + if(0 == new_num_points) + return true; + else if(0 == (object->data.seek_table.points = seekpoint_array_new_(new_num_points))) + 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); + + FLAC__ASSERT(object->data.seek_table.num_points > 0); + + if(new_size == 0) { + 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))) + return false; + + /* if growing, set new elements to placeholders */ + if(new_size > old_size) { + unsigned i; + for(i = object->data.seek_table.num_points; i < new_num_points; i++) { + object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; + object->data.seek_table.points[i].stream_offset = 0; + object->data.seek_table.points[i].frame_samples = 0; + } + } + } + + object->data.seek_table.num_points = new_num_points; + + seektable_calculate_length_(object); + return true; +} + +FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + FLAC__ASSERT(point_num < object->data.seek_table.num_points); + + object->data.seek_table.points[point_num] = point; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point) +{ + int i; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + FLAC__ASSERT(point_num <= object->data.seek_table.num_points); + + if(!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1)) + return false; + + /* move all points >= point_num forward one space */ + for(i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--) + object->data.seek_table.points[i] = object->data.seek_table.points[i-1]; + + FLAC__metadata_object_seektable_set_point(object, point_num, point); + seektable_calculate_length_(object); + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num) +{ + unsigned i; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + FLAC__ASSERT(point_num < object->data.seek_table.num_points); + + /* move all points > point_num backward one space */ + for(i = point_num; i < object->data.seek_table.num_points-1; i++) + object->data.seek_table.points[i] = object->data.seek_table.points[i+1]; + + return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1); +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + return FLAC__format_seektable_is_legal(&object->data.seek_table); +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + if(num > 0) + /* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */ + return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num); + else + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number) +{ + FLAC__StreamMetadata_SeekTable *seek_table; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + seek_table = &object->data.seek_table; + + if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1)) + return false; + + seek_table->points[seek_table->num_points - 1].sample_number = sample_number; + seek_table->points[seek_table->num_points - 1].stream_offset = 0; + seek_table->points[seek_table->num_points - 1].frame_samples = 0; + + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + FLAC__ASSERT(0 != sample_numbers || num == 0); + + if(num > 0) { + FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; + unsigned i, j; + + i = seek_table->num_points; + + if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num)) + return false; + + for(j = 0; j < num; i++, j++) { + seek_table->points[i].sample_number = sample_numbers[j]; + 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_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + FLAC__ASSERT(total_samples > 0); + + if(num > 0) { + FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table; + unsigned i, j; + + i = seek_table->num_points; + + if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num)) + return false; + + for(j = 0; j < num; i++, j++) { + seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num; + 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; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE); + + unique = FLAC__format_seektable_sort(&object->data.seek_table); + + return !compact || FLAC__metadata_object_seektable_resize_points(object, unique); +} + +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); +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + if(0 == object->data.vorbis_comment.comments) { + FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0); + if(0 == new_num_comments) + return true; + else if(0 == (object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments))) + 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); + + FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0); + + /* if shrinking, free the truncated entries */ + if(new_num_comments < object->data.vorbis_comment.num_comments) { + unsigned i; + for(i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++) + if(0 != object->data.vorbis_comment.comments[i].entry) + free(object->data.vorbis_comment.comments[i].entry); + } + + if(new_size == 0) { + 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))) + return false; + + /* if growing, zero all the length/pointers of new elements */ + if(new_size > old_size) + memset(object->data.vorbis_comment.comments + object->data.vorbis_comment.num_comments, 0, new_size - old_size); + } + + object->data.vorbis_comment.num_comments = new_num_comments; + + vorbiscomment_calculate_length_(object); + return 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) +{ + 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); +} + +FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy) +{ + FLAC__StreamMetadata_VorbisComment *vc; + + FLAC__ASSERT(0 != object); + 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)) + return false; + + /* move all comments >= comment_num forward one space */ + memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num)); + vc->comments[comment_num].length = 0; + vc->comments[comment_num].entry = 0; + + 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; + unsigned 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; + + if((i = vorbiscomment_find_entry_from_(object, 0, entry.entry, field_name_length)) >= 0) { + unsigned index = (unsigned)i; + if(!FLAC__metadata_object_vorbiscomment_set_comment(object, index, entry, copy)) + return false; + if(all && (index+1 < object->data.vorbis_comment.num_comments)) { + for(i = vorbiscomment_find_entry_from_(object, index+1, entry.entry, field_name_length); i >= 0; ) { + if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i)) + return false; + if((unsigned)i < object->data.vorbis_comment.num_comments) + i = vorbiscomment_find_entry_from_(object, (unsigned)i, 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; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments); + + vc = &object->data.vorbis_comment; + + /* free the comment at comment_num */ + if(0 != vc->comments[comment_num].entry) + free(vc->comments[comment_num].entry); + + /* move all comments > comment_num backward one space */ + memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1)); + vc->comments[vc->num_comments-1].length = 0; + vc->comments[vc->num_comments-1].entry = 0; + + return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1); +} + +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) +{ + 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(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 = (FLAC__byte*)malloc(entry->length+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 FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value) +{ + FLAC__ASSERT(0 != entry.entry && entry.length > 0); + FLAC__ASSERT(0 != field_name); + FLAC__ASSERT(0 != field_value); + + if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length)) + return false; + + { + 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 = (char*)malloc(nn+1))) + return false; + if(0 == (*field_value = (char*)malloc(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 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); +#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_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) +{ + const unsigned field_name_length = strlen(field_name); + unsigned i; + + FLAC__ASSERT(0 != object); + 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_delete_comment(object, i)) + return -1; + else + return 1; + } + } + + return 0; +} + +FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name) +{ + FLAC__bool ok = true; + unsigned matching = 0; + const unsigned field_name_length = strlen(field_name); + int i; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + /* 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)) { + matching++; + ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i); + } + } + + return ok? (int)matching : -1; +} + +FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new() +{ + return (FLAC__StreamMetadata_CueSheet_Track*)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) +{ + FLAC__StreamMetadata_CueSheet_Track *to; + + FLAC__ASSERT(0 != object); + + if(0 != (to = FLAC__metadata_object_cuesheet_track_new())) { + if(!copy_track_(to, object)) { + FLAC__metadata_object_cuesheet_track_delete(to); + return 0; + } + } + + return to; +} + +void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object) +{ + FLAC__ASSERT(0 != object); + + if(0 != object->indices) { + FLAC__ASSERT(object->num_indices > 0); + free(object->indices); + } +} + +FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object) +{ + FLAC__metadata_object_cuesheet_track_delete_data(object); + free(object); +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices) +{ + FLAC__StreamMetadata_CueSheet_Track *track; + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); + + track = &object->data.cue_sheet.tracks[track_num]; + + if(0 == track->indices) { + FLAC__ASSERT(track->num_indices == 0); + if(0 == new_num_indices) + return true; + else if(0 == (track->indices = cuesheet_track_index_array_new_(new_num_indices))) + 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); + + FLAC__ASSERT(track->num_indices > 0); + + if(new_size == 0) { + free(track->indices); + track->indices = 0; + } + else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)realloc(track->indices, new_size))) + return false; + + /* if growing, zero all the lengths/pointers of new elements */ + if(new_size > old_size) + memset(track->indices + track->num_indices, 0, new_size - old_size); + } + + track->num_indices = new_num_indices; + + cuesheet_calculate_length_(object); + 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__StreamMetadata_CueSheet_Track *track; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); + FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices); + + track = &object->data.cue_sheet.tracks[track_num]; + + if(!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1)) + return false; + + /* 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; + 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_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num) +{ + FLAC__StreamMetadata_CueSheet_Track *track; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); + FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices); + + track = &object->data.cue_sheet.tracks[track_num]; + + /* move all indices > index_num backward one space */ + memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1)); + + FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1); + cuesheet_calculate_length_(object); + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + + if(0 == object->data.cue_sheet.tracks) { + FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0); + if(0 == new_num_tracks) + return true; + else if(0 == (object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks))) + 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); + + FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0); + + /* if shrinking, free the truncated entries */ + if(new_num_tracks < object->data.cue_sheet.num_tracks) { + unsigned i; + for(i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++) + if(0 != object->data.cue_sheet.tracks[i].indices) + free(object->data.cue_sheet.tracks[i].indices); + } + + if(new_size == 0) { + 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))) + return false; + + /* if growing, zero all the lengths/pointers of new elements */ + if(new_size > old_size) + memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size); + } + + object->data.cue_sheet.num_tracks = new_num_tracks; + + cuesheet_calculate_length_(object); + return 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) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); + + return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy); +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy) +{ + FLAC__StreamMetadata_CueSheet *cs; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks); + + cs = &object->data.cue_sheet; + + if(!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1)) + return false; + + /* move all tracks >= track_num forward one space */ + memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num)); + cs->tracks[track_num].num_indices = 0; + cs->tracks[track_num].indices = 0; + + return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy); +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num) +{ + FLAC__StreamMetadata_CueSheet_Track track; + memset(&track, 0, sizeof(track)); + return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false); +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num) +{ + FLAC__StreamMetadata_CueSheet *cs; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks); + + cs = &object->data.cue_sheet; + + /* free the track at track_num */ + if(0 != cs->tracks[track_num].indices) + free(cs->tracks[track_num].indices); + + /* move all tracks > track_num backward one space */ + memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1)); + cs->tracks[cs->num_tracks-1].num_indices = 0; + cs->tracks[cs->num_tracks-1].indices = 0; + + return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1); +} + +FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET); + + return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation); +} diff --git a/apps/codecs/libFLAC/seekable_stream_decoder.c b/apps/codecs/libFLAC/seekable_stream_decoder.c new file mode 100644 index 0000000000..2c899f20b3 --- /dev/null +++ b/apps/codecs/libFLAC/seekable_stream_decoder.c @@ -0,0 +1,1111 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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 +#include /* for calloc() */ +#include /* for memcpy()/memcmp() */ +#include "FLAC/assert.h" +#include "protected/seekable_stream_decoder.h" +#include "protected/stream_decoder.h" +#include "private/float.h" /* for FLAC__double */ +#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() +{ + 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? upper_bound - lower_bound - 1 : 0); +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#if defined _MSC_VER || defined __MINGW32__ + /* with MSVC you have to spoon feed it the casting */ + pos = (FLAC__int64)lower_bound + (FLAC__int64)(((FLAC__double)(FLAC__int64)target_offset / (FLAC__double)(FLAC__int64)range_samples) * (FLAC__double)(FLAC__int64)(range_bytes-1)) - approx_bytes_per_frame; +#else + pos = (FLAC__int64)lower_bound + (FLAC__int64)(((FLAC__double)target_offset / (FLAC__double)range_samples) * (FLAC__double)range_bytes) - approx_bytes_per_frame; +#endif +#else + /* a little less accurate: */ + if (range_bytes <= 0xffffffff) + pos = (FLAC__int64)lower_bound + (FLAC__int64)((target_offset * range_bytes) / range_samples) - approx_bytes_per_frame; + else /* @@@ WATCHOUT, ~2TB limit */ + pos = (FLAC__int64)lower_bound + (FLAC__int64)(((target_offset>>8) * (range_bytes>>8)) / (range_samples>>16)) - 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) { + /* + * For max accuracy we should be using + * (stream_length-first_frame_offset-1) in the divisor, but the + * difference is trivial and (stream_length-first_frame_offset) + * has no chance of underflow. + */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY +#if defined _MSC_VER || defined __MINGW32__ + /* with VC++ you have to spoon feed it the casting */ + pos = (FLAC__int64)first_frame_offset + (FLAC__int64)(((FLAC__double)(FLAC__int64)target_sample / (FLAC__double)(FLAC__int64)total_samples) * (FLAC__double)(FLAC__int64)(stream_length-first_frame_offset)) - approx_bytes_per_frame; +#else + pos = (FLAC__int64)first_frame_offset + (FLAC__int64)(((FLAC__double)target_sample / (FLAC__double)total_samples) * (FLAC__double)(stream_length-first_frame_offset)) - approx_bytes_per_frame; +#endif +#else + /* a little less accurate: */ + if (stream_length < 0xffffffff) + pos = (FLAC__int64)first_frame_offset + (FLAC__int64)((target_sample * (stream_length-first_frame_offset)) / total_samples) - approx_bytes_per_frame; + else /* @@@ WATCHOUT, ~2TB limit */ + pos = (FLAC__int64)first_frame_offset + (FLAC__int64)(((target_sample>>8) * ((stream_length-first_frame_offset)>>8)) / (total_samples>>16)) - 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 */ + /* actually, we could have got_a_frame if our decoder is at FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM so we need to check for that also */ + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING && decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) { + 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/apps/codecs/libFLAC/seekable_stream_encoder.c b/apps/codecs/libFLAC/seekable_stream_encoder.c new file mode 100644 index 0000000000..18291a8052 --- /dev/null +++ b/apps/codecs/libFLAC/seekable_stream_encoder.c @@ -0,0 +1,943 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2002,2003,2004,2005 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 +#include /* for calloc() */ +#include /* 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" +}; + + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +FLAC_API FLAC__SeekableStreamEncoder *FLAC__seekable_stream_encoder_new() +{ + 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/apps/codecs/libFLAC/stream_decoder.c b/apps/codecs/libFLAC/stream_decoder.c new file mode 100644 index 0000000000..845ff90131 --- /dev/null +++ b/apps/codecs/libFLAC/stream_decoder.c @@ -0,0 +1,2157 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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 +#include /* for malloc() */ +#include /* for memset/memcpy() */ +#include "FLAC/assert.h" +#include "protected/stream_decoder.h" +#include "private/bitbuffer.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/memory.h" + +#ifdef HAVE_CONFIG_H +#include +#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 +#else +#define FLAC__U64L(x) x##LLU +#endif + +/*********************************************************************** + * + * Private static data + * + ***********************************************************************/ + +static FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' }; + +/*********************************************************************** + * + * Private class method prototypes + * + ***********************************************************************/ + +static void set_defaults_(FLAC__StreamDecoder *decoder); +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_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *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); +static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder); +static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode); +static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode); +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_zero_padding_(FLAC__StreamDecoder *decoder); +static FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *client_data); + +/*********************************************************************** + * + * Private class data + * + ***********************************************************************/ + +typedef struct FLAC__StreamDecoderPrivate { + FLAC__StreamDecoderReadCallback read_callback; + FLAC__StreamDecoderWriteCallback write_callback; + FLAC__StreamDecoderMetadataCallback metadata_callback; + FLAC__StreamDecoderErrorCallback error_callback; + /* generic 32-bit datapath: */ + void (*local_lpc_restore_signal)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); + /* generic 64-bit datapath: */ + 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; + 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 last_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 */ + FLAC__Frame frame; + FLAC__bool cached; /* true if there is a byte in lookahead */ + FLAC__CPUInfo cpuinfo; + FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */ + 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__StreamDecoderPrivate; + +/*********************************************************************** + * + * Public static class data + * + ***********************************************************************/ + +FLAC_API const char * const FLAC__StreamDecoderStateString[] = { + "FLAC__STREAM_DECODER_SEARCH_FOR_METADATA", + "FLAC__STREAM_DECODER_READ_METADATA", + "FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC", + "FLAC__STREAM_DECODER_READ_FRAME", + "FLAC__STREAM_DECODER_END_OF_STREAM", + "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__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__StreamDecoderWriteStatusString[] = { + "FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE", + "FLAC__STREAM_DECODER_WRITE_STATUS_ABORT" +}; + +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" +}; + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ +FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new() +{ + 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)); + if(decoder == 0) { + return 0; + } + + decoder->protected_ = (FLAC__StreamDecoderProtected*)calloc(1, sizeof(FLAC__StreamDecoderProtected)); + if(decoder->protected_ == 0) { + free(decoder); + return 0; + } + + decoder->private_ = (FLAC__StreamDecoderPrivate*)calloc(1, sizeof(FLAC__StreamDecoderPrivate)); + if(decoder->private_ == 0) { + free(decoder->protected_); + free(decoder); + return 0; + } + + decoder->private_->input = FLAC__bitbuffer_new(); + if(decoder->private_->input == 0) { + free(decoder->private_); + free(decoder->protected_); + free(decoder); + return 0; + } + + 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); + free(decoder->private_); + free(decoder->protected_); + free(decoder); + return 0; + } + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + decoder->private_->output[i] = 0; + decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; + } + + decoder->private_->output_capacity = 0; + decoder->private_->output_channels = 0; + decoder->private_->has_seek_table = false; + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]); + + set_defaults_(decoder); + + decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; + + return decoder; +} + +FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder) +{ + unsigned i; + + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->private_->input); + + FLAC__stream_decoder_finish(decoder); + + if(0 != decoder->private_->metadata_filter_ids) + free(decoder->private_->metadata_filter_ids); + + FLAC__bitbuffer_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]); + + free(decoder->private_); + free(decoder->protected_); + free(decoder); +} + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return decoder->protected_->state = FLAC__STREAM_DECODER_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; + + decoder->private_->last_frame_number = 0; + decoder->private_->last_block_size = 0; + decoder->private_->samples_decoded = 0; + decoder->private_->has_stream_info = false; + decoder->private_->cached = false; + + /* + * get the CPU info and set the function pointers + */ + FLAC__cpu_info(&decoder->private_->cpuinfo); + /* first default to the non-asm routines */ + 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 = 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; + } +#endif + } +#endif + + if(!FLAC__stream_decoder_reset(decoder)) + return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + + return decoder->protected_->state; +} + +FLAC_API void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder) +{ + unsigned i; + FLAC__ASSERT(0 != decoder); + if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) + return; + if(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); + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + /* WATCHOUT: + * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the + * output arrays 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. + */ + if(0 != decoder->private_->output[i]) { + free(decoder->private_->output[i]-4); + decoder->private_->output[i] = 0; + } + if(0 != decoder->private_->residual_unaligned[i]) { + free(decoder->private_->residual_unaligned[i]); + decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; + } + } + decoder->private_->output_capacity = 0; + decoder->private_->output_channels = 0; + + set_defaults_(decoder); + + decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; +} + +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; +} + +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; +} + +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; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_error_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorCallback 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; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_client_data(FLAC__StreamDecoder *decoder, void *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; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE); + /* double protection */ + if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE) + return false; + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->metadata_filter[type] = true; + if(type == FLAC__METADATA_TYPE_APPLICATION) + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != id); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + + if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION]) + return true; + + 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; + decoder->private_->metadata_filter_ids_capacity *= 2; + } + + memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); + decoder->private_->metadata_filter_ids_count++; + + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder) +{ + 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 false; + for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++) + decoder->private_->metadata_filter[i] = true; + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE); + /* double protection */ + if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE) + return false; + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->metadata_filter[type] = false; + if(type == FLAC__METADATA_TYPE_APPLICATION) + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != id); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + + if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION]) + return true; + + 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; + decoder->private_->metadata_filter_ids_capacity *= 2; + } + + memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); + decoder->private_->metadata_filter_ids_count++; + + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter)); + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->state; +} + +FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder) +{ + return FLAC__StreamDecoderStateString[decoder->protected_->state]; +} + +FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->channels; +} + +FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->channel_assignment; +} + +FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->bits_per_sample; +} + +FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->sample_rate; +} + +FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->blocksize; +} + +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->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + decoder->private_->last_frame_number = 0; + decoder->private_->last_block_size = 0; + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + + if(!FLAC__stream_decoder_flush(decoder)) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA; + + decoder->private_->samples_decoded = 0; + + return true; +} + +FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder) +{ + FLAC__bool got_a_frame; + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + + while(1) { + switch(decoder->protected_->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + if(!find_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_METADATA: + if(!read_metadata_(decoder)) + return false; /* above function sets the status for us */ + else + return true; + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + if(!frame_sync_(decoder)) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_FRAME: + if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true)) + return false; /* above function sets the status for us */ + if(got_a_frame) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + case FLAC__STREAM_DECODER_ABORTED: + return true; + default: + FLAC__ASSERT(0); + return false; + } + } +} + +FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + + while(1) { + switch(decoder->protected_->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + if(!find_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_METADATA: + if(!read_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + case FLAC__STREAM_DECODER_READ_FRAME: + case FLAC__STREAM_DECODER_END_OF_STREAM: + case FLAC__STREAM_DECODER_ABORTED: + return true; + default: + FLAC__ASSERT(0); + return false; + } + } +} + +FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder) +{ + FLAC__bool dummy; + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + + while(1) { + switch(decoder->protected_->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + if(!find_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_METADATA: + if(!read_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + if(!frame_sync_(decoder)) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_FRAME: + if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + case FLAC__STREAM_DECODER_ABORTED: + return true; + default: + FLAC__ASSERT(0); + return false; + } + } +} + +FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder) +{ + FLAC__bool got_a_frame; + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + + while(1) { + switch(decoder->protected_->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + case FLAC__STREAM_DECODER_READ_METADATA: + return false; /* above function sets the status for us */ + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + if(!frame_sync_(decoder)) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_FRAME: + if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false)) + return false; /* above function sets the status for us */ + if(got_a_frame) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + case FLAC__STREAM_DECODER_ABORTED: + return true; + default: + FLAC__ASSERT(0); + return false; + } + } +} + +/*********************************************************************** + * + * Protected class methods + * + ***********************************************************************/ + +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); +} + +/*********************************************************************** + * + * Private class methods + * + ***********************************************************************/ + +void set_defaults_(FLAC__StreamDecoder *decoder) +{ + decoder->private_->read_callback = 0; + decoder->private_->write_callback = 0; + decoder->private_->metadata_callback = 0; + decoder->private_->error_callback = 0; + decoder->private_->client_data = 0; + + 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; +} + +FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels) +{ + unsigned i; + FLAC__int32 *tmp; + + if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels) + return true; + + /* simply using realloc() is not practical because the number of channels may change mid-stream */ + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + if(0 != decoder->private_->output[i]) { + free(decoder->private_->output[i]-4); + decoder->private_->output[i] = 0; + } + if(0 != decoder->private_->residual_unaligned[i]) { + free(decoder->private_->residual_unaligned[i]); + decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; + } + } + + for(i = 0; i < channels; i++) { + /* WATCHOUT: + * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the + * output arrays 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. + */ + tmp = (FLAC__int32*)malloc(sizeof(FLAC__int32)*(size+4)); + if(tmp == 0) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + 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; + } + } + + decoder->private_->output_capacity = size; + decoder->private_->output_channels = channels; + + return true; +} + +FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id) +{ + unsigned i; + + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + + for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++) + if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))) + return true; + + return false; +} + +FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder) +{ + FLAC__uint32 x; + unsigned i, id; + FLAC__bool first = true; + + FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)); + + for(i = id = 0; i < 4; ) { + if(decoder->private_->cached) { + x = (FLAC__uint32)decoder->private_->lookahead; + 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(x == FLAC__STREAM_SYNC_STRING[i]) { + first = true; + i++; + id = 0; + continue; + } + 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 */ + } + continue; + } + 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 */ + + /* 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 */ + if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ + decoder->private_->lookahead = (FLAC__byte)x; + decoder->private_->cached = true; + } + else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */ + decoder->private_->header_warmup[1] = (FLAC__byte)x; + decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME; + return true; + } + } + i = 0; + if(first) { + decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data); + first = false; + } + } + + decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA; + return true; +} + +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)); + + 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 */ + 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__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(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]) + decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data); + } + else if(type == FLAC__METADATA_TYPE_SEEKTABLE) { + if(!read_metadata_seektable_(decoder, is_last, length)) + return false; + + decoder->private_->has_seek_table = true; + if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE]) + decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data); + } + else { + FLAC__bool skip_it = !decoder->private_->metadata_filter[type]; + unsigned real_length = length; + FLAC__StreamMetadata 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 */ + + real_length -= FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8; + + if(decoder->private_->metadata_filter_ids_count > 0 && has_id_filtered_(decoder, block.data.application.id)) + skip_it = !skip_it; + } + + 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 */ + } + else { + 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 */ + 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))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return 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 + block.data.application.data = 0; + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment)) + return false; + break; + case FLAC__METADATA_TYPE_CUESHEET: + if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet)) + return false; + break; + case FLAC__METADATA_TYPE_STREAMINFO: + case FLAC__METADATA_TYPE_SEEKTABLE: + FLAC__ASSERT(0); + break; + default: + if(real_length > 0) { + if(0 == (block.data.unknown.data = (FLAC__byte*)malloc(real_length))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return 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 + block.data.unknown.data = 0; + break; + } + decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data); + + /* now we have to free any malloc'ed data in the block */ + switch(type) { + case FLAC__METADATA_TYPE_PADDING: + break; + case FLAC__METADATA_TYPE_APPLICATION: + if(0 != block.data.application.data) + free(block.data.application.data); + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + if(0 != block.data.vorbis_comment.vendor_string.entry) + free(block.data.vorbis_comment.vendor_string.entry); + if(block.data.vorbis_comment.num_comments > 0) + for(i = 0; i < block.data.vorbis_comment.num_comments; i++) + if(0 != block.data.vorbis_comment.comments[i].entry) + free(block.data.vorbis_comment.comments[i].entry); + if(0 != block.data.vorbis_comment.comments) + free(block.data.vorbis_comment.comments); + break; + case FLAC__METADATA_TYPE_CUESHEET: + if(block.data.cue_sheet.num_tracks > 0) + for(i = 0; i < block.data.cue_sheet.num_tracks; i++) + if(0 != block.data.cue_sheet.tracks[i].indices) + free(block.data.cue_sheet.tracks[i].indices); + if(0 != block.data.cue_sheet.tracks) + free(block.data.cue_sheet.tracks); + break; + case FLAC__METADATA_TYPE_STREAMINFO: + case FLAC__METADATA_TYPE_SEEKTABLE: + FLAC__ASSERT(0); + default: + if(0 != block.data.unknown.data) + free(block.data.unknown.data); + break; + } + } + } + + if(is_last) + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + + return true; +} + +FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length) +{ + FLAC__uint32 x; + unsigned bits, used_bits = 0; + + FLAC__ASSERT(FLAC__bitbuffer_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 */ + 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 */ + 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 */ + 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 */ + 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 */ + 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 */ + 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 */ + 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 */ + 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 */ + 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 */ + + return true; +} + +FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length) +{ + FLAC__uint32 i, x; + FLAC__uint64 xx; + + FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)); + + decoder->private_->seek_table.type = FLAC__METADATA_TYPE_SEEKTABLE; + decoder->private_->seek_table.is_last = is_last; + decoder->private_->seek_table.length = length; + + 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)))) { + 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 */ + 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 */ + 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 */ + 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 */ + } + + return true; +} + +FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj) +{ + FLAC__uint32 i; + + FLAC__ASSERT(FLAC__bitbuffer_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+1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + 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 */ + obj->vendor_string.entry[obj->vendor_string.length] = '\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 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+1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + 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 */ + obj->comments[i].entry[obj->comments[i].length] = '\0'; + } + else + obj->comments[i].entry = 0; + } + } + else { + obj->comments = 0; + } + + return true; +} + +FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj) +{ + FLAC__uint32 i, j, x; + + FLAC__ASSERT(FLAC__bitbuffer_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__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__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 */ + 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__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 */ + 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)))) { + 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__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 */ + 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__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 */ + 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 */ + 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__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 */ + 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)))) { + 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 */ + + 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__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 */ + } + } + } + } + + 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 */ + /* 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 */ + 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 */ + return true; +} + +FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder) +{ + FLAC__uint32 x; + FLAC__bool first = true; + + /* 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) { + 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 */ + } + + while(1) { + if(decoder->private_->cached) { + x = (FLAC__uint32)decoder->private_->lookahead; + 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(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 */ + + /* 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 */ + if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ + decoder->private_->lookahead = (FLAC__byte)x; + decoder->private_->cached = true; + } + else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */ + 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); + first = false; + } + } + + return true; +} + +FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode) +{ + unsigned channel; + unsigned i; + FLAC__int32 mid, side, left, right; + FLAC__uint16 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); + + if(!read_frame_header_(decoder)) + return false; + if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) + return true; + if(!allocate_output_(decoder, decoder->private_->frame.header.blocksize, decoder->private_->frame.header.channels)) + return false; + for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) { + /* + * first figure the correct bits-per-sample of the subframe + */ + unsigned bps = decoder->private_->frame.header.bits_per_sample; + switch(decoder->private_->frame.header.channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + /* no adjustment needed */ + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + if(channel == 1) + bps++; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + if(channel == 0) + bps++; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + if(channel == 1) + bps++; + break; + default: + FLAC__ASSERT(0); + } + /* + * now read it + */ + 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; + return true; + } + } + if(!read_zero_padding_(decoder)) + return false; + + /* + * 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) { + if(do_full_decode) { + /* Undo any special channel coding */ + switch(decoder->private_->frame.header.channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + /* do nothing */ + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) + decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i]; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) + decoder->private_->output[0][i] += decoder->private_->output[1][i]; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + FLAC__ASSERT(decoder->private_->frame.header.channels == 2); + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { + 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; + } + break; + default: + FLAC__ASSERT(0); + break; + } + } + } + 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); + 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); + } + } + } + + *got_a_frame = true; + + /* 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; + decoder->protected_->bits_per_sample = decoder->private_->frame.header.bits_per_sample; + decoder->protected_->sample_rate = decoder->private_->frame.header.sample_rate; + decoder->protected_->blocksize = decoder->private_->frame.header.blocksize; + + FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize; + + /* 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) + return false; + } + + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; +} + +FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) +{ + FLAC__uint32 x; + FLAC__uint64 xx; + unsigned i, blocksize_hint = 0, sample_rate_hint = 0; + 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)); + + /* 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 */ + 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. + */ + + /* + * 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(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); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + raw_header[raw_header_len++] = (FLAC__byte)x; + } + + 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; + break; + case 1: + decoder->private_->frame.header.blocksize = 192; + break; + case 2: + case 3: + case 4: + case 5: + decoder->private_->frame.header.blocksize = 576 << (x-2); + break; + case 6: + case 7: + blocksize_hint = x; + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + decoder->private_->frame.header.blocksize = 256 << (x-8); + break; + default: + FLAC__ASSERT(0); + break; + } + + switch(x = raw_header[2] & 0x0f) { + case 0: + if(decoder->private_->has_stream_info) + decoder->private_->frame.header.sample_rate = decoder->private_->stream_info.data.stream_info.sample_rate; + else + is_unparseable = true; + break; + case 1: + case 2: + case 3: + is_unparseable = true; + break; + case 4: + decoder->private_->frame.header.sample_rate = 8000; + break; + case 5: + decoder->private_->frame.header.sample_rate = 16000; + break; + case 6: + decoder->private_->frame.header.sample_rate = 22050; + break; + case 7: + decoder->private_->frame.header.sample_rate = 24000; + break; + case 8: + decoder->private_->frame.header.sample_rate = 32000; + break; + case 9: + decoder->private_->frame.header.sample_rate = 44100; + break; + case 10: + decoder->private_->frame.header.sample_rate = 48000; + break; + case 11: + decoder->private_->frame.header.sample_rate = 96000; + break; + case 12: + case 13: + case 14: + sample_rate_hint = x; + break; + case 15: + 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; + default: + FLAC__ASSERT(0); + } + + x = (unsigned)(raw_header[3] >> 4); + if(x & 8) { + decoder->private_->frame.header.channels = 2; + switch(x & 7) { + case 0: + decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE; + break; + case 1: + decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE; + break; + case 2: + decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE; + break; + default: + is_unparseable = true; + break; + } + } + else { + decoder->private_->frame.header.channels = (unsigned)x + 1; + decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; + } + + switch(x = (unsigned)(raw_header[3] & 0x0e) >> 1) { + case 0: + if(decoder->private_->has_stream_info) + decoder->private_->frame.header.bits_per_sample = decoder->private_->stream_info.data.stream_info.bits_per_sample; + else + is_unparseable = true; + break; + case 1: + decoder->private_->frame.header.bits_per_sample = 8; + break; + case 2: + decoder->private_->frame.header.bits_per_sample = 12; + break; + case 4: + decoder->private_->frame.header.bits_per_sample = 16; + break; + case 5: + decoder->private_->frame.header.bits_per_sample = 20; + break; + case 6: + decoder->private_->frame.header.bits_per_sample = 24; + break; + case 3: + case 7: + is_unparseable = true; + break; + default: + FLAC__ASSERT(0); + 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; + } + + /* + * Now we get to the regrettable consequences of not knowing for sure + * whether we got a frame number or a sample number. There are no + * encoders that do variable-blocksize encoding so unless we know from + * the STREAMINFO that it is variable-blocksize we will assume it is + * fixed-blocksize. The trouble comes when we have no STREAMINFO; again + * we will guess that is fixed-blocksize. Where this can go wrong: 1) a + * variable-blocksize stream with no STREAMINFO; 2) a fixed-blocksize + * stream that was edited such that one or more frames before or + * including this one do not have the same number of samples as the + * STREAMINFO's min and max blocksize. + */ + if(is_known_variable_blocksize_stream) { + if(blocksize_hint) { + 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 */ + 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); + 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 + is_unparseable = true; + } + 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 */ + 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); + 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(decoder->private_->has_stream_info) { + FLAC__ASSERT(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_->last_block_size = decoder->private_->frame.header.blocksize; + } + else if(blocksize_hint) { + if(decoder->private_->last_block_size) + decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->last_block_size * (FLAC__uint64)x; + else + is_unparseable = true; + } + else { + decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->frame.header.blocksize * (FLAC__uint64)x; + decoder->private_->last_block_size = decoder->private_->frame.header.blocksize; + } + } + + 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 */ + 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 */ + raw_header[raw_header_len++] = (FLAC__byte)_x; + x = (x << 8) | _x; + } + decoder->private_->frame.header.blocksize = x+1; + } + + 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 */ + 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 */ + raw_header[raw_header_len++] = (FLAC__byte)_x; + x = (x << 8) | _x; + } + if(sample_rate_hint == 12) + decoder->private_->frame.header.sample_rate = x*1000; + else if(sample_rate_hint == 13) + decoder->private_->frame.header.sample_rate = x; + else + decoder->private_->frame.header.sample_rate = x*10; + } + + /* 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 */ + 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); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + + if(is_unparseable) { + decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; + return false; + } + + return true; +} + +FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode) +{ + FLAC__uint32 x; + FLAC__bool wasted_bits; + + 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 */ + + 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 */ + decoder->private_->frame.subframes[channel].wasted_bits = u+1; + bps -= decoder->private_->frame.subframes[channel].wasted_bits; + } + else + decoder->private_->frame.subframes[channel].wasted_bits = 0; + + /* + * Lots of magic numbers here + */ + if(x & 0x80) { + decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + else if(x == 0) { + if(!read_subframe_constant_(decoder, channel, bps, do_full_decode)) + return false; + } + else if(x == 2) { + if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode)) + return false; + } + else if(x < 16) { + decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; + return false; + } + else if(x <= 24) { + if(!read_subframe_fixed_(decoder, channel, bps, (x>>1)&7, do_full_decode)) + return false; + } + else if(x < 64) { + decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; + return false; + } + else { + if(!read_subframe_lpc_(decoder, channel, bps, ((x>>1)&31)+1, do_full_decode)) + return false; + } + + 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; + } + + return true; +} + +FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode) +{ + FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant; + FLAC__int32 x; + unsigned i; + FLAC__int32 *output = decoder->private_->output[channel]; + + 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 */ + + subframe->value = x; + + /* decode the subframe */ + if(do_full_decode) { + for(i = 0; i < decoder->private_->frame.header.blocksize; i++) + output[i] = x; + } + + return true; +} + +FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode) +{ + FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed; + FLAC__int32 i32; + FLAC__uint32 u32; + unsigned u; + + decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_FIXED; + + subframe->residual = decoder->private_->residual[channel]; + subframe->order = order; + + /* 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 */ + 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 */ + 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 */ + 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; + } + + /* 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])) + return false; + break; + default: + FLAC__ASSERT(0); + } + + /* decode the subframe */ + if(do_full_decode) { + memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order); + FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order); + } + + return true; +} + +FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode) +{ + FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc; + FLAC__int32 i32; + FLAC__uint32 u32; + unsigned u; + + decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_LPC; + + subframe->residual = decoder->private_->residual[channel]; + subframe->order = order; + + /* 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 */ + 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(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); + 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 */ + 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 */ + 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 */ + 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 */ + 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; + } + + /* 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])) + return false; + break; + default: + FLAC__ASSERT(0); + } + + /* decode the subframe */ + if(do_full_decode) { + memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order); + 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); + } + 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 + decoder->private_->local_lpc_restore_signal_64bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); + } + + return true; +} + +FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode) +{ + FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim; + FLAC__int32 x, *residual = decoder->private_->residual[channel]; + unsigned i; + + decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM; + + 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 */ + residual[i] = x; + } + + /* decode the subframe */ + if(do_full_decode) + memcpy(decoder->private_->output[channel], subframe->data, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize); + + 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__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; + + /* sanity checks */ + if(partition_order == 0) { + if(decoder->private_->frame.header.blocksize < predictor_order) { + decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + } + else { + if(partition_samples < predictor_order) { + decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data); + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + } + + if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, 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 */ + 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 + 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 */ + 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 */ + 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 */ + residual[sample] = i; + } + } + } + + return true; +} + +FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder) +{ + if(!FLAC__bitbuffer_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(zero != 0) { + decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data); + 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__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) + decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; + else if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT) + decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; + return status == FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; +} diff --git a/apps/codecs/libFLAC/stream_encoder.c b/apps/codecs/libFLAC/stream_encoder.c new file mode 100644 index 0000000000..33debfc06a --- /dev/null +++ b/apps/codecs/libFLAC/stream_encoder.c @@ -0,0 +1,3394 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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 +#include +#include /* for malloc() */ +#include /* for memcpy() */ +#include "FLAC/assert.h" +#include "FLAC/stream_decoder.h" +#include "protected/stream_encoder.h" +#include "private/bitbuffer.h" +#include "private/bitmath.h" +#include "private/crc.h" +#include "private/cpu.h" +#include "private/fixed.h" +#include "private/format.h" +#include "private/lpc.h" +#include "private/md5.h" +#include "private/memory.h" +#include "private/stream_encoder_framing.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#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)) + +typedef struct { + FLAC__int32 *data[FLAC__MAX_CHANNELS]; + unsigned size; /* of each data[] in samples */ + unsigned tail; +} verify_input_fifo; + +typedef struct { + const FLAC__byte *data; + unsigned capacity; + unsigned bytes; +} verify_output; + +typedef enum { + ENCODER_IN_MAGIC = 0, + ENCODER_IN_METADATA = 1, + ENCODER_IN_AUDIO = 2 +} EncoderStateHint; + +/*********************************************************************** + * + * Private class method prototypes + * + ***********************************************************************/ + +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 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[], +#ifndef FLAC__INTEGER_ONLY_LIBRARY + const FLAC__real real_signal[], +#endif + FLAC__Subframe *subframe[2], + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2], + FLAC__int32 *residual[2], + unsigned *best_subframe, + unsigned *best_bits +); + +static FLAC__bool add_subframe_( + FLAC__StreamEncoder *encoder, + const FLAC__FrameHeader *frame_header, + unsigned subframe_bps, + const FLAC__Subframe *subframe, + FLAC__BitBuffer *frame +); + +static unsigned evaluate_constant_subframe_( + const FLAC__int32 signal, + unsigned subframe_bps, + FLAC__Subframe *subframe +); + +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 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[], + unsigned blocksize, + unsigned subframe_bps, + unsigned order, + unsigned qlp_coeff_precision, + unsigned rice_parameter, + 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_( + const FLAC__int32 signal[], + unsigned blocksize, + unsigned subframe_bps, + FLAC__Subframe *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 min_partition_order, + unsigned max_partition_order, + FLAC__bool precompute_partition_sums, + FLAC__bool do_escape_coding, + unsigned rice_parameter_search_dist, + FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice +); + +static void precompute_partition_info_sums_( + const FLAC__uint32 abs_residual[], + FLAC__uint64 abs_residual_partition_sums[], + unsigned residual_samples, + unsigned predictor_order, + unsigned min_partition_order, + unsigned max_partition_order +); + +static void precompute_partition_info_escapes_( + const FLAC__int32 residual[], + unsigned raw_bits_per_partition[], + unsigned residual_samples, + unsigned predictor_order, + unsigned min_partition_order, + unsigned max_partition_order +); + +#ifdef DONT_ESTIMATE_RICE_BITS +static 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 +); + +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[], + 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 + +static unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples); + +/* verify-related routines: */ +static void append_to_verify_fifo_( + verify_input_fifo *fifo, + const FLAC__int32 * const input[], + unsigned input_offset, + unsigned channels, + unsigned wide_samples +); + +static void append_to_verify_fifo_interleaved_( + verify_input_fifo *fifo, + const FLAC__int32 input[], + unsigned input_offset, + unsigned channels, + 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 void verify_error_callback_( + const FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderErrorStatus status, + void *client_data +); + + +/*********************************************************************** + * + * Private class data + * + ***********************************************************************/ + +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) */ +#ifndef FLAC__INTEGER_ONLY_LIBRARY + 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) */ +#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 */ + FLAC__int32 *residual_workspace_mid_side[2][2]; + FLAC__Subframe subframe_workspace[FLAC__MAX_CHANNELS][2]; + FLAC__Subframe subframe_workspace_mid_side[2][2]; + FLAC__Subframe *subframe_workspace_ptr[FLAC__MAX_CHANNELS][2]; + FLAC__Subframe *subframe_workspace_ptr_mid_side[2][2]; + FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace[FLAC__MAX_CHANNELS][2]; + 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_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 */ + 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; + unsigned current_sample_number; + unsigned current_frame_number; + struct FLAC__MD5Context md5context; + FLAC__CPUInfo cpuinfo; +#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]); +#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]); +#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[]); +#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; + FLAC__StreamEncoderWriteCallback write_callback; + FLAC__StreamEncoderMetadataCallback metadata_callback; + void *client_data; + /* unaligned (original) pointers to allocated data */ + FLAC__int32 *integer_signal_unaligned[FLAC__MAX_CHANNELS]; + FLAC__int32 *integer_signal_mid_side_unaligned[2]; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + FLAC__real *real_signal_unaligned[FLAC__MAX_CHANNELS]; + FLAC__real *real_signal_mid_side_unaligned[2]; +#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 + */ + struct { + FLAC__StreamDecoder *decoder; + EncoderStateHint state_hint; + FLAC__bool needs_magic_hack; + verify_input_fifo input_fifo; + verify_output output; + struct { + FLAC__uint64 absolute_sample; + unsigned frame_number; + unsigned channel; + unsigned sample; + FLAC__int32 expected; + FLAC__int32 got; + } error_stats; + } verify; + FLAC__bool is_being_deleted; /* if true, call to ..._finish() from ..._delete() will not call the callbacks */ +} FLAC__StreamEncoderPrivate; + +/*********************************************************************** + * + * Public static class data + * + ***********************************************************************/ + +FLAC_API const char * const FLAC__StreamEncoderStateString[] = { + "FLAC__STREAM_ENCODER_OK", + "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_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_API const char * const FLAC__StreamEncoderWriteStatusString[] = { + "FLAC__STREAM_ENCODER_WRITE_STATUS_OK", + "FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR" +}; + +/*********************************************************************** + * + * Class constructor/destructor + * + */ +FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new() +{ + FLAC__StreamEncoder *encoder; + unsigned i; + + FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ + + encoder = (FLAC__StreamEncoder*)calloc(1, sizeof(FLAC__StreamEncoder)); + if(encoder == 0) { + return 0; + } + + encoder->protected_ = (FLAC__StreamEncoderProtected*)calloc(1, sizeof(FLAC__StreamEncoderProtected)); + if(encoder->protected_ == 0) { + free(encoder); + return 0; + } + + encoder->private_ = (FLAC__StreamEncoderPrivate*)calloc(1, sizeof(FLAC__StreamEncoderPrivate)); + if(encoder->private_ == 0) { + free(encoder->protected_); + free(encoder); + return 0; + } + + encoder->private_->frame = FLAC__bitbuffer_new(); + if(encoder->private_->frame == 0) { + free(encoder->private_); + free(encoder->protected_); + free(encoder); + return 0; + } + + set_defaults_(encoder); + + encoder->private_->is_being_deleted = false; + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + encoder->private_->subframe_workspace_ptr[i][0] = &encoder->private_->subframe_workspace[i][0]; + encoder->private_->subframe_workspace_ptr[i][1] = &encoder->private_->subframe_workspace[i][1]; + } + for(i = 0; i < 2; i++) { + encoder->private_->subframe_workspace_ptr_mid_side[i][0] = &encoder->private_->subframe_workspace_mid_side[i][0]; + encoder->private_->subframe_workspace_ptr_mid_side[i][1] = &encoder->private_->subframe_workspace_mid_side[i][1]; + } + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + encoder->private_->partitioned_rice_contents_workspace_ptr[i][0] = &encoder->private_->partitioned_rice_contents_workspace[i][0]; + encoder->private_->partitioned_rice_contents_workspace_ptr[i][1] = &encoder->private_->partitioned_rice_contents_workspace[i][1]; + } + for(i = 0; i < 2; i++) { + encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][0] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]; + encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][1] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]; + } + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][0]); + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][1]); + } + for(i = 0; i < 2; i++) { + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]); + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]); + } + for(i = 0; i < 2; i++) + FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_extra[i]); + + encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED; + + return encoder; +} + +FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder) +{ + unsigned i; + + FLAC__ASSERT(0 != encoder); + 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); + + if(0 != encoder->private_->verify.decoder) + FLAC__stream_decoder_delete(encoder->private_->verify.decoder); + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][0]); + FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][1]); + } + for(i = 0; i < 2; i++) { + FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]); + FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]); + } + 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); + free(encoder->private_); + free(encoder->protected_); + free(encoder); +} + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder *encoder) +{ + unsigned i; + FLAC__bool metadata_has_seektable, metadata_has_vorbis_comment; + + FLAC__ASSERT(0 != encoder); + + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return encoder->protected_->state = FLAC__STREAM_ENCODER_ALREADY_INITIALIZED; + + encoder->protected_->state = FLAC__STREAM_ENCODER_OK; + + if(0 == encoder->private_->write_callback || 0 == encoder->private_->metadata_callback) + return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_CALLBACK; + + if(encoder->protected_->channels == 0 || encoder->protected_->channels > FLAC__MAX_CHANNELS) + return encoder->protected_->state = FLAC__STREAM_ENCODER_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_->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 */ + + 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; + + if(!FLAC__format_sample_rate_is_valid(encoder->protected_->sample_rate)) + return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_SAMPLE_RATE; + + 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; + + if(encoder->protected_->max_lpc_order > FLAC__MAX_LPC_ORDER) + return encoder->protected_->state = FLAC__STREAM_ENCODER_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; + + 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); + } + else if(encoder->protected_->bits_per_sample == 16) { + if(encoder->protected_->blocksize <= 192) + encoder->protected_->qlp_coeff_precision = 7; + else if(encoder->protected_->blocksize <= 384) + encoder->protected_->qlp_coeff_precision = 8; + else if(encoder->protected_->blocksize <= 576) + encoder->protected_->qlp_coeff_precision = 9; + else if(encoder->protected_->blocksize <= 1152) + encoder->protected_->qlp_coeff_precision = 10; + else if(encoder->protected_->blocksize <= 2304) + encoder->protected_->qlp_coeff_precision = 11; + else if(encoder->protected_->blocksize <= 4608) + encoder->protected_->qlp_coeff_precision = 12; + else + encoder->protected_->qlp_coeff_precision = 13; + } + else { + if(encoder->protected_->blocksize <= 384) + encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-2; + else if(encoder->protected_->blocksize <= 1152) + encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-1; + else + encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION; + } + 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; + + 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( + encoder->protected_->bits_per_sample != 8 && + encoder->protected_->bits_per_sample != 12 && + encoder->protected_->bits_per_sample != 16 && + encoder->protected_->bits_per_sample != 20 && + encoder->protected_->bits_per_sample != 24 + ) + return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE; + if(encoder->protected_->max_residual_partition_order > FLAC__SUBSET_MAX_RICE_PARTITION_ORDER) + return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE; + } + + if(encoder->protected_->max_residual_partition_order >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) + encoder->protected_->max_residual_partition_order = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN) - 1; + 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; + + /* validate metadata */ + if(0 == encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) + return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA; + metadata_has_seektable = false; + metadata_has_vorbis_comment = 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) { + if(metadata_has_seektable) /* only one is allowed */ + return encoder->protected_->state = FLAC__STREAM_ENCODER_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; + } + else if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + if(metadata_has_vorbis_comment) /* only one is allowed */ + return encoder->protected_->state = FLAC__STREAM_ENCODER_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; + } + } + + 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 + } + 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; + encoder->private_->best_subframe[i] = 0; + } + for(i = 0; i < 2; i++) { + encoder->private_->residual_workspace_mid_side_unaligned[i][0] = encoder->private_->residual_workspace_mid_side[i][0] = 0; + 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; +#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; + encoder->private_->current_sample_number = 0; + 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_partition = (false); /*@@@ need to set this */ + + /* + * get the CPU info and set the function pointers + */ + 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_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor; +#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__INTEGER_ONLY_LIBRARY +# ifndef FLAC__NO_ASM + if(encoder->private_->cpuinfo.use_asm) { +# 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) { + 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 + encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32; + } + else +# endif /* FLAC__SSE_OS */ + 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_->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; + } + else { + 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; + } + 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; +# endif /* FLAC__HAS_NASM */ +# endif /* FLAC__CPU_IA32 */ + } +# endif /* !FLAC__NO_ASM */ +#endif /* !FLAC__INTEGER_ONLY_LIBRARY */ + /* 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; + } + + /* 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; + + if(!resize_buffers_(encoder, encoder->protected_->blocksize)) { + /* the above function sets the state for us in case of an error */ + return encoder->protected_->state; + } + + if(!FLAC__bitbuffer_init(encoder->private_->frame)) + return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + + /* + * Set up the verify stuff if necessary + */ + if(encoder->protected_->verify) { + /* + * First, set up the fifo which will hold the + * original signal to compare against + */ + encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize; + 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; + } + 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; + } + encoder->private_->verify.error_stats.absolute_sample = 0; + encoder->private_->verify.error_stats.frame_number = 0; + encoder->private_->verify.error_stats.channel = 0; + encoder->private_->verify.error_stats.sample = 0; + encoder->private_->verify.error_stats.expected = 0; + encoder->private_->verify.error_stats.got = 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)) { + /* the above function sets the state for us in case of an error */ + return encoder->protected_->state; + } + + /* + * write the STREAMINFO metadata block + */ + 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)) { + /* the above function sets the state for us in case of an error */ + return encoder->protected_->state; + } + + /* + * 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; + /* ... and clear this to 0 */ + encoder->private_->metadata.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 is true it will have already + * insured that the metadata list is properly ordered.) + */ + if(!metadata_has_vorbis_comment) { + FLAC__StreamMetadata vorbis_comment; + vorbis_comment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT; + vorbis_comment.is_last = (encoder->protected_->num_metadata_blocks == 0); + vorbis_comment.length = 4 + 4; /* MAGIC NUMBER */ + vorbis_comment.data.vorbis_comment.vendor_string.length = 0; + 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)) { + /* the above function sets the state for us in case of an error */ + return encoder->protected_->state; + } + } + + /* + * write the user's metadata blocks + */ + 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)) { + /* the above function sets the state for us in case of an error */ + return encoder->protected_->state; + } + } + + if(encoder->protected_->verify) + encoder->private_->verify.state_hint = ENCODER_IN_AUDIO; + + return encoder->protected_->state; +} + +FLAC_API void FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + + if(encoder->protected_->state == FLAC__STREAM_ENCODER_UNINITIALIZED) + return; + + if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) { + if(encoder->private_->current_sample_number != 0) { + encoder->protected_->blocksize = encoder->private_->current_sample_number; + process_frame_(encoder, true); /* true => is last frame */ + } + } + + FLAC__MD5Final(encoder->private_->metadata.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->protected_->verify && 0 != encoder->private_->verify.decoder) + FLAC__stream_decoder_finish(encoder->private_->verify.decoder); + + free_(encoder); + set_defaults_(encoder); + + encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; +#ifndef FLAC__MANDATORY_VERIFY_WHILE_ENCODING + encoder->protected_->verify = value; +#endif + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->streamable_subset = 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); + 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); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->loose_mid_side_stereo = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->channels = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->bits_per_sample = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + 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_blocksize(FLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->blocksize = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->max_lpc_order = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->qlp_coeff_precision = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->do_qlp_coeff_prec_search = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; +#if 0 + /*@@@ deprecated: */ + encoder->protected_->do_escape_coding = value; +#else + (void)value; +#endif + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->do_exhaustive_model_search = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->min_residual_partition_order = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->max_residual_partition_order = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; +#if 0 + /*@@@ deprecated: */ + encoder->protected_->rice_parameter_search_dist = value; +#else + (void)value; +#endif + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->protected_->total_samples_estimate = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks) +{ + FLAC__ASSERT(0 != encoder); + 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) + 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__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->private_->disable_constant_subframes = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->private_->disable_fixed_subframes = value; + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->private_->disable_verbatim_subframes = value; + return true; +} + +FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + return encoder->protected_->state; +} + +FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + if(encoder->protected_->verify) + return FLAC__stream_decoder_get_state(encoder->private_->verify.decoder); + else + return FLAC__STREAM_DECODER_UNINITIALIZED; +} + +FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder) +{ + if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) + return FLAC__StreamEncoderStateString[encoder->protected_->state]; + else + return FLAC__stream_decoder_get_resolved_state_string(encoder->private_->verify.decoder); +} + +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); + if(0 != absolute_sample) + *absolute_sample = encoder->private_->verify.error_stats.absolute_sample; + if(0 != frame_number) + *frame_number = encoder->private_->verify.error_stats.frame_number; + if(0 != channel) + *channel = encoder->private_->verify.error_stats.channel; + if(0 != sample) + *sample = encoder->private_->verify.error_stats.sample; + if(0 != expected) + *expected = encoder->private_->verify.error_stats.expected; + if(0 != got) + *got = encoder->private_->verify.error_stats.got; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + return encoder->protected_->verify; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + return encoder->protected_->streamable_subset; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(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_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + return encoder->protected_->channels; +} + +FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + return encoder->protected_->bits_per_sample; +} + +FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + return encoder->protected_->sample_rate; +} + +FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + return encoder->protected_->blocksize; +} + +FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + return encoder->protected_->max_lpc_order; +} + +FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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; + const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize; + + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK); + + j = 0; + /* + * we have several flavors of the same basic loop, optimized for + * different conditions: + */ + if(encoder->protected_->max_lpc_order > 0) { + if(encoder->protected_->do_mid_side_stereo && channels == 2) { + /* + * stereo coding: unroll channel loop + * with LPC: calculate floating point version of signal + */ + 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)); + + 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; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal[0][i] = (FLAC__real)x; +#endif + x = buffer[1][j]; + encoder->private_->integer_signal[1][i] = x; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal[1][i] = (FLAC__real)x; +#endif + 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; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal_mid_side[1][i] = (FLAC__real)side; + encoder->private_->real_signal_mid_side[0][i] = (FLAC__real)mid; +#endif + encoder->private_->current_sample_number++; + } + if(i == blocksize) { + if(!process_frame_(encoder, false)) /* false => not last frame */ + return false; + } + } while(j < samples); + } + else { + /* + * independent channel coding: buffer each channel in inner loop + * with LPC: calculate floating point version of signal + */ + 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)); + + 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; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal[channel][i] = (FLAC__real)x; +#endif + } + encoder->private_->current_sample_number++; + } + if(i == blocksize) { + if(!process_frame_(encoder, false)) /* false => not last frame */ + return false; + } + } while(j < samples); + } + } + else { + if(encoder->protected_->do_mid_side_stereo && channels == 2) { + /* + * stereo coding: unroll channel loop + * without LPC: no need to calculate floating point version of signal + */ + 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)); + + for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) { + encoder->private_->integer_signal[0][i] = mid = side = buffer[0][j]; + x = buffer[1][j]; + encoder->private_->integer_signal[1][i] = 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_->current_sample_number++; + } + if(i == blocksize) { + if(!process_frame_(encoder, false)) /* false => not last frame */ + return false; + } + } while(j < samples); + } + else { + /* + * independent channel coding: buffer each channel in inner loop + * without LPC: no need to calculate floating point version of signal + */ + 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)); + + 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[channel][j]; + encoder->private_->current_sample_number++; + } + if(i == blocksize) { + if(!process_frame_(encoder, false)) /* false => not last frame */ + return false; + } + } while(j < samples); + } + } + + return true; +} + +FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples) +{ + unsigned i, j, k, channel; + FLAC__int32 x, mid, side; + const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize; + + FLAC__ASSERT(0 != encoder); + 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_->max_lpc_order > 0) { + if(encoder->protected_->do_mid_side_stereo && channels == 2) { + /* + * stereo coding: unroll channel loop + * with LPC: calculate floating point version of signal + */ + 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)); + + 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; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal[0][i] = (FLAC__real)x; +#endif + x = buffer[k++]; + encoder->private_->integer_signal[1][i] = x; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal[1][i] = (FLAC__real)x; +#endif + 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; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal_mid_side[1][i] = (FLAC__real)side; + encoder->private_->real_signal_mid_side[0][i] = (FLAC__real)mid; +#endif + encoder->private_->current_sample_number++; + } + if(i == blocksize) { + if(!process_frame_(encoder, false)) /* false => not last frame */ + return false; + } + } while(j < samples); + } + else { + /* + * independent channel coding: buffer each channel in inner loop + * with LPC: calculate floating point version of signal + */ + 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)); + + 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; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal[channel][i] = (FLAC__real)x; +#endif + } + encoder->private_->current_sample_number++; + } + if(i == blocksize) { + if(!process_frame_(encoder, false)) /* false => not last frame */ + return false; + } + } while(j < samples); + } + } + else { + if(encoder->protected_->do_mid_side_stereo && channels == 2) { + /* + * stereo coding: unroll channel loop + * without LPC: no need to calculate floating point version of signal + */ + 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)); + + 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; + 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_->current_sample_number++; + } + if(i == blocksize) { + if(!process_frame_(encoder, false)) /* false => not last frame */ + return false; + } + } while(j < samples); + } + else { + /* + * independent channel coding: buffer each channel in inner loop + * without LPC: no need to calculate floating point version of signal + */ + 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)); + + 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++]; + encoder->private_->current_sample_number++; + } + if(i == blocksize) { + if(!process_frame_(encoder, false)) /* false => not last frame */ + return false; + } + } while(j < samples); + } + } + + return true; +} + +/*********************************************************************** + * + * Private class methods + * + ***********************************************************************/ + +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_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_->max_lpc_order = 0; + encoder->protected_->qlp_coeff_precision = 0; + encoder->protected_->do_qlp_coeff_prec_search = false; + encoder->protected_->do_exhaustive_model_search = false; + encoder->protected_->do_escape_coding = false; + encoder->protected_->min_residual_partition_order = 0; + encoder->protected_->max_residual_partition_order = 0; + encoder->protected_->rice_parameter_search_dist = 0; + encoder->protected_->total_samples_estimate = 0; + encoder->protected_->metadata = 0; + encoder->protected_->num_metadata_blocks = 0; + + encoder->private_->disable_constant_subframes = false; + encoder->private_->disable_fixed_subframes = false; + encoder->private_->disable_verbatim_subframes = false; + encoder->private_->write_callback = 0; + encoder->private_->metadata_callback = 0; + encoder->private_->client_data = 0; +} + +void free_(FLAC__StreamEncoder *encoder) +{ + unsigned i, channel; + + FLAC__ASSERT(0 != encoder); + 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 + } + for(channel = 0; channel < encoder->protected_->channels; channel++) { + for(i = 0; i < 2; i++) { + if(0 != encoder->private_->residual_workspace_unaligned[channel][i]) { + free(encoder->private_->residual_workspace_unaligned[channel][i]); + encoder->private_->residual_workspace_unaligned[channel][i] = 0; + } + } + } + for(channel = 0; channel < 2; channel++) { + for(i = 0; i < 2; i++) { + if(0 != encoder->private_->residual_workspace_mid_side_unaligned[channel][i]) { + free(encoder->private_->residual_workspace_mid_side_unaligned[channel][i]); + encoder->private_->residual_workspace_mid_side_unaligned[channel][i] = 0; + } + } + } + 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; + } + if(0 != encoder->private_->raw_bits_per_partition_unaligned) { + free(encoder->private_->raw_bits_per_partition_unaligned); + encoder->private_->raw_bits_per_partition_unaligned = 0; + } + if(encoder->protected_->verify) { + for(i = 0; i < encoder->protected_->channels; i++) { + if(0 != encoder->private_->verify.input_fifo.data[i]) { + free(encoder->private_->verify.input_fifo.data[i]); + encoder->private_->verify.input_fifo.data[i] = 0; + } + } + } + FLAC__bitbuffer_free(encoder->private_->frame); +} + +FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_size) +{ + FLAC__bool ok; + unsigned i, channel; + + FLAC__ASSERT(new_size > 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) + 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) + * 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. + */ + + 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]); +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(encoder->protected_->max_lpc_order > 0) + ok = ok && FLAC__memory_alloc_aligned_real_array(new_size, &encoder->private_->real_signal_unaligned[i], &encoder->private_->real_signal[i]); +#endif + memset(encoder->private_->integer_signal[i], 0, sizeof(FLAC__int32)*4); + encoder->private_->integer_signal[i] += 4; + } + 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]); +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(encoder->protected_->max_lpc_order > 0) + 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]); +#endif + memset(encoder->private_->integer_signal_mid_side[i], 0, sizeof(FLAC__int32)*4); + encoder->private_->integer_signal_mid_side[i] += 4; + } + 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]); + } + } + 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_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); + 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); + + if(ok) + encoder->private_->input_capacity = new_size; + else + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + + return ok; +} + +FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples) +{ + const FLAC__byte *buffer; + unsigned bytes; + + FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(encoder->private_->frame)); + + FLAC__bitbuffer_get_buffer(encoder->private_->frame, &buffer, &bytes); + + if(encoder->protected_->verify) { + encoder->private_->verify.output.data = buffer; + encoder->private_->verify.output.bytes = bytes; + if(encoder->private_->verify.state_hint == ENCODER_IN_MAGIC) { + encoder->private_->verify.needs_magic_hack = true; + } + else { + if(!FLAC__stream_decoder_process_single(encoder->private_->verify.decoder)) { + FLAC__bitbuffer_release_buffer(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; + } + } + } + + 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; + return false; + } + + FLAC__bitbuffer_release_buffer(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); + } + + return true; +} + +FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame) +{ + 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)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + /* + * Process the frame header and subframes into the frame bitbuffer + */ + if(!process_subframes_(encoder, is_last_frame)) { + /* the above function sets the state for us in case of an error */ + return false; + } + + /* + * Zero-pad the frame to a byte_boundary + */ + if(!FLAC__bitbuffer_zero_pad_to_byte_boundary(encoder->private_->frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + /* + * 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); + + /* + * Write it + */ + if(!write_bitbuffer_(encoder, encoder->protected_->blocksize)) { + /* the above function sets the state for us in case of an error */ + return false; + } + + /* + * Get ready for the next 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; + + return true; +} + +FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame) +{ + 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; + + /* + * Calculate the min,max Rice partition orders + */ + if(is_last_frame) { + 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); + } + 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); + + /* + * 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; + frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; /* the default unless the encoder determines otherwise */ + frame_header.bits_per_sample = encoder->protected_->bits_per_sample; + frame_header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER; + frame_header.number.frame_number = encoder->private_->current_frame_number; + + /* + * Figure out what channel assignments to try + */ + if(encoder->protected_->do_mid_side_stereo) { + if(encoder->protected_->loose_mid_side_stereo) { + if(encoder->private_->loose_mid_side_stereo_frame_count == 0) { + do_independent = true; + do_mid_side = true; + } + else { + do_independent = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT); + do_mid_side = !do_independent; + } + } + else { + do_independent = true; + do_mid_side = true; + } + } + else { + do_independent = true; + do_mid_side = false; + } + + FLAC__ASSERT(do_independent || do_mid_side); + + /* + * Check for wasted bits; set effective bps for each subframe + */ + if(do_independent) { + for(channel = 0; channel < encoder->protected_->channels; channel++) { + const unsigned w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize); + encoder->private_->subframe_workspace[channel][0].wasted_bits = encoder->private_->subframe_workspace[channel][1].wasted_bits = w; + encoder->private_->subframe_bps[channel] = encoder->protected_->bits_per_sample - w; + } + } + if(do_mid_side) { + FLAC__ASSERT(encoder->protected_->channels == 2); + for(channel = 0; channel < 2; channel++) { + const unsigned w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize); + encoder->private_->subframe_workspace_mid_side[channel][0].wasted_bits = encoder->private_->subframe_workspace_mid_side[channel][1].wasted_bits = w; + encoder->private_->subframe_bps_mid_side[channel] = encoder->protected_->bits_per_sample - w + (channel==0? 0:1); + } + } + + /* + * First do a normal encoding pass of each independent channel + */ + if(do_independent) { + for(channel = 0; channel < encoder->protected_->channels; channel++) { + if(! + process_subframe_( + encoder, + min_partition_order, + max_partition_order, + precompute_partition_sums, + &frame_header, + encoder->private_->subframe_bps[channel], + encoder->private_->integer_signal[channel], +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal[channel], +#endif + encoder->private_->subframe_workspace_ptr[channel], + encoder->private_->partitioned_rice_contents_workspace_ptr[channel], + encoder->private_->residual_workspace[channel], + encoder->private_->best_subframe+channel, + encoder->private_->best_subframe_bits+channel + ) + ) + return false; + } + } + + /* + * Now do mid and side channels if requested + */ + if(do_mid_side) { + FLAC__ASSERT(encoder->protected_->channels == 2); + + for(channel = 0; channel < 2; channel++) { + if(! + process_subframe_( + 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], +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->private_->real_signal_mid_side[channel], +#endif + 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], + encoder->private_->best_subframe_mid_side+channel, + encoder->private_->best_subframe_bits_mid_side+channel + ) + ) + return false; + } + } + + /* + * Compose the frame bitbuffer + */ + if(do_mid_side) { + unsigned left_bps = 0, right_bps = 0; /* initialized only to prevent superfluous compiler warning */ + FLAC__Subframe *left_subframe = 0, *right_subframe = 0; /* initialized only to prevent superfluous compiler warning */ + FLAC__ChannelAssignment channel_assignment; + + FLAC__ASSERT(encoder->protected_->channels == 2); + + if(encoder->protected_->loose_mid_side_stereo && encoder->private_->loose_mid_side_stereo_frame_count > 0) { + channel_assignment = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT? FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT : FLAC__CHANNEL_ASSIGNMENT_MID_SIDE); + } + else { + unsigned bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */ + unsigned min_bits; + FLAC__ChannelAssignment ca; + + FLAC__ASSERT(do_independent && do_mid_side); + + /* We have to figure out which channel assignent results in the smallest frame */ + bits[FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT] = encoder->private_->best_subframe_bits [0] + encoder->private_->best_subframe_bits [1]; + bits[FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE ] = encoder->private_->best_subframe_bits [0] + encoder->private_->best_subframe_bits_mid_side[1]; + 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)) { + if(bits[ca] < min_bits) { + min_bits = bits[ca]; + channel_assignment = ca; + } + } + } + + frame_header.channel_assignment = channel_assignment; + + if(!FLAC__frame_add_header(&frame_header, encoder->protected_->streamable_subset, encoder->private_->frame)) { + encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR; + return false; + } + + switch(channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]]; + right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]]; + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]]; + right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + left_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; + right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]]; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + left_subframe = &encoder->private_->subframe_workspace_mid_side[0][encoder->private_->best_subframe_mid_side[0]]; + right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; + break; + default: + FLAC__ASSERT(0); + } + + switch(channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + left_bps = encoder->private_->subframe_bps [0]; + right_bps = encoder->private_->subframe_bps [1]; + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + left_bps = encoder->private_->subframe_bps [0]; + right_bps = encoder->private_->subframe_bps_mid_side[1]; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + left_bps = encoder->private_->subframe_bps_mid_side[1]; + right_bps = encoder->private_->subframe_bps [1]; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + left_bps = encoder->private_->subframe_bps_mid_side[0]; + right_bps = encoder->private_->subframe_bps_mid_side[1]; + break; + default: + FLAC__ASSERT(0); + } + + /* 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)) + return false; + if(!add_subframe_(encoder, &frame_header, right_bps, right_subframe, encoder->private_->frame)) + return false; + } + else { + if(!FLAC__frame_add_header(&frame_header, encoder->protected_->streamable_subset, 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)) { + /* the above function sets the state for us in case of an error */ + return false; + } + } + } + + if(encoder->protected_->loose_mid_side_stereo) { + encoder->private_->loose_mid_side_stereo_frame_count++; + if(encoder->private_->loose_mid_side_stereo_frame_count >= encoder->private_->loose_mid_side_stereo_frames) + encoder->private_->loose_mid_side_stereo_frame_count = 0; + } + + encoder->private_->last_channel_assignment = frame_header.channel_assignment; + + return true; +} + +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[], +#ifndef FLAC__INTEGER_ONLY_LIBRARY + const FLAC__real real_signal[], +#endif + FLAC__Subframe *subframe[2], + FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2], + FLAC__int32 *residual[2], + unsigned *best_subframe, + unsigned *best_bits +) +{ +#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 routines need all the space */ + FLAC__double lpc_error[FLAC__MAX_LPC_ORDER]; + unsigned min_lpc_order, max_lpc_order, lpc_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; + + /* 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]); + + 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 && +#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 < frame_header->blocksize; i++) { + if(integer_signal[0] != integer_signal[i]) { + signal_is_constant = false; + break; + } + } + } + if(signal_is_constant) { + _candidate_bits = evaluate_constant_subframe_(integer_signal[0], subframe_bps, subframe[!_best_subframe]); + if(_candidate_bits < _best_bits) { + _best_subframe = !_best_subframe; + _best_bits = _candidate_bits; + } + } + else { + if(!encoder->private_->disable_fixed_subframes || (encoder->protected_->max_lpc_order == 0 && _best_bits == UINT_MAX)) { + /* encode fixed */ + if(encoder->protected_->do_exhaustive_model_search) { + min_fixed_order = 0; + max_fixed_order = FLAC__MAX_FIXED_ORDER; + } + else { + min_fixed_order = max_fixed_order = guess_fixed_order; + } + for(fixed_order = min_fixed_order; fixed_order <= max_fixed_order; fixed_order++) { +#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 */ +#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 +#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) @0\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1); +#endif + rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 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, + 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] + ); + if(_candidate_bits < _best_bits) { + _best_subframe = !_best_subframe; + _best_bits = _candidate_bits; + } + } + } + +#ifndef FLAC__INTEGER_ONLY_LIBRARY + /* encode lpc */ + if(encoder->protected_->max_lpc_order > 0) { + if(encoder->protected_->max_lpc_order >= frame_header->blocksize) + max_lpc_order = frame_header->blocksize-1; + 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__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 */ +#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; + } + 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], + 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] + ); + 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; + } + } + } + } + } + } + } +#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_subframe = _best_subframe; + *best_bits = _best_bits; + + return true; +} + +FLAC__bool add_subframe_( + FLAC__StreamEncoder *encoder, + const FLAC__FrameHeader *frame_header, + unsigned subframe_bps, + const FLAC__Subframe *subframe, + FLAC__BitBuffer *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; + 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; + 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; + 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; + return false; + } + break; + default: + FLAC__ASSERT(0); + } + + return true; +} + +unsigned evaluate_constant_subframe_( + const FLAC__int32 signal, + unsigned subframe_bps, + FLAC__Subframe *subframe +) +{ + 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; +} + +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 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; + const unsigned residual_samples = blocksize - order; + + FLAC__fixed_compute_residual(signal+order, residual_samples, order, residual); + + subframe->type = FLAC__SUBFRAME_TYPE_FIXED; + + subframe->data.fixed.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE; + subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents; + subframe->data.fixed.residual = residual; + + residual_bits = + find_best_partition_order_( + encoder->private_, + residual, + abs_residual, + abs_residual_partition_sums, + raw_bits_per_partition, + residual_samples, + order, + rice_parameter, + min_partition_order, + max_partition_order, + precompute_partition_sums, + do_escape_coding, + rice_parameter_search_dist, + &subframe->data.fixed.entropy_coding_method.data.partitioned_rice + ); + + 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; +} + +#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[], + unsigned blocksize, + unsigned subframe_bps, + unsigned order, + unsigned qlp_coeff_precision, + unsigned rice_parameter, + 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; + int quantization, ret; + const unsigned residual_samples = blocksize - order; + + /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps streams */ + 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)); + } + + ret = FLAC__lpc_quantize_coefficients(lp_coeff, order, qlp_coeff_precision, qlp_coeff, &quantization); + if(ret != 0) + return 0; /* this is a hack to indicate to the caller that we can't do lp at this order on this subframe */ + + if(subframe_bps + qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32) + if(subframe_bps <= 16 && qlp_coeff_precision <= 16) + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual); + else + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(signal+order, residual_samples, qlp_coeff, order, quantization, residual); + else + encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual); + + subframe->type = FLAC__SUBFRAME_TYPE_LPC; + + subframe->data.lpc.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE; + subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents; + subframe->data.lpc.residual = residual; + + residual_bits = + find_best_partition_order_( + encoder->private_, + residual, + abs_residual, + abs_residual_partition_sums, + raw_bits_per_partition, + residual_samples, + order, + rice_parameter, + min_partition_order, + max_partition_order, + precompute_partition_sums, + do_escape_coding, + rice_parameter_search_dist, + &subframe->data.fixed.entropy_coding_method.data.partitioned_rice + ); + + subframe->data.lpc.order = order; + subframe->data.lpc.qlp_coeff_precision = qlp_coeff_precision; + subframe->data.lpc.quantization_level = quantization; + memcpy(subframe->data.lpc.qlp_coeff, qlp_coeff, sizeof(FLAC__int32)*FLAC__MAX_LPC_ORDER); + 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; +} +#endif + +unsigned evaluate_verbatim_subframe_( + const FLAC__int32 signal[], + unsigned blocksize, + unsigned subframe_bps, + FLAC__Subframe *subframe +) +{ + 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); +} + +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 min_partition_order, + unsigned max_partition_order, + FLAC__bool precompute_partition_sums, + FLAC__bool do_escape_coding, + unsigned rice_parameter_search_dist, + FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice +) +{ + FLAC__int32 r; + unsigned residual_bits, best_residual_bits = 0; + unsigned residual_sample; + unsigned best_parameters_index = 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); + + if(precompute_partition_sums) { + int partition_order; + unsigned sum; + + 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); + + 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_( + 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 + ) + ) +#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; + } + sum += 1u << 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; + } + } + } + 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); + 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[], + FLAC__uint64 abs_residual_partition_sums[], + unsigned residual_samples, + unsigned predictor_order, + unsigned min_partition_order, + unsigned max_partition_order +) +{ + 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; + + 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++; + } + 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++; + } + } +} + +void precompute_partition_info_escapes_( + const FLAC__int32 residual[], + unsigned raw_bits_per_partition[], + unsigned residual_samples, + unsigned predictor_order, + unsigned min_partition_order, + unsigned max_partition_order +) +{ + 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__int32 r, residual_partition_min, residual_partition_max; + unsigned silog2_min, silog2_max; + unsigned partition, partition_sample, partition_samples, residual_sample; + const unsigned partitions = 1u << partition_order; + const unsigned default_partition_samples = blocksize >> partition_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; + residual_partition_min = residual_partition_max = 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++; + } + 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); + } + to_partition = partitions; + break; + } + + /* now merge partitions for lower orders */ + for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) { + unsigned m; + unsigned i; + const unsigned partitions = 1u << partition_order; + 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]); + 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 +) +#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 +) +#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 + /* 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 + */ + 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; +} + +#ifdef DONT_ESTIMATE_RICE_BITS +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 +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 bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; + unsigned *parameters, *raw_bits; + + 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; + raw_bits = partitioned_rice_contents->raw_bits; + + 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) @5\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[] 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; + } + } +#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) { + raw_bits[0] = raw_bits_per_partition[0]; + best_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; + best_partition_bits = flat_bits; + } + } + 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 = 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 + /* 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 + */ + 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) @6\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) @7\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[] instead of 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 + 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) { + raw_bits[partition] = raw_bits_per_partition[partition]; + best_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; + best_partition_bits = flat_bits; + } + } + parameters[partition] = best_rice_parameter; + bits_ += best_partition_bits; + } + } + + *bits = bits_; + return true; +} + +unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples) +{ + unsigned i, shift; + FLAC__int32 x = 0; + + for(i = 0; i < samples && !(x&1); i++) + x |= signal[i]; + + if(x == 0) { + shift = 0; + } + else { + for(shift = 0; !(x&1); shift++) + x >>= 1; + } + + if(shift > 0) { + for(i = 0; i < samples; i++) + signal[i] >>= shift; + } + + return shift; +} + +void append_to_verify_fifo_(verify_input_fifo *fifo, const FLAC__int32 * const input[], unsigned input_offset, unsigned channels, unsigned wide_samples) +{ + unsigned channel; + + for(channel = 0; channel < channels; channel++) + memcpy(&fifo->data[channel][fifo->tail], &input[channel][input_offset], sizeof(FLAC__int32) * wide_samples); + + fifo->tail += wide_samples; + + FLAC__ASSERT(fifo->tail <= fifo->size); +} + +void append_to_verify_fifo_interleaved_(verify_input_fifo *fifo, const FLAC__int32 input[], unsigned input_offset, unsigned channels, unsigned wide_samples) +{ + unsigned channel; + unsigned sample, wide_sample; + unsigned tail = fifo->tail; + + sample = input_offset * channels; + for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) { + for(channel = 0; channel < channels; channel++) + fifo->data[channel][tail] = input[sample++]; + tail++; + } + fifo->tail = tail; + + FLAC__ASSERT(fifo->tail <= fifo->size); +} + +FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) +{ + FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data; + const unsigned encoded_bytes = encoder->private_->verify.output.bytes; + (void)decoder; + + if(encoder->private_->verify.needs_magic_hack) { + FLAC__ASSERT(*bytes >= FLAC__STREAM_SYNC_LENGTH); + *bytes = FLAC__STREAM_SYNC_LENGTH; + memcpy(buffer, FLAC__STREAM_SYNC_STRING, *bytes); + encoder->private_->verify.needs_magic_hack = false; + } + else { + if(encoded_bytes == 0) { + /* + * If we get here, a FIFO underflow has occurred, + * which means there is a bug somewhere. + */ + FLAC__ASSERT(0); + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + else if(encoded_bytes < *bytes) + *bytes = encoded_bytes; + memcpy(buffer, encoder->private_->verify.output.data, *bytes); + encoder->private_->verify.output.data += *bytes; + encoder->private_->verify.output.bytes -= *bytes; + } + + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; +} + +FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder *)client_data; + unsigned channel; + const unsigned channels = FLAC__stream_decoder_get_channels(decoder); + const unsigned blocksize = frame->header.blocksize; + const unsigned bytes_per_block = sizeof(FLAC__int32) * blocksize; + + 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; + FLAC__int32 expect = 0, got = 0; + + for(i = 0; i < blocksize; i++) { + if(buffer[channel][i] != encoder->private_->verify.input_fifo.data[channel][i]) { + sample = i; + expect = (FLAC__int32)encoder->private_->verify.input_fifo.data[channel][i]; + got = (FLAC__int32)buffer[channel][i]; + break; + } + } + FLAC__ASSERT(i < blocksize); + FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + encoder->private_->verify.error_stats.absolute_sample = frame->header.number.sample_number + sample; + encoder->private_->verify.error_stats.frame_number = (unsigned)(frame->header.number.sample_number / blocksize); + encoder->private_->verify.error_stats.channel = channel; + encoder->private_->verify.error_stats.sample = sample; + encoder->private_->verify.error_stats.expected = expect; + encoder->private_->verify.error_stats.got = got; + encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } + /* 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; + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + (void)decoder, (void)metadata, (void)client_data; +} + +void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data; + (void)decoder, (void)status; + encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR; +} diff --git a/apps/codecs/libFLAC/stream_encoder_framing.c b/apps/codecs/libFLAC/stream_encoder_framing.c new file mode 100644 index 0000000000..36bf952456 --- /dev/null +++ b/apps/codecs/libFLAC/stream_encoder_framing.c @@ -0,0 +1,499 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000,2001,2002,2003,2004,2005 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 +#include /* 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); + +FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitBuffer *bb) +{ + 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)) + return false; + + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN)) + return false; + + /* + * First, for VORBIS_COMMENTs, adjust the length to reflect our vendor string + */ + i = metadata->length; + if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + FLAC__ASSERT(metadata->data.vorbis_comment.vendor_string.length == 0 || 0 != metadata->data.vorbis_comment.vendor_string.entry); + i -= metadata->data.vorbis_comment.vendor_string.length; + 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)) + 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)) + 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)) + 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)) + 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)) + 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)) + 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)) + 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)) + return false; + if(!FLAC__bitbuffer_write_raw_uint64(bb, 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)) + return false; + break; + case FLAC__METADATA_TYPE_PADDING: + if(!FLAC__bitbuffer_write_zeroes(bb, 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)) + return false; + if(!FLAC__bitbuffer_write_byte_block(bb, 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)) + return false; + if(!FLAC__bitbuffer_write_raw_uint64(bb, 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)) + return false; + } + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + if(!FLAC__bitbuffer_write_raw_uint32_little_endian(bb, vendor_string_length)) + return false; + if(!FLAC__bitbuffer_write_byte_block(bb, (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)) + 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)) + return false; + if(!FLAC__bitbuffer_write_byte_block(bb, 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)) + return false; + if(!FLAC__bitbuffer_write_raw_uint64(bb, 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)) + return false; + if(!FLAC__bitbuffer_write_zeroes(bb, 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)) + 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)) + return false; + if(!FLAC__bitbuffer_write_raw_uint32(bb, 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)) + return false; + if(!FLAC__bitbuffer_write_raw_uint32(bb, 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)) + return false; + if(!FLAC__bitbuffer_write_zeroes(bb, 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)) + return false; + for(j = 0; j < track->num_indices; j++) { + const FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j; + + if(!FLAC__bitbuffer_write_raw_uint64(bb, index->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)) + return false; + if(!FLAC__bitbuffer_write_zeroes(bb, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN)) + return false; + } + } + break; + default: + if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.unknown.data, metadata->length)) + return false; + break; + } + + FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(bb)); + return true; +} + +FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__bool streamable_subset, FLAC__BitBuffer *bb) +{ + unsigned u, blocksize_hint, sample_rate_hint; + + FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(bb)); + + if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN)) + return false; + + if(!FLAC__bitbuffer_write_raw_uint32(bb, 0, FLAC__FRAME_HEADER_RESERVED_LEN)) + return false; + + FLAC__ASSERT(header->blocksize > 0 && header->blocksize <= FLAC__MAX_BLOCK_SIZE); + /* when this assertion holds true, any legal blocksize can be expressed in the frame header */ + FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535u); + blocksize_hint = 0; + switch(header->blocksize) { + case 192: u = 1; break; + case 576: u = 2; break; + case 1152: u = 3; break; + case 2304: u = 4; break; + case 4608: u = 5; break; + case 256: u = 8; break; + case 512: u = 9; break; + case 1024: u = 10; break; + case 2048: u = 11; break; + case 4096: u = 12; break; + case 8192: u = 13; break; + case 16384: u = 14; break; + case 32768: u = 15; break; + default: + if(header->blocksize <= 0x100) + blocksize_hint = u = 6; + else if(header->blocksize <= 0x10000) + 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)) + 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; + default: + if(header->sample_rate <= 255000 && header->sample_rate % 1000 == 0) + sample_rate_hint = u = 12; + else if(header->sample_rate % 10 == 0) + 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)) + return false; + + FLAC__ASSERT(header->channels > 0 && header->channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN) && header->channels <= FLAC__MAX_CHANNELS); + switch(header->channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + u = header->channels - 1; + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + FLAC__ASSERT(header->channels == 2); + u = 8; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + FLAC__ASSERT(header->channels == 2); + u = 9; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + FLAC__ASSERT(header->channels == 2); + u = 10; + break; + default: + FLAC__ASSERT(0); + } + if(!FLAC__bitbuffer_write_raw_uint32(bb, 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)); + switch(header->bits_per_sample) { + case 8 : u = 1; break; + case 12: u = 2; break; + case 16: u = 4; break; + case 20: u = 5; break; + case 24: u = 6; break; + default: u = 0; break; + } + if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN)) + return false; + + if(!FLAC__bitbuffer_write_raw_uint32(bb, 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(blocksize_hint) + if(!FLAC__bitbuffer_write_raw_uint32(bb, 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)) + return false; + break; + case 13: + if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate, 16)) + return false; + break; + case 14: + if(!FLAC__bitbuffer_write_raw_uint32(bb, 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)) + 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 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) + ; + + 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) +{ + 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)) + return false; + if(wasted_bits) + if(!FLAC__bitbuffer_write_unary_unsigned(bb, wasted_bits-1)) + return false; + + for(i = 0; i < subframe->order; i++) + if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->warmup[i], subframe_bps)) + return false; + + if(!add_entropy_coding_method_(bb, &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)) + return false; + break; + default: + FLAC__ASSERT(0); + } + + 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) +{ + 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)) + return false; + if(wasted_bits) + if(!FLAC__bitbuffer_write_unary_unsigned(bb, wasted_bits-1)) + return false; + + for(i = 0; i < subframe->order; i++) + if(!FLAC__bitbuffer_write_raw_int32(bb, 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)) + return false; + if(!FLAC__bitbuffer_write_raw_int32(bb, 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)) + return false; + + if(!add_entropy_coding_method_(bb, &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)) + return false; + break; + default: + FLAC__ASSERT(0); + } + + return true; +} + +FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb) +{ + 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)) + return false; + if(wasted_bits) + if(!FLAC__bitbuffer_write_unary_unsigned(bb, wasted_bits-1)) + return false; + + for(i = 0; i < samples; i++) + if(!FLAC__bitbuffer_write_raw_int32(bb, signal[i], subframe_bps)) + return false; + + return true; +} + +FLAC__bool add_entropy_coding_method_(FLAC__BitBuffer *bb, const FLAC__EntropyCodingMethod *method) +{ + if(!FLAC__bitbuffer_write_raw_uint32(bb, 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)) + return false; + break; + default: + FLAC__ASSERT(0); + } + 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) +{ + 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 + } + } + else { + if(!FLAC__bitbuffer_write_raw_uint32(bb, 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])) + return false; + } + } + return true; + } + else { + unsigned i, j, k = 0, k_last = 0; + unsigned partition_samples; + const unsigned default_partition_samples = (residual_samples+predictor_order) >> partition_order; + for(i = 0; i < (1u<