pax_global_header00006660000000000000000000000064127600347210014514gustar00rootroot0000000000000052 comment=4242ad726f51b72561b6dbb0e731f272f5b57a77 fdkaac-0.6.3/000077500000000000000000000000001276003472100127335ustar00rootroot00000000000000fdkaac-0.6.3/.gitattributes000066400000000000000000000000551276003472100156260ustar00rootroot00000000000000* text=auto *.sln text eol=crlf *.lib binary fdkaac-0.6.3/.gitignore000066400000000000000000000003421276003472100147220ustar00rootroot00000000000000*.o *~ Makefile Makefile.in aclocal.m4 autom4te.cache compile config.guess config.h config.h.in config.log config.status config.sub configure depcomp install-sh missing missings/.deps/ src/.deps/ src/.dirstamp stamp-h1 fdkaac fdkaac-0.6.3/AUTHORS000066400000000000000000000000001276003472100137710ustar00rootroot00000000000000fdkaac-0.6.3/COPYING000066400000000000000000000113361276003472100137720ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: fdkaac Upstream-Contact: nu774 Source: https://github.com/nu774/fdkaac Files: * Copyright: 2013-2014 nu774 License: Zlib Files: missings/getopt.c Copyright: 2002 Todd C. Miller 2000 The NetBSD Foundation, Inc. License: BSD-4-clause Files: missings/getopt.h Copyright: 2000 The NetBSD Foundation, Inc. License: BSD-4-clause Files: src/parson.* Copyright: 2012 Krzysztof Gabis License: MIT Files: src/lpc.h Copyright: 1994-2007 the Xiph.Org Foundation License: BSD Files: src/lpc.c Copyright: 1994-2007 the Xiph.Org Foundation 1992, 1993, 1994 Jutta Degener and Carsten Bormann, Technische Universität Berlin License: BSD-style License: Zlib This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. . Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: . 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. License: MIT Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. License: BSD-4-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by the NetBSD Foundation, Inc. and its contributors. 4. Neither the name of The NetBSD 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 NETBSD FOUNDATION, INC. 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. License: BSD-style Any use of this software is permitted provided that this notice is not removed and that neither the authors nor the Technische Universita"t Berlin are deemed to have made any representations as to the suitability of this software for any purpose nor are held responsible for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. fdkaac-0.6.3/ChangeLog000066400000000000000000000176601276003472100145170ustar00rootroot000000000000002015-02-14 nu774 * update ChangeLog [HEAD] * bump version [v0.6.2] * take stco->co64 switch due to mdat relocation into account on finalizing m4a * fix incorrect iTunSMPB written when interrupted by signals 2014-09-13 nu774 * update ChangeLog [origin/master] * bump version 2014-09-12 nu774 * write actual number of channels to mp4a box 2014-08-17 nu774 * update INSTALL * add m4 macros 2014-08-13 nu774 * update ChangeLog * bump version [v0.6.0] 2014-08-12 nu774 * apply limiter when input is float * refactor pcm reader framework 2014-07-30 nu774 * update ChangeLog * win32compat: fix aacenc_printf() not to write junk characters [v0.5.4] 2014-05-12 nu774 * write INSTALL 2014-03-14 nu774 * update COPYING (patch from darealshinji) 2014-02-17 nu774 * update ChangeLog * bump version [v0.5.3] * fix: CAF chan chunk using channel bitmap was not correctly handled 2014-01-18 nu774 * update ChangeLog * bump version [v0.5.2] * fix reading of caf file without chan chunk 2013-11-17 nu774 * Merge pull request #9 from rbrito/fix-typo 2013-11-18 Rogério Brito * man: Regen manpage with hyphens escaped. * README: Remove trailing whitespaces that end up in the manpages. * README: Fix typo in bandwidth to match CLI options. 2013-11-08 nu774 * add genman.sh, update fdkaac.1 * update ChangeLog * bump version [v0.5.1] * fix to use libFDKAAC signaling mode 1 2013-11-05 nu774 * fix README 2013-11-04 nu774 * rename README.md -> README * Update README -> README.md, generate groff manpage from README.md * update ChangeLog * update git2changelog to accept non-ascii output * add manpage 2013-11-03 nu774 * fix gcc warnings * Merge pull request #7 from rbrito/misc-fixes 2013-11-03 Rogério Brito * gitignore: Add list of files to ignore. 2013-11-03 nu774 * update ChangeLog * bump version [v0.5.0] * add --sbr-ratio to support AACENC_SBR_RATIO appeared on libFDK 3.4.12 * support 7.1 channel mode added on FDK 3.4.12 2013-10-30 nu774 * update ChangeLog * bump version [v0.4.2] * use tell() to obtain data chunk offset * rename aacenc_result_t -> aacenc_frame_t, simplify write_sample() * prepend 1 sample zero padding in case of SBR and enc_delay is odd * cleanup interface of aac_encode_frame() * add some copyright notice 2013-10-29 nu774 * smart padding for better gapless playback * fix unused variable warning * fix warning: cast size_t as sprintf() arg to int * fix vcxproj * fix pcm_seek() to inline 2013-10-27 nu774 * bump version [v0.4.1] * add --include-sbr-delay * fix help message: show -I as shorthand for --ignorelength * remove --sbr-signaling 2013-10-26 nu774 * re-fix #ifdef cond for lrint() * tag mapping: add recorded date and tempo, remove performer->artist 2013-10-25 nu774 * fix MSVC12 build issue * fix build issue on platform where fileno is a naive macro * update ChangeLog * bump version [v0.4.0] * update README 2013-10-24 nu774 * caf input support * refactor pcm io routines 2013-10-23 nu774 * cleanup metadata handling * --tag-from-json: properly support number/total format in json track field 2013-10-22 nu774 * bump version [v0.3.3] * fixed bogus sgpd written on --gapless-mode=1 and 2 2013-10-21 nu774 * bump version [v0.3.2] 2013-10-20 nu774 * reimplement int16 conversion as pcm_reader * add abstraction layer for pcm reading * improve handling of avgBitrate 2013-10-19 nu774 * update ChangeLog and git2changelog.py 2013-10-18 nu774 * bump version [v0.3.1] * update README * set avgBitrate field to zero for 14496-1 compliance 2013-09-07 nu774 * updated ChangeLog with new git2changelog.py 2013-06-14 nu774 * add --moov-before-mdat [v0.3.0] 2013-03-04 nu774 * fix an error message 2013-03-03 nu774 * bump version [v0.2.0] * add --gapless-mode 2013-02-20 nu774 * simplify __timeb64 condition * use fseeko64() on i686-pc-mingw32 2013-02-18 nu774 * fix build issue on i686-pc-mingw (struct __timeb64 is missing) 2013-02-17 nu774 * bump version [v0.1.9] * fix to accept option -C 2013-02-16 nu774 * bump version [v0.1.8] * refine json metadata importing * m4af: duplication check on adding tags 2013-02-15 nu774 * add --tag-from-json [v0.1.7] * fix implicit int variable decl. * update m4af 2013-02-03 nu774 * bump version [v0.1.6] * win32: change _wfopen() -> wfsopen() 2013-01-30 nu774 * update README (add note for character encoding) 2013-01-28 nu774 * bump version [v0.1.5] * gracefully shutdown on signals 2013-01-27 nu774 * fix MSVC project build issue 2013-01-25 nu774 * bump version [v0.1.4] * add --tag-from-file 2013-01-24 nu774 * add --silent 2013-01-19 nu774 * retab * bump version [v0.1.3] * fix crash on wrong long option, rename --ignore-length to --ignorelength 2013-01-17 nu774 * bump version [v0.1.2] * compat_win32: free argv with atexit() * take care of COPYRIGHT-SIGN in UTF-8 2013-01-15 nu774 * bump version [v0.1.1] * fix return type of put_type_entry() to void * add ADTS header size(7) to output byte length 2013-01-13 nu774 * fix mp4 duration & version calcuration [v0.1.0] 2013-01-11 nu774 * add support for xid * support for i686-pc-mingw32 (missing _vscprintf) 2013-01-10 nu774 * bump version [v0.0.9] * rename basename() -> aacenc_basename() and move to compat layer 2013-01-09 nu774 * add --tag and --long-tag * fix corner case of progress display * calculate length from file size * raw input support 2013-01-08 nu774 * insert a white space in progress message 2013-01-07 nu774 * fix typo of bitrate-mode option [v0.0.8] * more static inlining (missed on the previous commit) [v0.0.7] * check error of fread() and fwrite() [v0.0.6] * change inline->static inline to follow C99 semantics (for Clang) * explicitly add -lfdk-aac to LDADD in Makefile.am * add some files to EXTRA_DIST in Makefile.am * fixed a typo in usage message [v0.0.5] 2013-01-06 nu774 * add MSVC projects * add .gitattributes * more tweak on configure.ac and Makefile.am (take care of getopt_long) [v0.0.4] * use fstat() to test seekability of input file * retrieve bitrate for tool tag with aacEncoder_GetParam() * output to current working directory by default 2013-01-05 nu774 * zero clear LIB_INFO before calling aacEncGetLibInfo() [v0.0.3] * tweak configure.ac and Makefile.am * update version.h [v0.0.2] * fixed to clip before converting float to int * initial commit [v0.0.1] fdkaac-0.6.3/INSTALL000066400000000000000000000016521276003472100137700ustar00rootroot00000000000000Prerequiste ----------- To build fdkaac, you need the followings: - libfdk-aac (https://github.com/mstorsjo/fdk-aac) - GNU autoconf, GNU automake libfdk-aac is always required, and probably you have to build it yourself. Others are required only when you build by configure and make on Unix-like enviromnent (including Cygwin or MinGW), and usually you can install them through package manager of your system if they are not already present. Unix-like environment --------------------- You can build and install libfdkaac and fdkaac in the following step. 1) extract the source, and cd to the source directory 2) autoreconf -i 3) ./configure 4) make 5) sudo make install Depending on your requirements, you might want to add some extra arguments to configure script. You have to install libfdk-aac first, and do the same for fdkaac. Windows, MSVC ------------- Extract libfdk-aac under fdkaac directory, and open MSVC/fdkaac.sln. fdkaac-0.6.3/MSVC/000077500000000000000000000000001276003472100135035ustar00rootroot00000000000000fdkaac-0.6.3/MSVC/fdk-aac.vcxproj000066400000000000000000000362151276003472100164150ustar00rootroot00000000000000 Debug Win32 Debug x64 Release Win32 Release x64 {D7D4B982-8B16-4A10-8B1C-9527BD789709} Win32Proj fdk-aac v140_xp v120_xp v110_xp v100 StaticLibrary Unicode true false NotUsing Level3 WIN32;_LIB;%(PreprocessorDefinitions) ../fdk-aac/libaacenc/include;../fdk-aac/libFDK/include;../fdk-aac/libMpegTPEnc/include;../fdk-aac/libPCMutils/include;../fdk-aac/libSBRenc/include;../fdk-aac/libSYS/include Disabled MaxSpeed /Qvec-report:1 %(AdditionalOptions) __x86_64__;%(PreprocessorDefinitions) fdkaac-0.6.3/MSVC/fdk-aac.vcxproj.filters000066400000000000000000000525011276003472100200600ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files fdkaac-0.6.3/MSVC/fdkaac.sln000066400000000000000000000037001276003472100154320ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fdkaac", "fdkaac.vcxproj", "{E62D32CF-E308-40BD-9FF0-8266C6CAA9AA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fdk-aac", "fdk-aac.vcxproj", "{D7D4B982-8B16-4A10-8B1C-9527BD789709}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {E62D32CF-E308-40BD-9FF0-8266C6CAA9AA}.Debug|Win32.ActiveCfg = Debug|Win32 {E62D32CF-E308-40BD-9FF0-8266C6CAA9AA}.Debug|Win32.Build.0 = Debug|Win32 {E62D32CF-E308-40BD-9FF0-8266C6CAA9AA}.Debug|x64.ActiveCfg = Debug|x64 {E62D32CF-E308-40BD-9FF0-8266C6CAA9AA}.Debug|x64.Build.0 = Debug|x64 {E62D32CF-E308-40BD-9FF0-8266C6CAA9AA}.Release|Win32.ActiveCfg = Release|Win32 {E62D32CF-E308-40BD-9FF0-8266C6CAA9AA}.Release|Win32.Build.0 = Release|Win32 {E62D32CF-E308-40BD-9FF0-8266C6CAA9AA}.Release|x64.ActiveCfg = Release|x64 {E62D32CF-E308-40BD-9FF0-8266C6CAA9AA}.Release|x64.Build.0 = Release|x64 {D7D4B982-8B16-4A10-8B1C-9527BD789709}.Debug|Win32.ActiveCfg = Debug|Win32 {D7D4B982-8B16-4A10-8B1C-9527BD789709}.Debug|Win32.Build.0 = Debug|Win32 {D7D4B982-8B16-4A10-8B1C-9527BD789709}.Debug|x64.ActiveCfg = Debug|x64 {D7D4B982-8B16-4A10-8B1C-9527BD789709}.Debug|x64.Build.0 = Debug|x64 {D7D4B982-8B16-4A10-8B1C-9527BD789709}.Release|Win32.ActiveCfg = Release|Win32 {D7D4B982-8B16-4A10-8B1C-9527BD789709}.Release|Win32.Build.0 = Release|Win32 {D7D4B982-8B16-4A10-8B1C-9527BD789709}.Release|x64.ActiveCfg = Release|x64 {D7D4B982-8B16-4A10-8B1C-9527BD789709}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal fdkaac-0.6.3/MSVC/fdkaac.vcxproj000066400000000000000000000123721276003472100163360ustar00rootroot00000000000000 Debug Win32 Debug x64 Release Win32 Release x64 {E62D32CF-E308-40BD-9FF0-8266C6CAA9AA} Win32Proj fdkaac v140_xp v120_xp v110_xp v100 Application Unicode true false Level3 HAVE_STDINT_H;inline=__inline;_CRT_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions) ./include;../missings;.;.. Console true copy ..\fdk-aac\libAACdec\include\aacdecoder_lib.h include\fdk-aac\ copy ..\fdk-aac\libAACenc\include\aacenc_lib.h include\fdk-aac\ copy ..\fdk-aac\libSYS\include\FDK_Audio.h include\fdk-aac\ copy ..\fdk-aac\libSYS\include\genericStds.h include\fdk-aac\ copy ..\fdk-aac\libSYS\include\machine_type.h include\fdk-aac\ Disabled MaxSpeed true true {d7d4b982-8b16-4a10-8b1c-9527bd789709} fdkaac-0.6.3/MSVC/fdkaac.vcxproj.filters000066400000000000000000000064011276003472100200010ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files fdkaac-0.6.3/MSVC/include/000077500000000000000000000000001276003472100151265ustar00rootroot00000000000000fdkaac-0.6.3/MSVC/include/fdk-aac/000077500000000000000000000000001276003472100164145ustar00rootroot00000000000000fdkaac-0.6.3/MSVC/include/fdk-aac/.gitkeep000066400000000000000000000000001276003472100200330ustar00rootroot00000000000000fdkaac-0.6.3/Makefile.am000066400000000000000000000020511276003472100147650ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = subdir-objects bin_PROGRAMS = fdkaac fdkaac_SOURCES = \ src/aacenc.c \ src/caf_reader.c \ src/extrapolater.c \ src/limiter.c \ src/lpc.c \ src/m4af.c \ src/main.c \ src/metadata.c \ src/parson.c \ src/pcm_float_converter.c \ src/pcm_native_converter.c \ src/pcm_readhelper.c \ src/pcm_sint16_converter.c \ src/progress.c \ src/wav_reader.c dist_man_MANS = man/fdkaac.1 fdkaac_LDADD = \ @LIBICONV@ -lfdk-aac -lm if FDK_PLATFORM_POSIX fdkaac_SOURCES += \ src/compat_posix.c endif if FDK_PLATFORM_WIN32 fdkaac_SOURCES += \ src/compat_win32.c endif if FDK_NO_GETOPT_LONG fdkaac_SOURCES += \ missings/getopt.c AM_CPPFLAGS = -Imissings endif EXTRA_DIST = \ m4/.gitkeep \ src/*.h \ missings/*.c \ missings/*.h \ MSVC/*.vcxproj \ MSVC/*.vcxproj.filters \ MSVC/*.sln fdkaac-0.6.3/NEWS000066400000000000000000000000001276003472100134200ustar00rootroot00000000000000fdkaac-0.6.3/README000066400000000000000000000162521276003472100136210ustar00rootroot00000000000000% FDKAAC(1) % nu774 % November, 2013 NAME ==== fdkaac - command line frontend for libfdk-aac encoder SYNOPSIS ======== **fdkaac** [OPTIONS] [FILE] DESCRIPTION =========== **fdkaac** reads linear PCM audio in either WAV, raw PCM, or CAF format, and encodes it into either M4A / AAC file. If the input file is "-", data is read from stdin. Likewise, if the output file is "-", data is written to stdout if one of streamable AAC transport formats are selected by **-f**. When CAF input and M4A output is used, tags in CAF file are copied into the resulting M4A. OPTIONS ======= -h, --help : Show command help -o \ : Output filename. -p, --profile \ : Target profile (MPEG4 audio object type, AOT) 2 : MPEG-4 AAC LC (default) 5 : MPEG-4 HE-AAC (SBR) 29 : MPEG-4 HE-AAC v2 (SBR+PS) 23 : MPEG-4 AAC LD 39 : MPEG-4 AAC ELD -b, --bitrate \ : Target bitrate (for CBR) -m, --bitrate-mode \ : Bitrate configuration mode. Available VBR quality value depends on other parameters such as profile, sample rate, or number of channels. 0 : CBR (default) 1-5 : VBR (higher value -\> higher bitrate) -w, --bandwidth \ : Frequency bandwidth (lowpass cut-off frequency) in Hz. Available on AAC LC only. -a, --afterburner \ : Configure afterburner mode. When enabled, quality is increased at the expense of additional computational workload. 0 : Off 1 : On (default) -L, --lowdelay-sbr \ : Configure SBR activity on AAC ELD. -1 : Use ELD SBR auto configuration 0 : Disable SBR on ELD (default) 1 : Enable SBR on ELD -s, --sbr-ratio \ : Controls activation of downsampled SBR. 0 : Use lib default (default) 1 : Use downsampled SBR (default for ELD+SBR) 2 : Use dual-rate SBR (default for HE-AAC) Dual-rate SBR is what is normally used for HE-AAC, where AAC is encoded at half the sample rate of SBR, hence "dual rate". On the other hand, downsampled SBR uses same sample rate for both of AAC and SBR (single rate), therefore downsampled SBR typically consumes more bitrate. Downsampled SBR is newly introduced feature in FDK encoder library version 3.4.12. When libfdk-aac in the system doesn't support this, dual-rate SBR will be used. When available, dual-rate SBR is the default for HE-AAC and downsampled SBR is the default for ELD+SBR. Note that downsampled HE-AAC is not so common as dual-rate one. When downsampled HE-AAC is selected, **fdkaac** is forced to choose explicit hierarchical SBR signaling, which (at least) iTunes doesn't accept. -f, --transport-format \ : Transport format. Tagging and gapless playback is only available on M4A. Streaming to stdout is only available on others. 0 : M4A (default) 1 : ADIF 2 : ADTS 6 : LATM MCP=1 7 : LATM MCP=0 10 : LOAS/LATM (LATM within LOAS) -C, --adts-crc-check : Add CRC protection on ADTS header. -h, --header-period \ : StreamMuxConfig/PCE repetition period in the transport layer. -G, --gapless-mode \ : Method to declare amount of encoder delay (and padding) in M4A container. These values are mandatory for proper gapless playback on player side. 0 : iTunSMPB (default) 1 : ISO standard (edts and sgpd) 2 : Both --include-sbr-delay : When specified, count SBR decoder delay in encoder delay. This is not iTunes compatible and will lead to gapless playback issue on LC only decoder, but this is the default behavior of FDK library. Whether counting SBR decoder delay in encoder delay or not result in incompatibility in gapless playback. You should pick which one will work for your favorite player. However, it's better not to choose SBR at all if you want gapless playback. LC doesn't have such issues. -I, --ignorelength : Ignore length field of data chunk in input WAV file. -S, --silent : Don't print progress messages. --moov-before-mdat : Place moov box before mdat box in M4A container. This option might be important for some hardware players, that are known to refuse moov box placed after mdat box. -R, --raw : Regard input as raw PCM. --raw-channels \ : Specify number of channels of raw input (default: 2) --raw-rate \ : Specify sample rate of raw input (default: 44100) --raw-format \ : Specify sample format of raw input (default: "S16L"). **Spec** is as the following (case insensitive): 1st char -- type of sample : **S** (igned) | **U** (nsigned) | **F** (loat) 2nd part (in digits) : bits per channel Last char -- endianness (can be omitted) : **L** (ittle, default) | **B** (ig) --title \ : Set title tag. --artist \ : Set artist tag. --album \ : Set album tag. --genre \ : Set genre tag. --date \ : Set date tag. --composer \ : Set composer tag. --grouping \ : Set grouping tag. --comment \ : Set comment tag. --album-artist \ : Set album artist tag. --track \ : Set track tag, with or without number of total tracks. --disk \ : Set disk tag, with or without number of total discs. --tempo \ : Set tempo (BPM) tag. --tag \:\ : Set iTunes predefined tag with explicit fourcc key and value. See [https://code.google.com/p/mp4v2/wiki/iTunesMetadata](https://code.google.com/p/mp4v2/wiki/iTunesMetadata) for known predefined keys. You can omit first char of **fcc** when it is the copyright sign. --tag-from-file \:\ : Same as --tag, but set content of file as tag value. --long-tag \:\ : Set arbitrary tag as iTunes custom metadata. Stored in com.apple.iTunes field. --tag-from-json \ : Read tags from JSON. By default, tags are assumed to be direct children of the root object in JSON. Optionally you can specify arbitrary dot notation to locate the object containing tags. EXAMPLES ======== Encode WAV file into a M4A file. MPEG4 AAC LC, VBR quality 3: fdkaac -m3 foo.wav Encode WAV file into a M4A file. MPEG4 HE-AAC, bitrate 64kbps: fdkaac -p5 -b64 foo.wav Piping from **ffmpeg** (you need version supporting CAF output): ffmpeg -i foo.flac -f caf - | fdkaac -b128 - -o foo.m4a Import tags via json: ffprobe -v 0 -of json -show_format foo.flac >foo.json flac -dc foo.flac | \ fdkaac - -ox.m4a -m2 --import-tag-from-json=foo.json?format.tags NOTES ===== Upto 32bit integer or 64bit floating point format is supported as input. However, FDK library is implemented based on fixed point math and only supports 16bit integer PCM. Therefore, be wary of clipping. You might want to dither/noise shape beforehand when your input has higher resolution. Following channel layouts are supported by the encoder. 1ch : C 2ch : L R 3ch : C L R 4ch : C L R Cs 5ch : C L R Ls Rs 5.1ch : C L R Ls Rs LFE 7.1ch (front) : C Lc Rc L R Ls Rs LFE 7.1ch (rear) : C L R Ls Rs Rls Rrs LFE fdkaac-0.6.3/config.rpath000066400000000000000000000000001276003472100152260ustar00rootroot00000000000000fdkaac-0.6.3/configure.ac000066400000000000000000000025021276003472100152200ustar00rootroot00000000000000m4_define([VERSION_H],m4_esyscmd([cat version.h])) changequote({{,}})dnl m4_define({{XX_VERSION}},m4_bregexp(VERSION_H,{{^const.*"\(.+\)";}},{{\1}})) changequote([,])dnl AC_INIT([fdkaac], [XX_VERSION], [honeycomb77@gmail.com]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE AC_PROG_CC AM_PROG_CC_C_O AC_CHECK_HEADERS([sys/time.h]) AC_CHECK_HEADERS([localcharset.h langinfo.h endian.h byteswap.h]) AC_CHECK_HEADERS([fdk-aac/aacenc_lib.h], , AC_MSG_ERROR([libfdk-aac is required])) AC_C_INLINE AC_C_BIGENDIAN AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT64_T AC_TYPE_INT8_T AC_TYPE_SIZE_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T AC_CHECK_TYPES([ptrdiff_t]) AC_SYS_LARGEFILE AC_CHECK_TYPES([struct __timeb64],[],[],[[#include ]]) AC_FUNC_FSEEKO AC_CHECK_FUNCS([sigaction gettimeofday nl_langinfo _vscprintf fseeko64]) AC_CHECK_FUNC(getopt_long) AM_CONDITIONAL([FDK_NO_GETOPT_LONG],[test "$ac_cv_func_getopt_long" != "yes"]) AC_SEARCH_LIBS([aacEncOpen],[fdk-aac],[],[],[]) AC_CANONICAL_HOST X_PLATFORM=posix case ${host} in *-*-mingw*) X_PLATFORM=win32 ;; *) AM_ICONV esac AM_CONDITIONAL([FDK_PLATFORM_POSIX],[test "$X_PLATFORM" = "posix"]) AM_CONDITIONAL([FDK_PLATFORM_WIN32],[test "$X_PLATFORM" = "win32"]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT fdkaac-0.6.3/genman.sh000077500000000000000000000001271276003472100145370ustar00rootroot00000000000000#!/bin/sh pandoc -s -f markdown -t man README >fdkaac.1 && mv -f fdkaac.1 man/fdkaac.1 fdkaac-0.6.3/git2changelog.py000077500000000000000000000030031276003472100160210ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (C) 2013 nu774 # For conditions of distribution and use, see copyright notice in COPYING import sys import re from subprocess import Popen, PIPE from itertools import groupby from collections import namedtuple GITLOG_FMT = 'commit %H%nauthor %cn <%ae>%ndate %ad%nsubject %s%nref %d%n%n' GITLOG_CMD = ['git','log','--date=short','--format={0}'.format(GITLOG_FMT)] Commit = namedtuple('Commit', 'commit author date subject ref') def parse_gitlog(stream): re_decode_ref = re.compile(r'(?<=\()([^,)]+)') re_strip_tag = re.compile(r'^tag: ') commit = dict() for line in stream: fields = line.decode('utf-8').rstrip('\r\n').split(' ', 1) if len(fields) == 2: key, value = fields if key == 'ref': m = re_decode_ref.search(value) if m: value = ' [{0}]'.format(re_strip_tag.sub('', m.group())) else: value = '' commit[key] = value elif commit: yield Commit(**commit) commit = dict() output=sys.stdout.write with Popen(GITLOG_CMD, shell=False, stdout=PIPE).stdout as pipe: commits = parse_gitlog(pipe) commits_by_date_author = groupby(commits, key=lambda x: (x.date, x.author)) for (date, author), commits in commits_by_date_author: output(u'{0} {1}\n\n'.format(date, author).encode('utf-8')) for c in commits: output(u' * {0}{1}\n\n'.format(c.subject, c.ref).encode('utf-8')) fdkaac-0.6.3/m4/000077500000000000000000000000001276003472100132535ustar00rootroot00000000000000fdkaac-0.6.3/m4/.gitkeep000066400000000000000000000000001276003472100146720ustar00rootroot00000000000000fdkaac-0.6.3/m4/iconv.m4000066400000000000000000000216201276003472100146340ustar00rootroot00000000000000# iconv.m4 serial 18 (gettext-0.18.2) dnl Copyright (C) 2000-2002, 2007-2014 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], [ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_LIB_LINKFLAGS_BODY([iconv]) ]) AC_DEFUN([AM_ICONV_LINK], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) dnl Add $INCICONV to CPPFLAGS before performing the following checks, dnl because if the user has installed libiconv and not disabled its use dnl via --without-libiconv-prefix, he wants to use it. The first dnl AC_LINK_IFELSE will then fail, the second AC_LINK_IFELSE will succeed. am_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #include ]], [[iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);]])], [am_cv_func_iconv=yes]) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #include ]], [[iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);]])], [am_cv_lib_iconv=yes] [am_cv_func_iconv=yes]) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ dnl This tests against bugs in AIX 5.1, AIX 6.1..7.1, HP-UX 11.11, dnl Solaris 10. am_save_LIBS="$LIBS" if test $am_cv_lib_iconv = yes; then LIBS="$LIBS $LIBICONV" fi AC_RUN_IFELSE( [AC_LANG_SOURCE([[ #include #include int main () { int result = 0; /* Test against AIX 5.1 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); if (cd_utf8_to_88591 != (iconv_t)(-1)) { static const char input[] = "\342\202\254"; /* EURO SIGN */ char buf[10]; const char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_utf8_to_88591, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 1; iconv_close (cd_utf8_to_88591); } } /* Test against Solaris 10 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); if (cd_ascii_to_88591 != (iconv_t)(-1)) { static const char input[] = "\263"; char buf[10]; const char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_ascii_to_88591, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 2; iconv_close (cd_ascii_to_88591); } } /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ { iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { static const char input[] = "\304"; static char buf[2] = { (char)0xDE, (char)0xAD }; const char *inptr = input; size_t inbytesleft = 1; char *outptr = buf; size_t outbytesleft = 1; size_t res = iconv (cd_88591_to_utf8, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) result |= 4; iconv_close (cd_88591_to_utf8); } } #if 0 /* This bug could be worked around by the caller. */ /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ { iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; char buf[50]; const char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_88591_to_utf8, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if ((int)res > 0) result |= 8; iconv_close (cd_88591_to_utf8); } } #endif /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is provided. */ if (/* Try standardized names. */ iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) /* Try IRIX, OSF/1 names. */ && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) /* Try AIX names. */ && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) /* Try HP-UX names. */ && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) result |= 16; return result; }]])], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no], [ changequote(,)dnl case "$host_os" in aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; *) am_cv_func_iconv_works="guessing yes" ;; esac changequote([,])dnl ]) LIBS="$am_save_LIBS" ]) case "$am_cv_func_iconv_works" in *no) am_func_iconv=no am_cv_lib_iconv=no ;; *) am_func_iconv=yes ;; esac else am_func_iconv=no am_cv_lib_iconv=no fi if test "$am_func_iconv" = yes; then AC_DEFINE([HAVE_ICONV], [1], [Define if you have the iconv() function and it works.]) fi if test "$am_cv_lib_iconv" = yes; then AC_MSG_CHECKING([how to link with libiconv]) AC_MSG_RESULT([$LIBICONV]) else dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV dnl either. CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi AC_SUBST([LIBICONV]) AC_SUBST([LTLIBICONV]) ]) dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to dnl avoid warnings like dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". dnl This is tricky because of the way 'aclocal' is implemented: dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. dnl Otherwise aclocal's initial scan pass would miss the macro definition. dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. dnl Otherwise aclocal would emit many "Use of uninitialized value $1" dnl warnings. m4_define([gl_iconv_AC_DEFUN], m4_version_prereq([2.64], [[AC_DEFUN_ONCE( [$1], [$2])]], [m4_ifdef([gl_00GNULIB], [[AC_DEFUN_ONCE( [$1], [$2])]], [[AC_DEFUN( [$1], [$2])]])])) gl_iconv_AC_DEFUN([AM_ICONV], [ AM_ICONV_LINK if test "$am_cv_func_iconv" = yes; then AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL([am_cv_proto_iconv], [ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ]], [[]])], [am_cv_proto_iconv_arg1=""], [am_cv_proto_iconv_arg1="const"]) am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` AC_MSG_RESULT([ $am_cv_proto_iconv]) AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1], [Define as const if the declaration of iconv() needs const.]) dnl Also substitute ICONV_CONST in the gnulib generated . m4_ifdef([gl_ICONV_H_DEFAULTS], [AC_REQUIRE([gl_ICONV_H_DEFAULTS]) if test -n "$am_cv_proto_iconv_arg1"; then ICONV_CONST="const" fi ]) fi ]) fdkaac-0.6.3/m4/lib-ld.m4000066400000000000000000000071431276003472100146650ustar00rootroot00000000000000# lib-ld.m4 serial 6 dnl Copyright (C) 1996-2003, 2009-2014 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl Subroutines of libtool.m4, dnl with replacements s/_*LT_PATH/AC_LIB_PROG/ and s/lt_/acl_/ to avoid dnl collision with libtool.m4. dnl From libtool-2.4. Sets the variable with_gnu_ld to yes or no. AC_DEFUN([AC_LIB_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld], [# I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 /dev/null 2>&1 \ && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ || PATH_SEPARATOR=';' } fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'` while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL([acl_cv_path_LD], [if test -z "$LD"; then acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$acl_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 = 1.10 to complain if config.rpath is missing. m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done ]) wl="$acl_cv_wl" acl_libext="$acl_cv_libext" acl_shlibext="$acl_cv_shlibext" acl_libname_spec="$acl_cv_libname_spec" acl_library_names_spec="$acl_cv_library_names_spec" acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" acl_hardcode_direct="$acl_cv_hardcode_direct" acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" dnl Determine whether the user wants rpath handling at all. AC_ARG_ENABLE([rpath], [ --disable-rpath do not hardcode runtime library paths], :, enable_rpath=yes) ]) dnl AC_LIB_FROMPACKAGE(name, package) dnl declares that libname comes from the given package. The configure file dnl will then not have a --with-libname-prefix option but a dnl --with-package-prefix option. Several libraries can come from the same dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar dnl macro call that searches for libname. AC_DEFUN([AC_LIB_FROMPACKAGE], [ pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) define([acl_frompackage_]NAME, [$2]) popdef([NAME]) pushdef([PACK],[$2]) pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) define([acl_libsinpackage_]PACKUP, m4_ifdef([acl_libsinpackage_]PACKUP, [m4_defn([acl_libsinpackage_]PACKUP)[, ]],)[lib$1]) popdef([PACKUP]) popdef([PACK]) ]) dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. AC_DEFUN([AC_LIB_LINKFLAGS_BODY], [ AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])]) pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])]) dnl Autoconf >= 2.61 supports dots in --with options. pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[m4_translit(PACK,[.],[_])],PACK)]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_ARG_WITH(P_A_C_K[-prefix], [[ --with-]]P_A_C_K[[-prefix[=DIR] search for ]PACKLIBS[ in DIR/include and DIR/lib --without-]]P_A_C_K[[-prefix don't search for ]PACKLIBS[ in includedir and libdir]], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" if test "$acl_libdirstem2" != "$acl_libdirstem" \ && ! test -d "$withval/$acl_libdirstem"; then additional_libdir="$withval/$acl_libdirstem2" fi fi fi ]) dnl Search the library and its dependencies in $additional_libdir and dnl $LDFLAGS. Using breadth-first-seach. LIB[]NAME= LTLIB[]NAME= INC[]NAME= LIB[]NAME[]_PREFIX= dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been dnl computed. So it has to be reset here. HAVE_LIB[]NAME= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='$1 $2' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" dnl See if it was already located by an earlier AC_LIB_LINKFLAGS dnl or AC_LIB_HAVE_LINKFLAGS call. uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" else dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined dnl that this library doesn't exist. So just drop it. : fi else dnl Search the library lib$name in $additional_libdir and $LDFLAGS dnl and the already constructed $LIBNAME/$LTLIBNAME. found_dir= found_la= found_so= found_a= eval libname=\"$acl_libname_spec\" # typically: libname=lib$name if test -n "$acl_shlibext"; then shrext=".$acl_shlibext" # typically: shrext=.so else shrext= fi if test $use_additional = yes; then dir="$additional_libdir" dnl The same code as in the loop below: dnl First look for a shared library. if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi dnl Then look for a static library. if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext"; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` dnl First look for a shared library. if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi dnl Then look for a static library. if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext"; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then dnl Found the library. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then dnl Linking with a shared library. We attempt to hardcode its dnl directory into the executable's runpath, unless it's the dnl standard /usr/lib. if test "$enable_rpath" = no \ || test "X$found_dir" = "X/usr/$acl_libdirstem" \ || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then dnl No hardcoding is needed. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl Use an explicit option to hardcode DIR into the resulting dnl binary. dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi dnl The hardcoding into $LIBNAME is system dependent. if test "$acl_hardcode_direct" = yes; then dnl Using DIR/libNAME.so during linking hardcodes DIR into the dnl resulting binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then dnl Use an explicit option to hardcode DIR into the resulting dnl binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else dnl Rely on "-L$found_dir". dnl But don't add it if it's already contained in the LDFLAGS dnl or the already constructed $LIBNAME haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" fi if test "$acl_hardcode_minus_L" != no; then dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH dnl here, because this doesn't fit in flags passed to the dnl compiler. So give up. No hardcoding. This affects only dnl very old systems. dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then dnl Linking with a static library. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" else dnl We shouldn't come here, but anyway it's good to have a dnl fallback. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" fi fi dnl Assume the include files are nearby. additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` if test "$name" = '$1'; then LIB[]NAME[]_PREFIX="$basedir" fi additional_includedir="$basedir/include" ;; */$acl_libdirstem2 | */$acl_libdirstem2/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` if test "$name" = '$1'; then LIB[]NAME[]_PREFIX="$basedir" fi additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then dnl Potentially add $additional_includedir to $INCNAME. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's /usr/local/include and we are using GCC on Linux, dnl 3. if it's already present in $CPPFLAGS or the already dnl constructed $INCNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INC[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $INCNAME. INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" fi fi fi fi fi dnl Look for dependencies. if test -n "$found_la"; then dnl Read the .la file. It defines the variables dnl dlname, library_names, old_library, dependency_libs, current, dnl age, revision, installed, dlopen, dlpreopen, libdir. save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" dnl We use only dependency_libs. for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's /usr/local/lib and we are using GCC on Linux, dnl 3. if it's already present in $LDFLAGS or the already dnl constructed $LIBNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LIBNAME. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LTLIBNAME. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) dnl Handle this in the next round. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) dnl Handle this in the next round. Throw away the .la's dnl directory; it is already contained in a preceding -L dnl option. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) dnl Most likely an immediate library name. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" ;; esac done fi else dnl Didn't find the library; assume it is in the system directories dnl known to the linker and runtime loader. (All the system dnl directories known to the linker should also be known to the dnl runtime loader, otherwise the system is severely misconfigured.) LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$acl_hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user must dnl pass all path elements in one option. We can arrange that for a dnl single library, but not when more than one $LIBNAMEs are used. alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" done dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" else dnl The -rpath options are cumulative. for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then dnl When using libtool, the option that works for both libraries and dnl executables is -R. The -R options are cumulative. for found_dir in $ltrpathdirs; do LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" done fi popdef([P_A_C_K]) popdef([PACKLIBS]) popdef([PACKUP]) popdef([PACK]) popdef([NAME]) ]) dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, dnl unless already present in VAR. dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes dnl contains two or three consecutive elements that belong together. AC_DEFUN([AC_LIB_APPENDTOVAR], [ for element in [$2]; do haveit= for x in $[$1]; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then [$1]="${[$1]}${[$1]:+ }$element" fi done ]) dnl For those cases where a variable contains several -L and -l options dnl referring to unknown libraries and directories, this macro determines the dnl necessary additional linker options for the runtime path. dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) dnl sets LDADDVAR to linker options needed together with LIBSVALUE. dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, dnl otherwise linking without libtool is assumed. AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], [ AC_REQUIRE([AC_LIB_RPATH]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) $1= if test "$enable_rpath" != no; then if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then dnl Use an explicit option to hardcode directories into the resulting dnl binary. rpathdirs= next= for opt in $2; do if test -n "$next"; then dir="$next" dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem" \ && test "X$dir" != "X/usr/$acl_libdirstem2"; then rpathdirs="$rpathdirs $dir" fi next= else case $opt in -L) next=yes ;; -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem" \ && test "X$dir" != "X/usr/$acl_libdirstem2"; then rpathdirs="$rpathdirs $dir" fi next= ;; *) next= ;; esac fi done if test "X$rpathdirs" != "X"; then if test -n ""$3""; then dnl libtool is used for linking. Use -R options. for dir in $rpathdirs; do $1="${$1}${$1:+ }-R$dir" done else dnl The linker is used for linking directly. if test -n "$acl_hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user dnl must pass all path elements in one option. alldirs= for dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="$flag" else dnl The -rpath options are cumulative. for dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$dir" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="${$1}${$1:+ }$flag" done fi fi fi fi fi AC_SUBST([$1]) ]) fdkaac-0.6.3/m4/lib-prefix.m4000066400000000000000000000204221276003472100155560ustar00rootroot00000000000000# lib-prefix.m4 serial 7 (gettext-0.18) dnl Copyright (C) 2001-2005, 2008-2014 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't dnl require excessive bracketing. ifdef([AC_HELP_STRING], [AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], [AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed dnl to access previously installed libraries. The basic assumption is that dnl a user will want packages to use other packages he previously installed dnl with the same --prefix option. dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate dnl libraries, but is otherwise very convenient. AC_DEFUN([AC_LIB_PREFIX], [ AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib-prefix], [ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib --without-lib-prefix don't search for libraries in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) if test $use_additional = yes; then dnl Potentially add $additional_includedir to $CPPFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's already present in $CPPFLAGS, dnl 3. if it's /usr/local/include and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= for x in $CPPFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $CPPFLAGS. CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" fi fi fi fi dnl Potentially add $additional_libdir to $LDFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's already present in $LDFLAGS, dnl 3. if it's /usr/local/lib and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= for x in $LDFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LDFLAGS. LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" fi fi fi fi fi ]) dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, dnl acl_final_exec_prefix, containing the values to which $prefix and dnl $exec_prefix will expand at the end of the configure script. AC_DEFUN([AC_LIB_PREPARE_PREFIX], [ dnl Unfortunately, prefix and exec_prefix get only finally determined dnl at the end of configure. if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" ]) dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the dnl variables prefix and exec_prefix bound to the values they will have dnl at the end of the configure script. AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], [ acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" $1 exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" ]) dnl AC_LIB_PREPARE_MULTILIB creates dnl - a variable acl_libdirstem, containing the basename of the libdir, either dnl "lib" or "lib64" or "lib/64", dnl - a variable acl_libdirstem2, as a secondary possible value for dnl acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or dnl "lib/amd64". AC_DEFUN([AC_LIB_PREPARE_MULTILIB], [ dnl There is no formal standard regarding lib and lib64. dnl On glibc systems, the current practice is that on a system supporting dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine dnl the compiler's default mode by looking at the compiler's library search dnl path. If at least one of its elements ends in /lib64 or points to a dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI. dnl Otherwise we use the default, namely "lib". dnl On Solaris systems, the current practice is that on a system supporting dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib. AC_REQUIRE([AC_CANONICAL_HOST]) acl_libdirstem=lib acl_libdirstem2= case "$host_os" in solaris*) dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment dnl . dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link." dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the dnl symlink is missing, so we set acl_libdirstem2 too. AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit], [AC_EGREP_CPP([sixtyfour bits], [ #ifdef _LP64 sixtyfour bits #endif ], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no]) ]) if test $gl_cv_solaris_64bit = yes; then acl_libdirstem=lib/64 case "$host_cpu" in sparc*) acl_libdirstem2=lib/sparcv9 ;; i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; esac fi ;; *) searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test -n "$searchpath"; then acl_save_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; */../ | */.. ) # Better ignore directories of this form. They are misleading. ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib64 ) acl_libdirstem=lib64 ;; esac ;; esac fi done IFS="$acl_save_IFS" fi ;; esac test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" ]) fdkaac-0.6.3/man/000077500000000000000000000000001276003472100135065ustar00rootroot00000000000000fdkaac-0.6.3/man/fdkaac.1000066400000000000000000000175061276003472100150120ustar00rootroot00000000000000.\" Automatically generated by Pandoc 1.17.1 .\" .TH "FDKAAC" "1" "November, 2013" "" "" .hy .SH NAME .PP fdkaac \- command line frontend for libfdk\-aac encoder .SH SYNOPSIS .PP \f[B]fdkaac\f[] [OPTIONS] [FILE] .SH DESCRIPTION .PP \f[B]fdkaac\f[] reads linear PCM audio in either WAV, raw PCM, or CAF format, and encodes it into either M4A / AAC file. .PP If the input file is "\-", data is read from stdin. Likewise, if the output file is "\-", data is written to stdout if one of streamable AAC transport formats are selected by \f[B]\-f\f[]. .PP When CAF input and M4A output is used, tags in CAF file are copied into the resulting M4A. .SH OPTIONS .TP .B \-h, \-\-help Show command help .RS .RE .TP .B \-o Output filename. .RS .RE .TP .B \-p, \-\-profile Target profile (MPEG4 audio object type, AOT) .RS .TP .B 2 MPEG\-4 AAC LC (default) .RS .RE .TP .B 5 MPEG\-4 HE\-AAC (SBR) .RS .RE .TP .B 29 MPEG\-4 HE\-AAC v2 (SBR+PS) .RS .RE .TP .B 23 MPEG\-4 AAC LD .RS .RE .TP .B 39 MPEG\-4 AAC ELD .RS .RE .RE .TP .B \-b, \-\-bitrate Target bitrate (for CBR) .RS .RE .TP .B \-m, \-\-bitrate\-mode Bitrate configuration mode. Available VBR quality value depends on other parameters such as profile, sample rate, or number of channels. .RS .TP .B 0 CBR (default) .RS .RE .TP .B 1\-5 VBR (higher value \-> higher bitrate) .RS .RE .RE .TP .B \-w, \-\-bandwidth Frequency bandwidth (lowpass cut\-off frequency) in Hz. Available on AAC LC only. .RS .RE .TP .B \-a, \-\-afterburner Configure afterburner mode. When enabled, quality is increased at the expense of additional computational workload. .RS .TP .B 0 Off .RS .RE .TP .B 1 On (default) .RS .RE .RE .TP .B \-L, \-\-lowdelay\-sbr Configure SBR activity on AAC ELD. .RS .TP .B \-1 Use ELD SBR auto configuration .RS .RE .TP .B 0 Disable SBR on ELD (default) .RS .RE .TP .B 1 Enable SBR on ELD .RS .RE .RE .TP .B \-s, \-\-sbr\-ratio Controls activation of downsampled SBR. .RS .TP .B 0 Use lib default (default) .RS .RE .TP .B 1 Use downsampled SBR (default for ELD+SBR) .RS .RE .TP .B 2 Use dual\-rate SBR (default for HE\-AAC) .RS .RE .PP Dual\-rate SBR is what is normally used for HE\-AAC, where AAC is encoded at half the sample rate of SBR, hence "dual rate". On the other hand, downsampled SBR uses same sample rate for both of AAC and SBR (single rate), therefore downsampled SBR typically consumes more bitrate. .PP Downsampled SBR is newly introduced feature in FDK encoder library version 3.4.12. When libfdk\-aac in the system doesn\[aq]t support this, dual\-rate SBR will be used. When available, dual\-rate SBR is the default for HE\-AAC and downsampled SBR is the default for ELD+SBR. .PP Note that downsampled HE\-AAC is not so common as dual\-rate one. When downsampled HE\-AAC is selected, \f[B]fdkaac\f[] is forced to choose explicit hierarchical SBR signaling, which (at least) iTunes doesn\[aq]t accept. .RE .TP .B \-f, \-\-transport\-format Transport format. Tagging and gapless playback is only available on M4A. Streaming to stdout is only available on others. .RS .TP .B 0 M4A (default) .RS .RE .TP .B 1 ADIF .RS .RE .TP .B 2 ADTS .RS .RE .TP .B 6 LATM MCP=1 .RS .RE .TP .B 7 LATM MCP=0 .RS .RE .TP .B 10 LOAS/LATM (LATM within LOAS) .RS .RE .RE .TP .B \-C, \-\-adts\-crc\-check Add CRC protection on ADTS header. .RS .RE .TP .B \-h, \-\-header\-period StreamMuxConfig/PCE repetition period in the transport layer. .RS .RE .TP .B \-G, \-\-gapless\-mode Method to declare amount of encoder delay (and padding) in M4A container. These values are mandatory for proper gapless playback on player side. .RS .TP .B 0 iTunSMPB (default) .RS .RE .TP .B 1 ISO standard (edts and sgpd) .RS .RE .TP .B 2 Both .RS .RE .RE .TP .B \-\-include\-sbr\-delay When specified, count SBR decoder delay in encoder delay. .RS .PP This is not iTunes compatible and will lead to gapless playback issue on LC only decoder, but this is the default behavior of FDK library. .PP Whether counting SBR decoder delay in encoder delay or not result in incompatibility in gapless playback. You should pick which one will work for your favorite player. .PP However, it\[aq]s better not to choose SBR at all if you want gapless playback. LC doesn\[aq]t have such issues. .RE .TP .B \-I, \-\-ignorelength Ignore length field of data chunk in input WAV file. .RS .RE .TP .B \-S, \-\-silent Don\[aq]t print progress messages. .RS .RE .TP .B \-\-moov\-before\-mdat Place moov box before mdat box in M4A container. This option might be important for some hardware players, that are known to refuse moov box placed after mdat box. .RS .RE .TP .B \-R, \-\-raw Regard input as raw PCM. .RS .RE .TP .B \-\-raw\-channels Specify number of channels of raw input (default: 2) .RS .RE .TP .B \-\-raw\-rate Specify sample rate of raw input (default: 44100) .RS .RE .TP .B \-\-raw\-format Specify sample format of raw input (default: "S16L"). \f[B]Spec\f[] is as the following (case insensitive): .RS .TP .B 1st char \-\- type of sample \f[B]S\f[] (igned) | \f[B]U\f[] (nsigned) | \f[B]F\f[] (loat) .RS .RE .TP .B 2nd part (in digits) bits per channel .RS .RE .TP .B Last char \-\- endianness (can be omitted) \f[B]L\f[] (ittle, default) | \f[B]B\f[] (ig) .RS .RE .RE .TP .B \-\-title Set title tag. .RS .RE .TP .B \-\-artist Set artist tag. .RS .RE .TP .B \-\-album Set album tag. .RS .RE .TP .B \-\-genre Set genre tag. .RS .RE .TP .B \-\-date Set date tag. .RS .RE .TP .B \-\-composer Set composer tag. .RS .RE .TP .B \-\-grouping Set grouping tag. .RS .RE .TP .B \-\-comment Set comment tag. .RS .RE .TP .B \-\-album\-artist Set album artist tag. .RS .RE .TP .B \-\-track Set track tag, with or without number of total tracks. .RS .RE .TP .B \-\-disk Set disk tag, with or without number of total discs. .RS .RE .TP .B \-\-tempo Set tempo (BPM) tag. .RS .RE .TP .B \-\-tag : Set iTunes predefined tag with explicit fourcc key and value. See for known predefined keys. You can omit first char of \f[B]fcc\f[] when it is the copyright sign. .RS .RE .TP .B \-\-tag\-from\-file : Same as \-\-tag, but set content of file as tag value. .RS .RE .TP .B \-\-long\-tag : Set arbitrary tag as iTunes custom metadata. Stored in com.apple.iTunes field. .RS .RE .TP .B \-\-tag\-from\-json Read tags from JSON. By default, tags are assumed to be direct children of the root object in JSON. Optionally you can specify arbitrary dot notation to locate the object containing tags. .RS .RE .SH EXAMPLES .PP Encode WAV file into a M4A file. MPEG4 AAC LC, VBR quality 3: .IP .nf \f[C] fdkaac\ \-m3\ foo.wav \f[] .fi .PP Encode WAV file into a M4A file. MPEG4 HE\-AAC, bitrate 64kbps: .IP .nf \f[C] fdkaac\ \-p5\ \-b64\ foo.wav \f[] .fi .PP Piping from \f[B]ffmpeg\f[] (you need version supporting CAF output): .IP .nf \f[C] ffmpeg\ \-i\ foo.flac\ \-f\ caf\ \-\ |\ fdkaac\ \-b128\ \-\ \-o\ foo.m4a \f[] .fi .PP Import tags via json: .IP .nf \f[C] ffprobe\ \-v\ 0\ \-of\ json\ \-show_format\ foo.flac\ >foo.json flac\ \-dc\ foo.flac\ |\ \\ fdkaac\ \-\ \-ox.m4a\ \-m2\ \-\-import\-tag\-from\-json=foo.json?format.tags \f[] .fi .SH NOTES .PP Upto 32bit integer or 64bit floating point format is supported as input. However, FDK library is implemented based on fixed point math and only supports 16bit integer PCM. Therefore, be wary of clipping. You might want to dither/noise shape beforehand when your input has higher resolution. .PP Following channel layouts are supported by the encoder. .TP .B 1ch C .RS .RE .TP .B 2ch L R .RS .RE .TP .B 3ch C L R .RS .RE .TP .B 4ch C L R Cs .RS .RE .TP .B 5ch C L R Ls Rs .RS .RE .TP .B 5.1ch C L R Ls Rs LFE .RS .RE .TP .B 7.1ch (front) C Lc Rc L R Ls Rs LFE .RS .RE .TP .B 7.1ch (rear) C L R Ls Rs Rls Rrs LFE .RS .RE .SH AUTHORS nu774 . fdkaac-0.6.3/missings/000077500000000000000000000000001276003472100145675ustar00rootroot00000000000000fdkaac-0.6.3/missings/getopt.c000066400000000000000000000423611276003472100162430ustar00rootroot00000000000000/* $OpenBSD: getopt_long.c,v 1.21 2006/09/22 17:22:05 millert Exp $ */ /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ /* * Copyright (c) 2002 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F39502-99-1-0512. */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD 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 NETBSD FOUNDATION, INC. 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. */ #if 0 #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: getopt_long.c,v 1.16 2004/02/04 18:17:25 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #endif #include #include #include #include #include #include "getopt.h" #define GNU_COMPATIBLE /* Be more compatible, configure's use us! */ #if 0 /* we prefer to keep our getopt(3) */ #define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ #endif int opterr = 1; /* if error message should be printed */ int optind = 1; /* index into parent argv vector */ int optopt = '?'; /* character checked for validity */ int optreset; /* reset getopt */ char *optarg; /* argument associated with option */ #define PRINT_ERROR ((opterr) && (*options != ':')) #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ /* return values */ #define BADCH (int)'?' #define BADARG ((*options == ':') ? (int)':' : (int)'?') #define INORDER (int)1 #define EMSG "" #ifdef GNU_COMPATIBLE #define NO_PREFIX (-1) #define D_PREFIX 0 #define DD_PREFIX 1 #define W_PREFIX 2 #endif static int getopt_internal(int, char * const *, const char *, const struct option *, int *, int); static int parse_long_options(char * const *, const char *, const struct option *, int *, int, int); static int gcd(int, int); static void permute_args(int, int, int, char * const *); static char *place = EMSG; /* option letter processing */ /* XXX: set optreset to 1 rather than these two */ static int nonopt_start = -1; /* first non option argument (for permute) */ static int nonopt_end = -1; /* first option after non options (for permute) */ /* Error messages */ static const char recargchar[] = "option requires an argument -- %c"; static const char illoptchar[] = "illegal option -- %c"; /* From P1003.2 */ #ifdef GNU_COMPATIBLE static int dash_prefix = NO_PREFIX; static const char gnuoptchar[] = "invalid option -- %c"; static const char recargstring[] = "option `%s%s' requires an argument"; static const char ambig[] = "option `%s%.*s' is ambiguous"; static const char noarg[] = "option `%s%.*s' doesn't allow an argument"; static const char illoptstring[] = "unrecognized option `%s%s'"; #else static const char recargstring[] = "option requires an argument -- %s"; static const char ambig[] = "ambiguous option -- %.*s"; static const char noarg[] = "option doesn't take an argument -- %.*s"; static const char illoptstring[] = "unknown option -- %s"; #endif static void warnx(const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); putc('\n', stderr); va_end(args); } /* * Compute the greatest common divisor of a and b. */ static int gcd(int a, int b) { int c; c = a % b; while (c != 0) { a = b; b = c; c = a % b; } return (b); } /* * Exchange the block from nonopt_start to nonopt_end with the block * from nonopt_end to opt_end (keeping the same order of arguments * in each block). */ static void permute_args(int panonopt_start, int panonopt_end, int opt_end, char * const *nargv) { int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; char *swap; /* * compute lengths of blocks and number and size of cycles */ nnonopts = panonopt_end - panonopt_start; nopts = opt_end - panonopt_end; ncycle = gcd(nnonopts, nopts); cyclelen = (opt_end - panonopt_start) / ncycle; for (i = 0; i < ncycle; i++) { cstart = panonopt_end+i; pos = cstart; for (j = 0; j < cyclelen; j++) { if (pos >= panonopt_end) pos -= nnonopts; else pos += nopts; swap = nargv[pos]; /* LINTED const cast */ ((char **) nargv)[pos] = nargv[cstart]; /* LINTED const cast */ ((char **)nargv)[cstart] = swap; } } } /* * parse_long_options -- * Parse long options in argc/argv argument vector. * Returns -1 if short_too is set and the option does not match long_options. */ static int parse_long_options(char * const *nargv, const char *options, const struct option *long_options, int *idx, int short_too, int flags) { char *current_argv, *has_equal; #ifdef GNU_COMPATIBLE char *current_dash; #endif size_t current_argv_len; int i, match, exact_match, second_partial_match; current_argv = place; #ifdef GNU_COMPATIBLE switch (dash_prefix) { case D_PREFIX: current_dash = "-"; break; case DD_PREFIX: current_dash = "--"; break; case W_PREFIX: current_dash = "-W "; break; default: current_dash = ""; break; } #endif match = -1; exact_match = 0; second_partial_match = 0; optind++; if ((has_equal = strchr(current_argv, '=')) != NULL) { /* argument found (--option=arg) */ current_argv_len = has_equal - current_argv; has_equal++; } else current_argv_len = strlen(current_argv); for (i = 0; long_options[i].name; i++) { /* find matching long option */ if (strncmp(current_argv, long_options[i].name, current_argv_len)) continue; if (strlen(long_options[i].name) == current_argv_len) { /* exact match */ match = i; exact_match = 1; break; } /* * If this is a known short option, don't allow * a partial match of a single character. */ if (short_too && current_argv_len == 1) continue; if (match == -1) /* first partial match */ match = i; else if ((flags & FLAG_LONGONLY) || long_options[i].has_arg != long_options[match].has_arg || long_options[i].flag != long_options[match].flag || long_options[i].val != long_options[match].val) second_partial_match = 1; } if (!exact_match && second_partial_match) { /* ambiguous abbreviation */ if (PRINT_ERROR) warnx(ambig, #ifdef GNU_COMPATIBLE current_dash, #endif (int)current_argv_len, current_argv); optopt = 0; return (BADCH); } if (match != -1) { /* option found */ if (long_options[match].has_arg == no_argument && has_equal) { if (PRINT_ERROR) warnx(noarg, #ifdef GNU_COMPATIBLE current_dash, #endif (int)current_argv_len, current_argv); /* * XXX: GNU sets optopt to val regardless of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; #ifdef GNU_COMPATIBLE return (BADCH); #else return (BADARG); #endif } if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) { if (has_equal) optarg = has_equal; else if (long_options[match].has_arg == required_argument) { /* * optional argument doesn't use next nargv */ optarg = nargv[optind++]; } } if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) { /* * Missing argument; leading ':' indicates no error * should be generated. */ if (PRINT_ERROR) warnx(recargstring, #ifdef GNU_COMPATIBLE current_dash, #endif current_argv); /* * XXX: GNU sets optopt to val regardless of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; --optind; return (BADARG); } } else { /* unknown option */ if (short_too) { --optind; return (-1); } if (PRINT_ERROR) warnx(illoptstring, #ifdef GNU_COMPATIBLE current_dash, #endif current_argv); optopt = 0; return (BADCH); } if (idx) *idx = match; if (long_options[match].flag) { *long_options[match].flag = long_options[match].val; return (0); } else return (long_options[match].val); } /* * getopt_internal -- * Parse argc/argv argument vector. Called by user level routines. */ static int getopt_internal(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx, int flags) { char *oli; /* option letter list index */ int optchar, short_too; int posixly_correct; /* no static, can be changed on the fly */ if (options == NULL) return (-1); /* * Disable GNU extensions if POSIXLY_CORRECT is set or options * string begins with a '+'. */ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); #ifdef GNU_COMPATIBLE if (*options == '-') flags |= FLAG_ALLARGS; else if (posixly_correct || *options == '+') flags &= ~FLAG_PERMUTE; #else if (posixly_correct || *options == '+') flags &= ~FLAG_PERMUTE; else if (*options == '-') flags |= FLAG_ALLARGS; #endif if (*options == '+' || *options == '-') options++; /* * XXX Some GNU programs (like cvs) set optind to 0 instead of * XXX using optreset. Work around this braindamage. */ if (optind == 0) optind = optreset = 1; optarg = NULL; if (optreset) nonopt_start = nonopt_end = -1; start: if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc) { /* end of argument vector */ place = EMSG; if (nonopt_end != -1) { /* do permutation, if we have to */ permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } else if (nonopt_start != -1) { /* * If we skipped non-options, set optind * to the first of them. */ optind = nonopt_start; } nonopt_start = nonopt_end = -1; return (-1); } if (*(place = nargv[optind]) != '-' || #ifdef GNU_COMPATIBLE place[1] == '\0') { #else (place[1] == '\0' && strchr(options, '-') == NULL)) { #endif place = EMSG; /* found non-option */ if (flags & FLAG_ALLARGS) { /* * GNU extension: * return non-option as argument to option 1 */ optarg = nargv[optind++]; return (INORDER); } if (!(flags & FLAG_PERMUTE)) { /* * If no permutation wanted, stop parsing * at first non-option. */ return (-1); } /* do permutation */ if (nonopt_start == -1) nonopt_start = optind; else if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); nonopt_start = optind - (nonopt_end - nonopt_start); nonopt_end = -1; } optind++; /* process next argument */ goto start; } if (nonopt_start != -1 && nonopt_end == -1) nonopt_end = optind; /* * If we have "-" do nothing, if "--" we are done. */ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { optind++; place = EMSG; /* * We found an option (--), so if we skipped * non-options, we have to permute. */ if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } nonopt_start = nonopt_end = -1; return (-1); } } /* * Check long options if: * 1) we were passed some * 2) the arg is not just "-" * 3) either the arg starts with -- we are getopt_long_only() */ if (long_options != NULL && place != nargv[optind] && (*place == '-' || (flags & FLAG_LONGONLY))) { short_too = 0; #ifdef GNU_COMPATIBLE dash_prefix = D_PREFIX; #endif if (*place == '-') { place++; /* --foo long option */ #ifdef GNU_COMPATIBLE dash_prefix = DD_PREFIX; #endif } else if (*place != ':' && strchr(options, *place) != NULL) short_too = 1; /* could be short option too */ optchar = parse_long_options(nargv, options, long_options, idx, short_too, flags); if (optchar != -1) { place = EMSG; return (optchar); } } if ((optchar = (int)*place++) == (int)':' || (optchar == (int)'-' && *place != '\0') || (oli = strchr(options, optchar)) == NULL) { /* * If the user specified "-" and '-' isn't listed in * options, return -1 (non-option) as per POSIX. * Otherwise, it is an unknown option character (or ':'). */ if (optchar == (int)'-' && *place == '\0') return (-1); if (!*place) ++optind; #ifdef GNU_COMPATIBLE if (PRINT_ERROR) warnx(posixly_correct ? illoptchar : gnuoptchar, optchar); #else if (PRINT_ERROR) warnx(illoptchar, optchar); #endif optopt = optchar; return (BADCH); } if (long_options != NULL && optchar == 'W' && oli[1] == ';') { /* -W long-option */ if (*place) /* no space */ /* NOTHING */; else if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; return (BADARG); } else /* white space */ place = nargv[optind]; #ifdef GNU_COMPATIBLE dash_prefix = W_PREFIX; #endif optchar = parse_long_options(nargv, options, long_options, idx, 0, flags); place = EMSG; return (optchar); } if (*++oli != ':') { /* doesn't take argument */ if (!*place) ++optind; } else { /* takes (optional) argument */ optarg = NULL; if (*place) /* no white space */ optarg = place; else if (oli[1] != ':') { /* arg not optional */ if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; return (BADARG); } else optarg = nargv[optind]; } place = EMSG; ++optind; } /* dump back option letter */ return (optchar); } /* * getopt -- * Parse argc/argv argument vector. * * [eventually this will replace the BSD getopt] */ int getopt(int nargc, char * const *nargv, const char *options) { /* * We don't pass FLAG_PERMUTE to getopt_internal() since * the BSD getopt(3) (unlike GNU) has never done this. * * Furthermore, since many privileged programs call getopt() * before dropping privileges it makes sense to keep things * as simple (and bug-free) as possible. */ return (getopt_internal(nargc, nargv, options, NULL, NULL, FLAG_PERMUTE)); } /* * getopt_long -- * Parse argc/argv argument vector. */ int getopt_long(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx) { return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE)); } /* * getopt_long_only -- * Parse argc/argv argument vector. */ int getopt_long_only(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx) { return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE|FLAG_LONGONLY)); } fdkaac-0.6.3/missings/getopt.h000066400000000000000000000064201276003472100162440ustar00rootroot00000000000000/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ /* $FreeBSD: src/include/getopt.h,v 1.6.34.1 2010/12/21 17:10:29 kensmith Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD 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 NETBSD FOUNDATION, INC. 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 _GETOPT_H_ #define _GETOPT_H_ #ifdef __cplusplus extern "C" { #endif /* * GNU-like getopt_long()/getopt_long_only() with 4.4BSD optreset extension. * getopt() is declared here too for GNU programs. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 struct option { /* name of long option */ const char *name; /* * one of no_argument, required_argument, and optional_argument: * whether option takes an argument */ int has_arg; /* if not NULL, set *flag to val when option found */ int *flag; /* if flag not NULL, value to set *flag to; else return value */ int val; }; int getopt_long(int, char * const *, const char *, const struct option *, int *); int getopt_long_only(int, char * const *, const char *, const struct option *, int *); #ifndef _GETOPT_DECLARED #define _GETOPT_DECLARED int getopt(int, char * const [], const char *); extern char *optarg; /* getopt(3) external variables */ extern int optind, opterr, optopt; #endif #ifndef _OPTRESET_DECLARED #define _OPTRESET_DECLARED extern int optreset; /* getopt(3) external variable */ #endif #ifdef __cplusplus } #endif #endif /* !_GETOPT_H_ */ fdkaac-0.6.3/src/000077500000000000000000000000001276003472100135225ustar00rootroot00000000000000fdkaac-0.6.3/src/aacenc.c000066400000000000000000000223021276003472100150770ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #include #include #include #include "aacenc.h" int aacenc_is_explicit_bw_compatible_sbr_signaling_available() { LIB_INFO lib_info; aacenc_get_lib_info(&lib_info); return lib_info.version > 0x03040900; } int aacenc_is_sbr_ratio_available() { #if AACENCODER_LIB_VL0 < 3 || (AACENCODER_LIB_VL0==3 && AACENCODER_LIB_VL1<4) return 0; #else LIB_INFO lib_info; aacenc_get_lib_info(&lib_info); return lib_info.version > 0x03040800; #endif } int aacenc_is_sbr_active(const aacenc_param_t *params) { switch (params->profile) { case AOT_SBR: case AOT_PS: case AOT_DRM_SBR: case AOT_DRM_MPEG_PS: return 1; } if (params->profile == AOT_ER_AAC_ELD && params->lowdelay_sbr) return 1; return 0; } int aacenc_is_dual_rate_sbr(const aacenc_param_t *params) { if (params->profile == AOT_PS) return 1; else if (params->profile == AOT_SBR) return params->sbr_ratio == 0 || params->sbr_ratio == 2; else if (params->profile == AOT_ER_AAC_ELD && params->lowdelay_sbr) return params->sbr_ratio == 2; return 0; } void aacenc_get_lib_info(LIB_INFO *info) { LIB_INFO *lib_info = 0; lib_info = calloc(FDK_MODULE_LAST, sizeof(LIB_INFO)); if (aacEncGetLibInfo(lib_info) == AACENC_OK) { int i; for (i = 0; i < FDK_MODULE_LAST; ++i) { if (lib_info[i].module_id == FDK_AACENC) { memcpy(info, &lib_info[i], sizeof(LIB_INFO)); break; } } } free(lib_info); } static const unsigned aacenc_sampling_freq_tab[] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0 }; static unsigned sampling_freq_index(unsigned rate) { unsigned i; for (i = 0; aacenc_sampling_freq_tab[i]; ++i) if (aacenc_sampling_freq_tab[i] == rate) return i; return 0xf; } /* * Append backward compatible SBR/PS signaling to implicit signaling ASC, * if SBR/PS is present. */ int aacenc_mp4asc(const aacenc_param_t *params, const uint8_t *asc, uint32_t ascsize, uint8_t *outasc, uint32_t *outsize) { unsigned asc_sfreq = aacenc_sampling_freq_tab[(asc[0]&0x7)<<1 |asc[1]>>7]; unsigned shift = aacenc_is_dual_rate_sbr(params); switch (params->profile) { case AOT_SBR: case AOT_PS: if (!shift) break; if (*outsize < ascsize + 3) return -1; memcpy(outasc, asc, ascsize); /* syncExtensionType:11 (value:0x2b7) */ outasc[ascsize+0] = 0x2b << 1; outasc[ascsize+1] = 0x7 << 5; /* extensionAudioObjectType:5 (value:5)*/ outasc[ascsize+1] |= 5; /* sbrPresentFlag:1 (value:1) */ outasc[ascsize+2] = 0x80; /* extensionSamplingFrequencyIndex:4 */ outasc[ascsize+2] |= sampling_freq_index(asc_sfreq << shift) << 3; if (params->profile == AOT_SBR) { *outsize = ascsize + 3; return 0; } if (*outsize < ascsize + 5) return -1; /* syncExtensionType:11 (value:0x548) */ outasc[ascsize+2] |= 0x5; outasc[ascsize+3] = 0x48; /* psPresentFlag:1 (value:1) */ outasc[ascsize+4] = 0x80; *outsize = ascsize + 5; return 0; } if (*outsize < ascsize) return -1; memcpy(outasc, asc, ascsize); *outsize = ascsize; return 0; } static int aacenc_channel_mode(const pcm_sample_description_t *format) { uint32_t chanmask = format->channel_mask; if (format->channels_per_frame > 8) return 0; if (!chanmask) { static uint32_t defaults[] = { 0x4, 0x3, 0x7, 0, 0x37, 0x3f, 0, 0x63f }; chanmask = defaults[format->channels_per_frame - 1]; } switch (chanmask) { case 0x3: return MODE_2; case 0x4: return MODE_1; case 0x7: return MODE_1_2; case 0x37: return MODE_1_2_2; case 0x3f: return MODE_1_2_2_1; case 0x107: return MODE_1_2_1; case 0x607: return MODE_1_2_2; case 0x60f: return MODE_1_2_2_1; #if AACENCODER_LIB_VL0 > 3 || (AACENCODER_LIB_VL0==3 && AACENCODER_LIB_VL1>=4) case 0xff: return MODE_1_2_2_2_1; case 0x63f: return MODE_7_1_REAR_SURROUND; #endif } return 0; } int aacenc_init(HANDLE_AACENCODER *encoder, const aacenc_param_t *params, const pcm_sample_description_t *format, AACENC_InfoStruct *info) { int channel_mode; int aot; LIB_INFO lib_info; *encoder = 0; aacenc_get_lib_info(&lib_info); if ((channel_mode = aacenc_channel_mode(format)) == 0) { fprintf(stderr, "ERROR: unsupported channel layout\n"); goto FAIL; } if (aacEncOpen(encoder, 0, 0) != AACENC_OK) { fprintf(stderr, "ERROR: aacEncOpen() failed\n"); goto FAIL; } aot = (params->profile ? params->profile : AOT_AAC_LC); if (aacEncoder_SetParam(*encoder, AACENC_AOT, aot) != AACENC_OK) { fprintf(stderr, "ERROR: unsupported profile\n"); goto FAIL; } if (params->bitrate_mode == 0) aacEncoder_SetParam(*encoder, AACENC_BITRATE, params->bitrate); else if (aacEncoder_SetParam(*encoder, AACENC_BITRATEMODE, params->bitrate_mode) != AACENC_OK) { fprintf(stderr, "ERROR: unsupported bitrate mode\n"); goto FAIL; } if (aacEncoder_SetParam(*encoder, AACENC_SAMPLERATE, format->sample_rate) != AACENC_OK) { fprintf(stderr, "ERROR: unsupported sample rate\n"); goto FAIL; } if (aacEncoder_SetParam(*encoder, AACENC_CHANNELMODE, channel_mode) != AACENC_OK) { fprintf(stderr, "ERROR: unsupported channel mode\n"); goto FAIL; } aacEncoder_SetParam(*encoder, AACENC_BANDWIDTH, params->bandwidth); aacEncoder_SetParam(*encoder, AACENC_CHANNELORDER, 1); aacEncoder_SetParam(*encoder, AACENC_AFTERBURNER, !!params->afterburner); aacEncoder_SetParam(*encoder, AACENC_SBR_MODE, params->lowdelay_sbr); #if AACENCODER_LIB_VL0 > 3 || (AACENCODER_LIB_VL0==3 && AACENCODER_LIB_VL1>=4) if (lib_info.version > 0x03040800) aacEncoder_SetParam(*encoder, AACENC_SBR_RATIO, params->sbr_ratio); #endif if (aacEncoder_SetParam(*encoder, AACENC_TRANSMUX, params->transport_format) != AACENC_OK) { fprintf(stderr, "ERROR: unsupported transport format\n"); goto FAIL; } if (aacEncoder_SetParam(*encoder, AACENC_SIGNALING_MODE, params->sbr_signaling) != AACENC_OK) { fprintf(stderr, "ERROR: failed to set SBR signaling mode\n"); goto FAIL; } if (params->adts_crc_check) aacEncoder_SetParam(*encoder, AACENC_PROTECTION, 1); if (params->header_period) aacEncoder_SetParam(*encoder, AACENC_HEADER_PERIOD, params->header_period); if (aacEncEncode(*encoder, 0, 0, 0, 0) != AACENC_OK) { fprintf(stderr, "ERROR: encoder initialization failed\n"); goto FAIL; } if (aacEncInfo(*encoder, info) != AACENC_OK) { fprintf(stderr, "ERROR: cannot retrieve encoder info\n"); goto FAIL; } return 0; FAIL: if (encoder) aacEncClose(encoder); return -1; } int aac_encode_frame(HANDLE_AACENCODER encoder, const pcm_sample_description_t *format, const int16_t *input, unsigned iframes, aacenc_frame_t *output) { uint32_t ilen = iframes * format->channels_per_frame; AACENC_BufDesc ibdesc = { 0 }, obdesc = { 0 }; AACENC_InArgs iargs = { 0 }; AACENC_OutArgs oargs = { 0 }; void *ibufs[] = { (void*)input }; void *obufs[1]; INT ibuf_ids[] = { IN_AUDIO_DATA }; INT obuf_ids[] = { OUT_BITSTREAM_DATA }; INT ibuf_sizes[] = { ilen * sizeof(int16_t) }; INT obuf_sizes[1]; INT ibuf_el_sizes[] = { sizeof(int16_t) }; INT obuf_el_sizes[] = { 1 }; AACENC_ERROR err; unsigned channel_mode, obytes; channel_mode = aacEncoder_GetParam(encoder, AACENC_CHANNELMODE); obytes = 6144 / 8 * channel_mode; if (!output->data || output->capacity < obytes) { uint8_t *p = realloc(output->data, obytes); if (!p) return -1; output->capacity = obytes; output->data = p; } obufs[0] = output->data; obuf_sizes[0] = obytes; iargs.numInSamples = ilen ? ilen : -1; /* -1 for signaling EOF */ ibdesc.numBufs = 1; ibdesc.bufs = ibufs; ibdesc.bufferIdentifiers = ibuf_ids; ibdesc.bufSizes = ibuf_sizes; ibdesc.bufElSizes = ibuf_el_sizes; obdesc.numBufs = 1; obdesc.bufs = obufs; obdesc.bufferIdentifiers = obuf_ids; obdesc.bufSizes = obuf_sizes; obdesc.bufElSizes = obuf_el_sizes; err = aacEncEncode(encoder, &ibdesc, &obdesc, &iargs, &oargs); if (err != AACENC_ENCODE_EOF && err != AACENC_OK) { fprintf(stderr, "ERROR: aacEncEncode() failed\n"); return -1; } output->size = oargs.numOutBytes; return oargs.numInSamples / format->channels_per_frame; } fdkaac-0.6.3/src/aacenc.h000066400000000000000000000027561276003472100151170ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #ifndef AACENC_H #define AACENC_H #include #include "lpcm.h" #define AACENC_PARAMS \ unsigned profile; \ unsigned bitrate; \ unsigned bitrate_mode; \ unsigned bandwidth; \ unsigned afterburner; \ unsigned lowdelay_sbr; \ unsigned sbr_ratio; \ unsigned sbr_signaling; \ unsigned transport_format; \ unsigned adts_crc_check; \ unsigned header_period; typedef struct aacenc_param_t { AACENC_PARAMS } aacenc_param_t; typedef struct aacenc_frame_t { uint8_t *data; uint32_t size, capacity; } aacenc_frame_t; int aacenc_is_explicit_bw_compatible_sbr_signaling_available(); int aacenc_is_sbr_ratio_available(); int aacenc_is_sbr_active(const aacenc_param_t *params); int aacenc_is_dual_rate_sbr(const aacenc_param_t *params); void aacenc_get_lib_info(LIB_INFO *info); int aacenc_mp4asc(const aacenc_param_t *params, const uint8_t *asc, uint32_t ascsize, uint8_t *outasc, uint32_t *outsize); int aacenc_init(HANDLE_AACENCODER *encoder, const aacenc_param_t *params, const pcm_sample_description_t *format, AACENC_InfoStruct *info); int aac_encode_frame(HANDLE_AACENCODER encoder, const pcm_sample_description_t *format, const int16_t *input, unsigned iframes, aacenc_frame_t *output); #endif fdkaac-0.6.3/src/caf_reader.c000066400000000000000000000164611276003472100157510ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #include #include #include #include #include "pcm_reader.h" #include "m4af.h" typedef struct caf_reader_t { pcm_reader_vtbl_t *vtbl; pcm_sample_description_t sample_format; int64_t length; int64_t position; int64_t data_offset; pcm_io_context_t io; aacenc_tag_callback_t tag_callback; void *tag_ctx; uint8_t chanmap[8]; } caf_reader_t; static const pcm_sample_description_t *caf_get_format(pcm_reader_t *reader) { return &((caf_reader_t *)reader)->sample_format; } static int64_t caf_get_length(pcm_reader_t *reader) { return ((caf_reader_t *)reader)->length; } static int64_t caf_get_position(pcm_reader_t *reader) { return ((caf_reader_t *)reader)->position; } static void caf_teardown(pcm_reader_t **reader) { free(*reader); *reader = 0; } static uint32_t caf_next_chunk(caf_reader_t *reader, int64_t *chunk_size) { uint32_t fcc; if (pcm_scanb(&reader->io, "LQ", &fcc, chunk_size) == 2) return fcc; return 0; } static int caf_desc(caf_reader_t *reader, int64_t chunk_size) { double mSampleRate; uint32_t mFormatID, mFormatFlags, mBytesPerPacket, mFramesPerPacket, mChannelsPerFrame, mBitsPerChannel; pcm_sample_description_t *desc = &reader->sample_format; ENSURE(chunk_size >= 32); TRY_IO(pcm_scanb(&reader->io, "QLLLLLL", &mSampleRate, &mFormatID, &mFormatFlags, &mBytesPerPacket, &mFramesPerPacket, &mChannelsPerFrame, &mBitsPerChannel) != 7); ENSURE(mFormatID == M4AF_FOURCC('l','p','c','m')); ENSURE(mSampleRate && mBytesPerPacket && mChannelsPerFrame >= 1 && mChannelsPerFrame <= 8 && mBitsPerChannel && mFramesPerPacket == 1 && mBytesPerPacket % mChannelsPerFrame == 0 && mBytesPerPacket >= mChannelsPerFrame * ((mBitsPerChannel + 7) / 8)); desc->sample_rate = mSampleRate; desc->bits_per_channel = mBitsPerChannel; desc->bytes_per_frame = mBytesPerPacket; desc->channels_per_frame = mChannelsPerFrame; switch (mFormatFlags) { case 0: desc->sample_type = PCM_TYPE_SINT_BE; break; case 1: desc->sample_type = PCM_TYPE_FLOAT_BE; break; case 2: desc->sample_type = PCM_TYPE_SINT; break; case 3: desc->sample_type = PCM_TYPE_FLOAT; break; default: goto FAIL; } TRY_IO(pcm_skip(&reader->io, chunk_size - 32)); return 0; FAIL: return -1; } static int caf_info(caf_reader_t *reader, int64_t chunk_size) { char *buf, *key, *val, *end; size_t len; if (chunk_size < 4 || (buf = malloc(chunk_size)) == 0) return -1; pcm_read(&reader->io, buf, chunk_size); key = buf + 4; end = buf + chunk_size; do { if ((val = key + strlen(key) + 1) < end) { len = strlen(val); if (reader->tag_callback) reader->tag_callback(reader->tag_ctx, key, val, len); key = val + len + 1; } } while (key < end && val < end); if (reader->tag_callback) reader->tag_callback(reader->tag_ctx, 0, 0, 0); free(buf); return 0; } static int caf_read_frames(pcm_reader_t *preader, void *buffer, unsigned nframes) { int rc; unsigned i, j, nbytes; caf_reader_t *reader = (caf_reader_t *)preader; unsigned bpf = reader->sample_format.bytes_per_frame; unsigned nchannels = reader->sample_format.channels_per_frame; unsigned bpc = bpf / nchannels; uint8_t tmp[64]; /* enough room for maximum bpf: 8ch float64 */ uint8_t *bp; uint8_t *chanmap = reader->chanmap; if (nframes > reader->length - reader->position) nframes = reader->length - reader->position; nbytes = nframes * bpf; if (nbytes) { if ((rc = pcm_read(&reader->io, buffer, nbytes)) < 0) return -1; nframes = rc / bpf; for (bp = buffer, i = 0; i < nframes; ++i, bp += bpf) { memcpy(tmp, bp, bpf); for (j = 0; j < nchannels; ++j) memcpy(bp + bpc * j, tmp + bpc * chanmap[j], bpc); } reader->position += nframes; } if (nframes == 0) { /* fetch info after data chunk */ uint32_t fcc; int64_t chunk_size; while ((fcc = caf_next_chunk(reader, &chunk_size)) != 0) { if (fcc == M4AF_FOURCC('i','n','f','o')) TRY_IO(caf_info(reader, chunk_size)); else TRY_IO(pcm_skip(&reader->io, chunk_size)); } } return nframes; FAIL: return 0; } static int caf_parse(caf_reader_t *reader, int64_t *data_length) { uint32_t fcc; int64_t chunk_size; *data_length = 0; /* CAFFileHeader */ TRY_IO(pcm_read32be(&reader->io, &fcc)); ENSURE(fcc == M4AF_FOURCC('c','a','f','f')); TRY_IO(pcm_skip(&reader->io, 4)); /* mFileVersion, mFileFlags */ while ((fcc = caf_next_chunk(reader, &chunk_size)) != 0) { if (fcc == M4AF_FOURCC('d','e','s','c')) TRY_IO(caf_desc(reader, chunk_size)); else if (fcc == M4AF_FOURCC('i','n','f','o')) TRY_IO(caf_info(reader, chunk_size)); else if (fcc == M4AF_FOURCC('c','h','a','n')) { ENSURE(reader->sample_format.channels_per_frame); if (apple_chan_chunk(&reader->io, chunk_size, &reader->sample_format, reader->chanmap) < 0) goto FAIL; } else if (fcc == M4AF_FOURCC('d','a','t','a')) { TRY_IO(pcm_skip(&reader->io, 4)); /* mEditCount */ *data_length = (chunk_size == ~0ULL) ? chunk_size : chunk_size - 4; reader->data_offset = pcm_tell(&reader->io); break; } else TRY_IO(pcm_skip(&reader->io, chunk_size)); } ENSURE(reader->sample_format.channels_per_frame); ENSURE(fcc == M4AF_FOURCC('d','a','t','a')); return 0; FAIL: return -1; } static pcm_reader_vtbl_t caf_vtable = { caf_get_format, caf_get_length, caf_get_position, caf_read_frames, caf_teardown }; pcm_reader_t *caf_open(pcm_io_context_t *io, aacenc_tag_callback_t tag_callback, void *tag_ctx) { caf_reader_t *reader = 0; int64_t data_length; unsigned bpf; if ((reader = calloc(1, sizeof(caf_reader_t))) == 0) return 0; memcpy(&reader->io, io, sizeof(pcm_io_context_t)); reader->tag_callback = tag_callback; reader->tag_ctx = tag_ctx; memcpy(reader->chanmap, "\000\001\002\003\004\005\006\007", 8); if (caf_parse(reader, &data_length) < 0) { free(reader); return 0; } bpf = reader->sample_format.bytes_per_frame; /* CAF uses -1 to indicate "unknown size" */ if (data_length < 0 || data_length % bpf) reader->length = INT64_MAX; else reader->length = data_length / bpf; if (reader->length == INT64_MAX) { if (pcm_seek(&reader->io, 0, SEEK_END) >= 0) { int64_t size = pcm_tell(&reader->io); if (size > 0) reader->length = (size - reader->data_offset) / bpf; pcm_seek(&reader->io, reader->data_offset, SEEK_SET); } } reader->vtbl = &caf_vtable; return (pcm_reader_t *)reader; } fdkaac-0.6.3/src/catypes.h000066400000000000000000000404641276003472100153530ustar00rootroot00000000000000#if !defined(__CoreAudioTypes_h__) #define __CoreAudioTypes_h__ enum { kVariableLengthArray = 1 }; typedef uint32_t AudioChannelLabel; typedef uint32_t AudioChannelLayoutTag; struct AudioChannelDescription { AudioChannelLabel mChannelLabel; uint32_t mChannelFlags; float mCoordinates[3]; }; typedef struct AudioChannelDescription AudioChannelDescription; struct AudioChannelLayout { AudioChannelLayoutTag mChannelLayoutTag; uint32_t mChannelBitmap; uint32_t mNumberChannelDescriptions; AudioChannelDescription mChannelDescriptions[kVariableLengthArray]; }; typedef struct AudioChannelLayout AudioChannelLayout; enum { kAudioChannelLabel_Unknown = 0xFFFFFFFF, // unknown or unspecified other use kAudioChannelLabel_Unused = 0, // channel is present, but has no intended use or destination kAudioChannelLabel_UseCoordinates = 100, // channel is described by the mCoordinates fields. kAudioChannelLabel_Left = 1, kAudioChannelLabel_Right = 2, kAudioChannelLabel_Center = 3, kAudioChannelLabel_LFEScreen = 4, kAudioChannelLabel_LeftSurround = 5, // WAVE: "Back Left" kAudioChannelLabel_RightSurround = 6, // WAVE: "Back Right" kAudioChannelLabel_LeftCenter = 7, kAudioChannelLabel_RightCenter = 8, kAudioChannelLabel_CenterSurround = 9, // WAVE: "Back Center" or plain "Rear Surround" kAudioChannelLabel_LeftSurroundDirect = 10, // WAVE: "Side Left" kAudioChannelLabel_RightSurroundDirect = 11, // WAVE: "Side Right" kAudioChannelLabel_TopCenterSurround = 12, kAudioChannelLabel_VerticalHeightLeft = 13, // WAVE: "Top Front Left" kAudioChannelLabel_VerticalHeightCenter = 14, // WAVE: "Top Front Center" kAudioChannelLabel_VerticalHeightRight = 15, // WAVE: "Top Front Right" kAudioChannelLabel_TopBackLeft = 16, kAudioChannelLabel_TopBackCenter = 17, kAudioChannelLabel_TopBackRight = 18, kAudioChannelLabel_RearSurroundLeft = 33, kAudioChannelLabel_RearSurroundRight = 34, kAudioChannelLabel_LeftWide = 35, kAudioChannelLabel_RightWide = 36, kAudioChannelLabel_LFE2 = 37, kAudioChannelLabel_LeftTotal = 38, // matrix encoded 4 channels kAudioChannelLabel_RightTotal = 39, // matrix encoded 4 channels kAudioChannelLabel_HearingImpaired = 40, kAudioChannelLabel_Narration = 41, kAudioChannelLabel_Mono = 42, kAudioChannelLabel_DialogCentricMix = 43, kAudioChannelLabel_CenterSurroundDirect = 44, // back center, non diffuse kAudioChannelLabel_Haptic = 45, // first order ambisonic channels kAudioChannelLabel_Ambisonic_W = 200, kAudioChannelLabel_Ambisonic_X = 201, kAudioChannelLabel_Ambisonic_Y = 202, kAudioChannelLabel_Ambisonic_Z = 203, // Mid/Side Recording kAudioChannelLabel_MS_Mid = 204, kAudioChannelLabel_MS_Side = 205, // X-Y Recording kAudioChannelLabel_XY_X = 206, kAudioChannelLabel_XY_Y = 207, // other kAudioChannelLabel_HeadphonesLeft = 301, kAudioChannelLabel_HeadphonesRight = 302, kAudioChannelLabel_ClickTrack = 304, kAudioChannelLabel_ForeignLanguage = 305, // generic discrete channel kAudioChannelLabel_Discrete = 400, // numbered discrete channel kAudioChannelLabel_Discrete_0 = (1L<<16) | 0, kAudioChannelLabel_Discrete_1 = (1L<<16) | 1, kAudioChannelLabel_Discrete_2 = (1L<<16) | 2, kAudioChannelLabel_Discrete_3 = (1L<<16) | 3, kAudioChannelLabel_Discrete_4 = (1L<<16) | 4, kAudioChannelLabel_Discrete_5 = (1L<<16) | 5, kAudioChannelLabel_Discrete_6 = (1L<<16) | 6, kAudioChannelLabel_Discrete_7 = (1L<<16) | 7, kAudioChannelLabel_Discrete_8 = (1L<<16) | 8, kAudioChannelLabel_Discrete_9 = (1L<<16) | 9, kAudioChannelLabel_Discrete_10 = (1L<<16) | 10, kAudioChannelLabel_Discrete_11 = (1L<<16) | 11, kAudioChannelLabel_Discrete_12 = (1L<<16) | 12, kAudioChannelLabel_Discrete_13 = (1L<<16) | 13, kAudioChannelLabel_Discrete_14 = (1L<<16) | 14, kAudioChannelLabel_Discrete_15 = (1L<<16) | 15, kAudioChannelLabel_Discrete_65535 = (1L<<16) | 65535 }; #define AudioChannelLayoutTag_GetNumberOfChannels(layoutTag) \ ((uint32_t)((layoutTag) & 0x0000FFFF)) enum { kAudioChannelLayoutTag_UseChannelDescriptions = (0L<<16) | 0, // use the array of AudioChannelDescriptions to define the mapping. kAudioChannelLayoutTag_UseChannelBitmap = (1L<<16) | 0, // use the bitmap to define the mapping. kAudioChannelLayoutTag_Mono = (100L<<16) | 1, // a standard mono stream kAudioChannelLayoutTag_Stereo = (101L<<16) | 2, // a standard stereo stream (L R) - implied playback kAudioChannelLayoutTag_StereoHeadphones = (102L<<16) | 2, // a standard stereo stream (L R) - implied headphone playbac kAudioChannelLayoutTag_MatrixStereo = (103L<<16) | 2, // a matrix encoded stereo stream (Lt, Rt) kAudioChannelLayoutTag_MidSide = (104L<<16) | 2, // mid/side recording kAudioChannelLayoutTag_XY = (105L<<16) | 2, // coincident mic pair (often 2 figure 8's) kAudioChannelLayoutTag_Binaural = (106L<<16) | 2, // binaural stereo (left, right) kAudioChannelLayoutTag_Ambisonic_B_Format = (107L<<16) | 4, // W, X, Y, Z kAudioChannelLayoutTag_Quadraphonic = (108L<<16) | 4, // front left, front right, back left, back right kAudioChannelLayoutTag_Pentagonal = (109L<<16) | 5, // left, right, rear left, rear right, center kAudioChannelLayoutTag_Hexagonal = (110L<<16) | 6, // left, right, rear left, rear right, center, rear kAudioChannelLayoutTag_Octagonal = (111L<<16) | 8, // front left, front right, rear left, rear right, // front center, rear center, side left, side right kAudioChannelLayoutTag_Cube = (112L<<16) | 8, // left, right, rear left, rear right // top left, top right, top rear left, top rear right // MPEG defined layouts kAudioChannelLayoutTag_MPEG_1_0 = kAudioChannelLayoutTag_Mono, // C kAudioChannelLayoutTag_MPEG_2_0 = kAudioChannelLayoutTag_Stereo, // L R kAudioChannelLayoutTag_MPEG_3_0_A = (113L<<16) | 3, // L R C kAudioChannelLayoutTag_MPEG_3_0_B = (114L<<16) | 3, // C L R kAudioChannelLayoutTag_MPEG_4_0_A = (115L<<16) | 4, // L R C Cs kAudioChannelLayoutTag_MPEG_4_0_B = (116L<<16) | 4, // C L R Cs kAudioChannelLayoutTag_MPEG_5_0_A = (117L<<16) | 5, // L R C Ls Rs kAudioChannelLayoutTag_MPEG_5_0_B = (118L<<16) | 5, // L R Ls Rs C kAudioChannelLayoutTag_MPEG_5_0_C = (119L<<16) | 5, // L C R Ls Rs kAudioChannelLayoutTag_MPEG_5_0_D = (120L<<16) | 5, // C L R Ls Rs kAudioChannelLayoutTag_MPEG_5_1_A = (121L<<16) | 6, // L R C LFE Ls Rs kAudioChannelLayoutTag_MPEG_5_1_B = (122L<<16) | 6, // L R Ls Rs C LFE kAudioChannelLayoutTag_MPEG_5_1_C = (123L<<16) | 6, // L C R Ls Rs LFE kAudioChannelLayoutTag_MPEG_5_1_D = (124L<<16) | 6, // C L R Ls Rs LFE kAudioChannelLayoutTag_MPEG_6_1_A = (125L<<16) | 7, // L R C LFE Ls Rs Cs kAudioChannelLayoutTag_MPEG_7_1_A = (126L<<16) | 8, // L R C LFE Ls Rs Lc Rc kAudioChannelLayoutTag_MPEG_7_1_B = (127L<<16) | 8, // C Lc Rc L R Ls Rs LFE (doc: IS-13818-7 MPEG2-AAC Table 3.1) kAudioChannelLayoutTag_MPEG_7_1_C = (128L<<16) | 8, // L R C LFE Ls Rs Rls Rrs kAudioChannelLayoutTag_Emagic_Default_7_1 = (129L<<16) | 8, // L R Ls Rs C LFE Lc Rc kAudioChannelLayoutTag_SMPTE_DTV = (130L<<16) | 8, // L R C LFE Ls Rs Lt Rt // (kAudioChannelLayoutTag_ITU_5_1 plus a matrix encoded stereo mix) // ITU defined layouts kAudioChannelLayoutTag_ITU_1_0 = kAudioChannelLayoutTag_Mono, // C kAudioChannelLayoutTag_ITU_2_0 = kAudioChannelLayoutTag_Stereo, // L R kAudioChannelLayoutTag_ITU_2_1 = (131L<<16) | 3, // L R Cs kAudioChannelLayoutTag_ITU_2_2 = (132L<<16) | 4, // L R Ls Rs kAudioChannelLayoutTag_ITU_3_0 = kAudioChannelLayoutTag_MPEG_3_0_A, // L R C kAudioChannelLayoutTag_ITU_3_1 = kAudioChannelLayoutTag_MPEG_4_0_A, // L R C Cs kAudioChannelLayoutTag_ITU_3_2 = kAudioChannelLayoutTag_MPEG_5_0_A, // L R C Ls Rs kAudioChannelLayoutTag_ITU_3_2_1 = kAudioChannelLayoutTag_MPEG_5_1_A, // L R C LFE Ls Rs kAudioChannelLayoutTag_ITU_3_4_1 = kAudioChannelLayoutTag_MPEG_7_1_C, // L R C LFE Ls Rs Rls Rrs // DVD defined layouts kAudioChannelLayoutTag_DVD_0 = kAudioChannelLayoutTag_Mono, // C (mono) kAudioChannelLayoutTag_DVD_1 = kAudioChannelLayoutTag_Stereo, // L R kAudioChannelLayoutTag_DVD_2 = kAudioChannelLayoutTag_ITU_2_1, // L R Cs kAudioChannelLayoutTag_DVD_3 = kAudioChannelLayoutTag_ITU_2_2, // L R Ls Rs kAudioChannelLayoutTag_DVD_4 = (133L<<16) | 3, // L R LFE kAudioChannelLayoutTag_DVD_5 = (134L<<16) | 4, // L R LFE Cs kAudioChannelLayoutTag_DVD_6 = (135L<<16) | 5, // L R LFE Ls Rs kAudioChannelLayoutTag_DVD_7 = kAudioChannelLayoutTag_MPEG_3_0_A, // L R C kAudioChannelLayoutTag_DVD_8 = kAudioChannelLayoutTag_MPEG_4_0_A, // L R C Cs kAudioChannelLayoutTag_DVD_9 = kAudioChannelLayoutTag_MPEG_5_0_A, // L R C Ls Rs kAudioChannelLayoutTag_DVD_10 = (136L<<16) | 4, // L R C LFE kAudioChannelLayoutTag_DVD_11 = (137L<<16) | 5, // L R C LFE Cs kAudioChannelLayoutTag_DVD_12 = kAudioChannelLayoutTag_MPEG_5_1_A, // L R C LFE Ls Rs // 13 through 17 are duplicates of 8 through 12. kAudioChannelLayoutTag_DVD_13 = kAudioChannelLayoutTag_DVD_8, // L R C Cs kAudioChannelLayoutTag_DVD_14 = kAudioChannelLayoutTag_DVD_9, // L R C Ls Rs kAudioChannelLayoutTag_DVD_15 = kAudioChannelLayoutTag_DVD_10, // L R C LFE kAudioChannelLayoutTag_DVD_16 = kAudioChannelLayoutTag_DVD_11, // L R C LFE Cs kAudioChannelLayoutTag_DVD_17 = kAudioChannelLayoutTag_DVD_12, // L R C LFE Ls Rs kAudioChannelLayoutTag_DVD_18 = (138L<<16) | 5, // L R Ls Rs LFE kAudioChannelLayoutTag_DVD_19 = kAudioChannelLayoutTag_MPEG_5_0_B, // L R Ls Rs C kAudioChannelLayoutTag_DVD_20 = kAudioChannelLayoutTag_MPEG_5_1_B, // L R Ls Rs C LFE // These layouts are recommended for AudioUnit usage // These are the symmetrical layouts kAudioChannelLayoutTag_AudioUnit_4 = kAudioChannelLayoutTag_Quadraphonic, kAudioChannelLayoutTag_AudioUnit_5 = kAudioChannelLayoutTag_Pentagonal, kAudioChannelLayoutTag_AudioUnit_6 = kAudioChannelLayoutTag_Hexagonal, kAudioChannelLayoutTag_AudioUnit_8 = kAudioChannelLayoutTag_Octagonal, // These are the surround-based layouts kAudioChannelLayoutTag_AudioUnit_5_0 = kAudioChannelLayoutTag_MPEG_5_0_B, // L R Ls Rs C kAudioChannelLayoutTag_AudioUnit_6_0 = (139L<<16) | 6, // L R Ls Rs C Cs kAudioChannelLayoutTag_AudioUnit_7_0 = (140L<<16) | 7, // L R Ls Rs C Rls Rrs kAudioChannelLayoutTag_AudioUnit_7_0_Front = (148L<<16) | 7, // L R Ls Rs C Lc Rc kAudioChannelLayoutTag_AudioUnit_5_1 = kAudioChannelLayoutTag_MPEG_5_1_A, // L R C LFE Ls Rs kAudioChannelLayoutTag_AudioUnit_6_1 = kAudioChannelLayoutTag_MPEG_6_1_A, // L R C LFE Ls Rs Cs kAudioChannelLayoutTag_AudioUnit_7_1 = kAudioChannelLayoutTag_MPEG_7_1_C, // L R C LFE Ls Rs Rls Rrs kAudioChannelLayoutTag_AudioUnit_7_1_Front = kAudioChannelLayoutTag_MPEG_7_1_A, // L R C LFE Ls Rs Lc Rc kAudioChannelLayoutTag_AAC_3_0 = kAudioChannelLayoutTag_MPEG_3_0_B, // C L R kAudioChannelLayoutTag_AAC_Quadraphonic = kAudioChannelLayoutTag_Quadraphonic, // L R Ls Rs kAudioChannelLayoutTag_AAC_4_0 = kAudioChannelLayoutTag_MPEG_4_0_B, // C L R Cs kAudioChannelLayoutTag_AAC_5_0 = kAudioChannelLayoutTag_MPEG_5_0_D, // C L R Ls Rs kAudioChannelLayoutTag_AAC_5_1 = kAudioChannelLayoutTag_MPEG_5_1_D, // C L R Ls Rs Lfe kAudioChannelLayoutTag_AAC_6_0 = (141L<<16) | 6, // C L R Ls Rs Cs kAudioChannelLayoutTag_AAC_6_1 = (142L<<16) | 7, // C L R Ls Rs Cs Lfe kAudioChannelLayoutTag_AAC_7_0 = (143L<<16) | 7, // C L R Ls Rs Rls Rrs kAudioChannelLayoutTag_AAC_7_1 = kAudioChannelLayoutTag_MPEG_7_1_B, // C Lc Rc L R Ls Rs Lfe kAudioChannelLayoutTag_AAC_Octagonal = (144L<<16) | 8, // C L R Ls Rs Rls Rrs Cs kAudioChannelLayoutTag_TMH_10_2_std = (145L<<16) | 16, // L R C Vhc Lsd Rsd Ls Rs Vhl Vhr Lw Rw Csd Cs LFE1 LFE2 kAudioChannelLayoutTag_TMH_10_2_full = (146L<<16) | 21, // TMH_10_2_std plus: Lc Rc HI VI Haptic kAudioChannelLayoutTag_AC3_1_0_1 = (149L<<16) | 2, // C LFE kAudioChannelLayoutTag_AC3_3_0 = (150L<<16) | 3, // L C R kAudioChannelLayoutTag_AC3_3_1 = (151L<<16) | 4, // L C R Cs kAudioChannelLayoutTag_AC3_3_0_1 = (152L<<16) | 4, // L C R LFE kAudioChannelLayoutTag_AC3_2_1_1 = (153L<<16) | 4, // L R Cs LFE kAudioChannelLayoutTag_AC3_3_1_1 = (154L<<16) | 5, // L C R Cs LFE kAudioChannelLayoutTag_DiscreteInOrder = (147L<<16) | 0, // needs to be ORed with the actual number of channels kAudioChannelLayoutTag_Unknown = 0xFFFF0000 // needs to be ORed with the actual number of channels }; #endif fdkaac-0.6.3/src/compat.h000066400000000000000000000015111276003472100151540ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #ifndef COMPAT_H #define COMPAT_H #ifndef HAVE_FSEEKO # if HAVE_FSEEKO64 # define fseeko fseeko64 # define ftello ftello64 # elif _MSC_VER >= 1400 # define fseeko _fseeki64 # define ftello _ftelli64 # else # define fseeko fseek # define ftello ftell # endif #endif int64_t aacenc_timer(void); FILE *aacenc_fopen(const char *name, const char *mode); #ifdef _WIN32 void aacenc_getmainargs(int *argc, char ***argv); #else #define aacenc_getmainargs(argc, argv) (void)0 #endif char *aacenc_to_utf8(const char *s); #ifdef _WIN32 int aacenc_fprintf(FILE *fp, const char *fmt, ...); #else #define aacenc_fprintf fprintf #endif const char *aacenc_basename(const char *path); int aacenc_seekable(FILE *fp); #endif fdkaac-0.6.3/src/compat_posix.c000066400000000000000000000055371276003472100164050ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #include #include #include #include #include #include "compat.h" int64_t aacenc_timer(void) { struct timeval tv = { 0 }; gettimeofday(&tv, 0); return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; } FILE *aacenc_fopen(const char *name, const char *mode) { FILE *fp; if (strcmp(name, "-") == 0) fp = (mode[0] == 'r') ? stdin : stdout; else fp = fopen(name, mode); return fp; } int aacenc_seekable(FILE *fp) { return fseek(fp, 0, SEEK_CUR) == 0; } /* * Different from POSIX basename() when path ends with /. * Since we use this only for a regular file, the difference doesn't matter. */ const char *aacenc_basename(const char *path) { const char *p = strrchr(path, '/'); return p ? p + 1: path; } #ifndef HAVE_ICONV char *aacenc_to_utf8(const char *s) { return strdup(s); } #else /* HAVE_ICONV */ #include #include #include #include #if HAVE_LOCALCHARSET_H #include #elif HAVE_LANGINFO_H #include static const char *locale_charset(void) { return nl_langinfo(CODESET); } #else static const char *locale_charset(void) { return 0; } #endif static int utf8_from_charset(const char *charset, const char *from, char **to) { iconv_t cd; size_t fromlen, obsize, ibleft, obleft; char *ip, *op; cd = iconv_open("UTF-8", charset); if (cd == (iconv_t)-1) return -1; fromlen = strlen(from); ibleft = fromlen; obsize = 2; obleft = obsize - 1; *to = malloc(obsize); ip = (char *)from; op = *to; while (ibleft > 0) { if (iconv(cd, &ip, &ibleft, &op, &obleft) != (size_t)-1) break; else { if (errno == E2BIG || obleft == 0) { ptrdiff_t offset = op - *to; obsize *= 2; *to = realloc(*to, obsize); op = *to + offset; obleft = obsize - offset - 1; } if (errno == EILSEQ) { ++ip; --ibleft; *op++ = '?'; --obleft; } if (errno != E2BIG && errno != EILSEQ) break; } } iconv_close(cd); *op = 0; if (fromlen > 0 && op == *to) { free(op); return -1; } return 0; } char *aacenc_to_utf8(const char *s) { char *result; const char *charset; if ((charset = locale_charset()) == 0) charset = "US-ASCII"; if (utf8_from_charset(charset, s, &result) < 0) result = strdup(s); return result; } #endif /* HAVE_ICONV */ fdkaac-0.6.3/src/compat_win32.c000066400000000000000000000077461276003472100162110ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #include #include #include #include #include #include #include #include #include #include "compat.h" #define WIN32_LEAN_AND_MEAN #include #include int64_t aacenc_timer(void) { #if HAVE_STRUCT___TIMEB64 struct __timeb64 tv; _ftime64(&tv); #else struct timeb tv; ftime(&tv); #endif return (int64_t)tv.time * 1000 + tv.millitm; } int aacenc_seekable(FILE *fp) { return GetFileType((HANDLE)_get_osfhandle(_fileno(fp))) == FILE_TYPE_DISK; } static int codepage_decode_wchar(int codepage, const char *from, wchar_t **to) { int nc = MultiByteToWideChar(codepage, 0, from, -1, 0, 0); if (nc == 0) return -1; *to = malloc(nc * sizeof(wchar_t)); MultiByteToWideChar(codepage, 0, from, -1, *to, nc); return 0; } static int codepage_encode_wchar(int codepage, const wchar_t *from, char **to) { int nc = WideCharToMultiByte(codepage, 0, from, -1, 0, 0, 0, 0); if (nc == 0) return -1; *to = malloc(nc); WideCharToMultiByte(codepage, 0, from, -1, *to, nc, 0, 0); return 0; } FILE *aacenc_fopen(const char *name, const char *mode) { wchar_t *wname, *wmode; FILE *fp; if (strcmp(name, "-") == 0) { fp = (mode[0] == 'r') ? stdin : stdout; _setmode(_fileno(fp), _O_BINARY); } else { int share = _SH_DENYRW; if (strchr(mode, 'r') && !strchr(mode, '+')) share = _SH_DENYWR; codepage_decode_wchar(CP_UTF8, name, &wname); codepage_decode_wchar(CP_UTF8, mode, &wmode); fp = _wfsopen(wname, wmode, share); free(wname); free(wmode); } return fp; } static char **__aacenc_argv__; static void aacenc_free_mainargs(void) { char **p = __aacenc_argv__; for (; *p; ++p) free(*p); free(__aacenc_argv__); } void aacenc_getmainargs(int *argc, char ***argv) { int i; wchar_t **wargv; wargv = CommandLineToArgvW(GetCommandLineW(), argc); *argv = malloc((*argc + 1) * sizeof(char*)); for (i = 0; i < *argc; ++i) codepage_encode_wchar(CP_UTF8, wargv[i], &(*argv)[i]); LocalFree(wargv); (*argv)[*argc] = 0; __aacenc_argv__ = *argv; atexit(aacenc_free_mainargs); } char *aacenc_to_utf8(const char *s) { return _strdup(s); } #if defined(__MINGW32__) && !defined(HAVE__VSCPRINTF) int _vscprintf(const char *fmt, va_list ap) { static int (*fp_vscprintf)(const char *, va_list) = 0; if (!fp_vscprintf) { HANDLE h = GetModuleHandleA("msvcrt.dll"); FARPROC fp = GetProcAddress(h, "_vscprintf"); InterlockedCompareExchangePointer(&fp_vscprintf, fp, 0); } assert(fp_vscprintf); return fp_vscprintf(fmt, ap); } #endif int aacenc_fprintf(FILE *fp, const char *fmt, ...) { va_list ap; int cnt; HANDLE fh = (HANDLE)_get_osfhandle(_fileno(fp)); if (GetFileType(fh) != FILE_TYPE_CHAR) { va_start(ap, fmt); cnt = vfprintf(fp, fmt, ap); va_end(ap); } else { char *s; wchar_t *ws; DWORD nw; va_start(ap, fmt); cnt = _vscprintf(fmt, ap); va_end(ap); s = malloc(cnt + 1); va_start(ap, fmt); cnt = _vsnprintf(s, cnt + 1, fmt, ap); va_end(ap); codepage_decode_wchar(CP_UTF8, s, &ws); free(s); fflush(fp); WriteConsoleW(fh, ws, wcslen(ws), &nw, 0); free(ws); } return cnt; } const char *aacenc_basename(const char *path) { /* * Since path is encoded with UTF-8, naive usage of strrchr() shoule be safe. */ const char *p = strrchr(path, '/'); const char *q = strrchr(path, '\\'); const char *r = strrchr(path, ':'); if (q > p) p = q; if (r > p) p = r; return p ? p + 1 : path; } fdkaac-0.6.3/src/extrapolater.c000066400000000000000000000145461276003472100164120ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #include #include #include #include "pcm_reader.h" #include "lpc.h" typedef int16_t sample_t; typedef struct buffer_t { sample_t *data; unsigned count; /* count in frames */ unsigned capacity; /* size in bytes */ } buffer_t; typedef struct extrapolater_t { pcm_reader_vtbl_t *vtbl; pcm_reader_t *src; pcm_sample_description_t format; buffer_t buffer[2]; unsigned nbuffer; int (*process)(struct extrapolater_t *, void *, unsigned); } extrapolater_t; #define LPC_ORDER 32 static inline pcm_reader_t *get_source(pcm_reader_t *reader) { return ((extrapolater_t *)reader)->src; } static const pcm_sample_description_t *get_format(pcm_reader_t *reader) { return pcm_get_format(get_source(reader)); } static int64_t get_length(pcm_reader_t *reader) { return pcm_get_length(get_source(reader)); } static int64_t get_position(pcm_reader_t *reader) { return pcm_get_position(get_source(reader)); } static int realloc_buffer(buffer_t *bp, size_t size) { if (bp->capacity < size) { void *p = realloc(bp->data, size); if (!p) return -1; bp->data = p; bp->capacity = size; } return 0; } static void reverse_buffer(sample_t *data, unsigned nframes, unsigned nchannels) { unsigned i = 0, j = nchannels * (nframes - 1), n; for (; i < j; i += nchannels, j -= nchannels) { for (n = 0; n < nchannels; ++n) { sample_t tmp = data[i + n]; data[i + n] = data[j + n]; data[j + n] = tmp; } } } static int fetch(extrapolater_t *self, unsigned nframes) { const pcm_sample_description_t *sfmt = pcm_get_format(self->src); buffer_t *bp = &self->buffer[self->nbuffer]; int rc = 0; if (realloc_buffer(bp, nframes * sfmt->bytes_per_frame) == 0) { rc = pcm_read_frames(self->src, bp->data, nframes); if (rc > 0) bp->count = rc; } if (rc > 0) self->nbuffer ^= 1; return rc <= 0 ? 0 : bp->count; } static int extrapolate(extrapolater_t *self, const buffer_t *bp, void *dst, unsigned nframes) { const pcm_sample_description_t *sfmt = pcm_get_format(self->src); unsigned i, n = sfmt->channels_per_frame; float lpc[LPC_ORDER]; for (i = 0; i < n; ++i) { vorbis_lpc_from_data(bp->data + i, lpc, bp->count, LPC_ORDER, n); vorbis_lpc_predict(lpc, &bp->data[i + n * (bp->count - LPC_ORDER)], LPC_ORDER, (sample_t*)dst + i, nframes, n); } return nframes; } static int process1(extrapolater_t *self, void *buffer, unsigned nframes); static int process2(extrapolater_t *self, void *buffer, unsigned nframes); static int process3(extrapolater_t *self, void *buffer, unsigned nframes); static int process0(extrapolater_t *self, void *buffer, unsigned nframes) { const pcm_sample_description_t *sfmt = pcm_get_format(self->src); unsigned nchannels = sfmt->channels_per_frame; buffer_t *bp = &self->buffer[self->nbuffer]; if (fetch(self, nframes) < 2 * LPC_ORDER) memset(buffer, 0, nframes * sfmt->bytes_per_frame); else { reverse_buffer(bp->data, bp->count, nchannels); extrapolate(self, bp, buffer, nframes); reverse_buffer(buffer, nframes, nchannels); reverse_buffer(bp->data, bp->count, nchannels); } if (bp->count) self->process = process1; else { memset(bp->data, 0, nframes * sfmt->bytes_per_frame); bp->count = nframes; self->process = process2; } return nframes; } static int process1(extrapolater_t *self, void *buffer, unsigned nframes) { const pcm_sample_description_t *sfmt = pcm_get_format(self->src); buffer_t *bp = &self->buffer[self->nbuffer ^ 1]; assert(bp->count <= nframes); memcpy(buffer, bp->data, bp->count * sfmt->bytes_per_frame); if (!fetch(self, nframes)) { buffer_t *bbp = &self->buffer[self->nbuffer]; if (bp->count < 2 * LPC_ORDER) { size_t total = bp->count + bbp->count; if (bbp->count && realloc_buffer(bbp, total * sfmt->bytes_per_frame) == 0 && realloc_buffer(bp, total * sfmt->bytes_per_frame) == 0) { memcpy(bbp->data + bbp->count * sfmt->channels_per_frame, bp->data, bp->count * sfmt->bytes_per_frame); memcpy(bp->data, bbp->data, total * sfmt->bytes_per_frame); bp->count = total; } } if (bp->count >= 2 * LPC_ORDER) extrapolate(self, bp, bbp->data, nframes); else memset(bbp->data, 0, nframes * sfmt->bytes_per_frame); bbp->count = nframes; self->process = process2; } return bp->count; } static int process2(extrapolater_t *self, void *buffer, unsigned nframes) { const pcm_sample_description_t *sfmt = pcm_get_format(self->src); buffer_t *bp = &self->buffer[self->nbuffer]; if (bp->count < nframes) nframes = bp->count; memcpy(buffer, bp->data, nframes * sfmt->bytes_per_frame); if (bp->count > nframes) memmove(bp->data, bp->data + nframes * sfmt->channels_per_frame, (bp->count - nframes) * sfmt->bytes_per_frame); bp->count -= nframes; if (bp->count == 0) self->process = process3; return nframes; } static int process3(extrapolater_t *self, void *buffer, unsigned nframes) { return 0; } static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes) { extrapolater_t *self = (extrapolater_t *)reader; return self->process(self, buffer, nframes); } static void teardown(pcm_reader_t **reader) { extrapolater_t *self = (extrapolater_t *)*reader; pcm_teardown(&self->src); free(self->buffer[0].data); free(self->buffer[1].data); free(self); *reader = 0; } static pcm_reader_vtbl_t my_vtable = { get_format, get_length, get_position, read_frames, teardown }; pcm_reader_t *extrapolater_open(pcm_reader_t *reader) { extrapolater_t *self = 0; if ((self = calloc(1, sizeof(extrapolater_t))) == 0) return 0; self->src = reader; self->vtbl = &my_vtable; self->process = process0; return (pcm_reader_t *)self; } fdkaac-0.6.3/src/limiter.c000066400000000000000000000130121276003472100153300ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #include #include #include #include #include #include "pcm_reader.h" #include "lpc.h" typedef struct buffer_t { void *data; unsigned count; unsigned capacity; unsigned head; } buffer_t; typedef struct limiter_t { pcm_reader_vtbl_t *vtbl; pcm_reader_t *src; pcm_sample_description_t format; int64_t position; buffer_t buffers[1]; } limiter_t; static inline pcm_reader_t *get_source(pcm_reader_t *reader) { return ((limiter_t *)reader)->src; } static const pcm_sample_description_t *get_format(pcm_reader_t *reader) { return pcm_get_format(get_source(reader)); } static int64_t get_length(pcm_reader_t *reader) { return pcm_get_length(get_source(reader)); } static int64_t get_position(pcm_reader_t *reader) { return ((limiter_t *)reader)->position; } static int reserve_buffer(buffer_t *bp, size_t required, unsigned unit) { if (bp->capacity < required) { unsigned newsize = 1; void *p; while (newsize < required) newsize <<= 1; p = realloc(bp->data, newsize * unit); if (!p) return -1; bp->data = p; bp->capacity = newsize; } return 0; } static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes) { limiter_t *self = (limiter_t *)reader; unsigned i, n, res, nch = self->format.channels_per_frame; size_t bytes = nframes * pcm_get_format(self->src)->bytes_per_frame; buffer_t *ibp = &self->buffers[nch]; float *obp = buffer; do { if (reserve_buffer(ibp, bytes, 1) < 0) return -1; res = pcm_read_frames(self->src, ibp->data, nframes); for (n = 0; n < nch; ++n) { float *ip = (float *)ibp->data, *x; buffer_t *bp = &self->buffers[n]; unsigned end, limit; if (reserve_buffer(bp, bp->count + res, sizeof(float)) < 0) return -1; x = bp->data; for (i = 0; i < res; ++i) x[bp->count++] = pcm_clip(ip[i * nch + n], -3.0, 3.0); limit = bp->count; if (limit > 0 && res > 0) { float last = x[limit - 1]; for (; limit > 0 && x[limit-1] * last > 0; --limit) ; } end = bp->head; while (end < limit) { unsigned start, peak_pos; float peak; for (peak_pos = end; peak_pos < limit; ++peak_pos) if (x[peak_pos] > 1.0f || x[peak_pos] < -1.0f) break; if (peak_pos == limit) break; start = peak_pos; peak = fabs(x[peak_pos]); while (start > bp->head && x[peak_pos] * x[start] >= 0.0f) --start; ++start; for (end = peak_pos + 1; end < limit; ++end) { float y; if (x[peak_pos] * x[end] < 0.0f) break; y = fabs(x[end]); if (y > peak) { peak = y; peak_pos = end; } } if (peak < 2.0f) { float a = (peak - 1.0f) / (peak * peak); if (x[peak_pos] > 0.0f) a = -a; for (i = start; i < end; ++i) x[i] = x[i] + a * x[i] * x[i]; } else { float u = peak, v = 1.0f; float a = (u - 2.0f * v) / (u * u * u); float b = (3.0f * v - 2.0f * u) / (u * u); if (x[peak_pos] < 0.0f) b = -b; for (i = start; i < end; ++i) x[i] = x[i] + b * x[i] * x[i] + a * x[i] * x[i] * x[i]; } } bp->head = limit; } res = nframes; for (n = 0; n < nch; ++n) if (self->buffers[n].head < res) res = self->buffers[n].head; for (i = 0; i < res; ++i) for (n = 0; n < nch; ++n) *obp++ = ((float *)self->buffers[n].data)[i]; if (res) { for (n = 0; n < nch; ++n) { buffer_t *bp = &self->buffers[n]; float *p = bp->data; memmove(p, p + res, (bp->count - res) * sizeof(float)); bp->count -= res; bp->head -= res; } } } while (res == 0 && self->buffers[0].count); self->position += res; return res; } static void teardown(pcm_reader_t **reader) { int i; limiter_t *self = (limiter_t *)*reader; pcm_teardown(&self->src); for (i = 0; i < self->format.channels_per_frame + 1; ++i) free(self->buffers[i].data); free(self); *reader = 0; } static pcm_reader_vtbl_t my_vtable = { get_format, get_length, get_position, read_frames, teardown }; pcm_reader_t *limiter_open(pcm_reader_t *reader) { limiter_t *self; int n = pcm_get_format(reader)->channels_per_frame; size_t size = sizeof(limiter_t) + offsetof(limiter_t, buffers[n + 1]); if ((self = calloc(1, size)) == 0) return 0; self->src = reader; self->vtbl = &my_vtable; self->format = *pcm_get_format(reader); self->format.bits_per_channel = 32; return (pcm_reader_t *)self; } fdkaac-0.6.3/src/lpc.c000066400000000000000000000112211276003472100144410ustar00rootroot00000000000000/******************************************************************** * * * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * * by the Xiph.Org Foundation http://www.xiph.org/ * * * ******************************************************************** function: LPC low level routines last mod: $Id: lpc.c 16227 2009-07-08 06:58:46Z xiphmont $ ********************************************************************/ /* Some of these routines (autocorrelator, LPC coefficient estimator) are derived from code written by Jutta Degener and Carsten Bormann; thus we include their copyright below. The entirety of this file is freely redistributable on the condition that both of these copyright notices are preserved without modification. */ /* Preserved Copyright: *********************************************/ /* Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, Technische Universita"t Berlin Any use of this software is permitted provided that this notice is not removed and that neither the authors nor the Technische Universita"t Berlin are deemed to have made any representations as to the suitability of this software for any purpose nor are held responsible for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. As a matter of courtesy, the authors request to be informed about uses this software has found, about bugs in this software, and about any improvements that may be of general interest. Berlin, 28.11.1994 Jutta Degener Carsten Bormann *********************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #include #include #include #include "lpc.h" #include "lpcm.h" /* Autocorrelation LPC coeff generation algorithm invented by N. Levinson in 1947, modified by J. Durbin in 1959. */ /* Input : n elements of time doamin data Output: m lpc coefficients, excitation energy */ float vorbis_lpc_from_data(short *data,float *lpci,int n,int m,int stride){ double *aut=malloc(sizeof(*aut)*(m+1)); double *lpc=malloc(sizeof(*lpc)*(m)); double error; double epsilon; int i,j; /* autocorrelation, p+1 lag coefficients */ j=m+1; while(j--){ double d=0; /* double needed for accumulator depth */ for(i=j;isample_type & 1) #define PCM_IS_UINT(desc) ((desc)->sample_type & 2) #define PCM_IS_FLOAT(desc) ((desc)->sample_type & 4) #define PCM_IS_BIG_ENDIAN(desc) ((desc)->sample_type & 8) #define PCM_BYTES_PER_CHANNEL(desc) \ ((desc)->bytes_per_frame / (desc)->channels_per_frame) #if defined(_MSC_VER) && _MSC_VER < 1800 # ifdef _M_IX86 static inline int lrint(double x) { int n; _asm { fld x fistp n } return n; } # else # include static inline int lrint(double x) { return _mm_cvtsd_si32(_mm_load_sd(&x)); } # endif #endif static inline double pcm_clip(double n, double min_value, double max_value) { if (n < min_value) return min_value; else if (n > max_value) return max_value; return n; } #endif fdkaac-0.6.3/src/m4af.c000066400000000000000000001253271276003472100145270ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #if HAVE_STDINT_H # include #endif #if HAVE_INTTYPES_H # include #elif defined _MSC_VER # define PRId64 "I64d" #endif #include "m4af.h" #include "m4af_endian.h" #define m4af_realloc(memory,size) realloc(memory, size) #define m4af_free(memory) free(memory) #define m4af_max(a,b) ((a)<(b)?(b):(a)) #define M4AF_ATOM_WILD 0xffffffff typedef struct m4af_sample_entry_t { uint32_t size; uint32_t delta; } m4af_sample_entry_t; typedef struct m4af_chunk_entry_t { int64_t offset; uint32_t size; uint32_t samples_per_chunk; uint32_t duration; } m4af_chunk_entry_t; typedef struct m4af_itmf_entry_t { uint32_t fcc; char *name; uint32_t type_code; char *data; uint32_t data_size; } m4af_itmf_entry_t; typedef struct m4af_track_t { uint32_t codec; uint32_t timescale; uint16_t num_channels; int64_t creation_time; int64_t modification_time; int64_t duration; uint32_t frame_duration; uint32_t encoder_delay; uint32_t padding; uint8_t *decSpecificInfo; uint32_t decSpecificInfoSize; uint32_t bufferSizeDB; uint32_t maxBitrate; uint32_t avgBitrate; int is_vbr; m4af_sample_entry_t *sample_table; uint32_t num_samples; uint32_t sample_table_capacity; m4af_chunk_entry_t *chunk_table; uint32_t num_chunks; uint32_t chunk_table_capacity; uint8_t *chunk_buffer; uint32_t chunk_size; uint32_t chunk_capacity; /* temporary, to help parsing */ uint64_t stsc_pos; uint64_t stsc_size; uint64_t stts_pos; uint64_t stts_size; } m4af_track_t; struct m4af_ctx_t { uint32_t timescale; int64_t creation_time; int64_t modification_time; int64_t mdat_pos; int64_t mdat_size; int priming_mode; int last_error; m4af_itmf_entry_t *itmf_table; uint32_t num_tags; uint32_t itmf_table_capacity; m4af_io_callbacks_t io; void *io_cookie; uint16_t num_tracks; m4af_track_t track[2]; m4af_itmf_entry_t current_tag; }; typedef struct m4af_box_parser_t { uint32_t name; int (*handler)(m4af_ctx_t *ctx, uint32_t name, uint64_t size); } m4af_box_parser_t; static int m4af_write_null_cb(void *cookie, const void *data, uint32_t size) { int64_t *pos = cookie; *pos += size; return 0; } static int m4af_seek_null_cb(void *cookie, int64_t off, int whence) { int64_t *pos = cookie; *pos = off; /* XXX: we use only SEEK_SET */ return 0; } static int64_t m4af_tell_null_cb(void *cookie) { return *((int64_t*)cookie); } static m4af_io_callbacks_t m4af_null_io_callbacks = { 0, m4af_write_null_cb, m4af_seek_null_cb, m4af_tell_null_cb }; static int64_t m4af_timestamp(void) { return (int64_t)(time(0)) + (((1970 - 1904) * 365) + 17) * 24 * 60 * 60; } /* * http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */ static uint32_t m4af_roundup(uint32_t n) { n--; n |= n >> 1; n |= n >> 2; n |= n >> 4; n |= n >> 8; n |= n >> 16; n++; return n; } static int64_t m4af_tell(m4af_ctx_t *ctx) { int64_t pos = -1; if ((pos = ctx->io.tell(ctx->io_cookie)) < 0) ctx->last_error = M4AF_IO_ERROR; return pos; } static int m4af_set_pos(m4af_ctx_t *ctx, int64_t pos) { int rc = -1; if ((rc = ctx->io.seek(ctx->io_cookie, pos, SEEK_SET)) < 0) ctx->last_error = M4AF_IO_ERROR; return rc; } static int m4af_write(m4af_ctx_t *ctx, const void *data, uint32_t size) { int rc = -1; if ((rc = ctx->io.write(ctx->io_cookie, data, size)) < 0) ctx->last_error = M4AF_IO_ERROR; return rc; } static int m4af_write16(m4af_ctx_t *ctx, uint32_t data) { data = m4af_htob16(data); return m4af_write(ctx, &data, 2); } static int m4af_write32(m4af_ctx_t *ctx, uint32_t data) { data = m4af_htob32(data); return m4af_write(ctx, &data, 4); } static int m4af_write64(m4af_ctx_t *ctx, uint64_t data) { data = m4af_htob64(data); return m4af_write(ctx, &data, 8); } static int m4af_write24(m4af_ctx_t *ctx, uint32_t data) { data = m4af_htob32(data << 8); return m4af_write(ctx, &data, 3); } static void m4af_write32_at(m4af_ctx_t *ctx, int64_t pos, uint32_t value) { int64_t current_pos = m4af_tell(ctx); m4af_set_pos(ctx, pos); m4af_write32(ctx, value); m4af_set_pos(ctx, current_pos); } m4af_ctx_t *m4af_create(uint32_t codec, uint32_t timescale, m4af_io_callbacks_t *io, void *io_cookie) { m4af_ctx_t *ctx; int64_t timestamp; if (codec != M4AF_FOURCC('m','p','4','a') && codec != M4AF_FOURCC('a','l','a','c')) return 0; if ((ctx = m4af_realloc(0, sizeof(m4af_ctx_t))) == 0) return 0; memset(ctx, 0, sizeof(m4af_ctx_t)); memcpy(&ctx->io, io, sizeof(m4af_io_callbacks_t)); ctx->io_cookie = io_cookie; ctx->timescale = timescale; timestamp = m4af_timestamp(); ctx->creation_time = timestamp; ctx->modification_time = timestamp; ctx->num_tracks = 1; ctx->track[0].codec = codec; ctx->track[0].timescale = timescale; ctx->track[0].creation_time = timestamp; ctx->track[0].modification_time = timestamp; ctx->track[0].num_channels = 2; return ctx; } static void m4af_free_itmf_table(m4af_ctx_t *ctx) { uint32_t i; m4af_itmf_entry_t *entry = ctx->itmf_table; for (i = 0; i < ctx->num_tags; ++i, ++entry) { if (entry->fcc == M4AF_FOURCC('-','-','-','-')) m4af_free(entry->name); m4af_free(entry->data); } m4af_free(ctx->itmf_table); } static void m4af_clear_track(m4af_ctx_t *ctx, int track_idx) { m4af_track_t *track = ctx->track + track_idx; if (track->decSpecificInfo) m4af_free(track->decSpecificInfo); if (track->sample_table) m4af_free(track->sample_table); if (track->chunk_table) m4af_free(track->chunk_table); if (track->chunk_buffer) m4af_free(track->chunk_buffer); memset(track, 0, sizeof(m4af_track_t)); } void m4af_teardown(m4af_ctx_t **ctxp) { unsigned i; m4af_ctx_t *ctx = *ctxp; for (i = 0; i < ctx->num_tracks; ++i) m4af_clear_track(ctx, i); if (ctx->itmf_table) m4af_free_itmf_table(ctx); m4af_free(ctx); *ctxp = 0; } void m4af_set_num_channels(m4af_ctx_t *ctx, uint32_t track_idx, uint16_t channels) { ctx->track[track_idx].num_channels = channels; } void m4af_set_fixed_frame_duration(m4af_ctx_t *ctx, uint32_t track_idx, uint32_t length) { ctx->track[track_idx].frame_duration = length; } int m4af_set_decoder_specific_info(m4af_ctx_t *ctx, uint32_t track_idx, uint8_t *data, uint32_t size) { m4af_track_t *track = &ctx->track[track_idx]; if (size > track->decSpecificInfoSize) { uint8_t *memory = m4af_realloc(track->decSpecificInfo, size); if (memory == 0) { ctx->last_error = M4AF_NO_MEMORY; goto DONE; } track->decSpecificInfo = memory; } if (size > 0) memcpy(track->decSpecificInfo, data, size); track->decSpecificInfoSize = size; DONE: return ctx->last_error; } void m4af_set_vbr_mode(m4af_ctx_t *ctx, uint32_t track_idx, int is_vbr) { m4af_track_t *track = &ctx->track[track_idx]; track->is_vbr = is_vbr; } void m4af_set_priming(m4af_ctx_t *ctx, uint32_t track_idx, uint32_t encoder_delay, uint32_t padding) { m4af_track_t *track = &ctx->track[track_idx]; track->encoder_delay = encoder_delay; track->padding = padding; } void m4af_set_priming_mode(m4af_ctx_t *ctx, int mode) { ctx->priming_mode = mode; } static int m4af_add_sample_entry(m4af_ctx_t *ctx, uint32_t track_idx, uint32_t size, uint32_t delta) { m4af_track_t *track = &ctx->track[track_idx]; m4af_sample_entry_t *entry; if (ctx->last_error) return -1; if (track->num_samples == track->sample_table_capacity) { uint32_t new_size = track->sample_table_capacity; new_size = new_size ? new_size * 2 : 1; entry = m4af_realloc(track->sample_table, new_size * sizeof(*entry)); if (entry == 0) { ctx->last_error = M4AF_NO_MEMORY; return -1; } track->sample_table = entry; track->sample_table_capacity = new_size; } entry = track->sample_table + track->num_samples; entry->size = size; entry->delta = delta; ++track->num_samples; return 0; } static int m4af_flush_chunk(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; m4af_chunk_entry_t *entry; if (!track->num_chunks || !track->chunk_size) return 0; entry = &track->chunk_table[track->num_chunks - 1]; entry->offset = m4af_tell(ctx); m4af_write(ctx, track->chunk_buffer, track->chunk_size); ctx->mdat_size += track->chunk_size; track->chunk_size = 0; return ctx->last_error ? -1 : 0; } static int m4af_add_chunk_entry(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; m4af_chunk_entry_t *entry; if (track->num_chunks == track->chunk_table_capacity) { uint32_t new_size = track->chunk_table_capacity; new_size = new_size ? new_size * 2 : 1; entry = m4af_realloc(track->chunk_table, new_size * sizeof(*entry)); if (entry == 0) { ctx->last_error = M4AF_NO_MEMORY; return -1; } track->chunk_table = entry; track->chunk_table_capacity = new_size; } memset(&track->chunk_table[track->num_chunks++], 0, sizeof(m4af_chunk_entry_t)); return 0; } static int m4af_update_chunk_table(m4af_ctx_t *ctx, uint32_t track_idx, uint32_t size, uint32_t delta) { m4af_track_t *track = &ctx->track[track_idx]; m4af_chunk_entry_t *entry; int add_new_chunk = 0; if (ctx->last_error) return -1; if (track->num_chunks == 0) add_new_chunk = 1; else { entry = &track->chunk_table[track->num_chunks - 1]; if (entry->duration + delta > track->timescale / 2) add_new_chunk = 1; } if (add_new_chunk) { m4af_flush_chunk(ctx, track_idx); if (m4af_add_chunk_entry(ctx, track_idx) < 0) return -1; } entry = &track->chunk_table[track->num_chunks - 1]; entry->size += size; ++entry->samples_per_chunk; entry->duration += delta; return 0; } static void m4af_update_max_bitrate(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; uint32_t duration = 0, size = 0, bitrate; m4af_sample_entry_t *ent = track->sample_table + track->num_samples - 1; for (; ent >= track->sample_table && duration < track->timescale; --ent) { duration += ent->delta; size += ent->size; } bitrate = (uint32_t)(size * 8.0 * track->timescale / duration + .5); if (bitrate > track->maxBitrate) track->maxBitrate = bitrate; } static int m4af_append_sample_to_chunk(m4af_ctx_t *ctx, uint32_t track_idx, const void *data, uint32_t size) { m4af_track_t *track = &ctx->track[track_idx]; uint32_t newsize = track->chunk_size + size; if (ctx->last_error) return -1; if (track->chunk_capacity < newsize) { uint32_t capacity = m4af_roundup(newsize); uint8_t *memory = realloc(track->chunk_buffer, capacity); if (!memory) { ctx->last_error = M4AF_NO_MEMORY; return -1; } track->chunk_buffer = memory; track->chunk_capacity = capacity; } memcpy(track->chunk_buffer + track->chunk_size, data, size); track->chunk_size = newsize; return 0; } int m4af_write_sample(m4af_ctx_t *ctx, uint32_t track_idx, const void *data, uint32_t size, uint32_t duration) { m4af_track_t *track = &ctx->track[track_idx]; if (track->frame_duration) duration = track->frame_duration; if (size > track->bufferSizeDB) track->bufferSizeDB = size; track->duration += duration; m4af_add_sample_entry(ctx, track_idx, size, duration); m4af_update_chunk_table(ctx, track_idx, size, duration); m4af_update_max_bitrate(ctx, track_idx); m4af_append_sample_to_chunk(ctx, track_idx, data, size); return ctx->last_error; } static m4af_itmf_entry_t *m4af_find_itmf_slot(m4af_ctx_t *ctx, uint32_t fcc, const char *name) { m4af_itmf_entry_t *entry = ctx->itmf_table; if (name) fcc = M4AF_FOURCC('-','-','-','-'); if (fcc != M4AF_TAG_ARTWORK) for (; entry != ctx->itmf_table + ctx->num_tags; ++entry) if (fcc == entry->fcc && (!name || !strcmp(name, entry->name))) return entry; if (ctx->num_tags == ctx->itmf_table_capacity) { uint32_t new_size = ctx->itmf_table_capacity; new_size = new_size ? new_size * 2 : 1; entry = m4af_realloc(ctx->itmf_table, new_size * sizeof(*entry)); if (entry == 0) { ctx->last_error = M4AF_NO_MEMORY; return 0; } ctx->itmf_table = entry; ctx->itmf_table_capacity = new_size; } entry = &ctx->itmf_table[ctx->num_tags++]; memset(entry, 0, sizeof(m4af_itmf_entry_t)); entry->fcc = fcc; if (name) { char *name_copy = m4af_realloc(0, strlen(name) + 1); if (!name_copy) { ctx->last_error = M4AF_NO_MEMORY; --ctx->num_tags; return 0; } strcpy(name_copy, name); entry->name = name_copy; } return entry; } int m4af_add_itmf_long_tag(m4af_ctx_t *ctx, const char *name, const char *data) { m4af_itmf_entry_t *entry; char *data_copy = 0; size_t name_len = strlen(name); size_t data_len = strlen(data); if (!name_len || !data_len) return 0; if ((entry = m4af_find_itmf_slot(ctx, 0, name)) == 0) goto FAIL; entry->type_code = M4AF_UTF8; if ((data_copy = m4af_realloc(entry->data, data_len)) == 0) { ctx->last_error = M4AF_NO_MEMORY; goto FAIL; } memcpy(data_copy, data, data_len); entry->data = data_copy; entry->data_size = data_len; return 0; FAIL: return ctx->last_error; } int m4af_add_itmf_short_tag(m4af_ctx_t *ctx, uint32_t fcc, uint32_t type_code, const void *data, uint32_t data_size) { m4af_itmf_entry_t *entry; char *data_copy = 0; if (!data_size) return 0; if ((entry = m4af_find_itmf_slot(ctx, fcc, 0)) == 0) goto FAIL; entry->type_code = type_code; if ((data_copy = m4af_realloc(entry->data, data_size)) == 0) { ctx->last_error = M4AF_NO_MEMORY; goto FAIL; } memcpy(data_copy, data, data_size); entry->data = data_copy; entry->data_size = data_size; return 0; FAIL: return ctx->last_error; } int m4af_add_itmf_string_tag(m4af_ctx_t *ctx, uint32_t fcc, const char *data) { return m4af_add_itmf_short_tag(ctx, fcc, M4AF_UTF8, data, strlen(data)); } int m4af_add_itmf_int8_tag(m4af_ctx_t *ctx, uint32_t fcc, int value) { uint8_t data = value; return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 1); } int m4af_add_itmf_int16_tag(m4af_ctx_t *ctx, uint32_t fcc, int value) { uint16_t data = m4af_htob16(value); return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 2); } int m4af_add_itmf_int32_tag(m4af_ctx_t *ctx, uint32_t fcc, uint32_t value) { uint32_t data = m4af_htob32(value); return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 4); } int m4af_add_itmf_int64_tag(m4af_ctx_t *ctx, uint32_t fcc, uint64_t value) { uint64_t data = m4af_htob64(value); return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 8); } int m4af_add_itmf_track_tag(m4af_ctx_t *ctx, int track, int total) { uint16_t data[4] = { 0 }; data[1] = m4af_htob16(track); data[2] = m4af_htob16(total); return m4af_add_itmf_short_tag(ctx, M4AF_FOURCC('t','r','k','n'), M4AF_IMPLICIT, &data, 8); } int m4af_add_itmf_disk_tag(m4af_ctx_t *ctx, int disk, int total) { uint16_t data[3] = { 0 }; data[1] = m4af_htob16(disk); data[2] = m4af_htob16(total); return m4af_add_itmf_short_tag(ctx, M4AF_FOURCC('d','i','s','k'), M4AF_IMPLICIT, &data, 6); } int m4af_add_itmf_genre_tag(m4af_ctx_t *ctx, int genre) { uint16_t data = m4af_htob16(genre); return m4af_add_itmf_short_tag(ctx, M4AF_FOURCC('g','n','r','e'), M4AF_IMPLICIT, &data, 2); } static int m4af_set_iTunSMPB(m4af_ctx_t *ctx) { const char *fmt = " 00000000 %08X %08X %08X%08X 00000000 00000000 " "00000000 00000000 00000000 00000000 00000000 00000000"; m4af_track_t *track = &ctx->track[0]; char buf[256]; uint64_t length = track->duration - track->encoder_delay - track->padding; sprintf(buf, fmt, track->encoder_delay, track->padding, (uint32_t)(length >> 32), (uint32_t)length); return m4af_add_itmf_long_tag(ctx, "iTunSMPB", buf); } static uint32_t m4af_update_box_size(m4af_ctx_t *ctx, int64_t pos) { int64_t current_pos = m4af_tell(ctx); m4af_set_pos(ctx, pos); m4af_write32(ctx, current_pos - pos); m4af_set_pos(ctx, current_pos); return current_pos - pos; } static void m4af_write_descriptor(m4af_ctx_t *ctx, uint32_t tag, uint32_t size) { uint8_t buf[5]; buf[0] = tag; buf[1] = ((size >> 21) | 0x80); buf[2] = ((size >> 14) | 0x80); buf[3] = ((size >> 7) | 0x80); buf[4] = (size & 0x7f); m4af_write(ctx, buf, 5); } static void m4af_write_ftyp_box(m4af_ctx_t *ctx) { m4af_write(ctx, "\0\0\0\040""ftypM4A \0\0\0\0M4A mp42isom\0\0\0\0", 32); } static void m4af_write_free_box(m4af_ctx_t *ctx, uint32_t size) { int64_t pos = m4af_tell(ctx); m4af_write32(ctx, size + 8); m4af_write(ctx, "free", 4); if (size > 0) m4af_set_pos(ctx, pos + size + 8); } int m4af_begin_write(m4af_ctx_t *ctx) { m4af_write_ftyp_box(ctx); m4af_write_free_box(ctx, 0); m4af_write(ctx, "\0\0\0\0mdat", 8); ctx->mdat_pos = m4af_tell(ctx); return ctx->last_error; } static void m4af_write_stco_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; uint32_t i; m4af_chunk_entry_t *index = track->chunk_table; int is_co64 = index[track->num_chunks - 1].offset > 0xffffffff; int64_t pos = m4af_tell(ctx); m4af_write32(ctx, 0); /* size */ m4af_write(ctx, is_co64 ? "co64" : "stco", 4); m4af_write32(ctx, 0); /* version and flags */ m4af_write32(ctx, track->num_chunks); for (i = 0; i < track->num_chunks; ++i, ++index) { if (is_co64) m4af_write64(ctx, index->offset); else m4af_write32(ctx, index->offset); } m4af_update_box_size(ctx, pos); } static void m4af_write_stsz_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; m4af_sample_entry_t *index = track->sample_table; uint32_t i; int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0" /* size */ "stsz" /* type */ "\0" /* version */ "\0\0\0" /* flags */ "\0\0\0\0" /* sample_size: 0(variable) */ , 16); m4af_write32(ctx, track->num_samples); for (i = 0; i < track->num_samples; ++i, ++index) m4af_write32(ctx, index->size); m4af_update_box_size(ctx, pos); } static void m4af_write_stsc_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; m4af_chunk_entry_t *index = track->chunk_table; uint32_t i, prev_samples_per_chunk = 0, entry_count = 0; int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0" /* size */ "stsc" /* type */ "\0" /* version */ "\0\0\0" /* flags */ "\0\0\0\0" /* entry_count */ , 16); for (i = 0; i < track->num_chunks; ++i, ++index) { if (index->samples_per_chunk != prev_samples_per_chunk) { ++entry_count; m4af_write32(ctx, i + 1); m4af_write32(ctx, index->samples_per_chunk); m4af_write32(ctx, 1); /* sample_description_index */ prev_samples_per_chunk = index->samples_per_chunk; } } m4af_write32_at(ctx, pos + 12, entry_count); m4af_update_box_size(ctx, pos); } static void m4af_write_stts_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; m4af_sample_entry_t *index = track->sample_table; uint32_t i, prev_delta = 0, entry_count = 0, sample_count = 0; int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0" /* size */ "stts" /* type */ "\0" /* version */ "\0\0\0" /* flags */ "\0\0\0\0" /* entry_count */ , 16); for (i = 0; i < track->num_samples; ++i, ++index) { if (index->delta == prev_delta) ++sample_count; else { ++entry_count; if (sample_count) { m4af_write32(ctx, sample_count); m4af_write32(ctx, prev_delta); } prev_delta = index->delta; sample_count = 1; } } if (sample_count) { m4af_write32(ctx, sample_count); m4af_write32(ctx, prev_delta); } m4af_write32_at(ctx, pos + 12, entry_count); m4af_update_box_size(ctx, pos); } static void m4af_write_esds_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0esds", 8); m4af_write32(ctx, 0); /* version + flags */ /* ES_Descriptor */ m4af_write_descriptor(ctx, 3, 32 + track->decSpecificInfoSize); m4af_write(ctx, "\0\0\0", 3); /* DecoderConfigDescriptor */ m4af_write_descriptor(ctx, 4, 18 + track->decSpecificInfoSize); m4af_write(ctx, "\x40" /* objectTypeIndication: 0x40(Audio ISO/IEC 14496-3)*/ "\x15" /* streamType(6): 0x05(AudioStream) * upStream(1) : 0 * reserved(1) : 1 */ , 2); m4af_write24(ctx, track->bufferSizeDB); m4af_write32(ctx, track->maxBitrate); m4af_write32(ctx, track->is_vbr ? 0: track->avgBitrate); /* DecoderSpecificInfo */ m4af_write_descriptor(ctx, 5, track->decSpecificInfoSize); m4af_write(ctx, track->decSpecificInfo, track->decSpecificInfoSize); /* SLConfigDescriptor */ m4af_write_descriptor(ctx, 6, 1); m4af_write(ctx, "\002", 1); /* predefined */ m4af_update_box_size(ctx, pos); } static void m4af_write_alac_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0" /* size */ "alac" /* type */ "\0" /* version */ "\0\0\0" /* flags */ , 12); m4af_write(ctx, track->decSpecificInfo, track->decSpecificInfoSize); m4af_update_box_size(ctx, pos); } static void m4af_write_mp4a_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; int64_t pos = m4af_tell(ctx); m4af_write32(ctx, 0); /* size */ m4af_write32(ctx, track->codec); /* mp4a or alac */ m4af_write(ctx, "\0\0\0\0\0\0" /* reserved */ "\0\001" /* data_reference_index: 1 */ "\0\0\0\0" /* reserved[0] */ "\0\0\0\0" /* reserved[1] */ ,16); m4af_write16(ctx, track->num_channels); m4af_write(ctx, "\0\020" /* samplesize: 16 */ "\0\0" /* pre_defined */ "\0\0" /* reserved */ ,6); if (track->codec == M4AF_FOURCC('m','p','4','a')) { m4af_write32(ctx, track->timescale << 16); m4af_write_esds_box(ctx, track_idx); } else { m4af_write32(ctx, 44100 << 16); m4af_write_alac_box(ctx, track_idx); } m4af_update_box_size(ctx, pos); } static void m4af_write_stsd_box(m4af_ctx_t *ctx, uint32_t track_idx) { int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0stsd", 8); m4af_write(ctx, "\0" /* version */ "\0\0\0" /* flags */ "\0\0\0\001" /* entry_count: 1 */ , 8); m4af_write_mp4a_box(ctx, track_idx); m4af_update_box_size(ctx, pos); } static void m4af_write_sbgp_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; m4af_write(ctx, "\0\0\0\034" /* size: 28 */ "sbgp" /* type */ "\0" /* version */ "\0\0\0" /* flags */ "roll" /* grouping_type */ "\0\0\0\001" /* entry_count: 1 */ , 20); m4af_write32(ctx, track->num_samples); m4af_write32(ctx, 1); /* group_description_index */ } static void m4af_write_sgpd_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_write(ctx, "\0\0\0\026" /* size: 22 */ "sgpd" /* type */ "\0" /* version */ "\0\0\0" /* flags */ "roll" /* grouping_type */ "\0\0\0\001" /* entry_count: 1 */ "\377\377" /* payload_data: -1 */ , 22); } static void m4af_write_stbl_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0stbl", 8); m4af_write_stsd_box(ctx, track_idx); if ((ctx->priming_mode & M4AF_PRIMING_MODE_EDTS) && (track->encoder_delay || track->padding)) { m4af_write_sbgp_box(ctx, track_idx); m4af_write_sgpd_box(ctx, track_idx); } m4af_write_stts_box(ctx, track_idx); m4af_write_stsc_box(ctx, track_idx); m4af_write_stsz_box(ctx, track_idx); m4af_write_stco_box(ctx, track_idx); m4af_update_box_size(ctx, pos); } static void m4af_write_url_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_write(ctx, "\0\0\0\014" /* size */ "url " /* type */ "\0" /* version */ "\0\0\001" /* flags: 1(in the same file) */ , 12); } static void m4af_write_dref_box(m4af_ctx_t *ctx, uint32_t track_idx) { int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0dref", 8); m4af_write(ctx, "\0" /* version */ "\0\0\0" /* flags */ "\0\0\0\001" /* entry_count: 1 */ ,8); m4af_write_url_box(ctx, track_idx); m4af_update_box_size(ctx, pos); } static void m4af_write_dinf_box(m4af_ctx_t *ctx, uint32_t track_idx) { int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0dinf", 8); m4af_write_dref_box(ctx, track_idx); m4af_update_box_size(ctx, pos); } static void m4af_write_smhd_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_write(ctx, "\0\0\0\020" /* size */ "smhd" /* type */ "\0" /* version */ "\0\0\0" /* flags */ "\0\0" /* balance */ "\0\0" /* reserved */ , 16); } static void m4af_write_minf_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0minf", 8); /* TODO: add TEXT support */ if (track->codec != M4AF_CODEC_TEXT) m4af_write_smhd_box(ctx, track_idx); m4af_write_dinf_box(ctx, track_idx); m4af_write_stbl_box(ctx, track_idx); m4af_update_box_size(ctx, pos); } static void m4af_write_mdhd_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; int64_t pos = m4af_tell(ctx); uint8_t version = (track->creation_time > UINT32_MAX || track->modification_time > UINT32_MAX || track->duration > UINT32_MAX); m4af_write(ctx, "\0\0\0\0mdhd", 8); m4af_write(ctx, &version, 1); m4af_write(ctx, "\0\0\0", 3); /* flags */ if (version) { m4af_write64(ctx, track->creation_time); m4af_write64(ctx, track->modification_time); m4af_write32(ctx, track->timescale); m4af_write64(ctx, track->duration); } else { m4af_write32(ctx, track->creation_time); m4af_write32(ctx, track->modification_time); m4af_write32(ctx, track->timescale); m4af_write32(ctx, track->duration); } m4af_write(ctx, "\x55\xc4" /* language: und */ "\0\0" /* pre_defined */ , 4); m4af_update_box_size(ctx, pos); } static void m4af_write_hdlr_box(m4af_ctx_t *ctx, uint32_t track_idx, const char *type) { int64_t pos = m4af_tell(ctx); static const char reserved_and_name[10] = { 0 }; m4af_write(ctx, "\0\0\0\0" /* size */ "hdlr" /* type */ "\0" /* version */ "\0\0\0" /* flags */ "\0\0\0\0" /* pre_defined */ , 16); m4af_write(ctx, type, 4); /* handler_type */ /* reserved[0] */ m4af_write(ctx, !strcmp(type, "mdir") ? "appl" : "\0\0\0\0", 4); /* reserved[1], reserved[2], name */ m4af_write(ctx, reserved_and_name, 9); m4af_update_box_size(ctx, pos); } static void m4af_write_mdia_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; const char *hdlr = (track->codec == M4AF_CODEC_TEXT) ? "text" : "soun"; int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0mdia", 8); m4af_write_mdhd_box(ctx, track_idx); m4af_write_hdlr_box(ctx, track_idx, hdlr); m4af_write_minf_box(ctx, track_idx); m4af_update_box_size(ctx, pos); } static void m4af_write_elst_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; uint8_t version; int64_t duration = track->duration - track->encoder_delay - track->padding; int64_t pos = m4af_tell(ctx); duration = (double)duration / track->timescale * ctx->timescale + .5; version = (duration > UINT32_MAX); m4af_write(ctx, "\0\0\0\0elst", 8); m4af_write(ctx, &version, 1); m4af_write(ctx, "\0\0\0", 3); /* flags */ m4af_write32(ctx, 1); /* entry_count: 1 */ if (version) { m4af_write64(ctx, duration); m4af_write64(ctx, track->encoder_delay); } else { m4af_write32(ctx, duration); m4af_write32(ctx, track->encoder_delay); } m4af_write16(ctx, 1); /* media_rate_integer */ m4af_write16(ctx, 0); /* media_rate_fraction */ m4af_update_box_size(ctx, pos); } static void m4af_write_edts_box(m4af_ctx_t *ctx, uint32_t track_idx) { int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0edts", 8); m4af_write_elst_box(ctx, track_idx); m4af_update_box_size(ctx, pos); } static void m4af_write_tkhd_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; int64_t pos = m4af_tell(ctx); int64_t duration = (double)track->duration / track->timescale * ctx->timescale + .5; uint8_t version = (track->creation_time > UINT32_MAX || track->modification_time > UINT32_MAX || duration > UINT32_MAX); m4af_write(ctx, "\0\0\0\0tkhd", 8); m4af_write(ctx, &version, 1); m4af_write(ctx, "\0\0\007", 3); /* flags */ if (version) { m4af_write64(ctx, track->creation_time); m4af_write64(ctx, track->modification_time); m4af_write32(ctx, track_idx + 1); m4af_write(ctx, "\0\0\0\0" /* reserved */ , 4); m4af_write64(ctx, duration); } else { m4af_write32(ctx, track->creation_time); m4af_write32(ctx, track->modification_time); m4af_write32(ctx, track_idx + 1); m4af_write(ctx, "\0\0\0\0" /* reserved */ , 4); m4af_write32(ctx, duration); } m4af_write(ctx, "\0\0\0\0" /* reserved[0] */ "\0\0\0\0" /* reserved[1] */ "\0\0" /* layer */ "\0\0" /* alternate_group */ "\001\0" /* volume: 1.0 */ "\0\0" /* reserved */ "\0\001\0\0" /* matrix[0] */ "\0\0\0\0" /* matrix[1] */ "\0\0\0\0" /* matrix[2] */ "\0\0\0\0" /* matrix[3] */ "\0\001\0\0" /* matrix[4] */ "\0\0\0\0" /* matrix[5] */ "\0\0\0\0" /* matrix[6] */ "\0\0\0\0" /* matrix[7] */ "\100\0\0\0" /* matrix[8] */ "\0\0\0\0" /* width */ "\0\0\0\0" /* height */ , 60); m4af_update_box_size(ctx, pos); } static void m4af_write_trak_box(m4af_ctx_t *ctx, uint32_t track_idx) { m4af_track_t *track = &ctx->track[track_idx]; int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0trak", 8); m4af_write_tkhd_box(ctx, track_idx); if ((ctx->priming_mode & M4AF_PRIMING_MODE_EDTS) && (track->encoder_delay || track->padding)) m4af_write_edts_box(ctx, track_idx); m4af_write_mdia_box(ctx, track_idx); m4af_update_box_size(ctx, pos); } static int64_t m4af_movie_duration(m4af_ctx_t *ctx) { int64_t movie_duration = 0; unsigned i; for (i = 0; i < ctx->num_tracks; ++i) { double x = ctx->track[i].duration; int64_t duration = x / ctx->track[i].timescale * ctx->timescale + .5; if (duration > movie_duration) movie_duration = duration; } return movie_duration; } static void m4af_write_mvhd_box(m4af_ctx_t *ctx) { int64_t pos = m4af_tell(ctx); int64_t movie_duration = m4af_movie_duration(ctx); uint8_t version = (ctx->creation_time > UINT32_MAX || ctx->modification_time > UINT32_MAX || movie_duration > UINT32_MAX); m4af_write(ctx, "\0\0\0\0mvhd", 8); m4af_write(ctx, &version, 1); m4af_write(ctx, "\0\0\0", 3); /* flags */ if (version) { m4af_write64(ctx, ctx->creation_time); m4af_write64(ctx, ctx->modification_time); m4af_write32(ctx, ctx->timescale); m4af_write64(ctx, movie_duration); } else { m4af_write32(ctx, ctx->creation_time); m4af_write32(ctx, ctx->modification_time); m4af_write32(ctx, ctx->timescale); m4af_write32(ctx, movie_duration); } m4af_write(ctx, "\0\001\0\0" /* rate: 1.0 */ "\001\0" /* volume: 1.0 */ "\0\0" /* reserved */ "\0\0\0\0" /* reserved[0] */ "\0\0\0\0" /* reserved[1] */ "\0\001\0\0" /* matrix[0] */ "\0\0\0\0" /* matrix[1] */ "\0\0\0\0" /* matrix[2] */ "\0\0\0\0" /* matrix[3] */ "\0\001\0\0" /* matrix[4] */ "\0\0\0\0" /* matrix[5] */ "\0\0\0\0" /* matrix[6] */ "\0\0\0\0" /* matrix[7] */ "\100\0\0\0" /* matrix[8] */ "\0\0\0\0" /* pre_defined[0] */ "\0\0\0\0" /* pre_defined[1] */ "\0\0\0\0" /* pre_defined[2] */ "\0\0\0\0" /* pre_defined[3] */ "\0\0\0\0" /* pre_defined[4] */ "\0\0\0\0" /* pre_defined[5] */ , 76); m4af_write32(ctx, ctx->num_tracks + 1); m4af_update_box_size(ctx, pos); } static void m4af_write_mean_box(m4af_ctx_t *ctx) { m4af_write(ctx, "\0\0\0\034" /* size */ "mean" "\0" /* version */ "\0\0\0" /* flags */ "com.apple.iTunes" /* meaning-string */ , 28); } static void m4af_write_name_box(m4af_ctx_t *ctx, const char *name) { int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0" /* size */ "name" /* type */ "\0" /* version */ "\0\0\0" /* flags */ , 12); m4af_write(ctx, name, strlen(name)); m4af_update_box_size(ctx, pos); } static void m4af_write_data_box(m4af_ctx_t *ctx, uint32_t type_code, const char *data, uint32_t data_size) { int64_t pos = m4af_tell(ctx); uint8_t code = type_code; m4af_write(ctx, "\0\0\0\0" /* size */ "data" /* type */ "\0\0" /* reserved */ "\0" /* type_set_indifier */ ,11); m4af_write(ctx, &code, 1); m4af_write(ctx, "\0\0\0\0", 4); /* locale */ m4af_write(ctx, data, data_size); m4af_update_box_size(ctx, pos); } static void m4af_write_metadata(m4af_ctx_t *ctx, m4af_itmf_entry_t *entry) { int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0", 4); m4af_write32(ctx, entry->fcc); if (entry->fcc != M4AF_FOURCC('-','-','-','-')) m4af_write_data_box(ctx, entry->type_code, entry->data, entry->data_size); else { m4af_write_mean_box(ctx); m4af_write_name_box(ctx, entry->name); m4af_write_data_box(ctx, 1, entry->data, entry->data_size); } m4af_update_box_size(ctx, pos); } static void m4af_write_ilst_box(m4af_ctx_t *ctx) { uint32_t i; int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0ilst", 8); for (i = 0; i < ctx->num_tags; ++i) m4af_write_metadata(ctx, &ctx->itmf_table[i]); m4af_update_box_size(ctx, pos); } static void m4af_write_meta_box(m4af_ctx_t *ctx) { int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0" /* size */ "meta" /* type */ "\0" /* version */ "\0\0\0" /* flags */ , 12); m4af_write_hdlr_box(ctx, 0, "mdir"); m4af_write_ilst_box(ctx); m4af_update_box_size(ctx, pos); } static void m4af_write_udta_box(m4af_ctx_t *ctx) { int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0udta", 8); m4af_write_meta_box(ctx); m4af_update_box_size(ctx, pos); } static uint32_t m4af_write_moov_box(m4af_ctx_t *ctx) { unsigned i; int64_t pos = m4af_tell(ctx); m4af_write(ctx, "\0\0\0\0moov", 8); m4af_write_mvhd_box(ctx); for (i = 0; i < ctx->num_tracks; ++i) m4af_write_trak_box(ctx, i); if (ctx->num_tags) m4af_write_udta_box(ctx); return m4af_update_box_size(ctx, pos); } static void m4af_finalize_mdat(m4af_ctx_t *ctx) { if (ctx->mdat_size + 8 > UINT32_MAX) { m4af_set_pos(ctx, ctx->mdat_pos - 16); m4af_write32(ctx, 1); m4af_write(ctx, "mdat", 4); m4af_write64(ctx, ctx->mdat_size + 16); } else { m4af_set_pos(ctx, ctx->mdat_pos - 8); m4af_write32(ctx, ctx->mdat_size + 8); } m4af_set_pos(ctx, ctx->mdat_pos + ctx->mdat_size); } static uint64_t m4af_patch_moov(m4af_ctx_t *ctx, uint32_t moov_size, uint32_t offset) { int64_t pos = 0; uint32_t moov_size2; int i, j; m4af_io_callbacks_t io_reserve = ctx->io; void *io_cookie_reserve = ctx->io_cookie; for (i = 0; i < ctx->num_tracks; ++i) for (j = 0; j < ctx->track[i].num_chunks; ++j) ctx->track[i].chunk_table[j].offset += offset; ctx->io = m4af_null_io_callbacks; ctx->io_cookie = &pos; moov_size2 = m4af_write_moov_box(ctx); if (moov_size2 != moov_size) { /* stco -> co64 switching */ for (i = 0; i < ctx->num_tracks; ++i) for (j = 0; j < ctx->track[i].num_chunks; ++j) ctx->track[i].chunk_table[j].offset += moov_size2 - moov_size; moov_size2 = m4af_write_moov_box(ctx); } ctx->io = io_reserve; ctx->io_cookie = io_cookie_reserve; return moov_size2; } static void m4af_shift_mdat_pos(m4af_ctx_t *ctx, uint32_t offset) { int64_t begin, end; char *buf; buf = malloc(1024*1024*2); end = ctx->mdat_pos + ctx->mdat_size; for (; (begin = m4af_max(ctx->mdat_pos, end - 1024*1024*2)) < end; end = begin) { m4af_set_pos(ctx, begin); ctx->io.read(ctx->io_cookie, buf, end - begin); m4af_set_pos(ctx, begin + offset); m4af_write(ctx, buf, end - begin); } ctx->mdat_pos += offset; m4af_set_pos(ctx, ctx->mdat_pos - 16); m4af_write_free_box(ctx, 0); m4af_write(ctx, "\0\0\0\0mdat", 8); m4af_finalize_mdat(ctx); free(buf); } int m4af_finalize(m4af_ctx_t *ctx, int optimize) { unsigned i; m4af_track_t *track; uint32_t moov_size; for (i = 0; i < ctx->num_tracks; ++i) { track = ctx->track + i; if (track->duration) { int64_t track_size = 0; unsigned j; for (j = 0; j < track->num_chunks; ++j) track_size += track->chunk_table[j].size; track->avgBitrate = 8.0 * track_size * track->timescale / track->duration + .5; } m4af_flush_chunk(ctx, i); } track = ctx->track; if ((ctx->priming_mode & M4AF_PRIMING_MODE_ITUNSMPB) && (track->encoder_delay || track->padding)) m4af_set_iTunSMPB(ctx); m4af_finalize_mdat(ctx); moov_size = m4af_write_moov_box(ctx); if (optimize) { int64_t pos; uint32_t moov_size2 = m4af_patch_moov(ctx, moov_size, moov_size + 1024); m4af_shift_mdat_pos(ctx, moov_size2 + 1024); m4af_set_pos(ctx, 32); m4af_write_moov_box(ctx); pos = m4af_tell(ctx); m4af_write_free_box(ctx, ctx->mdat_pos - pos - 24); } return ctx->last_error; } fdkaac-0.6.3/src/m4af.h000066400000000000000000000106371276003472100145310ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #ifndef M4AF_H #define M4AF_H #define M4AF_FOURCC(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d)) enum m4af_error_code { M4AF_IO_ERROR = -1, M4AF_NO_MEMORY = -2, M4AF_FORMAT_ERROR = -3, M4AF_NOT_SUPPORTED = -4, }; enum m4af_itmf_tag { M4AF_TAG_TITLE = M4AF_FOURCC('\xa9','n','a','m'), M4AF_TAG_ARTIST = M4AF_FOURCC('\xa9','A','R','T'), M4AF_TAG_ALBUM = M4AF_FOURCC('\xa9','a','l','b'), M4AF_TAG_GENRE = M4AF_FOURCC('\xa9','g','e','n'), M4AF_TAG_DATE = M4AF_FOURCC('\xa9','d','a','y'), M4AF_TAG_COMPOSER = M4AF_FOURCC('\xa9','w','r','t'), M4AF_TAG_GROUPING = M4AF_FOURCC('\xa9','g','r','p'), M4AF_TAG_COMMENT = M4AF_FOURCC('\xa9','c','m','t'), M4AF_TAG_LYRICS = M4AF_FOURCC('\xa9','l','y','r'), M4AF_TAG_TOOL = M4AF_FOURCC('\xa9','t','o','o'), M4AF_TAG_ALBUM_ARTIST = M4AF_FOURCC('a','A','R','T'), M4AF_TAG_TRACK = M4AF_FOURCC('t','r','k','n'), M4AF_TAG_DISK = M4AF_FOURCC('d','i','s','k'), M4AF_TAG_GENRE_ID3 = M4AF_FOURCC('g','n','r','e'), M4AF_TAG_TEMPO = M4AF_FOURCC('t','m','p','o'), M4AF_TAG_DESCRIPTION = M4AF_FOURCC('d','e','s','c'), M4AF_TAG_LONG_DESCRIPTION = M4AF_FOURCC('l','d','e','s'), M4AF_TAG_COPYRIGHT = M4AF_FOURCC('c','p','r','t'), M4AF_TAG_COMPILATION = M4AF_FOURCC('c','p','i','l'), M4AF_TAG_ARTWORK = M4AF_FOURCC('c','o','v','r'), }; enum m4af_itmf_type_code { M4AF_IMPLICIT = 0, M4AF_UTF8 = 1, M4AF_GIF = 12, M4AF_JPEG = 13, M4AF_PNG = 14, M4AF_INTEGER = 21, }; enum m4af_codec_type { M4AF_CODEC_MP4A = M4AF_FOURCC('m','p','4','a'), M4AF_CODEC_ALAC = M4AF_FOURCC('a','l','a','c'), M4AF_CODEC_TEXT = M4AF_FOURCC('t','e','x','t'), }; enum m4af_priming_mode { M4AF_PRIMING_MODE_ITUNSMPB = 1, M4AF_PRIMING_MODE_EDTS = 2, M4AF_PRIMING_MODE_BOTH = 3 }; typedef int (*m4af_read_callback)(void *cookie, void *buffer, uint32_t size); typedef int (*m4af_write_callback)(void *cookie, const void *data, uint32_t size); typedef int (*m4af_seek_callback)(void *cookie, int64_t off, int whence); typedef int64_t (*m4af_tell_callback)(void *cookie); typedef struct m4af_io_callbacks_t { m4af_read_callback read; m4af_write_callback write; m4af_seek_callback seek; m4af_tell_callback tell; } m4af_io_callbacks_t; typedef struct m4af_ctx_t m4af_ctx_t; m4af_ctx_t *m4af_create(uint32_t codec, uint32_t timescale, m4af_io_callbacks_t *io, void *io_cookie); int m4af_begin_write(m4af_ctx_t *ctx); int m4af_finalize(m4af_ctx_t *ctx, int optimize); void m4af_teardown(m4af_ctx_t **ctx); int m4af_write_sample(m4af_ctx_t *ctx, uint32_t track_idx, const void *data, uint32_t size, uint32_t duration); int m4af_set_decoder_specific_info(m4af_ctx_t *ctx, uint32_t track_idx, uint8_t *data, uint32_t size); void m4af_set_vbr_mode(m4af_ctx_t *ctx, uint32_t track_idx, int is_vbr); void m4af_set_priming(m4af_ctx_t *ctx, uint32_t track_idx, uint32_t encoder_delay, uint32_t padding); void m4af_set_priming_mode(m4af_ctx_t *ctx, int mode); void m4af_set_num_channels(m4af_ctx_t *ctx, uint32_t track_idx, uint16_t channels); void m4af_set_fixed_frame_duration(m4af_ctx_t *ctx, uint32_t track_idx, uint32_t length); int m4af_add_itmf_long_tag(m4af_ctx_t *ctx, const char *name, const char *data); int m4af_add_itmf_short_tag(m4af_ctx_t *ctx, uint32_t fcc, uint32_t type_code, const void *data, uint32_t data_size); int m4af_add_itmf_string_tag(m4af_ctx_t *ctx, uint32_t fcc, const char *data); int m4af_add_itmf_int8_tag(m4af_ctx_t *ctx, uint32_t fcc, int value); int m4af_add_itmf_int16_tag(m4af_ctx_t *ctx, uint32_t fcc, int value); int m4af_add_itmf_int32_tag(m4af_ctx_t *ctx, uint32_t fcc, uint32_t value); int m4af_add_itmf_int64_tag(m4af_ctx_t *ctx, uint32_t fcc, uint64_t value); int m4af_add_itmf_track_tag(m4af_ctx_t *ctx, int track, int total); int m4af_add_itmf_disk_tag(m4af_ctx_t *ctx, int disk, int total); int m4af_add_itmf_genre_tag(m4af_ctx_t *ctx, int genre); #endif fdkaac-0.6.3/src/m4af_endian.h000066400000000000000000000043441276003472100160450ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #ifndef M4AF_ENDIAN_H #define M4AF_ENDIAN_H #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #if HAVE_ENDIAN_H # include # define m4af_htob16(x) htobe16(x) # define m4af_htob32(x) htobe32(x) # define m4af_htob64(x) htobe64(x) # define m4af_btoh16(x) be16toh(x) # define m4af_btoh32(x) be32toh(x) # define m4af_btoh64(x) be64toh(x) # define m4af_htol16(x) htole16(x) # define m4af_htol32(x) htole32(x) # define m4af_htol64(x) htole64(x) # define m4af_ltoh16(x) le16toh(x) # define m4af_ltoh32(x) le32toh(x) # define m4af_ltoh64(x) le64toh(x) #elif WORDS_BIGENDIAN # define m4af_htob16(x) (x) # define m4af_htob32(x) (x) # define m4af_htob64(x) (x) # define m4af_btoh16(x) (x) # define m4af_btoh32(x) (x) # define m4af_btoh64(x) (x) # define m4af_ltoh16(x) m4af_swap16(x) # define m4af_ltoh32(x) m4af_swap32(x) # define m4af_ltoh64(x) m4af_swap64(x) # define m4af_htol16(x) m4af_swap16(x) # define m4af_htol32(x) m4af_swap32(x) # define m4af_htol64(x) m4af_swap64(x) #else # define m4af_htob16(x) m4af_swap16(x) # define m4af_htob32(x) m4af_swap32(x) # define m4af_htob64(x) m4af_swap64(x) # define m4af_btoh16(x) m4af_swap16(x) # define m4af_btoh32(x) m4af_swap32(x) # define m4af_btoh64(x) m4af_swap64(x) # define m4af_ltoh16(x) (x) # define m4af_ltoh32(x) (x) # define m4af_ltoh64(x) (x) # define m4af_htol16(x) (x) # define m4af_htol32(x) (x) # define m4af_htol64(x) (x) #endif #if _MSC_VER >= 1400 # include # define m4af_swap16(x) _byteswap_ushort(x) # define m4af_swap32(x) _byteswap_ulong(x) # define m4af_swap64(x) _byteswap_uint64(x) #elif HAVE_BYTESWAP_H # include # define m4af_swap16(x) bswap_16(x) # define m4af_swap32(x) bswap_32(x) # define m4af_swap64(x) bswap_64(x) #else static inline uint16_t m4af_swap16(uint16_t x) { return (x >> 8) | (x << 8); } static inline uint32_t m4af_swap32(uint32_t x) { return (m4af_htob16(x) << 16) | m4af_htob16(x >> 16); } static inline uint64_t m4af_swap64(uint64_t x) { return ((uint64_t)m4af_htob32(x) << 32) | m4af_htob32(x >> 32); } #endif #endif /* M4AF_ENDIAN_H */ fdkaac-0.6.3/src/main.c000066400000000000000000000746211276003472100146240ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #if HAVE_INTTYPES_H # include #elif defined(_MSC_VER) # define SCNd64 "I64d" #endif #include #include #include #include #include #include #include #include #if HAVE_UNISTD_H #include #endif #if HAVE_SIGACTION #include #endif #ifdef _WIN32 #include #define WIN32_LEAN_AND_MEAN #include #endif #include "compat.h" #include "pcm_reader.h" #include "aacenc.h" #include "m4af.h" #include "progress.h" #include "version.h" #include "metadata.h" #define PROGNAME "fdkaac" static volatile int g_interrupted = 0; #if HAVE_SIGACTION static void signal_handler(int signum) { g_interrupted = 1; } static void handle_signals(void) { int i, sigs[] = { SIGINT, SIGHUP, SIGTERM }; for (i = 0; i < sizeof(sigs)/sizeof(sigs[0]); ++i) { struct sigaction sa; memset(&sa, 0, sizeof sa); sa.sa_handler = signal_handler; sa.sa_flags |= SA_RESTART; sigaction(sigs[i], &sa, 0); } } #elif defined(_WIN32) static BOOL WINAPI signal_handler(DWORD type) { g_interrupted = 1; return TRUE; } static void handle_signals(void) { SetConsoleCtrlHandler(signal_handler, TRUE); } #else static void handle_signals(void) { } #endif static int read_callback(void *cookie, void *data, uint32_t size) { size_t rc = fread(data, 1, size, (FILE*)cookie); return ferror((FILE*)cookie) ? -1 : (int)rc; } static int write_callback(void *cookie, const void *data, uint32_t size) { size_t rc = fwrite(data, 1, size, (FILE*)cookie); return ferror((FILE*)cookie) ? -1 : (int)rc; } static int seek_callback(void *cookie, int64_t off, int whence) { return fseeko((FILE*)cookie, off, whence); } static int64_t tell_callback(void *cookie) { return ftello((FILE*)cookie); } static void usage(void) { printf( PROGNAME " %s\n" "Usage: " PROGNAME " [options] input_file\n" "Options:\n" " -h, --help Print this help message\n" " -p, --profile Profile (audio object type)\n" " 2: MPEG-4 AAC LC (default)\n" " 5: MPEG-4 HE-AAC (SBR)\n" " 29: MPEG-4 HE-AAC v2 (SBR+PS)\n" " 23: MPEG-4 AAC LD\n" " 39: MPEG-4 AAC ELD\n" " -b, --bitrate Bitrate in bits per seconds (for CBR)\n" " -m, --bitrate-mode Bitrate configuration\n" " 0: CBR (default)\n" " 1-5: VBR\n" " (VBR mode is not officially supported, and\n" " works only on a certain combination of\n" " parameter settings, sample rate, and\n" " channel configuration)\n" " -w, --bandwidth Frequency bandwidth in Hz (AAC LC only)\n" " -a, --afterburner Afterburner\n" " 0: Off\n" " 1: On(default)\n" " -L, --lowdelay-sbr <-1|0|1> Configure SBR activity on AAC ELD\n" " -1: Use ELD SBR auto configurator\n" " 0: Disable SBR on ELD (default)\n" " 1: Enable SBR on ELD\n" " -s, --sbr-ratio <0|1|2> Controls activation of downsampled SBR\n" " 0: Use lib default (default)\n" " 1: downsampled SBR (default for ELD+SBR)\n" " 2: dual-rate SBR (default for HE-AAC)\n" " -f, --transport-format Transport format\n" " 0: RAW (default, muxed into M4A)\n" " 1: ADIF\n" " 2: ADTS\n" " 6: LATM MCP=1\n" " 7: LATM MCP=0\n" " 10: LOAS/LATM (LATM within LOAS)\n" " -C, --adts-crc-check Add CRC protection on ADTS header\n" " -h, --header-period StreamMuxConfig/PCE repetition period in\n" " transport layer\n" "\n" " -o Output filename\n" " -G, --gapless-mode Encoder delay signaling for gapless playback\n" " 0: iTunSMPB (default)\n" " 1: ISO standard (edts + sgpd)\n" " 2: Both\n" " --include-sbr-delay Count SBR decoder delay in encoder delay\n" " This is not iTunes compatible, but is default\n" " behavior of FDK library.\n" " -I, --ignorelength Ignore length of WAV header\n" " -S, --silent Don't print progress messages\n" " --moov-before-mdat Place moov box before mdat box on m4a output\n" "\n" "Options for raw (headerless) input:\n" " -R, --raw Treat input as raw (by default WAV is\n" " assumed)\n" " --raw-channels Number of channels (default: 2)\n" " --raw-rate Sample rate (default: 44100)\n" " --raw-format Sample format, default is \"S16L\".\n" " Spec is as follows:\n" " 1st char: S(igned)|U(nsigned)|F(loat)\n" " 2nd part: bits per channel\n" " Last char: L(ittle)|B(ig)\n" " Last char can be omitted, in which case L is\n" " assumed. Spec is case insensitive, therefore\n" " \"u16b\" is same as \"U16B\".\n" "\n" "Tagging options:\n" " --title \n" " --artist \n" " --album \n" " --genre \n" " --date \n" " --composer \n" " --grouping \n" " --comment \n" " --album-artist \n" " --track \n" " --disk \n" " --tempo \n" " --tag : Set iTunes predefined tag with four char code.\n" " --tag-from-file :\n" " Same as above, but value is read from file.\n" " --long-tag : Set arbitrary tag as iTunes custom metadata.\n" " --tag-from-json \n" " Read tags from JSON. By default, tags are\n" " assumed to be direct children of the root\n" " object(dictionary).\n" " Optionally, position of the dictionary\n" " that contains tags can be specified with\n" " dotted notation.\n" " Example:\n" " --tag-from-json /path/to/json?format.tags\n" , fdkaac_version); } typedef struct aacenc_param_ex_t { AACENC_PARAMS char *input_filename; FILE *input_fp; char *output_filename; FILE *output_fp; unsigned gapless_mode; unsigned include_sbr_delay; unsigned ignore_length; int silent; int moov_before_mdat; int is_raw; unsigned raw_channels; unsigned raw_rate; const char *raw_format; aacenc_tag_store_t tags; aacenc_tag_store_t source_tags; aacenc_translate_generic_text_tag_ctx_t source_tag_ctx; char *json_filename; } aacenc_param_ex_t; static int parse_options(int argc, char **argv, aacenc_param_ex_t *params) { int ch; int n; #define OPT_INCLUDE_SBR_DELAY M4AF_FOURCC('s','d','l','y') #define OPT_MOOV_BEFORE_MDAT M4AF_FOURCC('m','o','o','v') #define OPT_RAW_CHANNELS M4AF_FOURCC('r','c','h','n') #define OPT_RAW_RATE M4AF_FOURCC('r','r','a','t') #define OPT_RAW_FORMAT M4AF_FOURCC('r','f','m','t') #define OPT_SHORT_TAG M4AF_FOURCC('s','t','a','g') #define OPT_SHORT_TAG_FILE M4AF_FOURCC('s','t','g','f') #define OPT_LONG_TAG M4AF_FOURCC('l','t','a','g') #define OPT_TAG_FROM_JSON M4AF_FOURCC('t','f','j','s') static struct option long_options[] = { { "help", no_argument, 0, 'h' }, { "profile", required_argument, 0, 'p' }, { "bitrate", required_argument, 0, 'b' }, { "bitrate-mode", required_argument, 0, 'm' }, { "bandwidth", required_argument, 0, 'w' }, { "afterburner", required_argument, 0, 'a' }, { "lowdelay-sbr", required_argument, 0, 'L' }, { "sbr-ratio", required_argument, 0, 's' }, { "transport-format", required_argument, 0, 'f' }, { "adts-crc-check", no_argument, 0, 'C' }, { "header-period", required_argument, 0, 'P' }, { "gapless-mode", required_argument, 0, 'G' }, { "include-sbr-delay", no_argument, 0, OPT_INCLUDE_SBR_DELAY }, { "ignorelength", no_argument, 0, 'I' }, { "silent", no_argument, 0, 'S' }, { "moov-before-mdat", no_argument, 0, OPT_MOOV_BEFORE_MDAT }, { "raw", no_argument, 0, 'R' }, { "raw-channels", required_argument, 0, OPT_RAW_CHANNELS }, { "raw-rate", required_argument, 0, OPT_RAW_RATE }, { "raw-format", required_argument, 0, OPT_RAW_FORMAT }, { "title", required_argument, 0, M4AF_TAG_TITLE }, { "artist", required_argument, 0, M4AF_TAG_ARTIST }, { "album", required_argument, 0, M4AF_TAG_ALBUM }, { "genre", required_argument, 0, M4AF_TAG_GENRE }, { "date", required_argument, 0, M4AF_TAG_DATE }, { "composer", required_argument, 0, M4AF_TAG_COMPOSER }, { "grouping", required_argument, 0, M4AF_TAG_GROUPING }, { "comment", required_argument, 0, M4AF_TAG_COMMENT }, { "album-artist", required_argument, 0, M4AF_TAG_ALBUM_ARTIST }, { "track", required_argument, 0, M4AF_TAG_TRACK }, { "disk", required_argument, 0, M4AF_TAG_DISK }, { "tempo", required_argument, 0, M4AF_TAG_TEMPO }, { "tag", required_argument, 0, OPT_SHORT_TAG }, { "tag-from-file", required_argument, 0, OPT_SHORT_TAG_FILE }, { "long-tag", required_argument, 0, OPT_LONG_TAG }, { "tag-from-json", required_argument, 0, OPT_TAG_FROM_JSON }, { 0, 0, 0, 0 }, }; params->afterburner = 1; aacenc_getmainargs(&argc, &argv); while ((ch = getopt_long(argc, argv, "hp:b:m:w:a:Ls:f:CP:G:Io:SR", long_options, 0)) != EOF) { switch (ch) { case 'h': return usage(), -1; case 'p': if (sscanf(optarg, "%u", &n) != 1) { fprintf(stderr, "invalid arg for profile\n"); return -1; } params->profile = n; break; case 'b': if (sscanf(optarg, "%u", &n) != 1) { fprintf(stderr, "invalid arg for bitrate\n"); return -1; } params->bitrate = n; break; case 'm': if (sscanf(optarg, "%u", &n) != 1 || n > 5) { fprintf(stderr, "invalid arg for bitrate-mode\n"); return -1; } params->bitrate_mode = n; break; case 'w': if (sscanf(optarg, "%u", &n) != 1) { fprintf(stderr, "invalid arg for bandwidth\n"); return -1; } params->bandwidth = n; break; case 'a': if (sscanf(optarg, "%u", &n) != 1 || n > 1) { fprintf(stderr, "invalid arg for afterburner\n"); return -1; } params->afterburner = n; break; case 'L': if (sscanf(optarg, "%d", &n) != 1 || n < -1 || n > 1) { fprintf(stderr, "invalid arg for lowdelay-sbr\n"); return -1; } params->lowdelay_sbr = n; break; case 's': if (sscanf(optarg, "%u", &n) != 1 || n > 2) { fprintf(stderr, "invalid arg for sbr-ratio\n"); return -1; } params->sbr_ratio = n; break; case 'f': if (sscanf(optarg, "%u", &n) != 1) { fprintf(stderr, "invalid arg for transport-format\n"); return -1; } params->transport_format = n; break; case 'C': params->adts_crc_check = 1; break; case 'P': if (sscanf(optarg, "%u", &n) != 1) { fprintf(stderr, "invalid arg for header-period\n"); return -1; } params->header_period = n; break; case 'o': params->output_filename = optarg; break; case 'G': if (sscanf(optarg, "%u", &n) != 1 || n > 2) { fprintf(stderr, "invalid arg for gapless-mode\n"); return -1; } params->gapless_mode = n; break; case OPT_INCLUDE_SBR_DELAY: params->include_sbr_delay = 1; break; case 'I': params->ignore_length = 1; break; case 'S': params->silent = 1; break; case OPT_MOOV_BEFORE_MDAT: params->moov_before_mdat = 1; break; case 'R': params->is_raw = 1; break; case OPT_RAW_CHANNELS: if (sscanf(optarg, "%u", &n) != 1) { fprintf(stderr, "invalid arg for raw-channels\n"); return -1; } params->raw_channels = n; break; case OPT_RAW_RATE: if (sscanf(optarg, "%u", &n) != 1) { fprintf(stderr, "invalid arg for raw-rate\n"); return -1; } params->raw_rate = n; break; case OPT_RAW_FORMAT: params->raw_format = optarg; break; case M4AF_TAG_TITLE: case M4AF_TAG_ARTIST: case M4AF_TAG_ALBUM: case M4AF_TAG_GENRE: case M4AF_TAG_DATE: case M4AF_TAG_COMPOSER: case M4AF_TAG_GROUPING: case M4AF_TAG_COMMENT: case M4AF_TAG_ALBUM_ARTIST: case M4AF_TAG_TRACK: case M4AF_TAG_DISK: case M4AF_TAG_TEMPO: aacenc_add_tag_to_store(¶ms->tags, ch, 0, optarg, strlen(optarg), 0); break; case OPT_SHORT_TAG: case OPT_SHORT_TAG_FILE: case OPT_LONG_TAG: { char *val; size_t klen; unsigned fcc = M4AF_FOURCC('-','-','-','-'); if ((val = strchr(optarg, ':')) == 0) { fprintf(stderr, "invalid arg for tag\n"); return -1; } *val++ = '\0'; if (ch == OPT_SHORT_TAG || ch == OPT_SHORT_TAG_FILE) { /* * take care of U+00A9(COPYRIGHT SIGN). * 1) if length of fcc is 3, we prepend '\xa9'. * 2) U+00A9 becomes "\xc2\xa9" in UTF-8. Therefore * we remove first '\xc2'. */ if (optarg[0] == '\xc2') ++optarg; if ((klen = strlen(optarg))== 3) fcc = 0xa9; else if (klen != 4) { fprintf(stderr, "invalid arg for tag\n"); return -1; } for (; *optarg; ++optarg) fcc = ((fcc << 8) | (*optarg & 0xff)); } aacenc_add_tag_to_store(¶ms->tags, fcc, optarg, val, strlen(val), ch == OPT_SHORT_TAG_FILE); } break; case OPT_TAG_FROM_JSON: params->json_filename = optarg; break; default: return usage(), -1; } } if (argc == optind) return usage(), -1; if (!params->bitrate && !params->bitrate_mode) { fprintf(stderr, "bitrate or bitrate-mode is mandatory\n"); return -1; } if (params->output_filename && !strcmp(params->output_filename, "-") && !params->transport_format) { fprintf(stderr, "stdout streaming is not available on M4A output\n"); return -1; } if (params->bitrate && params->bitrate < 10000) params->bitrate *= 1000; if (params->is_raw) { if (!params->raw_channels) params->raw_channels = 2; if (!params->raw_rate) params->raw_rate = 44100; if (!params->raw_format) params->raw_format = "S16L"; } params->input_filename = argv[optind]; return 0; }; static int write_sample(FILE *ofp, m4af_ctx_t *m4af, aacenc_frame_t *frame) { if (!m4af) { fwrite(frame->data, 1, frame->size, ofp); if (ferror(ofp)) { fprintf(stderr, "ERROR: fwrite(): %s\n", strerror(errno)); return -1; } } else if (m4af_write_sample(m4af, 0, frame->data, frame->size, 0) < 0) { fprintf(stderr, "ERROR: failed to write m4a sample\n"); return -1; } return 0; } static int encode(aacenc_param_ex_t *params, pcm_reader_t *reader, HANDLE_AACENCODER encoder, uint32_t frame_length, m4af_ctx_t *m4af) { int16_t *ibuf = 0, *ip; aacenc_frame_t obuf[2] = {{ 0 }}, *obp; unsigned flip = 0; int nread = 1; int rc = -1; int remaining, consumed; int frames_written = 0, encoded = 0; aacenc_progress_t progress = { 0 }; const pcm_sample_description_t *fmt = pcm_get_format(reader); ibuf = malloc(frame_length * fmt->bytes_per_frame); aacenc_progress_init(&progress, pcm_get_length(reader), fmt->sample_rate); for (;;) { /* * Since we delay the write, we cannot just exit loop when interrupted. * Instead, we regard it as EOF. */ if (g_interrupted) nread = 0; if (nread > 0) { if ((nread = pcm_read_frames(reader, ibuf, frame_length)) < 0) { fprintf(stderr, "ERROR: read failed\n"); goto END; } if (!params->silent) aacenc_progress_update(&progress, pcm_get_position(reader), fmt->sample_rate * 2); } ip = ibuf; remaining = nread; do { obp = &obuf[flip]; consumed = aac_encode_frame(encoder, fmt, ip, remaining, obp); if (consumed < 0) goto END; if (consumed == 0 && obp->size == 0) goto DONE; if (obp->size == 0) break; remaining -= consumed; ip += consumed * fmt->channels_per_frame; flip ^= 1; /* * As we pad 1 frame at beginning and ending by our extrapolator, * we want to drop them. * We delay output by 1 frame by double buffering, and discard * second frame and final frame from the encoder. * Since sbr_header is included in the first frame (in case of * SBR), we cannot discard first frame. So we pick second instead. */ ++encoded; if (encoded == 1 || encoded == 3) continue; if (write_sample(params->output_fp, m4af, &obuf[flip]) < 0) goto END; ++frames_written; } while (remaining > 0); /* * When interrupted, we haven't pulled out last extrapolated frames * from the reader. Therefore, we have to write the final outcome. */ if (g_interrupted) { if (write_sample(params->output_fp, m4af, &obp[flip^1]) < 0) goto END; ++frames_written; } } DONE: if (!params->silent) aacenc_progress_finish(&progress, pcm_get_position(reader)); rc = frames_written; END: if (ibuf) free(ibuf); if (obuf[0].data) free(obuf[0].data); if (obuf[1].data) free(obuf[1].data); return rc; } static void put_tool_tag(m4af_ctx_t *m4af, const aacenc_param_ex_t *params, HANDLE_AACENCODER encoder) { char tool_info[256]; char *p = tool_info; LIB_INFO lib_info; p += sprintf(p, PROGNAME " %s, ", fdkaac_version); aacenc_get_lib_info(&lib_info); p += sprintf(p, "libfdk-aac %s, ", lib_info.versionStr); if (params->bitrate_mode) sprintf(p, "VBR mode %d", params->bitrate_mode); else sprintf(p, "CBR %dkbps", aacEncoder_GetParam(encoder, AACENC_BITRATE) / 1000); m4af_add_itmf_string_tag(m4af, M4AF_TAG_TOOL, tool_info); } static int finalize_m4a(m4af_ctx_t *m4af, const aacenc_param_ex_t *params, HANDLE_AACENCODER encoder) { unsigned i; aacenc_tag_entry_t *tag; tag = params->source_tags.tag_table; for (i = 0; i < params->source_tags.tag_count; ++i, ++tag) aacenc_write_tag_entry(m4af, tag); if (params->json_filename) aacenc_write_tags_from_json(m4af, params->json_filename); tag = params->tags.tag_table; for (i = 0; i < params->tags.tag_count; ++i, ++tag) aacenc_write_tag_entry(m4af, tag); put_tool_tag(m4af, params, encoder); if (m4af_finalize(m4af, params->moov_before_mdat) < 0) { fprintf(stderr, "ERROR: failed to finalize m4a\n"); return -1; } return 0; } static char *generate_output_filename(const char *filename, const char *ext) { char *p = 0; size_t ext_len = strlen(ext); if (strcmp(filename, "-") == 0) { p = malloc(ext_len + 6); sprintf(p, "stdin%s", ext); } else { const char *base = aacenc_basename(filename); size_t ilen = strlen(base); const char *ext_org = strrchr(base, '.'); if (ext_org) ilen = ext_org - base; p = malloc(ilen + ext_len + 1); sprintf(p, "%.*s%s", (int)ilen, base, ext); } return p; } static int parse_raw_spec(const char *spec, pcm_sample_description_t *desc) { unsigned bits; unsigned char c_type, c_endian = 'L'; int type; if (sscanf(spec, "%c%u%c", &c_type, &bits, &c_endian) < 2) return -1; c_type = toupper(c_type); c_endian = toupper(c_endian); if (c_type == 'S') type = 1; else if (c_type == 'U') type = 2; else if (c_type == 'F') type = 4; else return -1; if (c_endian == 'B') type |= 8; else if (c_endian != 'L') return -1; if (c_type == 'F' && bits != 32 && bits != 64) return -1; if (c_type != 'F' && (bits < 8 || bits > 32)) return -1; desc->sample_type = type; desc->bits_per_channel = bits; return 0; } static pcm_io_vtbl_t pcm_io_vtbl = { read_callback, seek_callback, tell_callback }; static pcm_io_vtbl_t pcm_io_vtbl_noseek = { read_callback, 0, tell_callback }; static pcm_reader_t *open_input(aacenc_param_ex_t *params) { pcm_io_context_t io = { 0 }; pcm_reader_t *reader = 0; if ((params->input_fp = aacenc_fopen(params->input_filename, "rb")) == 0) { aacenc_fprintf(stderr, "ERROR: %s: %s\n", params->input_filename, strerror(errno)); goto FAIL; } io.cookie = params->input_fp; if (aacenc_seekable(params->input_fp)) io.vtbl = &pcm_io_vtbl; else io.vtbl = &pcm_io_vtbl_noseek; if (params->is_raw) { int bytes_per_channel; pcm_sample_description_t desc = { 0 }; if (parse_raw_spec(params->raw_format, &desc) < 0) { fprintf(stderr, "ERROR: invalid raw-format spec\n"); goto FAIL; } desc.sample_rate = params->raw_rate; desc.channels_per_frame = params->raw_channels; bytes_per_channel = (desc.bits_per_channel + 7) / 8; desc.bytes_per_frame = params->raw_channels * bytes_per_channel; if ((reader = raw_open(&io, &desc)) == 0) { fprintf(stderr, "ERROR: failed to open raw input\n"); goto FAIL; } } else { int c; ungetc(c = getc(params->input_fp), params->input_fp); switch (c) { case 'R': if ((reader = wav_open(&io, params->ignore_length)) == 0) { fprintf(stderr, "ERROR: broken / unsupported input file\n"); goto FAIL; } break; case 'c': params->source_tag_ctx.add = aacenc_add_tag_entry_to_store; params->source_tag_ctx.add_ctx = ¶ms->source_tags; if ((reader = caf_open(&io, aacenc_translate_generic_text_tag, ¶ms->source_tag_ctx)) == 0) { fprintf(stderr, "ERROR: broken / unsupported input file\n"); goto FAIL; } break; default: fprintf(stderr, "ERROR: unsupported input file\n"); goto FAIL; } } reader = pcm_open_native_converter(reader); if (reader && PCM_IS_FLOAT(pcm_get_format(reader))) reader = limiter_open(reader); if (reader && (reader = pcm_open_sint16_converter(reader)) != 0) reader = extrapolater_open(reader); return reader; FAIL: return 0; } int main(int argc, char **argv) { static m4af_io_callbacks_t m4af_io = { read_callback, write_callback, seek_callback, tell_callback }; aacenc_param_ex_t params = { 0 }; int result = 2; char *output_filename = 0; pcm_reader_t *reader = 0; HANDLE_AACENCODER encoder = 0; AACENC_InfoStruct aacinfo = { 0 }; m4af_ctx_t *m4af = 0; const pcm_sample_description_t *sample_format; int frame_count = 0; int sbr_mode = 0; unsigned scale_shift = 0; setlocale(LC_CTYPE, ""); setbuf(stderr, 0); if (parse_options(argc, argv, ¶ms) < 0) return 1; if ((reader = open_input(¶ms)) == 0) goto END; sample_format = pcm_get_format(reader); sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)¶ms); if (sbr_mode && !aacenc_is_sbr_ratio_available()) { fprintf(stderr, "WARNING: Only dual-rate SBR is available " "for this version\n"); params.sbr_ratio = 2; } scale_shift = aacenc_is_dual_rate_sbr((aacenc_param_t*)¶ms); params.sbr_signaling = 0; if (sbr_mode) { if (params.transport_format == TT_MP4_LOAS || !scale_shift) params.sbr_signaling = 2; if (params.transport_format == TT_MP4_RAW && aacenc_is_explicit_bw_compatible_sbr_signaling_available()) params.sbr_signaling = 1; } if (aacenc_init(&encoder, (aacenc_param_t*)¶ms, sample_format, &aacinfo) < 0) goto END; if (!params.output_filename) { const char *ext = params.transport_format ? ".aac" : ".m4a"; output_filename = generate_output_filename(params.input_filename, ext); params.output_filename = output_filename; } if ((params.output_fp = aacenc_fopen(params.output_filename, "wb+")) == 0) { aacenc_fprintf(stderr, "ERROR: %s: %s\n", params.output_filename, strerror(errno)); goto END; } handle_signals(); if (!params.transport_format) { uint32_t scale; unsigned framelen = aacinfo.frameLength; scale = sample_format->sample_rate >> scale_shift; if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io, params.output_fp)) < 0) goto END; m4af_set_num_channels(m4af, 0, sample_format->channels_per_frame); m4af_set_fixed_frame_duration(m4af, 0, framelen >> scale_shift); if (aacenc_is_explicit_bw_compatible_sbr_signaling_available()) m4af_set_decoder_specific_info(m4af, 0, aacinfo.confBuf, aacinfo.confSize); else { uint8_t mp4asc[32]; uint32_t ascsize = sizeof(mp4asc); aacenc_mp4asc((aacenc_param_t*)¶ms, aacinfo.confBuf, aacinfo.confSize, mp4asc, &ascsize); m4af_set_decoder_specific_info(m4af, 0, mp4asc, ascsize); } m4af_set_vbr_mode(m4af, 0, params.bitrate_mode); m4af_set_priming_mode(m4af, params.gapless_mode + 1); m4af_begin_write(m4af); } if (scale_shift && (aacinfo.encoderDelay & 1)) { /* * Since odd delay cannot be exactly expressed in downsampled scale, * we push one zero frame to the encoder here, to make delay even */ int16_t zero[8] = { 0 }; aacenc_frame_t frame = { 0 }; aac_encode_frame(encoder, sample_format, zero, 1, &frame); free(frame.data); } frame_count = encode(¶ms, reader, encoder, aacinfo.frameLength, m4af); if (frame_count < 0) goto END; if (m4af) { uint32_t delay = aacinfo.encoderDelay; uint32_t padding; int64_t frames_read = pcm_get_position(reader); if (sbr_mode && params.profile != AOT_ER_AAC_ELD && !params.include_sbr_delay) delay -= 481 << scale_shift; if (scale_shift && (delay & 1)) ++delay; padding = frame_count * aacinfo.frameLength - frames_read - delay; m4af_set_priming(m4af, 0, delay >> scale_shift, padding >> scale_shift); if (finalize_m4a(m4af, ¶ms, encoder) < 0) goto END; } result = 0; END: if (reader) pcm_teardown(&reader); if (params.input_fp) fclose(params.input_fp); if (m4af) m4af_teardown(&m4af); if (params.output_fp) fclose(params.output_fp); if (encoder) aacEncClose(&encoder); if (output_filename) free(output_filename); if (params.tags.tag_table) aacenc_free_tag_store(¶ms.tags); if (params.source_tags.tag_table) aacenc_free_tag_store(¶ms.source_tags); return result; } fdkaac-0.6.3/src/metadata.c000066400000000000000000000344111276003472100154510ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #if HAVE_INTTYPES_H # include #elif defined(_MSC_VER) # define SCNd64 "I64d" #endif #include #include #include #include #include #include "m4af.h" #include "metadata.h" #include "compat.h" #include "parson.h" typedef struct tag_key_mapping_t { const char *name; uint32_t fcc; } tag_key_mapping_t; enum { TAG_TOTAL_DISCS = 1, TAG_TOTAL_TRACKS = 2 }; static tag_key_mapping_t tag_mapping_table[] = { { "album", M4AF_TAG_ALBUM }, { "albumartist", M4AF_TAG_ALBUM_ARTIST }, { "albumartistsort", M4AF_FOURCC('s','o','a','a') }, { "albumartistsortorder", M4AF_FOURCC('s','o','a','a') }, { "albumsort", M4AF_FOURCC('s','o','a','l') }, { "albumsortorder", M4AF_FOURCC('s','o','a','l') }, { "artist", M4AF_TAG_ARTIST }, { "artistsort", M4AF_FOURCC('s','o','a','r') }, { "artistsortorder", M4AF_FOURCC('s','o','a','r') }, { "band", M4AF_TAG_ALBUM_ARTIST }, { "bpm", M4AF_TAG_TEMPO }, { "comment", M4AF_TAG_COMMENT }, { "compilation", M4AF_TAG_COMPILATION }, { "composer", M4AF_TAG_COMPOSER }, { "composersort", M4AF_FOURCC('s','o','c','o') }, { "composersortorder", M4AF_FOURCC('s','o','c','o') }, { "contentgroup", M4AF_TAG_GROUPING }, { "copyright", M4AF_TAG_COPYRIGHT }, { "date", M4AF_TAG_DATE }, { "disc", M4AF_TAG_DISK }, { "discnumber", M4AF_TAG_DISK }, { "disctotal", TAG_TOTAL_DISCS }, { "genre", M4AF_TAG_GENRE }, { "grouping", M4AF_TAG_GROUPING }, { "itunescompilation", M4AF_TAG_COMPILATION }, { "lyrics", M4AF_TAG_LYRICS }, { "tempo", M4AF_TAG_TEMPO }, { "recordeddate", M4AF_TAG_DATE }, { "title", M4AF_TAG_TITLE }, { "titlesort", M4AF_FOURCC('s','o','n','m') }, { "titlesortorder", M4AF_FOURCC('s','o','n','m') }, { "totaldiscs", TAG_TOTAL_DISCS }, { "totaltracks", TAG_TOTAL_TRACKS }, { "track", M4AF_TAG_TRACK }, { "tracknumber", M4AF_TAG_TRACK }, { "tracktotal", TAG_TOTAL_TRACKS }, { "unsyncedlyrics", M4AF_TAG_LYRICS }, { "year", M4AF_TAG_DATE }, }; static int tag_key_comparator(const void *k, const void *v) { return strcmp((const char *)k, ((tag_key_mapping_t*)v)->name); } static uint32_t get_tag_fcc_from_name(const char *name) { char *name_p = 0, *p; const tag_key_mapping_t *ent; name_p = malloc(strlen(name) + 1); for (p = name_p; *name; ++name) { unsigned char c = *name; if (c != ' ' && c != '-' && c != '_') *p++ = tolower(c); } *p = 0; ent = bsearch(name_p, tag_mapping_table, sizeof(tag_mapping_table) / sizeof(tag_mapping_table[0]), sizeof(tag_mapping_table[0]), tag_key_comparator); free(name_p); return ent ? ent->fcc : 0; } static char *aacenc_load_tag_from_file(const char *path, uint32_t *data_size) { FILE *fp = 0; char *data = 0; int64_t size; if ((fp = aacenc_fopen(path, "rb")) == NULL) { aacenc_fprintf(stderr, "WARNING: %s: %s\n", path, strerror(errno)); goto END; } fseeko(fp, 0, SEEK_END); size = ftello(fp); if (size > 5*1024*1024) { aacenc_fprintf(stderr, "WARNING: %s: size too large\n", path); goto END; } fseeko(fp, 0, SEEK_SET); data = malloc(size + 1); if (data) fread(data, 1, size, fp); data[size] = 0; *data_size = (uint32_t)size; END: if (fp) fclose(fp); return data; } static int aacenc_is_string_tag(uint32_t tag) { switch (tag) { case M4AF_TAG_TITLE: case M4AF_TAG_ARTIST: case M4AF_TAG_ALBUM: case M4AF_TAG_GENRE: case M4AF_TAG_DATE: case M4AF_TAG_COMPOSER: case M4AF_TAG_GROUPING: case M4AF_TAG_COMMENT: case M4AF_TAG_LYRICS: case M4AF_TAG_TOOL: case M4AF_TAG_ALBUM_ARTIST: case M4AF_TAG_DESCRIPTION: case M4AF_TAG_LONG_DESCRIPTION: case M4AF_TAG_COPYRIGHT: case M4AF_FOURCC('a','p','I','D'): case M4AF_FOURCC('c','a','t','g'): case M4AF_FOURCC('k','e','y','w'): case M4AF_FOURCC('p','u','r','d'): case M4AF_FOURCC('p','u','r','l'): case M4AF_FOURCC('s','o','a','a'): case M4AF_FOURCC('s','o','a','l'): case M4AF_FOURCC('s','o','a','r'): case M4AF_FOURCC('s','o','c','o'): case M4AF_FOURCC('s','o','n','m'): case M4AF_FOURCC('s','o','s','n'): case M4AF_FOURCC('t','v','e','n'): case M4AF_FOURCC('t','v','n','n'): case M4AF_FOURCC('t','v','s','h'): case M4AF_FOURCC('x','i','d',' '): case M4AF_FOURCC('\xa9','e','n','c'): case M4AF_FOURCC('\xa9','s','t','3'): case M4AF_FOURCC('-','-','-','-'): return 1; } return 0; } void aacenc_add_tag_to_store(aacenc_tag_store_t *store, uint32_t tag, const char *key, const char *value, uint32_t size, int is_file_name) { aacenc_tag_entry_t entry = { 0 }; char *dp = 0; if (!is_file_name && !size) return; entry.tag = tag; if (tag == M4AF_FOURCC('-','-','-','-')) entry.name = (char *)key; if (is_file_name) { entry.data = dp = aacenc_load_tag_from_file(value, &size); entry.data_size = size; } else if (aacenc_is_string_tag(tag)) { entry.data = dp = aacenc_to_utf8(value); entry.data_size = strlen(entry.data); } else { entry.data = (char *)value; entry.data_size = size; } aacenc_add_tag_entry_to_store(store, &entry); free(dp); } void aacenc_add_tag_entry_to_store(void *ctx, const aacenc_tag_entry_t *tag) { aacenc_tag_store_t *store = ctx; aacenc_tag_entry_t *entry; if (store->tag_count == store->tag_table_capacity) { unsigned newsize = store->tag_table_capacity; newsize = newsize ? newsize * 2 : 1; store->tag_table = realloc(store->tag_table, newsize * sizeof(aacenc_tag_entry_t)); store->tag_table_capacity = newsize; } entry = store->tag_table + store->tag_count; entry->tag = tag->tag; entry->data_size = tag->data_size; entry->name = tag->name ? strdup(tag->name) : 0; entry->data = malloc(tag->data_size + 1); memcpy(entry->data, tag->data, tag->data_size); entry->data[tag->data_size] = 0; store->tag_count++; } static void tag_put_number_pair(aacenc_translate_generic_text_tag_ctx_t *ctx, uint32_t fcc, unsigned number, unsigned total) { char buf[128]; aacenc_tag_entry_t entry = { 0 }; if (number) { if (total) sprintf(buf, "%u/%u", number, total); else sprintf(buf, "%u", number); entry.tag = fcc; entry.data = buf; entry.data_size = strlen(buf); ctx->add(ctx->add_ctx, &entry); } } void aacenc_translate_generic_text_tag(void *pctx, const char *key, const char *val, uint32_t size) { aacenc_translate_generic_text_tag_ctx_t *ctx = pctx; aacenc_tag_entry_t entry = { 0 }; uint32_t fcc; /* * Since track/disc number pair (number and total) can be stored within * either single tag or separately, we cannot instantly translate * them in one-to-one manner. * Instead, we keep and store them until all tags are processed, * then finally submit. */ if (!key) { /* use null key as flushing signal */ tag_put_number_pair(ctx, M4AF_TAG_TRACK, ctx->track, ctx->track_total); tag_put_number_pair(ctx, M4AF_TAG_DISK, ctx->disc, ctx->disc_total); return; } if (!val || !size) return; if ((fcc = get_tag_fcc_from_name(key)) == 0) return; switch (fcc) { case TAG_TOTAL_DISCS: sscanf(val, "%d", &ctx->disc_total); break; case TAG_TOTAL_TRACKS: sscanf(val, "%d", &ctx->track_total); break; case M4AF_TAG_DISK: sscanf(val, "%d/%d", &ctx->disc, &ctx->disc_total); break; case M4AF_TAG_TRACK: sscanf(val, "%d/%d", &ctx->track, &ctx->track_total); break; default: { entry.tag = fcc; entry.data = (char *)val; entry.data_size = (size == ~0U) ? strlen(val) : size; ctx->add(ctx->add_ctx, &entry); } } } static const char *aacenc_json_object_get_string(JSON_Object *obj, const char *key, char *buf) { JSON_Value_Type type; const char *val = 0; type = json_value_get_type(json_object_get_value(obj, key)); if (type == JSONString) val = json_object_get_string(obj, key); else if (type == JSONNumber) { double num = json_object_get_number(obj, key); sprintf(buf, "%.15g", num); val = buf; } else if (type == JSONBoolean) { int n = json_object_get_boolean(obj, key); sprintf(buf, "%d", n); val = buf; } return val; } void aacenc_write_tags_from_json(m4af_ctx_t *m4af, const char *json_filename) { char *data = 0; JSON_Value *json = 0; JSON_Object *root; size_t i, nelts; uint32_t data_size; char *json_dot_path; char *filename = 0; aacenc_translate_generic_text_tag_ctx_t ctx = { 0 }; ctx.add = aacenc_write_tag_entry; ctx.add_ctx = m4af; filename = strdup(json_filename); if ((json_dot_path = strchr(filename, '?')) != 0) *json_dot_path++ = '\0'; if (!(data = aacenc_load_tag_from_file(filename, &data_size))) goto DONE; if (!(json = json_parse_string(data))) { aacenc_fprintf(stderr, "WARNING: failed to parse JSON\n"); goto DONE; } root = json_value_get_object(json); if (json_dot_path) { if (!(root = json_object_dotget_object(root, json_dot_path))) { aacenc_fprintf(stderr, "WARNING: %s not found in JSON\n", json_dot_path); goto DONE; } } nelts = json_object_get_count(root); for (i = 0; i < nelts; ++i) { char buf[256]; const char *key = json_object_get_name(root, i); const char *val = aacenc_json_object_get_string(root, key, buf); if (val) aacenc_translate_generic_text_tag(&ctx, key, val, ~0U); } aacenc_translate_generic_text_tag(&ctx, 0, 0, 0); DONE: if (data) free(data); if (filename) free(filename); if (json) json_value_free(json); } void aacenc_free_tag_store(aacenc_tag_store_t *store) { if (store->tag_table) { unsigned i; for (i = 0; i < store->tag_count; ++i) { aacenc_tag_entry_t *ent = &store->tag_table[i]; free(ent->name); free(ent->data); } free(store->tag_table); store->tag_table = 0; store->tag_count = 0; } } void aacenc_write_tag_entry(void *ctx, const aacenc_tag_entry_t *tag) { m4af_ctx_t *m4af = ctx; unsigned m, n = 0; const char *data = tag->data; switch (tag->tag) { case M4AF_TAG_TRACK: if (sscanf(data, "%u/%u", &m, &n) >= 1) m4af_add_itmf_track_tag(m4af, m, n); break; case M4AF_TAG_DISK: if (sscanf(data, "%u/%u", &m, &n) >= 1) m4af_add_itmf_disk_tag(m4af, m, n); break; case M4AF_TAG_GENRE_ID3: if (sscanf(data, "%u", &n) == 1) m4af_add_itmf_genre_tag(m4af, n); break; case M4AF_TAG_TEMPO: if (sscanf(data, "%u", &n) == 1) m4af_add_itmf_int16_tag(m4af, tag->tag, n); break; case M4AF_TAG_COMPILATION: case M4AF_FOURCC('a','k','I','D'): case M4AF_FOURCC('h','d','v','d'): case M4AF_FOURCC('p','c','s','t'): case M4AF_FOURCC('p','g','a','p'): case M4AF_FOURCC('r','t','n','g'): case M4AF_FOURCC('s','t','i','k'): if (sscanf(data, "%u", &n) == 1) m4af_add_itmf_int8_tag(m4af, tag->tag, n); break; case M4AF_FOURCC('a','t','I','D'): case M4AF_FOURCC('c','m','I','D'): case M4AF_FOURCC('c','n','I','D'): case M4AF_FOURCC('g','e','I','D'): case M4AF_FOURCC('s','f','I','D'): case M4AF_FOURCC('t','v','s','n'): case M4AF_FOURCC('t','v','s','s'): if (sscanf(data, "%u", &n) == 1) m4af_add_itmf_int32_tag(m4af, tag->tag, n); break; case M4AF_FOURCC('p','l','I','D'): { int64_t qn; if (sscanf(data, "%" SCNd64, &qn) == 1) m4af_add_itmf_int64_tag(m4af, tag->tag, qn); break; } case M4AF_TAG_ARTWORK: { int data_type = 0; if (!memcmp(data, "GIF", 3)) data_type = M4AF_GIF; else if (!memcmp(data, "\xff\xd8\xff", 3)) data_type = M4AF_JPEG; else if (!memcmp(data, "\x89PNG", 4)) data_type = M4AF_PNG; if (data_type) m4af_add_itmf_short_tag(m4af, tag->tag, data_type, data, tag->data_size); break; } case M4AF_FOURCC('-','-','-','-'): { m4af_add_itmf_long_tag(m4af, tag->name, data); break; } default: if (aacenc_is_string_tag(tag->tag)) m4af_add_itmf_string_tag(m4af, tag->tag, data); else fprintf(stderr, "WARNING: unknown/unsupported tag: %c%c%c%c\n", tag->tag >> 24, (tag->tag >> 16) & 0xff, (tag->tag >> 8) & 0xff, tag->tag & 0xff); } } fdkaac-0.6.3/src/metadata.h000066400000000000000000000026711276003472100154610ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #ifndef METADATA_H #define METADATA_H #include "m4af.h" typedef struct aacenc_tag_entry_t { uint32_t tag; char *name; char *data; uint32_t data_size; } aacenc_tag_entry_t; typedef struct aacenc_tag_store_t { aacenc_tag_entry_t *tag_table; unsigned tag_count; unsigned tag_table_capacity; } aacenc_tag_store_t; typedef struct aacenc_translate_generic_text_tag_ctx_t { unsigned track, track_total, disc, disc_total; void (*add)(void *, const aacenc_tag_entry_t *); void *add_ctx; } aacenc_translate_generic_text_tag_ctx_t; typedef void (*aacenc_tag_callback_t)(void *ctx, const char *key, const char *value, uint32_t size); void aacenc_translate_generic_text_tag(void *ctx, const char *key, const char *val, uint32_t size); void aacenc_add_tag_to_store(aacenc_tag_store_t *store, uint32_t tag, const char *key, const char *value, uint32_t size, int is_file_name); void aacenc_add_tag_entry_to_store(void *store, const aacenc_tag_entry_t *tag); void aacenc_free_tag_store(aacenc_tag_store_t *store); void aacenc_write_tags_from_json(m4af_ctx_t *m4af, const char *json_filename); void aacenc_write_tag_entry(void *m4af, const aacenc_tag_entry_t *tag); #endif fdkaac-0.6.3/src/parson.c000066400000000000000000000553651276003472100152060ustar00rootroot00000000000000/* Parson ( http://kgabis.github.com/parson/ ) Copyright (c) 2012 Krzysztof Gabis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "parson.h" #include #include #include #include #define ERROR 0 #define SUCCESS 1 #define STARTING_CAPACITY 15 #define ARRAY_MAX_CAPACITY 122880 /* 15*(2^13) */ #define OBJECT_MAX_CAPACITY 960 /* 15*(2^6) */ #define MAX_NESTING 19 #define sizeof_token(a) (sizeof(a) - 1) #define skip_char(str) ((*str)++) #define skip_whitespaces(str) while (isspace(**string)) { skip_char(string); } #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define parson_malloc(a) malloc(a) #define parson_free(a) free((void*)a) #define parson_realloc(a, b) realloc(a, b) /* Type definitions */ typedef union json_value_value { const char *string; double number; JSON_Object *object; JSON_Array *array; int boolean; int null; } JSON_Value_Value; struct json_value_t { JSON_Value_Type type; JSON_Value_Value value; }; struct json_object_t { const char **names; JSON_Value **values; size_t count; size_t capacity; }; struct json_array_t { JSON_Value **items; size_t count; size_t capacity; }; /* Various */ static int try_realloc(void **ptr, size_t new_size); static char * parson_strndup(const char *string, size_t n); static int is_utf(const unsigned char *string); static int is_decimal(const char *string, size_t length); /* JSON Object */ static JSON_Object * json_object_init(void); static int json_object_add(JSON_Object *object, const char *name, JSON_Value *value); static int json_object_resize(JSON_Object *object, size_t capacity); static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n); static void json_object_free(JSON_Object *object); /* JSON Array */ static JSON_Array * json_array_init(void); static int json_array_add(JSON_Array *array, JSON_Value *value); static int json_array_resize(JSON_Array *array, size_t capacity); static void json_array_free(JSON_Array *array); /* JSON Value */ static JSON_Value * json_value_init_object(void); static JSON_Value * json_value_init_array(void); static JSON_Value * json_value_init_string(const char *string); static JSON_Value * json_value_init_number(double number); static JSON_Value * json_value_init_boolean(int boolean); static JSON_Value * json_value_init_null(void); /* Parser */ static void skip_quotes(const char **string); static const char * get_processed_string(const char **string); static JSON_Value * parse_object_value(const char **string, size_t nesting); static JSON_Value * parse_array_value(const char **string, size_t nesting); static JSON_Value * parse_string_value(const char **string); static JSON_Value * parse_boolean_value(const char **string); static JSON_Value * parse_number_value(const char **string); static JSON_Value * parse_null_value(const char **string); static JSON_Value * parse_value(const char **string, size_t nesting); /* Various */ static int try_realloc(void **ptr, size_t new_size) { void *reallocated_ptr = parson_realloc(*ptr, new_size); if (!reallocated_ptr) { return ERROR; } *ptr = reallocated_ptr; return SUCCESS; } static char * parson_strndup(const char *string, size_t n) { char *output_string = (char*)parson_malloc(n + 1); if (!output_string) { return NULL; } output_string[n] = '\0'; strncpy(output_string, string, n); return output_string; } static int is_utf(const unsigned char *s) { return isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]); } static int is_decimal(const char *string, size_t length) { if (length > 1 && string[0] == '0' && string[1] != '.') { return 0; } if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') { return 0; } while (length--) { if (strchr("xX", string[length])) { return 0; } } return 1; } /* JSON Object */ static JSON_Object * json_object_init(void) { JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object)); if (!new_obj) { return NULL; } new_obj->names = (const char**)NULL; new_obj->values = (JSON_Value**)NULL; new_obj->capacity = 0; new_obj->count = 0; return new_obj; } static int json_object_add(JSON_Object *object, const char *name, JSON_Value *value) { size_t index; if (object->count >= object->capacity) { size_t new_capacity = MAX(object->capacity * 2, STARTING_CAPACITY); if (new_capacity > OBJECT_MAX_CAPACITY) { return ERROR; } if (json_object_resize(object, new_capacity) == ERROR) { return ERROR; } } if (json_object_get_value(object, name) != NULL) { return ERROR; } index = object->count; object->names[index] = parson_strndup(name, strlen(name)); if (!object->names[index]) { return ERROR; } object->values[index] = value; object->count++; return SUCCESS; } static int json_object_resize(JSON_Object *object, size_t capacity) { if (try_realloc((void**)&object->names, capacity * sizeof(char*)) == ERROR) { return ERROR; } if (try_realloc((void**)&object->values, capacity * sizeof(JSON_Value*)) == ERROR) { return ERROR; } object->capacity = capacity; return SUCCESS; } static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n) { size_t i, name_length; for (i = 0; i < json_object_get_count(object); i++) { name_length = strlen(object->names[i]); if (name_length != n) { continue; } if (strncmp(object->names[i], name, n) == 0) { return object->values[i]; } } return NULL; } static void json_object_free(JSON_Object *object) { while(object->count--) { parson_free(object->names[object->count]); json_value_free(object->values[object->count]); } parson_free(object->names); parson_free(object->values); parson_free(object); } /* JSON Array */ static JSON_Array * json_array_init(void) { JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array)); if (!new_array) { return NULL; } new_array->items = (JSON_Value**)NULL; new_array->capacity = 0; new_array->count = 0; return new_array; } static int json_array_add(JSON_Array *array, JSON_Value *value) { if (array->count >= array->capacity) { size_t new_capacity = MAX(array->capacity * 2, STARTING_CAPACITY); if (new_capacity > ARRAY_MAX_CAPACITY) { return ERROR; } if (!json_array_resize(array, new_capacity)) { return ERROR; } } array->items[array->count] = value; array->count++; return SUCCESS; } static int json_array_resize(JSON_Array *array, size_t capacity) { if (try_realloc((void**)&array->items, capacity * sizeof(JSON_Value*)) == ERROR) { return ERROR; } array->capacity = capacity; return SUCCESS; } static void json_array_free(JSON_Array *array) { while (array->count--) { json_value_free(array->items[array->count]); } parson_free(array->items); parson_free(array); } /* JSON Value */ static JSON_Value * json_value_init_object(void) { JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); if (!new_value) { return NULL; } new_value->type = JSONObject; new_value->value.object = json_object_init(); if (!new_value->value.object) { parson_free(new_value); return NULL; } return new_value; } static JSON_Value * json_value_init_array(void) { JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); if (!new_value) { return NULL; } new_value->type = JSONArray; new_value->value.array = json_array_init(); if (!new_value->value.array) { parson_free(new_value); return NULL; } return new_value; } static JSON_Value * json_value_init_string(const char *string) { JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); if (!new_value) { return NULL; } new_value->type = JSONString; new_value->value.string = string; return new_value; } static JSON_Value * json_value_init_number(double number) { JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); if (!new_value) { return NULL; } new_value->type = JSONNumber; new_value->value.number = number; return new_value; } static JSON_Value * json_value_init_boolean(int boolean) { JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); if (!new_value) { return NULL; } new_value->type = JSONBoolean; new_value->value.boolean = boolean; return new_value; } static JSON_Value * json_value_init_null(void) { JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); if (!new_value) { return NULL; } new_value->type = JSONNull; return new_value; } /* Parser */ static void skip_quotes(const char **string) { skip_char(string); while (**string != '\"') { if (**string == '\0') { return; } if (**string == '\\') { skip_char(string); if (**string == '\0') { return; }} skip_char(string); } skip_char(string); } /* Returns contents of a string inside double quotes and parses escaped characters inside. Example: "\u006Corem ipsum" -> lorem ipsum */ static const char * get_processed_string(const char **string) { const char *string_start = *string; char *output, *processed_ptr, *unprocessed_ptr, current_char; unsigned int utf_val; skip_quotes(string); if (**string == '\0') { return NULL; } output = parson_strndup(string_start + 1, *string - string_start - 2); if (!output) { return NULL; } processed_ptr = unprocessed_ptr = output; while (*unprocessed_ptr) { current_char = *unprocessed_ptr; if (current_char == '\\') { unprocessed_ptr++; current_char = *unprocessed_ptr; switch (current_char) { case '\"': case '\\': case '/': break; case 'b': current_char = '\b'; break; case 'f': current_char = '\f'; break; case 'n': current_char = '\n'; break; case 'r': current_char = '\r'; break; case 't': current_char = '\t'; break; case 'u': unprocessed_ptr++; if (!is_utf((const unsigned char*)unprocessed_ptr) || sscanf(unprocessed_ptr, "%4x", &utf_val) == EOF) { parson_free(output); return NULL; } if (utf_val < 0x80) { current_char = utf_val; } else if (utf_val < 0x800) { *processed_ptr++ = (utf_val >> 6) | 0xC0; current_char = ((utf_val | 0x80) & 0xBF); } else { *processed_ptr++ = (utf_val >> 12) | 0xE0; *processed_ptr++ = (((utf_val >> 6) | 0x80) & 0xBF); current_char = ((utf_val | 0x80) & 0xBF); } unprocessed_ptr += 3; break; default: parson_free(output); return NULL; break; } } else if ((unsigned char)current_char < 0x20) { /* 0x00-0x19 are invalid characters for json string (http://www.ietf.org/rfc/rfc4627.txt) */ parson_free(output); return NULL; } *processed_ptr = current_char; processed_ptr++; unprocessed_ptr++; } *processed_ptr = '\0'; if (try_realloc((void**)&output, strlen(output) + 1) == ERROR) { return NULL; } return output; } static JSON_Value * parse_value(const char **string, size_t nesting) { if (nesting > MAX_NESTING) { return NULL; } skip_whitespaces(string); switch (**string) { case '{': return parse_object_value(string, nesting + 1); case '[': return parse_array_value(string, nesting + 1); case '\"': return parse_string_value(string); case 'f': case 't': return parse_boolean_value(string); case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return parse_number_value(string); case 'n': return parse_null_value(string); default: return NULL; } } static JSON_Value * parse_object_value(const char **string, size_t nesting) { JSON_Value *output_value = json_value_init_object(), *new_value = NULL; JSON_Object *output_object = json_value_get_object(output_value); const char *new_key = NULL; if (!output_value) { return NULL; } skip_char(string); skip_whitespaces(string); if (**string == '}') { skip_char(string); return output_value; } /* empty object */ while (**string != '\0') { new_key = get_processed_string(string); skip_whitespaces(string); if (!new_key || **string != ':') { json_value_free(output_value); return NULL; } skip_char(string); new_value = parse_value(string, nesting); if (!new_value) { parson_free(new_key); json_value_free(output_value); return NULL; } if(!json_object_add(output_object, new_key, new_value)) { parson_free(new_key); parson_free(new_value); json_value_free(output_value); return NULL; } parson_free(new_key); skip_whitespaces(string); if (**string != ',') { break; } skip_char(string); skip_whitespaces(string); } skip_whitespaces(string); if (**string != '}' || /* Trim object after parsing is over */ json_object_resize(output_object, json_object_get_count(output_object)) == ERROR) { json_value_free(output_value); return NULL; } skip_char(string); return output_value; } static JSON_Value * parse_array_value(const char **string, size_t nesting) { JSON_Value *output_value = json_value_init_array(), *new_array_value = NULL; JSON_Array *output_array = json_value_get_array(output_value); if (!output_value) { return NULL; } skip_char(string); skip_whitespaces(string); if (**string == ']') { /* empty array */ skip_char(string); return output_value; } while (**string != '\0') { new_array_value = parse_value(string, nesting); if (!new_array_value) { json_value_free(output_value); return NULL; } if(json_array_add(output_array, new_array_value) == ERROR) { parson_free(new_array_value); json_value_free(output_value); return NULL; } skip_whitespaces(string); if (**string != ',') { break; } skip_char(string); skip_whitespaces(string); } skip_whitespaces(string); if (**string != ']' || /* Trim array after parsing is over */ json_array_resize(output_array, json_array_get_count(output_array)) == ERROR) { json_value_free(output_value); return NULL; } skip_char(string); return output_value; } static JSON_Value * parse_string_value(const char **string) { const char *new_string = get_processed_string(string); if (!new_string) { return NULL; } return json_value_init_string(new_string); } static JSON_Value * parse_boolean_value(const char **string) { size_t true_token_size = sizeof_token("true"); size_t false_token_size = sizeof_token("false"); if (strncmp("true", *string, true_token_size) == 0) { *string += true_token_size; return json_value_init_boolean(1); } else if (strncmp("false", *string, false_token_size) == 0) { *string += false_token_size; return json_value_init_boolean(0); } return NULL; } static JSON_Value * parse_number_value(const char **string) { char *end; double number = strtod(*string, &end); JSON_Value *output_value; if (is_decimal(*string, end - *string)) { *string = end; output_value = json_value_init_number(number); } else { output_value = NULL; } return output_value; } static JSON_Value * parse_null_value(const char **string) { size_t token_size = sizeof_token("null"); if (strncmp("null", *string, token_size) == 0) { *string += token_size; return json_value_init_null(); } return NULL; } /* Parser API */ JSON_Value * json_parse_file(const char *filename) { FILE *fp = fopen(filename, "r"); size_t file_size; char *file_contents; JSON_Value *output_value; if (!fp) { return NULL; } fseek(fp, 0L, SEEK_END); file_size = ftell(fp); rewind(fp); file_contents = (char*)parson_malloc(sizeof(char) * (file_size + 1)); if (!file_contents) { fclose(fp); return NULL; } fread(file_contents, file_size, 1, fp); fclose(fp); file_contents[file_size] = '\0'; output_value = json_parse_string(file_contents); parson_free(file_contents); return output_value; } JSON_Value * json_parse_string(const char *string) { if (!string || (*string != '{' && *string != '[')) { return NULL; } return parse_value((const char**)&string, 0); } /* JSON Object API */ JSON_Value * json_object_get_value(const JSON_Object *object, const char *name) { return json_object_nget_value(object, name, strlen(name)); } const char * json_object_get_string(const JSON_Object *object, const char *name) { return json_value_get_string(json_object_get_value(object, name)); } double json_object_get_number(const JSON_Object *object, const char *name) { return json_value_get_number(json_object_get_value(object, name)); } JSON_Object * json_object_get_object(const JSON_Object *object, const char *name) { return json_value_get_object(json_object_get_value(object, name)); } JSON_Array * json_object_get_array(const JSON_Object *object, const char *name) { return json_value_get_array(json_object_get_value(object, name)); } int json_object_get_boolean(const JSON_Object *object, const char *name) { return json_value_get_boolean(json_object_get_value(object, name)); } JSON_Value * json_object_dotget_value(const JSON_Object *object, const char *name) { const char *dot_position = strchr(name, '.'); if (!dot_position) { return json_object_get_value(object, name); } object = json_value_get_object(json_object_nget_value(object, name, dot_position - name)); return json_object_dotget_value(object, dot_position + 1); } const char * json_object_dotget_string(const JSON_Object *object, const char *name) { return json_value_get_string(json_object_dotget_value(object, name)); } double json_object_dotget_number(const JSON_Object *object, const char *name) { return json_value_get_number(json_object_dotget_value(object, name)); } JSON_Object * json_object_dotget_object(const JSON_Object *object, const char *name) { return json_value_get_object(json_object_dotget_value(object, name)); } JSON_Array * json_object_dotget_array(const JSON_Object *object, const char *name) { return json_value_get_array(json_object_dotget_value(object, name)); } int json_object_dotget_boolean(const JSON_Object *object, const char *name) { return json_value_get_boolean(json_object_dotget_value(object, name)); } size_t json_object_get_count(const JSON_Object *object) { return object ? object->count : 0; } const char * json_object_get_name(const JSON_Object *object, size_t index) { if (index >= json_object_get_count(object)) { return NULL; } return object->names[index]; } /* JSON Array API */ JSON_Value * json_array_get_value(const JSON_Array *array, size_t index) { if (index >= json_array_get_count(array)) { return NULL; } return array->items[index]; } const char * json_array_get_string(const JSON_Array *array, size_t index) { return json_value_get_string(json_array_get_value(array, index)); } double json_array_get_number(const JSON_Array *array, size_t index) { return json_value_get_number(json_array_get_value(array, index)); } JSON_Object * json_array_get_object(const JSON_Array *array, size_t index) { return json_value_get_object(json_array_get_value(array, index)); } JSON_Array * json_array_get_array(const JSON_Array *array, size_t index) { return json_value_get_array(json_array_get_value(array, index)); } int json_array_get_boolean(const JSON_Array *array, size_t index) { return json_value_get_boolean(json_array_get_value(array, index)); } size_t json_array_get_count(const JSON_Array *array) { return array ? array->count : 0; } /* JSON Value API */ JSON_Value_Type json_value_get_type(const JSON_Value *value) { return value ? value->type : JSONError; } JSON_Object * json_value_get_object(const JSON_Value *value) { return json_value_get_type(value) == JSONObject ? value->value.object : NULL; } JSON_Array * json_value_get_array(const JSON_Value *value) { return json_value_get_type(value) == JSONArray ? value->value.array : NULL; } const char * json_value_get_string(const JSON_Value *value) { return json_value_get_type(value) == JSONString ? value->value.string : NULL; } double json_value_get_number(const JSON_Value *value) { return json_value_get_type(value) == JSONNumber ? value->value.number : 0; } int json_value_get_boolean(const JSON_Value *value) { return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1; } void json_value_free(JSON_Value *value) { switch (json_value_get_type(value)) { case JSONObject: json_object_free(value->value.object); break; case JSONString: if (value->value.string) { parson_free(value->value.string); } break; case JSONArray: json_array_free(value->value.array); break; default: break; } parson_free(value); } fdkaac-0.6.3/src/parson.h000066400000000000000000000104601276003472100151760ustar00rootroot00000000000000/* Parson ( http://kgabis.github.com/parson/ ) Copyright (c) 2012 Krzysztof Gabis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef parson_parson_h #define parson_parson_h #ifdef __cplusplus extern "C" { #endif #include /* size_t */ /* Types and enums */ typedef struct json_object_t JSON_Object; typedef struct json_array_t JSON_Array; typedef struct json_value_t JSON_Value; typedef enum json_value_type { JSONError = 0, JSONNull = 1, JSONString = 2, JSONNumber = 3, JSONObject = 4, JSONArray = 5, JSONBoolean = 6 } JSON_Value_Type; /* Parses first JSON value in a file, returns NULL in case of error */ JSON_Value * json_parse_file(const char *filename); /* Parses first JSON value in a string, returns NULL in case of error */ JSON_Value * json_parse_string(const char *string); /* JSON Object */ JSON_Value * json_object_get_value (const JSON_Object *object, const char *name); const char * json_object_get_string (const JSON_Object *object, const char *name); JSON_Object * json_object_get_object (const JSON_Object *object, const char *name); JSON_Array * json_object_get_array (const JSON_Object *object, const char *name); double json_object_get_number (const JSON_Object *object, const char *name); int json_object_get_boolean(const JSON_Object *object, const char *name); /* dotget functions enable addressing values with dot notation in nested objects, just like in structs or c++/java/c# objects (e.g. objectA.objectB.value). Because valid names in JSON can contain dots, some values may be inaccessible this way. */ JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name); const char * json_object_dotget_string (const JSON_Object *object, const char *name); JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name); JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name); double json_object_dotget_number (const JSON_Object *object, const char *name); int json_object_dotget_boolean(const JSON_Object *object, const char *name); /* Functions to get available names */ size_t json_object_get_count(const JSON_Object *object); const char * json_object_get_name (const JSON_Object *object, size_t index); /* JSON Array */ JSON_Value * json_array_get_value (const JSON_Array *array, size_t index); const char * json_array_get_string (const JSON_Array *array, size_t index); JSON_Object * json_array_get_object (const JSON_Array *array, size_t index); JSON_Array * json_array_get_array (const JSON_Array *array, size_t index); double json_array_get_number (const JSON_Array *array, size_t index); int json_array_get_boolean(const JSON_Array *array, size_t index); size_t json_array_get_count (const JSON_Array *array); /* JSON Value */ JSON_Value_Type json_value_get_type (const JSON_Value *value); JSON_Object * json_value_get_object (const JSON_Value *value); JSON_Array * json_value_get_array (const JSON_Value *value); const char * json_value_get_string (const JSON_Value *value); double json_value_get_number (const JSON_Value *value); int json_value_get_boolean(const JSON_Value *value); void json_value_free (JSON_Value *value); #ifdef __cplusplus } #endif #endif fdkaac-0.6.3/src/pcm_float_converter.c000066400000000000000000000043131276003472100177220ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #include #include #if HAVE_STDINT_H # include #endif #include "pcm_reader.h" typedef struct pcm_float_converter_t { pcm_reader_vtbl_t *vtbl; pcm_reader_t *src; pcm_sample_description_t format; } pcm_float_converter_t; static inline pcm_reader_t *get_source(pcm_reader_t *reader) { return ((pcm_float_converter_t *)reader)->src; } static const pcm_sample_description_t *get_format(pcm_reader_t *reader) { return &((pcm_float_converter_t *)reader)->format; } static int64_t get_length(pcm_reader_t *reader) { return pcm_get_length(get_source(reader)); } static int64_t get_position(pcm_reader_t *reader) { return pcm_get_position(get_source(reader)); } static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes) { pcm_float_converter_t *self = (pcm_float_converter_t *)reader; const pcm_sample_description_t *sfmt = pcm_get_format(self->src); nframes = pcm_read_frames(self->src, buffer, nframes); if (!(sfmt->sample_type & PCM_TYPE_FLOAT)) { int32_t *ip = buffer; float *op = buffer; unsigned i, count = nframes * sfmt->channels_per_frame; for (i = 0; i < count; ++i) op[i] = ip[i] / 2147483648.0f; } return nframes; } static void teardown(pcm_reader_t **reader) { pcm_float_converter_t *self = (pcm_float_converter_t *)*reader; pcm_teardown(&self->src); free(self); *reader = 0; } static pcm_reader_vtbl_t my_vtable = { get_format, get_length, get_position, read_frames, teardown }; pcm_reader_t *pcm_open_float_converter(pcm_reader_t *reader) { pcm_float_converter_t *self = 0; pcm_sample_description_t *fmt; if ((self = calloc(1, sizeof(pcm_float_converter_t))) == 0) return 0; self->src = reader; self->vtbl = &my_vtable; memcpy(&self->format, pcm_get_format(reader), sizeof(self->format)); fmt = &self->format; fmt->bits_per_channel = 32; fmt->sample_type = PCM_TYPE_FLOAT; fmt->bytes_per_frame = 4 * fmt->channels_per_frame; return (pcm_reader_t *)self; } fdkaac-0.6.3/src/pcm_native_converter.c000066400000000000000000000154571276003472100201160ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #include #include #if HAVE_STDINT_H # include #endif #include "m4af_endian.h" #include "pcm_reader.h" static inline float pcm_i2f(int32_t n) { union { int32_t ivalue; float fvalue; } u; u.ivalue = n; return u.fvalue; } static inline double pcm_i2d(int64_t n) { union { int64_t ivalue; double fvalue; } u; u.ivalue = n; return u.fvalue; } static inline int32_t pcm_s8_to_s32(int8_t n) { return n << 24; } static inline int32_t pcm_u8_to_s32(uint8_t n) { return (n << 24) ^ 0x80000000; } static inline int32_t pcm_s16le_to_s32(int16_t n) { return m4af_ltoh16(n) << 16; } static inline int32_t pcm_s16be_to_s32(int16_t n) { return m4af_btoh16(n) << 16; } static inline int32_t pcm_u16le_to_s32(uint16_t n) { return (m4af_ltoh16(n) << 16) ^ 0x80000000; } static inline int32_t pcm_u16be_to_s32(uint16_t n) { return (m4af_btoh16(n) << 16) ^ 0x80000000; } static inline int32_t pcm_s24le_to_s32(uint8_t *p) { return p[0]<<8 | p[1]<<16 | p[2]<<24; } static inline int32_t pcm_s24be_to_s32(uint8_t *p) { return p[0]<<24 | p[1]<<16 | p[2]<<8; } static inline int32_t pcm_u24le_to_s32(uint8_t *p) { return pcm_s24le_to_s32(p) ^ 0x80000000; } static inline int32_t pcm_u24be_to_s32(uint8_t *p) { return pcm_s24be_to_s32(p) ^ 0x80000000; } static inline int32_t pcm_s32le_to_s32(int32_t n) { return m4af_ltoh32(n); } static inline int32_t pcm_s32be_to_s32(int32_t n) { return m4af_btoh32(n); } static inline int32_t pcm_u32le_to_s32(int32_t n) { return m4af_ltoh32(n) ^ 0x80000000; } static inline int32_t pcm_u32be_to_s32(int32_t n) { return m4af_btoh32(n) ^ 0x80000000; } static inline float pcm_f32le_to_f32(int32_t n) { return pcm_i2f(m4af_ltoh32(n)); } static inline float pcm_f32be_to_f32(int32_t n) { return pcm_i2f(m4af_btoh32(n)); } static inline float pcm_f64le_to_f32(int64_t n) { return pcm_i2d(m4af_ltoh64(n)); } static inline float pcm_f64be_to_f32(int64_t n) { return pcm_i2d(m4af_btoh64(n)); } static int pcm_convert_to_native(const pcm_sample_description_t *format, const void *input, uint32_t nframes, void *result) { #define CONVERT(type, rtype, conv) \ do { \ unsigned i; \ type *ip = (type *)input; \ for (i = 0; i < count; ++i) { \ ((rtype *)result)[i] = conv(ip[i]); \ } \ } while(0) #define CONVERT_BYTES(rtype, conv) \ do { \ unsigned i, bytes_per_channel; \ uint8_t *ip = (uint8_t *)input; \ bytes_per_channel = PCM_BYTES_PER_CHANNEL(format); \ for (i = 0; i < count; ++i) { \ ((rtype *)result)[i] = conv(ip); \ ip += bytes_per_channel; \ } \ } while(0) uint32_t count = nframes * format->channels_per_frame; if (!count) return 0; switch (PCM_BYTES_PER_CHANNEL(format) | format->sample_type<<4) { case 1 | PCM_TYPE_SINT<<4: CONVERT(int8_t, int32_t, pcm_s8_to_s32); break; case 1 | PCM_TYPE_UINT<<4: CONVERT(uint8_t, int32_t, pcm_u8_to_s32); break; case 2 | PCM_TYPE_SINT<<4: CONVERT(int16_t, int32_t, pcm_s16le_to_s32); break; case 2 | PCM_TYPE_UINT<<4: CONVERT(uint16_t, int32_t, pcm_u16le_to_s32); break; case 2 | PCM_TYPE_SINT_BE<<4: CONVERT(int16_t, int32_t, pcm_s16be_to_s32); break; case 2 | PCM_TYPE_UINT_BE<<4: CONVERT(int16_t, int32_t, pcm_u16be_to_s32); break; case 3 | PCM_TYPE_SINT<<4: CONVERT_BYTES(int32_t, pcm_s24le_to_s32); break; case 3 | PCM_TYPE_UINT<<4: CONVERT_BYTES(int32_t, pcm_u24le_to_s32); break; case 3 | PCM_TYPE_SINT_BE<<4: CONVERT_BYTES(int32_t, pcm_s24be_to_s32); break; case 3 | PCM_TYPE_UINT_BE<<4: CONVERT_BYTES(int32_t, pcm_u24be_to_s32); break; case 4 | PCM_TYPE_SINT<<4: CONVERT(int32_t, int32_t, pcm_s32le_to_s32); break; case 4 | PCM_TYPE_UINT<<4: CONVERT(uint32_t, int32_t, pcm_u32le_to_s32); break; case 4 | PCM_TYPE_FLOAT<<4: CONVERT(int32_t, float, pcm_f32le_to_f32); break; case 4 | PCM_TYPE_SINT_BE<<4: CONVERT(int32_t, int32_t, pcm_s32be_to_s32); break; case 4 | PCM_TYPE_UINT_BE<<4: CONVERT(uint32_t, int32_t, pcm_u32be_to_s32); break; case 4 | PCM_TYPE_FLOAT_BE<<4: CONVERT(int32_t, float, pcm_f32be_to_f32); break; case 8 | PCM_TYPE_FLOAT<<4: CONVERT(int64_t, float, pcm_f64le_to_f32); break; case 8 | PCM_TYPE_FLOAT_BE<<4: CONVERT(int64_t, float, pcm_f64be_to_f32); break; default: return -1; } return 0; } typedef struct pcm_native_converter_t { pcm_reader_vtbl_t *vtbl; pcm_reader_t *src; pcm_sample_description_t format; void *pivot; unsigned capacity; } pcm_native_converter_t; static inline pcm_reader_t *get_source(pcm_reader_t *reader) { return ((pcm_native_converter_t *)reader)->src; } static const pcm_sample_description_t *get_format(pcm_reader_t *reader) { return &((pcm_native_converter_t *)reader)->format; } static int64_t get_length(pcm_reader_t *reader) { return pcm_get_length(get_source(reader)); } static int64_t get_position(pcm_reader_t *reader) { return pcm_get_position(get_source(reader)); } static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes) { pcm_native_converter_t *self = (pcm_native_converter_t *)reader; const pcm_sample_description_t *sfmt = pcm_get_format(self->src); unsigned bytes = nframes * sfmt->bytes_per_frame; if (self->capacity < bytes) { void *p = realloc(self->pivot, bytes); if (!p) return -1; self->pivot = p; self->capacity = bytes; } nframes = pcm_read_frames(self->src, self->pivot, nframes); if (pcm_convert_to_native(sfmt, self->pivot, nframes, buffer) < 0) return -1; return nframes; } static void teardown(pcm_reader_t **reader) { pcm_native_converter_t *self = (pcm_native_converter_t *)*reader; pcm_teardown(&self->src); free(self->pivot); free(self); *reader = 0; } static pcm_reader_vtbl_t my_vtable = { get_format, get_length, get_position, read_frames, teardown }; pcm_reader_t *pcm_open_native_converter(pcm_reader_t *reader) { pcm_native_converter_t *self = 0; pcm_sample_description_t *fmt; if ((self = calloc(1, sizeof(pcm_native_converter_t))) == 0) return 0; self->src = reader; self->vtbl = &my_vtable; memcpy(&self->format, pcm_get_format(reader), sizeof(self->format)); fmt = &self->format; fmt->sample_type = PCM_IS_FLOAT(fmt) ? PCM_TYPE_FLOAT : PCM_TYPE_SINT; fmt->bytes_per_frame = 4 * fmt->channels_per_frame; return (pcm_reader_t *)self; } fdkaac-0.6.3/src/pcm_reader.h000066400000000000000000000070121276003472100157740ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #ifndef PCM_READER_H #define PCM_READER_H #include "lpcm.h" #include "metadata.h" typedef struct pcm_reader_t pcm_reader_t; typedef struct pcm_reader_vtbl_t { const pcm_sample_description_t *(*get_format)(pcm_reader_t *); int64_t (*get_length)(pcm_reader_t *); int64_t (*get_position)(pcm_reader_t *); int (*read_frames)(pcm_reader_t *, void *, unsigned); void (*teardown)(pcm_reader_t **); } pcm_reader_vtbl_t; struct pcm_reader_t { pcm_reader_vtbl_t *vtbl; }; typedef int (*pcm_read_callback)(void *cookie, void *data, uint32_t count); typedef int (*pcm_seek_callback)(void *cookie, int64_t off, int whence); typedef int64_t (*pcm_tell_callback)(void *cookie); typedef struct pcm_io_vtbl_t { pcm_read_callback read; pcm_seek_callback seek; pcm_tell_callback tell; } pcm_io_vtbl_t; typedef struct pcm_io_context_t { pcm_io_vtbl_t *vtbl; void *cookie; } pcm_io_context_t; static inline const pcm_sample_description_t *pcm_get_format(pcm_reader_t *r) { return r->vtbl->get_format(r); } static inline int64_t pcm_get_length(pcm_reader_t *r) { return r->vtbl->get_length(r); } static inline int64_t pcm_get_position(pcm_reader_t *r) { return r->vtbl->get_position(r); } int pcm_read_frames(pcm_reader_t *r, void *data, unsigned nframes); static inline void pcm_teardown(pcm_reader_t **r) { (*r)->vtbl->teardown(r); } static inline uint32_t bitcount(uint32_t bits) { bits = (bits & 0x55555555) + (bits >> 1 & 0x55555555); bits = (bits & 0x33333333) + (bits >> 2 & 0x33333333); bits = (bits & 0x0f0f0f0f) + (bits >> 4 & 0x0f0f0f0f); bits = (bits & 0x00ff00ff) + (bits >> 8 & 0x00ff00ff); return (bits & 0x0000ffff) + (bits >>16 & 0x0000ffff); } #define TRY_IO(expr) \ do { \ if ((expr)) goto FAIL; \ } while (0) #define ENSURE(expr) \ do { \ if (!(expr)) goto FAIL;\ } while (0) int pcm_read(pcm_io_context_t *io, void *buffer, uint32_t size); int pcm_skip(pcm_io_context_t *io, int64_t count); static inline int pcm_seek(pcm_io_context_t *io, int64_t off, int whence) { return io->vtbl->seek ? io->vtbl->seek(io->cookie, off, whence) : -1; } static inline int64_t pcm_tell(pcm_io_context_t *io) { return io->vtbl->tell ? io->vtbl->tell(io->cookie) : -1; } int pcm_read16le(pcm_io_context_t *io, uint16_t *value); int pcm_read16be(pcm_io_context_t *io, uint16_t *value); int pcm_read32le(pcm_io_context_t *io, uint32_t *value); int pcm_read32be(pcm_io_context_t *io, uint32_t *value); int pcm_read64le(pcm_io_context_t *io, uint64_t *value); int pcm_read64be(pcm_io_context_t *io, uint64_t *value); int pcm_scanl(pcm_io_context_t *io, const char *fmt, ...); int pcm_scanb(pcm_io_context_t *io, const char *fmt, ...); int apple_chan_chunk(pcm_io_context_t *io, uint32_t chunk_size, pcm_sample_description_t *fmt, uint8_t *mapping); pcm_reader_t *wav_open(pcm_io_context_t *io, int ignore_length); pcm_reader_t *raw_open(pcm_io_context_t *io, const pcm_sample_description_t *desc); pcm_reader_t *caf_open(pcm_io_context_t *io, aacenc_tag_callback_t tag_callback, void *tag_ctx); pcm_reader_t *pcm_open_native_converter(pcm_reader_t *reader); pcm_reader_t *pcm_open_float_converter(pcm_reader_t *reader); pcm_reader_t *pcm_open_sint16_converter(pcm_reader_t *reader); pcm_reader_t *extrapolater_open(pcm_reader_t *reader); pcm_reader_t *limiter_open(pcm_reader_t *reader); #endif fdkaac-0.6.3/src/pcm_readhelper.c000066400000000000000000000263451276003472100166520ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #include #include #include #include #include "pcm_reader.h" #include "m4af_endian.h" #include "catypes.h" int pcm_read_frames(pcm_reader_t *r, void *data, unsigned nframes) { int n; unsigned count = 0; uint8_t *bp = data; unsigned bpf = pcm_get_format(r)->bytes_per_frame; do { n = r->vtbl->read_frames(r, bp, nframes - count); if (n > 0) { count += n; bp += n * bpf; } } while (n > 0 && count < nframes); return count; } int pcm_read(pcm_io_context_t *io, void *buffer, uint32_t size) { int rc; uint32_t count = 0; uint8_t *bp = buffer; do { rc = io->vtbl->read(io->cookie, bp, size - count); if (rc > 0) { count += rc; bp += rc; } } while (rc > 0 && count < size); return count > 0 ? count : rc; } int pcm_skip(pcm_io_context_t *io, int64_t count) { char buff[8192]; int rc; pcm_io_vtbl_t *vp = io->vtbl; if (count == 0 || pcm_seek(io, count, SEEK_CUR) >= 0) return 0; do { if ((rc = vp->read(io->cookie, buff, count > 8192 ? 8192 : count)) > 0) count -= rc; } while (rc > 0 && count > 0); return count == 0 ? 0 : -1; } int pcm_read16le(pcm_io_context_t *io, uint16_t *value) { if (pcm_read(io, value, 2) == 2) { *value = m4af_ltoh16(*value); return 0; } return -1; } int pcm_read16be(pcm_io_context_t *io, uint16_t *value) { if (pcm_read(io, value, 2) == 2) { *value = m4af_btoh16(*value); return 0; } return -1; } int pcm_read32le(pcm_io_context_t *io, uint32_t *value) { if (pcm_read(io, value, 4) == 4) { *value = m4af_ltoh32(*value); return 0; } return -1; } int pcm_read32be(pcm_io_context_t *io, uint32_t *value) { if (pcm_read(io, value, 4) == 4) { *value = m4af_btoh32(*value); return 0; } return -1; } int pcm_read64le(pcm_io_context_t *io, uint64_t *value) { if (pcm_read(io, value, 8) == 8) { *value = m4af_ltoh64(*value); return 0; } return -1; } int pcm_read64be(pcm_io_context_t *io, uint64_t *value) { if (pcm_read(io, value, 8) == 8) { *value = m4af_btoh64(*value); return 0; } return -1; } int pcm_scanl(pcm_io_context_t *io, const char *fmt, ...) { int c, count = 0; va_list ap; va_start(ap, fmt); while ((c = *fmt++)) { switch (c) { case 'S': TRY_IO(pcm_read16le(io, va_arg(ap, uint16_t*))); ++count; break; case 'L': TRY_IO(pcm_read32le(io, va_arg(ap, uint32_t*))); ++count; break; case 'Q': TRY_IO(pcm_read64le(io, va_arg(ap, uint64_t*))); ++count; break; } } FAIL: va_end(ap); return count; } int pcm_scanb(pcm_io_context_t *io, const char *fmt, ...) { int c, count = 0; va_list ap; va_start(ap, fmt); while ((c = *fmt++)) { switch (c) { case 'S': TRY_IO(pcm_read16be(io, va_arg(ap, uint16_t*))); ++count; break; case 'L': TRY_IO(pcm_read32be(io, va_arg(ap, uint32_t*))); ++count; break; case 'Q': TRY_IO(pcm_read64be(io, va_arg(ap, uint64_t*))); ++count; break; } } FAIL: va_end(ap); return count; } static int channel_compare(const void *a, const void *b) { return (*(const uint8_t **)a)[0] - (*(const uint8_t **)b)[0]; } void apple_translate_channel_labels(uint8_t *channels, unsigned n) { unsigned i; char *has_side = strpbrk((char*)channels, "\x0A\x0B"); for (i = 0; i < n; ++i) { switch (channels[i]) { case kAudioChannelLabel_LeftSurround: case kAudioChannelLabel_RightSurround: if (!has_side) channels[i] += 5; // map to SL/SR break; case kAudioChannelLabel_RearSurroundLeft: case kAudioChannelLabel_RearSurroundRight: if (!has_side) channels[i] -= 28; // map to BL/BR break; case kAudioChannelLabel_Mono: channels[i] = kAudioChannelLabel_Center; break; } } } int apple_chan_chunk(pcm_io_context_t *io, uint32_t chunk_size, pcm_sample_description_t *fmt, uint8_t *mapping) { /* * Although FDK encoder supports upto 5.1ch, we handle upto * 8 channels here. */ uint32_t i, mChannelLayoutTag, mChannelBitmap, mNumberChannelDescriptions; uint32_t mask = 0; const uint32_t nchannels = fmt->channels_per_frame; uint8_t channels[9] = { 0 }; uint8_t *index[8] = { 0 }; const char *layout = 0; ENSURE(chunk_size >= 12); TRY_IO(pcm_scanb(io, "LLL", &mChannelLayoutTag, &mChannelBitmap, &mNumberChannelDescriptions) != 3); switch (mChannelLayoutTag) { case kAudioChannelLayoutTag_UseChannelBitmap: ENSURE(bitcount(mChannelBitmap) == nchannels); TRY_IO(pcm_skip(io, chunk_size - 12)); fmt->channel_mask = mChannelBitmap; for (i = 0; i < nchannels; ++i) mapping[i] = i; return 0; case kAudioChannelLayoutTag_UseChannelDescriptions: ENSURE(mNumberChannelDescriptions == nchannels); ENSURE(chunk_size >= 12 + nchannels * 20); for (i = 0; i < mNumberChannelDescriptions; ++i) { uint32_t mChannelLabel; TRY_IO(pcm_read32be(io, &mChannelLabel)); ENSURE(mChannelLabel && mChannelLabel <= 0xff); channels[i] = mChannelLabel; TRY_IO(pcm_skip(io, 16)); } TRY_IO(pcm_skip(io, chunk_size - 12 - nchannels * 20)); apple_translate_channel_labels(channels, nchannels); for (i = 0; i < nchannels; ++i) if (channels[i] > kAudioChannelLabel_TopBackLeft) goto FAIL; break; default: ENSURE((mChannelLayoutTag & 0xffff) == nchannels); TRY_IO(pcm_skip(io, chunk_size - 12)); switch (mChannelLayoutTag) { /* 1ch */ case kAudioChannelLayoutTag_Mono: layout = "\x03"; break; /* 1.1ch */ case kAudioChannelLayoutTag_AC3_1_0_1: layout = "\x03\x04"; break; /* 2ch */ case kAudioChannelLayoutTag_Stereo: case kAudioChannelLayoutTag_MatrixStereo: case kAudioChannelLayoutTag_Binaural: layout = "\x01\x02"; break; /* 2.1ch */ case kAudioChannelLayoutTag_DVD_4: layout = "\x01\x02\x04"; break; /* 3ch */ case kAudioChannelLayoutTag_MPEG_3_0_A: layout = "\x01\x02\x03"; break; case kAudioChannelLayoutTag_AC3_3_0: layout = "\x01\x03\x02"; break; case kAudioChannelLayoutTag_MPEG_3_0_B: layout = "\x03\x01\x02"; break; case kAudioChannelLayoutTag_ITU_2_1: layout = "\x01\x02\x09"; break; /* 3.1ch */ case kAudioChannelLayoutTag_DVD_10: layout = "\x01\x02\x03\x04"; break; case kAudioChannelLayoutTag_AC3_3_0_1: layout = "\x01\x03\x02\x04"; break; case kAudioChannelLayoutTag_DVD_5: layout = "\x01\x02\x04\x09"; break; case kAudioChannelLayoutTag_AC3_2_1_1: layout = "\x01\x02\x09\x04"; break; /* 4ch */ case kAudioChannelLayoutTag_Quadraphonic: case kAudioChannelLayoutTag_ITU_2_2: layout = "\x01\x02\x0A\x0B"; break; case kAudioChannelLayoutTag_MPEG_4_0_A: layout = "\x01\x02\x03\x09"; break; case kAudioChannelLayoutTag_MPEG_4_0_B: layout = "\x03\x01\x02\x09"; break; case kAudioChannelLayoutTag_AC3_3_1: layout = "\x01\x03\x02\x09"; break; /* 4.1ch */ case kAudioChannelLayoutTag_DVD_6: layout = "\x01\x02\x04\x0A\x0B"; break; case kAudioChannelLayoutTag_DVD_18: layout = "\x01\x02\x0A\x0B\x04"; break; case kAudioChannelLayoutTag_DVD_11: layout = "\x01\x02\x03\x04\x09"; break; case kAudioChannelLayoutTag_AC3_3_1_1: layout = "\x01\x03\x02\x09\x04"; break; /* 5ch */ case kAudioChannelLayoutTag_MPEG_5_0_A: layout = "\x01\x02\x03\x0A\x0B"; break; case kAudioChannelLayoutTag_Pentagonal: case kAudioChannelLayoutTag_MPEG_5_0_B: layout = "\x01\x02\x0A\x0B\x03"; break; case kAudioChannelLayoutTag_MPEG_5_0_C: layout = "\x01\x03\x02\x0A\x0B"; break; case kAudioChannelLayoutTag_MPEG_5_0_D: layout = "\x03\x01\x02\x0A\x0B"; break; /* 5.1ch */ case kAudioChannelLayoutTag_MPEG_5_1_A: layout = "\x01\x02\x03\x04\x0A\x0B"; break; case kAudioChannelLayoutTag_MPEG_5_1_B: layout = "\x01\x02\x0A\x0B\x03\x04"; break; case kAudioChannelLayoutTag_MPEG_5_1_C: layout = "\x01\x03\x02\x0A\x0B\x04"; break; case kAudioChannelLayoutTag_MPEG_5_1_D: layout = "\x03\x01\x02\x0A\x0B\x04"; break; /* 6ch */ case kAudioChannelLayoutTag_Hexagonal: case kAudioChannelLayoutTag_AudioUnit_6_0: layout = "\x01\x02\x0A\x0B\x03\x09"; break; case kAudioChannelLayoutTag_AAC_6_0: layout = "\x03\x01\x02\x0A\x0B\x09"; break; /* 6.1ch */ case kAudioChannelLayoutTag_MPEG_6_1_A: layout = "\x01\x02\x03\x04\x0A\x0B\x09"; break; case kAudioChannelLayoutTag_AAC_6_1: layout = "\x03\x01\x02\x0A\x0B\x09\x04"; break; /* 7ch */ case kAudioChannelLayoutTag_AudioUnit_7_0: layout = "\x01\x02\x0A\x0B\x03\x05\x06"; break; case kAudioChannelLayoutTag_AudioUnit_7_0_Front: layout = "\x01\x02\x0A\x0B\x03\x07\x08"; break; case kAudioChannelLayoutTag_AAC_7_0: layout = "\x03\x01\x02\x0A\x0B\x05\x06"; break; /* 7.1ch */ case kAudioChannelLayoutTag_MPEG_7_1_A: layout = "\x01\x02\x03\x04\x0A\x0B\x07\x08"; break; case kAudioChannelLayoutTag_MPEG_7_1_B: layout = "\x03\x07\x08\x01\x02\x05\x06\x04"; break; case kAudioChannelLayoutTag_MPEG_7_1_C: layout = "\x01\x02\x03\x04\x0A\x0B\x05\x06"; break; case kAudioChannelLayoutTag_Emagic_Default_7_1: layout = "\x01\x02\x0A\x0B\x03\x04\x07\x08"; break; /* 8ch */ case kAudioChannelLayoutTag_Octagonal: layout = "\x01\x02\x05\x06\x03\x09\x0A\x0B"; break; case kAudioChannelLayoutTag_AAC_Octagonal: layout = "\x03\x01\x02\x0A\x0B\x05\x06\x09"; break; default: goto FAIL; } strcpy((char*)channels, layout); } for (i = 0; i < nchannels; ++i) mask |= 1 << (channels[i] - 1); fmt->channel_mask = mask; ENSURE(bitcount(mask) == nchannels); for (i = 0; i < nchannels; ++i) index[i] = channels + i; qsort(index, nchannels, sizeof(char*), channel_compare); for (i = 0; i < nchannels; ++i) mapping[i] = index[i] - channels; return 0; FAIL: return -1; } fdkaac-0.6.3/src/pcm_sint16_converter.c000066400000000000000000000056121276003472100177440ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #include #include #if HAVE_STDINT_H # include #endif #include "pcm_reader.h" typedef struct pcm_sint16_converter_t { pcm_reader_vtbl_t *vtbl; pcm_reader_t *src; pcm_sample_description_t format; void *pivot; unsigned capacity; } pcm_sint16_converter_t; static inline pcm_reader_t *get_source(pcm_reader_t *reader) { return ((pcm_sint16_converter_t *)reader)->src; } static const pcm_sample_description_t *get_format(pcm_reader_t *reader) { return &((pcm_sint16_converter_t *)reader)->format; } static int64_t get_length(pcm_reader_t *reader) { return pcm_get_length(get_source(reader)); } static int64_t get_position(pcm_reader_t *reader) { return pcm_get_position(get_source(reader)); } static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes) { unsigned i, count; pcm_sint16_converter_t *self = (pcm_sint16_converter_t *)reader; const pcm_sample_description_t *sfmt = pcm_get_format(self->src); unsigned bytes = nframes * sfmt->bytes_per_frame; if (self->capacity < bytes) { void *p = realloc(self->pivot, bytes); if (!p) return -1; self->pivot = p; self->capacity = bytes; } nframes = pcm_read_frames(self->src, self->pivot, nframes); count = nframes * sfmt->channels_per_frame; if (PCM_IS_FLOAT(sfmt)) { float *ip = self->pivot; int16_t *op = buffer; for (i = 0; i < count; ++i) op[i] = pcm_clip(ip[i] * 32768.0, -32768.0, 32767.0); } else { int32_t *ip = self->pivot; int16_t *op = buffer; if (sfmt->bits_per_channel <= 16) { for (i = 0; i < count; ++i) op[i] = ip[i] >> 16; } else { for (i = 0; i < count; ++i) { int n = ((ip[i] >> 15) + 1) >> 1; op[i] = (n == 0x8000) ? 0x7fff : n; } } } return nframes; } static void teardown(pcm_reader_t **reader) { pcm_sint16_converter_t *self = (pcm_sint16_converter_t *)*reader; pcm_teardown(&self->src); free(self->pivot); free(self); *reader = 0; } static pcm_reader_vtbl_t my_vtable = { get_format, get_length, get_position, read_frames, teardown }; pcm_reader_t *pcm_open_sint16_converter(pcm_reader_t *reader) { pcm_sint16_converter_t *self = 0; pcm_sample_description_t *fmt; if ((self = calloc(1, sizeof(pcm_sint16_converter_t))) == 0) return 0; self->src = reader; self->vtbl = &my_vtable; memcpy(&self->format, pcm_get_format(reader), sizeof(self->format)); fmt = &self->format; fmt->bits_per_channel = 16; fmt->sample_type = PCM_TYPE_SINT; fmt->bytes_per_frame = 2 * fmt->channels_per_frame; return (pcm_reader_t *)self; } fdkaac-0.6.3/src/progress.c000066400000000000000000000053731276003472100155420ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #if HAVE_STDINT_H # include #endif #if HAVE_INTTYPES_H # include #elif defined _MSC_VER # define PRId64 "I64d" #endif #include "compat.h" #include "progress.h" static void seconds_to_hms(double seconds, int *h, int *m, int *s, int *millis) { *h = (int)(seconds / 3600.0); seconds -= *h * 3600; *m = (int)(seconds / 60.0); seconds -= *m * 60; *s = (int)seconds; *millis = (int)((seconds - *s) * 1000.0 + 0.5); } static void print_seconds(FILE *fp, double seconds) { int h, m, s, millis; seconds_to_hms(seconds, &h, &m, &s, &millis); if (h) fprintf(stderr, "%d:%02d:%02d.%03d", h, m, s, millis); else fprintf(stderr, "%02d:%02d.%03d", m, s, millis); } void aacenc_progress_init(aacenc_progress_t *progress, int64_t total, int32_t timescale) { progress->start = aacenc_timer(); progress->timescale = timescale; progress->total = total; } void aacenc_progress_update(aacenc_progress_t *progress, int64_t current, int period) { double seconds = current / progress->timescale; double ellapsed = (aacenc_timer() - progress->start) / 1000.0; double speed = ellapsed ? seconds / ellapsed : 1.0; int percent = progress->total ? 100.0 * current / progress->total + .5 : 100; double eta = current ? ellapsed * (progress->total / (double)current - 1.0) : progress->total ? DBL_MAX : 0; if (current < progress->processed + period) return; if (progress->total == INT64_MAX) { putc('\r', stderr); print_seconds(stderr, seconds); fprintf(stderr, " (%.0fx) ", speed); } else { fprintf(stderr, "\r[%d%%] ", percent); print_seconds(stderr, seconds); putc('/', stderr); print_seconds(stderr, progress->total / progress->timescale); fprintf(stderr, " (%.0fx), ETA ", speed); print_seconds(stderr, eta); fputs(" ", stderr); } progress->processed = current; } void aacenc_progress_finish(aacenc_progress_t *progress, int64_t current) { double ellapsed = (aacenc_timer() - progress->start) / 1000.0; aacenc_progress_update(progress, current, 0); if (progress->total == INT64_MAX) fprintf(stderr, "\n%" PRId64 " samples processed in ", current); else fprintf(stderr, "\n%" PRId64 "/%" PRId64 " samples processed in ", current, progress->total); print_seconds(stderr, ellapsed); putc('\n', stderr); } fdkaac-0.6.3/src/progress.h000066400000000000000000000011331276003472100155350ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #ifndef PROGRESS_H #define PROGRESS_H typedef struct aacenc_progress_t { double start; double timescale; int64_t total; int64_t processed; } aacenc_progress_t; void aacenc_progress_init(aacenc_progress_t *progress, int64_t total, int32_t timescale); void aacenc_progress_update(aacenc_progress_t *progress, int64_t current, int period); void aacenc_progress_finish(aacenc_progress_t *progress, int64_t current); #endif fdkaac-0.6.3/src/wav_reader.c000066400000000000000000000164211276003472100160110ustar00rootroot00000000000000/* * Copyright (C) 2013 nu774 * For conditions of distribution and use, see copyright notice in COPYING */ #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_STDINT_H # include #endif #include #include #include #include #include "pcm_reader.h" #define RIFF_FOURCC(a,b,c,d) ((a)|((b)<<8)|((c)<<16)|((d)<<24)) typedef struct wav_reader_t { pcm_reader_vtbl_t *vtbl; pcm_sample_description_t sample_format; int64_t length; int64_t position; int32_t data_offset; int ignore_length; pcm_io_context_t io; } wav_reader_t; static const uint8_t WAV_GUID_PCM[] = { 1, 0, 0, 0, 0, 0, 0x10, 0, 0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71 }; static const uint8_t WAV_GUID_FLOAT[] = { 3, 0, 0, 0, 0, 0, 0x10, 0, 0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71 }; static const pcm_sample_description_t *wav_get_format(pcm_reader_t *reader) { return &((wav_reader_t *)reader)->sample_format; } static int64_t wav_get_length(pcm_reader_t *reader) { return ((wav_reader_t *)reader)->length; } static int64_t wav_get_position(pcm_reader_t *reader) { return ((wav_reader_t *)reader)->position; } static void wav_teardown(pcm_reader_t **reader) { free(*reader); *reader = 0; } static uint32_t riff_next_chunk(wav_reader_t *reader, uint32_t *chunk_size) { uint32_t fcc; return (pcm_scanl(&reader->io, "LL", &fcc, chunk_size) == 2) ? fcc : 0; } static int wav_read_frames(pcm_reader_t *preader, void *buffer, unsigned nframes) { int rc; unsigned nbytes; wav_reader_t *reader = (wav_reader_t *)preader; if (!reader->ignore_length && nframes > reader->length - reader->position) nframes = reader->length - reader->position; nbytes = nframes * reader->sample_format.bytes_per_frame; if (nbytes) { if ((rc = pcm_read(&reader->io, buffer, nbytes)) < 0) return -1; nframes = rc / reader->sample_format.bytes_per_frame; reader->position += nframes; } return nframes; } static int riff_ds64(wav_reader_t *reader, int64_t *length) { uint32_t fcc, chunk_size, table_size; uint64_t riff_size, sample_count; fcc = riff_next_chunk(reader, &chunk_size); ENSURE(fcc == RIFF_FOURCC('d','s','6','4') && chunk_size >= 28); TRY_IO(pcm_scanl(&reader->io, "QQQL", &riff_size, length, &sample_count, &table_size) != 4); TRY_IO(pcm_skip(&reader->io, (chunk_size - 27) & ~1)); FAIL: return -1; } static int wav_fmt(wav_reader_t *reader, uint32_t size) { uint16_t wFormatTag, nChannels, nBlockAlign, wBitsPerSample, cbSize; uint32_t nSamplesPerSec, nAvgBytesPerSec, dwChannelMask = 0; uint16_t wValidBitsPerSample; uint8_t guid[16]; int is_float = 0; ENSURE(size >= 16); TRY_IO(pcm_scanl(&reader->io, "SSLLSS", &wFormatTag, &nChannels, &nSamplesPerSec, &nAvgBytesPerSec, &nBlockAlign, &wBitsPerSample) != 6); wValidBitsPerSample = wBitsPerSample; ENSURE(wFormatTag == 1 || wFormatTag == 3 || wFormatTag == 0xfffe); ENSURE(nChannels && nSamplesPerSec && nAvgBytesPerSec && nBlockAlign && wBitsPerSample && !(wBitsPerSample & 7) && nBlockAlign == nChannels * wBitsPerSample / 8); if (wFormatTag == 3) is_float = 1; if (wFormatTag != 0xfffe) TRY_IO(pcm_skip(&reader->io, (size - 15) & ~1)); else { ENSURE(size >= 40); TRY_IO(pcm_scanl(&reader->io, "SSL", &cbSize, &wValidBitsPerSample, &dwChannelMask) != 3); TRY_IO(pcm_read(&reader->io, guid, 16) != 16); if (memcmp(guid, WAV_GUID_FLOAT, 16) == 0) is_float = 1; else if (memcmp(guid, WAV_GUID_PCM, 16) != 0) goto FAIL; ENSURE(wValidBitsPerSample && wValidBitsPerSample <= wBitsPerSample); TRY_IO(pcm_skip(&reader->io, (size - 39) & ~1)); } reader->sample_format.sample_rate = nSamplesPerSec; reader->sample_format.bits_per_channel = wValidBitsPerSample; reader->sample_format.bytes_per_frame = nBlockAlign; reader->sample_format.channels_per_frame = nChannels; reader->sample_format.channel_mask = dwChannelMask; if (is_float) reader->sample_format.sample_type = PCM_TYPE_FLOAT; else if (wBitsPerSample == 8) reader->sample_format.sample_type = PCM_TYPE_UINT; else reader->sample_format.sample_type = PCM_TYPE_SINT; return 0; FAIL: return -1; } static int wav_parse(wav_reader_t *reader, int64_t *data_length) { uint32_t container, fcc, chunk_size; *data_length = 0; container = riff_next_chunk(reader, &chunk_size); ENSURE(container == RIFF_FOURCC('R','I','F','F') || container == RIFF_FOURCC('R','F','6','4')); TRY_IO(pcm_read32le(&reader->io, &fcc)); ENSURE(fcc == RIFF_FOURCC('W','A','V','E')); if (container == RIFF_FOURCC('R','F','6','4')) riff_ds64(reader, data_length); while ((fcc = riff_next_chunk(reader, &chunk_size)) != 0) { if (fcc == RIFF_FOURCC('f','m','t',' ')) { if (wav_fmt(reader, chunk_size) < 0) goto FAIL; } else if (fcc == RIFF_FOURCC('d','a','t','a')) { if (container == RIFF_FOURCC('R','I','F','F')) *data_length = chunk_size; reader->data_offset = pcm_tell(&reader->io); break; } else { TRY_IO(pcm_skip(&reader->io, (chunk_size + 1) & ~1)); } } if (fcc == RIFF_FOURCC('d','a','t','a')) return 0; FAIL: return -1; } static pcm_reader_vtbl_t wav_vtable = { wav_get_format, wav_get_length, wav_get_position, wav_read_frames, wav_teardown }; pcm_reader_t *wav_open(pcm_io_context_t *io, int ignore_length) { wav_reader_t *reader = 0; int64_t data_length; unsigned bpf; if ((reader = calloc(1, sizeof(wav_reader_t))) == 0) return 0; memcpy(&reader->io, io, sizeof(pcm_io_context_t)); reader->ignore_length = ignore_length; if (wav_parse(reader, &data_length) < 0) { free(reader); return 0; } bpf = reader->sample_format.bytes_per_frame; if (ignore_length || !data_length || data_length % bpf) reader->length = INT64_MAX; else reader->length = data_length / bpf; if (reader->length == INT64_MAX) { if (pcm_seek(&reader->io, 0, SEEK_END) >= 0) { int64_t size = pcm_tell(&reader->io); if (size > 0) reader->length = (size - reader->data_offset) / bpf; pcm_seek(&reader->io, reader->data_offset, SEEK_SET); } } reader->vtbl = &wav_vtable; return (pcm_reader_t *)reader; } pcm_reader_t *raw_open(pcm_io_context_t *io, const pcm_sample_description_t *desc) { wav_reader_t *reader = 0; if ((reader = calloc(1, sizeof(wav_reader_t))) == 0) return 0; memcpy(&reader->io, io, sizeof(pcm_io_context_t)); memcpy(&reader->sample_format, desc, sizeof(pcm_sample_description_t)); if (pcm_seek(&reader->io, 0, SEEK_END) >= 0) { int64_t size = pcm_tell(&reader->io); if (size > 0) reader->length = size / reader->sample_format.bytes_per_frame; pcm_seek(&reader->io, 0, SEEK_SET); } else reader->length = INT64_MAX; reader->vtbl = &wav_vtable; return (pcm_reader_t *)reader; } fdkaac-0.6.3/version.h000066400000000000000000000001211276003472100145630ustar00rootroot00000000000000#ifndef VERSION_H #define VERSION_H const char *fdkaac_version = "0.6.3"; #endif