diff options
49 files changed, 3908 insertions, 76 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8dcc4e4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,215 @@ +name: CI +on: [push, pull_request] + +jobs: + linux-autotools: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build + run: | + ./autogen.sh + ./configure --enable-example + make -j$(nproc) CFLAGS="-g -O2 -Werror" CXXFLAGS="-g -O2 -Werror" + - name: Run tests + run: | + sudo apt-get install --no-install-recommends ffmpeg + ./test/run-test.sh + + linux-cmake: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build + run: | + cmake . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_PROGRAMS=YES -DCMAKE_C_FLAGS="-Werror" -DCMAKE_CXX_FLAGS="-Werror -Wno-stringop-overflow" + cmake --build build + - name: Run tests + run: | + sudo apt-get install --no-install-recommends ffmpeg + cd build + ../test/run-test.sh + + linux-sanitizers-gcc-autotools: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build + run: | + ./autogen.sh + FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize=shift-base -DDEBUG -fno-sanitize-recover=all" + CC="gcc $FLAGS" CXX="g++ $FLAGS" ./configure --enable-example + make -j$(nproc) + - name: Run tests + run: | + sudo apt-get install --no-install-recommends ffmpeg + ./test/run-test.sh + + linux-sanitizers-clang-cmake: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build + run: | + FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize=shift-base -DDEBUG -fno-sanitize-recover=all -fno-sanitize=vptr -fno-sanitize=function" + cmake . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_PROGRAMS=YES -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS="$FLAGS" -DCMAKE_CXX_FLAGS="$FLAGS" + cmake --build build + - name: Run tests + run: | + sudo apt-get install --no-install-recommends ffmpeg + cd build + ../test/run-test.sh + + macos-autotools: + runs-on: macos-latest + steps: + - name: Install autotools + run: | + brew install automake + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build + run: | + ./autogen.sh + ./configure --enable-example + make -j$(sysctl -n hw.ncpu) CFLAGS="-g -O2 -Werror" CXXFLAGS="-g -O2 -Werror -Wno-deprecated-declarations" + + macos-cmake: + runs-on: macos-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build + run: | + cmake . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_PROGRAMS=YES -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -DCMAKE_C_FLAGS="-Werror" -DCMAKE_CXX_FLAGS="-Werror -Wno-deprecated-declarations" + cmake --build build + + mingw-cross-autotools: + runs-on: ubuntu-latest + steps: + - name: Install cross compiler + run: | + sudo apt-get install g++-mingw-w64-x86-64 + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build + run: | + ./autogen.sh + ./configure --enable-example --host=x86_64-w64-mingw32 + make -j$(nproc) CFLAGS="-g -O2 -Werror" CXXFLAGS="-g -O2 -Werror" + + mingw-cross-cmake: + runs-on: ubuntu-latest + steps: + - name: Install cross compiler + run: | + sudo apt-get install g++-mingw-w64-x86-64 + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build + run: | + cmake . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_PROGRAMS=YES -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ -DCMAKE_CROSSCOMPILING=TRUE -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_C_FLAGS="-Werror" -DCMAKE_CXX_FLAGS="-Werror -Wno-stringop-overflow" + cmake --build build + + msys-cmake: + runs-on: windows-latest + defaults: + run: + shell: msys2 {0} + steps: + - uses: msys2/setup-msys2@v2 + with: + msystem: mingw64 + update: true + install: >- + git + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-cmake + mingw-w64-x86_64-ninja + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build + run: | + cmake . -G Ninja -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_PROGRAMS=YES + cmake --build build + + msvc-cmake: + runs-on: windows-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build + run: | + cmake . -B build -DBUILD_PROGRAMS=YES + cmake --build build --config Release + + msvc-cmake-ninja-arm: + runs-on: windows-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Set up the environment + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64_arm + - name: Build + run: | + cmake . -G Ninja -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_PROGRAMS=YES + cmake --build build + + msvc-cmake-arm64: + runs-on: windows-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build + run: | + cmake . -B build -DBUILD_PROGRAMS=YES -A ARM64 + cmake --build build --config Release + + llvm-mingw: + runs-on: ubuntu-latest + steps: + - name: Install llvm-mingw + run: | + wget https://github.com/mstorsjo/llvm-mingw/releases/download/20231003/llvm-mingw-20231003-ucrt-ubuntu-20.04-x86_64.tar.xz + tar -Jxvf llvm-mingw-*-ucrt-ubuntu-*-x86_64.tar.xz + rm llvm-mingw-*.tar.xz + sudo mv llvm-mingw-* /opt/llvm-mingw + echo /opt/llvm-mingw/bin >> $GITHUB_PATH + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build fdk-aac + run: | + ./autogen.sh + ./configure --host=aarch64-w64-mingw32 --enable-example + make -j$(nproc) CFLAGS="-g -O2 -Werror" CXXFLAGS="-g -O2 -Werror" + + linux-ffmpeg: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Build fdk-aac + run: | + ./autogen.sh + mkdir build + cd build + ../configure --enable-example --prefix=$(pwd)/../prefix + make -j$(nproc) + make -j$(nproc) install + - name: Checkout FFmpeg + uses: actions/checkout@v4 + with: + repository: ffmpeg/ffmpeg + path: ffmpeg + - name: Build FFmpeg + run: | + sudo apt-get install -y nasm + cd ffmpeg + PKG_CONFIG_PATH=$(pwd)/../prefix/lib/pkgconfig ./configure --enable-libfdk-aac --enable-nonfree + make -j$(nproc) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..da516d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +*.o +*.lo +*.la +.deps +.libs +.dirstamp +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +configure +fdk-aac.pc +config.guess +config.log +config.status +config.sub +depcomp +install-sh +libtool +ltmain.sh +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +missing +stamp-h1 +aac-enc +compile + +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +CMakeSettings.json + +*[Bb]uild*/ + +.vs/ +.vscode/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..35d8d98 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,600 @@ +# # CMake project for fdk-aac +# +# ## Basic usage +# +# 1. Download and install CMake >= 3.10 (CMake >= 3.15 is recommended) +# 2. Clone fdk-aac repository +# 3. In fdk-aac directory create and go to `build` subdirectory: +# +# mkdir build +# cd build +# +# 4. Run cmake to configure project with desired build type (Release|Debug): +# +# cmake .. -DCMAKE_BUILD_TYPE=Release +# +# Note CMake configuration without CMAKE_BUILD_TYPE option will not set build +# type to some default and it is most likely is not what you want. +# +# If you want to build static (default is shared library), add BUILD_SHARED_LIBS=OFF option: +# +# # cmake .. -DBUILD_SHARED_LIBS=OFF +# +# You can combine options as well: +# +# cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF +# +# 5. Run cmake to build project: +# +# cmake --build . -c Release + +cmake_minimum_required(VERSION 3.5.1) + +# Policies + +## Enables CMAKE_MSVC_RUNTIME_LIBRARY option support for CMake >= 3.15 +## if you want to use a MSVC multi-threaded statically-linked runtime library +## If you enable it, CMake will build fdk-acc.dll without external dependencies. +## +## Example usage: +## +## cmake .. -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded$<$<CONFIG:Debug>:Debug> +if(POLICY CMP0091) + cmake_policy(SET CMP0091 NEW) +endif() + +project(fdk-aac VERSION 2.0.2) + +# Includes + +include(CheckFunctionExists) +include(CheckLibraryExists) +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +if(CMAKE_VERSION VERSION_LESS 3.11) + set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) + set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) + set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) +endif() +include(CPack) + +# Options + +option(BUILD_SHARED_LIBS "Build shared library" ON) +option(BUILD_PROGRAMS "Build aac-enc utility" OFF) +option(FDK_AAC_INSTALL_CMAKE_CONFIG_MODULE "Install CMake package configuration file" ON) +option(FDK_AAC_INSTALL_PKGCONFIG_MODULE "Install pkg-config .pc file" ON) + +# Checks + +## Check if math functions are in separate library (Most of Linux distros, maybe some other OSes) +check_function_exists(sin HAVE_DEFAULT_MATH) +if(NOT HAVE_DEFAULT_MATH) + check_library_exists(m sin "" HAVE_LIBM) +endif() + +# Library + +## Sources + +set(AACDEC_SRC + libAACdec/src/FDK_delay.cpp + libAACdec/src/aac_ram.cpp + libAACdec/src/aac_rom.cpp + libAACdec/src/aacdec_drc.cpp + libAACdec/src/aacdec_hcr.cpp + libAACdec/src/aacdec_hcr_bit.cpp + libAACdec/src/aacdec_hcrs.cpp + libAACdec/src/aacdec_pns.cpp + libAACdec/src/aacdec_tns.cpp + libAACdec/src/aacdecoder.cpp + libAACdec/src/aacdecoder_lib.cpp + libAACdec/src/block.cpp + libAACdec/src/channel.cpp + libAACdec/src/channelinfo.cpp + libAACdec/src/conceal.cpp + libAACdec/src/ldfiltbank.cpp + libAACdec/src/pulsedata.cpp + libAACdec/src/rvlc.cpp + libAACdec/src/rvlcbit.cpp + libAACdec/src/rvlcconceal.cpp + libAACdec/src/stereo.cpp + libAACdec/src/usacdec_ace_d4t64.cpp + libAACdec/src/usacdec_ace_ltp.cpp + libAACdec/src/usacdec_acelp.cpp + libAACdec/src/usacdec_fac.cpp + libAACdec/src/usacdec_lpc.cpp + libAACdec/src/usacdec_lpd.cpp + libAACdec/src/usacdec_rom.cpp + libAACdec/src/aac_ram.h + libAACdec/src/aac_rom.h + libAACdec/src/aacdec_drc.h + libAACdec/src/aacdec_drc_types.h + libAACdec/src/aacdec_hcr.h + libAACdec/src/aacdec_hcr_bit.h + libAACdec/src/aacdec_hcr_types.h + libAACdec/src/aacdec_hcrs.h + libAACdec/src/aacdec_pns.h + libAACdec/src/aacdec_tns.h + libAACdec/src/aacdecoder.h + libAACdec/src/block.h + libAACdec/src/channel.h + libAACdec/src/channelinfo.h + libAACdec/src/conceal.h + libAACdec/src/conceal_types.h + libAACdec/src/FDK_delay.h + libAACdec/src/ldfiltbank.h + libAACdec/src/overlapadd.h + libAACdec/src/pulsedata.h + libAACdec/src/rvlc.h + libAACdec/src/rvlc_info.h + libAACdec/src/rvlcbit.h + libAACdec/src/rvlcconceal.h + libAACdec/src/stereo.h + libAACdec/src/usacdec_ace_d4t64.h + libAACdec/src/usacdec_ace_ltp.h + libAACdec/src/usacdec_acelp.h + libAACdec/src/usacdec_const.h + libAACdec/src/usacdec_fac.h + libAACdec/src/usacdec_lpc.h + libAACdec/src/usacdec_lpd.h + libAACdec/src/usacdec_rom.h) + +set(AACENC_SRC + libAACenc/src/aacEnc_ram.cpp + libAACenc/src/aacEnc_rom.cpp + libAACenc/src/aacenc.cpp + libAACenc/src/aacenc_lib.cpp + libAACenc/src/aacenc_pns.cpp + libAACenc/src/aacenc_tns.cpp + libAACenc/src/adj_thr.cpp + libAACenc/src/band_nrg.cpp + libAACenc/src/bandwidth.cpp + libAACenc/src/bit_cnt.cpp + libAACenc/src/bitenc.cpp + libAACenc/src/block_switch.cpp + libAACenc/src/channel_map.cpp + libAACenc/src/chaosmeasure.cpp + libAACenc/src/dyn_bits.cpp + libAACenc/src/grp_data.cpp + libAACenc/src/intensity.cpp + libAACenc/src/line_pe.cpp + libAACenc/src/metadata_compressor.cpp + libAACenc/src/metadata_main.cpp + libAACenc/src/mps_main.cpp + libAACenc/src/ms_stereo.cpp + libAACenc/src/noisedet.cpp + libAACenc/src/pnsparam.cpp + libAACenc/src/pre_echo_control.cpp + libAACenc/src/psy_configuration.cpp + libAACenc/src/psy_main.cpp + libAACenc/src/qc_main.cpp + libAACenc/src/quantize.cpp + libAACenc/src/sf_estim.cpp + libAACenc/src/spreading.cpp + libAACenc/src/tonality.cpp + libAACenc/src/transform.cpp + libAACenc/src/aacenc.h + libAACenc/src/aacenc_pns.h + libAACenc/src/aacEnc_ram.h + libAACenc/src/aacEnc_rom.h + libAACenc/src/aacenc_tns.h + libAACenc/src/adj_thr.h + libAACenc/src/adj_thr_data.h + libAACenc/src/band_nrg.h + libAACenc/src/bandwidth.h + libAACenc/src/bit_cnt.h + libAACenc/src/bitenc.h + libAACenc/src/block_switch.h + libAACenc/src/channel_map.h + libAACenc/src/chaosmeasure.h + libAACenc/src/dyn_bits.h + libAACenc/src/grp_data.h + libAACenc/src/intensity.h + libAACenc/src/interface.h + libAACenc/src/line_pe.h + libAACenc/src/metadata_compressor.h + libAACenc/src/metadata_main.h + libAACenc/src/mps_main.h + libAACenc/src/ms_stereo.h + libAACenc/src/noisedet.h + libAACenc/src/pns_func.h + libAACenc/src/pnsparam.h + libAACenc/src/pre_echo_control.h + libAACenc/src/psy_configuration.h + libAACenc/src/psy_const.h + libAACenc/src/psy_data.h + libAACenc/src/psy_main.h + libAACenc/src/qc_data.h + libAACenc/src/qc_main.h + libAACenc/src/quantize.h + libAACenc/src/sf_estim.h + libAACenc/src/spreading.h + libAACenc/src/tns_func.h + libAACenc/src/tonality.h + libAACenc/src/transform.h) + +set(ARITHCODING_SRC + libArithCoding/src/ac_arith_coder.cpp) + +set(DRCDEC_SRC + libDRCdec/src/FDK_drcDecLib.cpp + libDRCdec/src/drcDec_gainDecoder.cpp + libDRCdec/src/drcDec_reader.cpp + libDRCdec/src/drcDec_rom.cpp + libDRCdec/src/drcDec_selectionProcess.cpp + libDRCdec/src/drcDec_tools.cpp + libDRCdec/src/drcGainDec_init.cpp + libDRCdec/src/drcGainDec_preprocess.cpp + libDRCdec/src/drcGainDec_process.cpp + libDRCdec/src/drcDec_gainDecoder.h + libDRCdec/src/drcDec_reader.h + libDRCdec/src/drcDec_rom.h + libDRCdec/src/drcDec_selectionProcess.h + libDRCdec/src/drcDec_tools.h + libDRCdec/src/drcDec_types.h + libDRCdec/src/drcDecoder.h + libDRCdec/src/drcGainDec_init.h + libDRCdec/src/drcGainDec_preprocess.h + libDRCdec/src/drcGainDec_process.h) + +set(FDK_SRC + libFDK/src/FDK_bitbuffer.cpp + libFDK/src/FDK_core.cpp + libFDK/src/FDK_crc.cpp + libFDK/src/FDK_decorrelate.cpp + libFDK/src/FDK_hybrid.cpp + libFDK/src/FDK_lpc.cpp + libFDK/src/FDK_matrixCalloc.cpp + libFDK/src/FDK_qmf_domain.cpp + libFDK/src/FDK_tools_rom.cpp + libFDK/src/FDK_trigFcts.cpp + libFDK/src/autocorr2nd.cpp + libFDK/src/dct.cpp + libFDK/src/fft.cpp + libFDK/src/fft_rad2.cpp + libFDK/src/fixpoint_math.cpp + libFDK/src/huff_nodes.cpp + libFDK/src/mdct.cpp + libFDK/src/nlc_dec.cpp + libFDK/src/qmf.cpp + libFDK/src/scale.cpp) + +set(MPEGTPDEC_SRC + libMpegTPDec/src/tpdec_adif.cpp + libMpegTPDec/src/tpdec_adts.cpp + libMpegTPDec/src/tpdec_asc.cpp + libMpegTPDec/src/tpdec_drm.cpp + libMpegTPDec/src/tpdec_latm.cpp + libMpegTPDec/src/tpdec_lib.cpp + libMpegTPDec/src/tp_version.h + libMpegTPDec/src/tpdec_adif.h + libMpegTPDec/src/tpdec_adts.h + libMpegTPDec/src/tpdec_drm.h + libMpegTPDec/src/tpdec_latm.h) + +set(MPEGTPENC_SRC + libMpegTPEnc/src/tpenc_adif.cpp + libMpegTPEnc/src/tpenc_adts.cpp + libMpegTPEnc/src/tpenc_asc.cpp + libMpegTPEnc/src/tpenc_latm.cpp + libMpegTPEnc/src/tpenc_lib.cpp + libMpegTPEnc/src/tp_version.h + libMpegTPEnc/src/tpenc_adif.h + libMpegTPEnc/src/tpenc_adts.h + libMpegTPEnc/src/tpenc_asc.h + libMpegTPEnc/src/tpenc_latm.h) + +set(PCMUTILS_SRC + libPCMutils/src/limiter.cpp + libPCMutils/src/pcm_utils.cpp + libPCMutils/src/pcmdmx_lib.cpp + libPCMutils/src/version.h) + +set(SACDEC_SRC + libSACdec/src/sac_bitdec.cpp + libSACdec/src/sac_calcM1andM2.cpp + libSACdec/src/sac_dec.cpp + libSACdec/src/sac_dec_conceal.cpp + libSACdec/src/sac_dec_lib.cpp + libSACdec/src/sac_process.cpp + libSACdec/src/sac_qmf.cpp + libSACdec/src/sac_reshapeBBEnv.cpp + libSACdec/src/sac_rom.cpp + libSACdec/src/sac_smoothing.cpp + libSACdec/src/sac_stp.cpp + libSACdec/src/sac_tsd.cpp + libSACdec/src/sac_bitdec.h + libSACdec/src/sac_calcM1andM2.h + libSACdec/src/sac_dec.h + libSACdec/src/sac_dec_conceal.h + libSACdec/src/sac_dec_interface.h + libSACdec/src/sac_dec_ssc_struct.h + libSACdec/src/sac_process.h + libSACdec/src/sac_qmf.h + libSACdec/src/sac_reshapeBBEnv.h + libSACdec/src/sac_rom.h + libSACdec/src/sac_smoothing.h + libSACdec/src/sac_stp.h + libSACdec/src/sac_tsd.h) + +set(SACENC_SRC + libSACenc/src/sacenc_bitstream.cpp + libSACenc/src/sacenc_delay.cpp + libSACenc/src/sacenc_dmx_tdom_enh.cpp + libSACenc/src/sacenc_filter.cpp + libSACenc/src/sacenc_framewindowing.cpp + libSACenc/src/sacenc_huff_tab.cpp + libSACenc/src/sacenc_lib.cpp + libSACenc/src/sacenc_nlc_enc.cpp + libSACenc/src/sacenc_onsetdetect.cpp + libSACenc/src/sacenc_paramextract.cpp + libSACenc/src/sacenc_staticgain.cpp + libSACenc/src/sacenc_tree.cpp + libSACenc/src/sacenc_vectorfunctions.cpp + libSACenc/src/sacenc_bitstream.h + libSACenc/src/sacenc_const.h + libSACenc/src/sacenc_delay.h + libSACenc/src/sacenc_dmx_tdom_enh.h + libSACenc/src/sacenc_filter.h + libSACenc/src/sacenc_framewindowing.h + libSACenc/src/sacenc_huff_tab.h + libSACenc/src/sacenc_nlc_enc.h + libSACenc/src/sacenc_onsetdetect.h + libSACenc/src/sacenc_paramextract.h + libSACenc/src/sacenc_staticgain.h + libSACenc/src/sacenc_tree.h + libSACenc/src/sacenc_vectorfunctions.h) + +set(SBRDEC_SRC + libSBRdec/src/HFgen_preFlat.cpp + libSBRdec/src/env_calc.cpp + libSBRdec/src/env_dec.cpp + libSBRdec/src/env_extr.cpp + libSBRdec/src/hbe.cpp + libSBRdec/src/huff_dec.cpp + libSBRdec/src/lpp_tran.cpp + libSBRdec/src/psbitdec.cpp + libSBRdec/src/psdec.cpp + libSBRdec/src/psdec_drm.cpp + libSBRdec/src/psdecrom_drm.cpp + libSBRdec/src/pvc_dec.cpp + libSBRdec/src/sbr_deb.cpp + libSBRdec/src/sbr_dec.cpp + libSBRdec/src/sbr_ram.cpp + libSBRdec/src/sbr_rom.cpp + libSBRdec/src/sbrdec_drc.cpp + libSBRdec/src/sbrdec_freq_sca.cpp + libSBRdec/src/sbrdecoder.cpp + libSBRdec/src/env_calc.h + libSBRdec/src/env_dec.h + libSBRdec/src/env_extr.h + libSBRdec/src/hbe.h + libSBRdec/src/HFgen_preFlat.h + libSBRdec/src/huff_dec.h + libSBRdec/src/lpp_tran.h + libSBRdec/src/psbitdec.h + libSBRdec/src/psdec.h + libSBRdec/src/psdec_drm.h + libSBRdec/src/pvc_dec.h + libSBRdec/src/sbr_deb.h + libSBRdec/src/sbr_dec.h + libSBRdec/src/sbr_ram.h + libSBRdec/src/sbr_rom.h + libSBRdec/src/sbrdec_drc.h + libSBRdec/src/sbrdec_freq_sca.h + libSBRdec/src/transcendent.h) + +set(SBRENC_SRC + libSBRenc/src/bit_sbr.cpp + libSBRenc/src/code_env.cpp + libSBRenc/src/env_bit.cpp + libSBRenc/src/env_est.cpp + libSBRenc/src/fram_gen.cpp + libSBRenc/src/invf_est.cpp + libSBRenc/src/mh_det.cpp + libSBRenc/src/nf_est.cpp + libSBRenc/src/ps_bitenc.cpp + libSBRenc/src/ps_encode.cpp + libSBRenc/src/ps_main.cpp + libSBRenc/src/resampler.cpp + libSBRenc/src/sbr_encoder.cpp + libSBRenc/src/sbr_misc.cpp + libSBRenc/src/sbrenc_freq_sca.cpp + libSBRenc/src/sbrenc_ram.cpp + libSBRenc/src/sbrenc_rom.cpp + libSBRenc/src/ton_corr.cpp + libSBRenc/src/tran_det.cpp + libSBRenc/src/bit_sbr.h + libSBRenc/src/cmondata.h + libSBRenc/src/code_env.h + libSBRenc/src/env_bit.h + libSBRenc/src/env_est.h + libSBRenc/src/fram_gen.h + libSBRenc/src/invf_est.h + libSBRenc/src/mh_det.h + libSBRenc/src/nf_est.h + libSBRenc/src/ps_bitenc.h + libSBRenc/src/ps_const.h + libSBRenc/src/ps_encode.h + libSBRenc/src/ps_main.h + libSBRenc/src/resampler.h + libSBRenc/src/sbr.h + libSBRenc/src/sbr_def.h + libSBRenc/src/sbr_misc.h + libSBRenc/src/sbrenc_freq_sca.h + libSBRenc/src/sbrenc_ram.h + libSBRenc/src/sbrenc_rom.h + libSBRenc/src/ton_corr.h + libSBRenc/src/tran_det.h) + +set(SYS_SRC + libSYS/src/genericStds.cpp + libSYS/src/syslib_channelMapDescr.cpp) + +set(fdk_aacinclude_HEADERS + libSYS/include/machine_type.h + libSYS/include/genericStds.h + libSYS/include/FDK_audio.h + libSYS/include/syslib_channelMapDescr.h + libAACenc/include/aacenc_lib.h + libAACdec/include/aacdecoder_lib.h) + +set(libfdk_aac_SOURCES + ${AACDEC_SRC} ${AACENC_SRC} + ${ARITHCODING_SRC} + ${DRCDEC_SRC} + ${MPEGTPDEC_SRC} ${MPEGTPENC_SRC} + ${SACDEC_SRC} ${SACENC_SRC} + ${SBRDEC_SRC} ${SBRENC_SRC} + ${PCMUTILS_SRC} ${FDK_SRC} ${SYS_SRC}) + +if(WIN32 AND BUILD_SHARED_LIBS) + set(libfdk_aac_SOURCES ${libfdk_aac_SOURCES} fdk-aac.def) +endif() + +## Create Library target. Actually fdk-aac is enough, but we also create +## FDK-AAC::fdk-aac for consistence with config-file package. + +add_library(fdk-aac ${libfdk_aac_SOURCES}) +add_library(FDK-AAC::fdk-aac ALIAS fdk-aac) + +## Library target configuration + +### Library target includes +target_include_directories(fdk-aac + PUBLIC + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/libAACdec/include> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/libAACenc/include> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/libSYS/include> + PRIVATE + libArithCoding/include + libDRCdec/include + libSACdec/include + libSACenc/include + libSBRdec/include + libSBRenc/include + libMpegTPDec/include + libMpegTPEnc/include + libFDK/include + libPCMutils/include) + +### Link math library if required +target_link_libraries(fdk-aac PRIVATE $<$<BOOL:${HAVE_LIBM}>:m>) + +### Set public headers and shared library version. Version info is critical for Unix-like OSes. +set_target_properties(fdk-aac PROPERTIES + PUBLIC_HEADER "${fdk_aacinclude_HEADERS}" + VERSION 2.0.2 + SOVERSION 2 + MACHO_COMPATIBILITY_VERSION 3.0.0 + MACHO_CURRENT_VERSION 3.2.0 + LINKER_LANGUAGE C) + +### Some compiler options from Makefile.am +if(MSVC) + target_compile_options(fdk-aac PRIVATE /EHsc) +else() + target_compile_options(fdk-aac PRIVATE -fno-exceptions -fno-rtti) +endif() + +### Set proper name for MinGW or Cygwin DLL + +if((MINGW OR CYGWIN) AND BUILD_SHARED_LIBS) + set_property(TARGET fdk-aac PROPERTY RUNTIME_OUTPUT_NAME fdk-aac-2) +endif() + +## Library installation + +### Note we export `fdk-aac-targets` to use with config-file package. +install(TARGETS fdk-aac EXPORT fdk-aac-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT BIN + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT DEV + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT DEV + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/fdk-aac COMPONENT DEV) + +### Configure and install pkg-config module. +if(FDK_AAC_INSTALL_PKGCONFIG_MODULE) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix "\$\{prefix\}") + set(libdir "\$\{exec_prefix\}/${CMAKE_INSTALL_LIBDIR}") + set(includedir "\$\{prefix\}/${CMAKE_INSTALL_INCLUDEDIR}") + set(PACKAGE_VERSION ${PROJECT_VERSION}) + if(HAVE_LIBM) + if(BUILD_SHARED_LIBS) + set(LIBS_PRIVATE "-lm") + else() + set(LIBS_PUBLIC "-lm") + endif() + endif() + configure_file(fdk-aac.pc.in fdk-aac.pc @ONLY) + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/fdk-aac.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif() + +### Configure and install config-file package. Something like pkg-config module, but for Windows. +if(FDK_AAC_INSTALL_CMAKE_CONFIG_MODULE) + + set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/fdk-aac) + + configure_package_config_file(fdk-aac-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/fdk-aac-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) + + if(CMAKE_VERSION VERSION_LESS 3.11) + write_basic_package_version_file(fdk-aac-config-version.cmake COMPATIBILITY SameMajorVersion) + else() + write_basic_package_version_file(fdk-aac-config-version.cmake COMPATIBILITY SameMinorVersion) + endif() + + install(EXPORT fdk-aac-targets + NAMESPACE FDK-AAC:: + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/fdk-aac-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/fdk-aac-config-version.cmake + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) + +endif() + +# Programs + +if(BUILD_PROGRAMS) + + ## Program sources + + set(aac_enc_SOURCES + aac-enc.c + wavreader.c + wavreader.h) + + ## Program target + add_executable(aac-enc ${aac_enc_SOURCES}) + + ## Program target configuration + target_link_libraries(aac-enc PRIVATE fdk-aac) + target_compile_definitions(aac-enc PRIVATE $<$<BOOL:${MSVC}>:_CRT_SECURE_NO_WARNINGS>) + if(WIN32) + target_sources(aac-enc PRIVATE win32/getopt.h) + target_include_directories(aac-enc PRIVATE win32) + endif() + + ## Program target installation + install(TARGETS aac-enc RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + + + ## Tool for testing the library + set(test_encode_decode_SOURCES + test-encode-decode.c + wavreader.c + wavreader.h + sha1.c + sha1.h) + + add_executable(test-encode-decode ${test_encode_decode_SOURCES}) + target_link_libraries(test-encode-decode PRIVATE fdk-aac) +endif() diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..c391bd9 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,57 @@ +2.0.2 + - Minor upstream updates + - Lots of upstream and local fuzzing fixes + - Added CMake project files + - Removed the MSVC specific makefile + +2.0.1 + - Minor release with a number of crash/fuzz fixes, primarily for the decoder + +2.0.0 + - Major update in the upstream source base, with support for new + profiles and features, and numerous crash/fuzz fixes. The new + upstream version is referred to as FDKv2, thus skipping the + major version 1 and syncing the fdk-aac major version number to 2. + +0.1.6 + - Lots of minor assorted crash/fuzz fixes, mostly for the decoder but + also some for the encoder + +0.1.5 + - Updated upstream sources + - Fixed building with GCC 3.3 and 3.4 + - Fixed building with GCC 6 + - AArch64 optimizations + - Makefiles for building with MSVC + - Support building the code in C++11 mode + +0.1.4 + - Updated upstream sources, with minor changes to the decoder API + breaking the ABI. (Calling code using AUDIO_CHANNEL_TYPE may need to + be updated. A new option AAC_PCM_LIMITER_ENABLE has been added, enabled + by default, which incurs extra decoding delay.) + - PowerPC optimizations, fixes for building on AIX + - Support for reading streamed wav files in the encoder example + - Fix VBR encoding of sample rates over 64 kHz + +0.1.3 + - Updated upstream sources, with a number of crash fixes and new features + (including support for encoding 7.1) + +0.1.2 + - Fix a few more crashes + - Include dependency libs (such as -lm) in the pkg-config file + +0.1.1 + - Updated to a new upstream version from Android 4.2, fixing a lot of crashes + - Cleanup of autotools usage + - Make sure the shared library links to libm if necessary + - Performance improvements on x86 + - Added support for WG4/DVD audio channel mappings + - Minimized the differences to upstream + - Added an example encoder tool + +0.1.0 + - Initial release of fdk-aac + - autotools based build system + - Enable setting VBR bitrate modes diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..c71af1d --- /dev/null +++ b/Makefile.am @@ -0,0 +1,304 @@ +ACLOCAL_AMFLAGS = -I m4 +AUTOMAKE_OPTIONS = subdir-objects + +AM_CPPFLAGS = \ + -I$(top_srcdir)/libAACdec/include \ + -I$(top_srcdir)/libAACenc/include \ + -I$(top_srcdir)/libArithCoding/include \ + -I$(top_srcdir)/libDRCdec/include \ + -I$(top_srcdir)/libSACdec/include \ + -I$(top_srcdir)/libSACenc/include \ + -I$(top_srcdir)/libSBRdec/include \ + -I$(top_srcdir)/libSBRenc/include \ + -I$(top_srcdir)/libMpegTPDec/include \ + -I$(top_srcdir)/libMpegTPEnc/include \ + -I$(top_srcdir)/libSYS/include \ + -I$(top_srcdir)/libFDK/include \ + -I$(top_srcdir)/libPCMutils/include + +AM_CXXFLAGS = -fno-exceptions -fno-rtti +libfdk_aac_la_LINK = $(LINK) $(libfdk_aac_la_LDFLAGS) +# Mention a dummy pure C file to trigger generation of the $(LINK) variable +nodist_EXTRA_libfdk_aac_la_SOURCES = dummy.c + +fdk_aacincludedir = $(includedir)/fdk-aac +fdk_aacinclude_HEADERS = \ + $(top_srcdir)/libSYS/include/machine_type.h \ + $(top_srcdir)/libSYS/include/genericStds.h \ + $(top_srcdir)/libSYS/include/FDK_audio.h \ + $(top_srcdir)/libSYS/include/syslib_channelMapDescr.h \ + $(top_srcdir)/libAACenc/include/aacenc_lib.h \ + $(top_srcdir)/libAACdec/include/aacdecoder_lib.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = fdk-aac.pc + +lib_LTLIBRARIES = libfdk-aac.la + +libfdk_aac_la_LDFLAGS = -version-info @FDK_AAC_VERSION@ -no-undefined \ + -export-symbols $(top_srcdir)/fdk-aac.sym + +if EXAMPLE +bin_PROGRAMS = aac-enc$(EXEEXT) +noinst_PROGRAMS = test-encode-decode$(EXEEXT) + +aac_enc_LDADD = libfdk-aac.la +aac_enc_SOURCES = aac-enc.c wavreader.c + +test_encode_decode_LDADD = libfdk-aac.la +test_encode_decode_SOURCES = test-encode-decode.c wavreader.c sha1.c + +noinst_HEADERS = wavreader.h +endif + +AACDEC_SRC = \ + libAACdec/src/FDK_delay.cpp \ + libAACdec/src/aac_ram.cpp \ + libAACdec/src/aac_rom.cpp \ + libAACdec/src/aacdec_drc.cpp \ + libAACdec/src/aacdec_hcr.cpp \ + libAACdec/src/aacdec_hcr_bit.cpp \ + libAACdec/src/aacdec_hcrs.cpp \ + libAACdec/src/aacdec_pns.cpp \ + libAACdec/src/aacdec_tns.cpp \ + libAACdec/src/aacdecoder.cpp \ + libAACdec/src/aacdecoder_lib.cpp \ + libAACdec/src/block.cpp \ + libAACdec/src/channel.cpp \ + libAACdec/src/channelinfo.cpp \ + libAACdec/src/conceal.cpp \ + libAACdec/src/ldfiltbank.cpp \ + libAACdec/src/pulsedata.cpp \ + libAACdec/src/rvlc.cpp \ + libAACdec/src/rvlcbit.cpp \ + libAACdec/src/rvlcconceal.cpp \ + libAACdec/src/stereo.cpp \ + libAACdec/src/usacdec_ace_d4t64.cpp \ + libAACdec/src/usacdec_ace_ltp.cpp \ + libAACdec/src/usacdec_acelp.cpp \ + libAACdec/src/usacdec_fac.cpp \ + libAACdec/src/usacdec_lpc.cpp \ + libAACdec/src/usacdec_lpd.cpp \ + libAACdec/src/usacdec_rom.cpp + +AACENC_SRC = \ + libAACenc/src/aacEnc_ram.cpp \ + libAACenc/src/aacEnc_rom.cpp \ + libAACenc/src/aacenc.cpp \ + libAACenc/src/aacenc_lib.cpp \ + libAACenc/src/aacenc_pns.cpp \ + libAACenc/src/aacenc_tns.cpp \ + libAACenc/src/adj_thr.cpp \ + libAACenc/src/band_nrg.cpp \ + libAACenc/src/bandwidth.cpp \ + libAACenc/src/bit_cnt.cpp \ + libAACenc/src/bitenc.cpp \ + libAACenc/src/block_switch.cpp \ + libAACenc/src/channel_map.cpp \ + libAACenc/src/chaosmeasure.cpp \ + libAACenc/src/dyn_bits.cpp \ + libAACenc/src/grp_data.cpp \ + libAACenc/src/intensity.cpp \ + libAACenc/src/line_pe.cpp \ + libAACenc/src/metadata_compressor.cpp \ + libAACenc/src/metadata_main.cpp \ + libAACenc/src/mps_main.cpp \ + libAACenc/src/ms_stereo.cpp \ + libAACenc/src/noisedet.cpp \ + libAACenc/src/pnsparam.cpp \ + libAACenc/src/pre_echo_control.cpp \ + libAACenc/src/psy_configuration.cpp \ + libAACenc/src/psy_main.cpp \ + libAACenc/src/qc_main.cpp \ + libAACenc/src/quantize.cpp \ + libAACenc/src/sf_estim.cpp \ + libAACenc/src/spreading.cpp \ + libAACenc/src/tonality.cpp \ + libAACenc/src/transform.cpp + +ARITHCODING_SRC = \ + libArithCoding/src/ac_arith_coder.cpp + +DRCDEC_SRC = \ + libDRCdec/src/FDK_drcDecLib.cpp \ + libDRCdec/src/drcDec_gainDecoder.cpp \ + libDRCdec/src/drcDec_reader.cpp \ + libDRCdec/src/drcDec_rom.cpp \ + libDRCdec/src/drcDec_selectionProcess.cpp \ + libDRCdec/src/drcDec_tools.cpp \ + libDRCdec/src/drcGainDec_init.cpp \ + libDRCdec/src/drcGainDec_preprocess.cpp \ + libDRCdec/src/drcGainDec_process.cpp + +FDK_SRC = \ + libFDK/src/FDK_bitbuffer.cpp \ + libFDK/src/FDK_core.cpp \ + libFDK/src/FDK_crc.cpp \ + libFDK/src/FDK_decorrelate.cpp \ + libFDK/src/FDK_hybrid.cpp \ + libFDK/src/FDK_lpc.cpp \ + libFDK/src/FDK_matrixCalloc.cpp \ + libFDK/src/FDK_qmf_domain.cpp \ + libFDK/src/FDK_tools_rom.cpp \ + libFDK/src/FDK_trigFcts.cpp \ + libFDK/src/autocorr2nd.cpp \ + libFDK/src/dct.cpp \ + libFDK/src/fft.cpp \ + libFDK/src/fft_rad2.cpp \ + libFDK/src/fixpoint_math.cpp \ + libFDK/src/huff_nodes.cpp \ + libFDK/src/mdct.cpp \ + libFDK/src/nlc_dec.cpp \ + libFDK/src/qmf.cpp \ + libFDK/src/scale.cpp + +MPEGTPDEC_SRC = \ + libMpegTPDec/src/tpdec_adif.cpp \ + libMpegTPDec/src/tpdec_adts.cpp \ + libMpegTPDec/src/tpdec_asc.cpp \ + libMpegTPDec/src/tpdec_drm.cpp \ + libMpegTPDec/src/tpdec_latm.cpp \ + libMpegTPDec/src/tpdec_lib.cpp + +MPEGTPENC_SRC = \ + libMpegTPEnc/src/tpenc_adif.cpp \ + libMpegTPEnc/src/tpenc_adts.cpp \ + libMpegTPEnc/src/tpenc_asc.cpp \ + libMpegTPEnc/src/tpenc_latm.cpp \ + libMpegTPEnc/src/tpenc_lib.cpp + +PCMUTILS_SRC = \ + libPCMutils/src/limiter.cpp \ + libPCMutils/src/pcm_utils.cpp \ + libPCMutils/src/pcmdmx_lib.cpp + +SACDEC_SRC = \ + libSACdec/src/sac_bitdec.cpp \ + libSACdec/src/sac_calcM1andM2.cpp \ + libSACdec/src/sac_dec.cpp \ + libSACdec/src/sac_dec_conceal.cpp \ + libSACdec/src/sac_dec_lib.cpp \ + libSACdec/src/sac_process.cpp \ + libSACdec/src/sac_qmf.cpp \ + libSACdec/src/sac_reshapeBBEnv.cpp \ + libSACdec/src/sac_rom.cpp \ + libSACdec/src/sac_smoothing.cpp \ + libSACdec/src/sac_stp.cpp \ + libSACdec/src/sac_tsd.cpp + +SACENC_SRC = \ + libSACenc/src/sacenc_bitstream.cpp \ + libSACenc/src/sacenc_delay.cpp \ + libSACenc/src/sacenc_dmx_tdom_enh.cpp \ + libSACenc/src/sacenc_filter.cpp \ + libSACenc/src/sacenc_framewindowing.cpp \ + libSACenc/src/sacenc_huff_tab.cpp \ + libSACenc/src/sacenc_lib.cpp \ + libSACenc/src/sacenc_nlc_enc.cpp \ + libSACenc/src/sacenc_onsetdetect.cpp \ + libSACenc/src/sacenc_paramextract.cpp \ + libSACenc/src/sacenc_staticgain.cpp \ + libSACenc/src/sacenc_tree.cpp \ + libSACenc/src/sacenc_vectorfunctions.cpp + +SBRDEC_SRC = \ + libSBRdec/src/HFgen_preFlat.cpp \ + libSBRdec/src/env_calc.cpp \ + libSBRdec/src/env_dec.cpp \ + libSBRdec/src/env_extr.cpp \ + libSBRdec/src/hbe.cpp \ + libSBRdec/src/huff_dec.cpp \ + libSBRdec/src/lpp_tran.cpp \ + libSBRdec/src/psbitdec.cpp \ + libSBRdec/src/psdec.cpp \ + libSBRdec/src/psdec_drm.cpp \ + libSBRdec/src/psdecrom_drm.cpp \ + libSBRdec/src/pvc_dec.cpp \ + libSBRdec/src/sbr_deb.cpp \ + libSBRdec/src/sbr_dec.cpp \ + libSBRdec/src/sbr_ram.cpp \ + libSBRdec/src/sbr_rom.cpp \ + libSBRdec/src/sbrdec_drc.cpp \ + libSBRdec/src/sbrdec_freq_sca.cpp \ + libSBRdec/src/sbrdecoder.cpp + +SBRENC_SRC = \ + libSBRenc/src/bit_sbr.cpp \ + libSBRenc/src/code_env.cpp \ + libSBRenc/src/env_bit.cpp \ + libSBRenc/src/env_est.cpp \ + libSBRenc/src/fram_gen.cpp \ + libSBRenc/src/invf_est.cpp \ + libSBRenc/src/mh_det.cpp \ + libSBRenc/src/nf_est.cpp \ + libSBRenc/src/ps_bitenc.cpp \ + libSBRenc/src/ps_encode.cpp \ + libSBRenc/src/ps_main.cpp \ + libSBRenc/src/resampler.cpp \ + libSBRenc/src/sbr_encoder.cpp \ + libSBRenc/src/sbr_misc.cpp \ + libSBRenc/src/sbrenc_freq_sca.cpp \ + libSBRenc/src/sbrenc_ram.cpp \ + libSBRenc/src/sbrenc_rom.cpp \ + libSBRenc/src/ton_corr.cpp \ + libSBRenc/src/tran_det.cpp + +SYS_SRC = \ + libSYS/src/genericStds.cpp \ + libSYS/src/syslib_channelMapDescr.cpp + +libfdk_aac_la_SOURCES = \ + $(AACDEC_SRC) $(AACENC_SRC) \ + $(ARITHCODING_SRC) \ + $(DRCDEC_SRC) \ + $(MPEGTPDEC_SRC) $(MPEGTPENC_SRC) \ + $(SACDEC_SRC) $(SACENC_SRC) \ + $(SBRDEC_SRC) $(SBRENC_SRC) \ + $(PCMUTILS_SRC) $(FDK_SRC) $(SYS_SRC) + +EXTRA_DIST = \ + $(top_srcdir)/CMakeLists.txt \ + $(top_srcdir)/.clang-format \ + $(top_srcdir)/autogen.sh \ + $(top_srcdir)/MODULE_LICENSE_FRAUNHOFER \ + $(top_srcdir)/NOTICE \ + $(top_srcdir)/OWNERS \ + $(top_srcdir)/Android.bp \ + $(top_srcdir)/fdk-aac.def \ + $(top_srcdir)/fdk-aac.sym \ + $(top_srcdir)/fdk-aac-config.cmake.in \ + $(top_srcdir)/documentation/*.pdf \ + $(top_srcdir)/fuzzer/* \ + $(top_srcdir)/libAACdec/src/*.h \ + $(top_srcdir)/libAACdec/src/arm/*.cpp \ + $(top_srcdir)/libAACenc/src/*.h \ + $(top_srcdir)/libArithCoding/include/*.h \ + $(top_srcdir)/libDRCdec/include/*.h \ + $(top_srcdir)/libDRCdec/src/*.h \ + $(top_srcdir)/libSACdec/include/*.h \ + $(top_srcdir)/libSACdec/src/*.h \ + $(top_srcdir)/libSACenc/include/*.h \ + $(top_srcdir)/libSACenc/src/*.h \ + $(top_srcdir)/libSBRenc/src/*.h \ + $(top_srcdir)/libSBRenc/include/*.h \ + $(top_srcdir)/libSBRdec/src/*.h \ + $(top_srcdir)/libSBRdec/src/arm/*.cpp \ + $(top_srcdir)/libSBRdec/include/*.h \ + $(top_srcdir)/libSYS/include/*.h \ + $(top_srcdir)/libPCMutils/include/*.h \ + $(top_srcdir)/libPCMutils/src/*.h \ + $(top_srcdir)/libMpegTPEnc/include/*.h \ + $(top_srcdir)/libMpegTPEnc/src/*.h \ + $(top_srcdir)/libMpegTPDec/include/*.h \ + $(top_srcdir)/libMpegTPDec/src/*.h \ + $(top_srcdir)/libFDK/include/*.h \ + $(top_srcdir)/libFDK/include/arm/*.h \ + $(top_srcdir)/libFDK/include/mips/*.h \ + $(top_srcdir)/libFDK/include/ppc/*.h \ + $(top_srcdir)/libFDK/include/x86/*.h \ + $(top_srcdir)/libFDK/src/arm/*.cpp \ + $(top_srcdir)/libFDK/src/mips/*.cpp \ + $(top_srcdir)/METADATA \ + $(top_srcdir)/PREUPLOAD.cfg \ + $(top_srcdir)/win32/*.h + diff --git a/aac-enc.c b/aac-enc.c new file mode 100644 index 0000000..7f443f2 --- /dev/null +++ b/aac-enc.c @@ -0,0 +1,237 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2011 Martin Storsjo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdint.h> + +#if defined(_MSC_VER) +#include <getopt.h> +#else +#include <unistd.h> +#endif + +#include <stdlib.h> +#include "libAACenc/include/aacenc_lib.h" +#include "wavreader.h" + +void usage(const char* name) { + fprintf(stderr, "%s [-r bitrate] [-t aot] [-a afterburner] [-s sbr] [-v vbr] in.wav out.aac\n", name); + fprintf(stderr, "Supported AOTs:\n"); + fprintf(stderr, "\t2\tAAC-LC\n"); + fprintf(stderr, "\t5\tHE-AAC\n"); + fprintf(stderr, "\t29\tHE-AAC v2\n"); + fprintf(stderr, "\t23\tAAC-LD\n"); + fprintf(stderr, "\t39\tAAC-ELD\n"); +} + +int main(int argc, char *argv[]) { + int bitrate = 64000; + int ch; + const char *infile, *outfile; + FILE *out; + void *wav; + int format, sample_rate, channels, bits_per_sample; + int input_size; + uint8_t* input_buf; + int16_t* convert_buf; + int aot = 2; + int afterburner = 1; + int eld_sbr = 0; + int vbr = 0; + HANDLE_AACENCODER handle; + CHANNEL_MODE mode; + AACENC_InfoStruct info = { 0 }; + while ((ch = getopt(argc, argv, "r:t:a:s:v:")) != -1) { + switch (ch) { + case 'r': + bitrate = atoi(optarg); + break; + case 't': + aot = atoi(optarg); + break; + case 'a': + afterburner = atoi(optarg); + break; + case 's': + eld_sbr = atoi(optarg); + break; + case 'v': + vbr = atoi(optarg); + break; + case '?': + default: + usage(argv[0]); + return 1; + } + } + if (argc - optind < 2) { + usage(argv[0]); + return 1; + } + infile = argv[optind]; + outfile = argv[optind + 1]; + + wav = wav_read_open(infile); + if (!wav) { + fprintf(stderr, "Unable to open wav file %s\n", infile); + return 1; + } + if (!wav_get_header(wav, &format, &channels, &sample_rate, &bits_per_sample, NULL)) { + fprintf(stderr, "Bad wav file %s\n", infile); + return 1; + } + if (format != 1) { + fprintf(stderr, "Unsupported WAV format %d\n", format); + return 1; + } + if (bits_per_sample != 16) { + fprintf(stderr, "Unsupported WAV sample depth %d\n", bits_per_sample); + return 1; + } + switch (channels) { + case 1: mode = MODE_1; break; + case 2: mode = MODE_2; break; + case 3: mode = MODE_1_2; break; + case 4: mode = MODE_1_2_1; break; + case 5: mode = MODE_1_2_2; break; + case 6: mode = MODE_1_2_2_1; break; + default: + fprintf(stderr, "Unsupported WAV channels %d\n", channels); + return 1; + } + if (aacEncOpen(&handle, 0, channels) != AACENC_OK) { + fprintf(stderr, "Unable to open encoder\n"); + return 1; + } + if (aacEncoder_SetParam(handle, AACENC_AOT, aot) != AACENC_OK) { + fprintf(stderr, "Unable to set the AOT\n"); + return 1; + } + if (aot == 39 && eld_sbr) { + if (aacEncoder_SetParam(handle, AACENC_SBR_MODE, 1) != AACENC_OK) { + fprintf(stderr, "Unable to set SBR mode for ELD\n"); + return 1; + } + } + if (aacEncoder_SetParam(handle, AACENC_SAMPLERATE, sample_rate) != AACENC_OK) { + fprintf(stderr, "Unable to set the sample rate\n"); + return 1; + } + if (aacEncoder_SetParam(handle, AACENC_CHANNELMODE, mode) != AACENC_OK) { + fprintf(stderr, "Unable to set the channel mode\n"); + return 1; + } + if (aacEncoder_SetParam(handle, AACENC_CHANNELORDER, 1) != AACENC_OK) { + fprintf(stderr, "Unable to set the wav channel order\n"); + return 1; + } + if (vbr) { + if (aacEncoder_SetParam(handle, AACENC_BITRATEMODE, vbr) != AACENC_OK) { + fprintf(stderr, "Unable to set the VBR bitrate mode\n"); + return 1; + } + } else { + if (aacEncoder_SetParam(handle, AACENC_BITRATE, bitrate) != AACENC_OK) { + fprintf(stderr, "Unable to set the bitrate\n"); + return 1; + } + } + if (aacEncoder_SetParam(handle, AACENC_TRANSMUX, TT_MP4_ADTS) != AACENC_OK) { + fprintf(stderr, "Unable to set the ADTS transmux\n"); + return 1; + } + if (aacEncoder_SetParam(handle, AACENC_AFTERBURNER, afterburner) != AACENC_OK) { + fprintf(stderr, "Unable to set the afterburner mode\n"); + return 1; + } + if (aacEncEncode(handle, NULL, NULL, NULL, NULL) != AACENC_OK) { + fprintf(stderr, "Unable to initialize the encoder\n"); + return 1; + } + if (aacEncInfo(handle, &info) != AACENC_OK) { + fprintf(stderr, "Unable to get the encoder info\n"); + return 1; + } + + out = fopen(outfile, "wb"); + if (!out) { + perror(outfile); + return 1; + } + + input_size = channels*2*info.frameLength; + input_buf = (uint8_t*) malloc(input_size); + convert_buf = (int16_t*) malloc(input_size); + + while (1) { + AACENC_BufDesc in_buf = { 0 }, out_buf = { 0 }; + AACENC_InArgs in_args = { 0 }; + AACENC_OutArgs out_args = { 0 }; + int in_identifier = IN_AUDIO_DATA; + int in_size, in_elem_size; + int out_identifier = OUT_BITSTREAM_DATA; + int out_size, out_elem_size; + int read, i; + void *in_ptr, *out_ptr; + uint8_t outbuf[20480]; + AACENC_ERROR err; + + read = wav_read_data(wav, input_buf, input_size); + for (i = 0; i < read/2; i++) { + const uint8_t* in = &input_buf[2*i]; + convert_buf[i] = in[0] | (in[1] << 8); + } + in_ptr = convert_buf; + in_size = read; + in_elem_size = 2; + + in_args.numInSamples = read <= 0 ? -1 : read/2; + in_buf.numBufs = 1; + in_buf.bufs = &in_ptr; + in_buf.bufferIdentifiers = &in_identifier; + in_buf.bufSizes = &in_size; + in_buf.bufElSizes = &in_elem_size; + + out_ptr = outbuf; + out_size = sizeof(outbuf); + out_elem_size = 1; + out_buf.numBufs = 1; + out_buf.bufs = &out_ptr; + out_buf.bufferIdentifiers = &out_identifier; + out_buf.bufSizes = &out_size; + out_buf.bufElSizes = &out_elem_size; + + if ((err = aacEncEncode(handle, &in_buf, &out_buf, &in_args, &out_args)) != AACENC_OK) { + if (err == AACENC_ENCODE_EOF) + break; + fprintf(stderr, "Encoding failed\n"); + return 1; + } + if (out_args.numOutBytes == 0) + continue; + fwrite(outbuf, 1, out_args.numOutBytes, out); + } + free(input_buf); + free(convert_buf); + fclose(out); + wav_read_close(wav); + aacEncClose(&handle); + + return 0; +} + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..210ccb8 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,2 @@ +#!/bin/sh +autoreconf -fiv diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..c49fa3d --- /dev/null +++ b/configure.ac @@ -0,0 +1,38 @@ +dnl -*- Autoconf -*- +dnl Process this file with autoconf to produce a configure script. + +AC_INIT([fdk-aac], [2.0.2], [http://sourceforge.net/projects/opencore-amr/]) +AC_CONFIG_AUX_DIR(.) +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE([tar-ustar foreign]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +dnl Various options for configure +AC_ARG_ENABLE([example], + [AS_HELP_STRING([--enable-example], + [enable example encoding program (default is no)])], + [example=$enableval], [example=no]) + +dnl Automake conditionals to set +AM_CONDITIONAL(EXAMPLE, test x$example = xyes) + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_CXX +LT_INIT + +AC_SEARCH_LIBS([sin], [m]) + +dnl soname version to use +dnl goes by ‘current[:revision[:age]]’ with the soname ending up as +dnl current.age.revision +FDK_AAC_VERSION=2:2:0 + +AS_IF([test x$enable_shared = xyes], [LIBS_PRIVATE=$LIBS], [LIBS_PUBLIC=$LIBS]) +AC_SUBST(FDK_AAC_VERSION) +AC_SUBST(LIBS_PUBLIC) +AC_SUBST(LIBS_PRIVATE) + +AC_CONFIG_FILES([Makefile + fdk-aac.pc]) +AC_OUTPUT diff --git a/fdk-aac-config.cmake.in b/fdk-aac-config.cmake.in new file mode 100644 index 0000000..26bd209 --- /dev/null +++ b/fdk-aac-config.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +include(${CMAKE_CURRENT_LIST_DIR}/fdk-aac-targets.cmake) + +check_required_components(FDK-AAC) diff --git a/fdk-aac.def b/fdk-aac.def new file mode 100644 index 0000000..7e81466 --- /dev/null +++ b/fdk-aac.def @@ -0,0 +1,19 @@ +EXPORTS + aacDecoder_AncDataGet + aacDecoder_AncDataInit + aacDecoder_Close + aacDecoder_ConfigRaw + aacDecoder_DecodeFrame + aacDecoder_Fill + aacDecoder_GetFreeBytes + aacDecoder_GetLibInfo + aacDecoder_GetStreamInfo + aacDecoder_Open + aacDecoder_SetParam + aacEncClose + aacEncEncode + aacEncGetLibInfo + aacEncInfo + aacEncOpen + aacEncoder_GetParam + aacEncoder_SetParam diff --git a/fdk-aac.pc.in b/fdk-aac.pc.in new file mode 100644 index 0000000..2edac45 --- /dev/null +++ b/fdk-aac.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Fraunhofer FDK AAC Codec Library +Description: AAC codec library +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lfdk-aac @LIBS_PUBLIC@ +Libs.private: @LIBS_PRIVATE@ +Cflags: -I${includedir} diff --git a/fdk-aac.sym b/fdk-aac.sym new file mode 100644 index 0000000..2a06c41 --- /dev/null +++ b/fdk-aac.sym @@ -0,0 +1,18 @@ +aacDecoder_AncDataGet +aacDecoder_AncDataInit +aacDecoder_Close +aacDecoder_ConfigRaw +aacDecoder_DecodeFrame +aacDecoder_Fill +aacDecoder_GetFreeBytes +aacDecoder_GetLibInfo +aacDecoder_GetStreamInfo +aacDecoder_Open +aacDecoder_SetParam +aacEncClose +aacEncEncode +aacEncGetLibInfo +aacEncInfo +aacEncOpen +aacEncoder_GetParam +aacEncoder_SetParam diff --git a/libAACdec/include/aacdecoder_lib.h b/libAACdec/include/aacdecoder_lib.h index 02596b2..a009ba0 100644 --- a/libAACdec/include/aacdecoder_lib.h +++ b/libAACdec/include/aacdecoder_lib.h @@ -436,6 +436,11 @@ Where N equals to CStreamInfo::frameSize . #define AACDECODER_LIB_VL2 0 #include "genericStds.h" + +#define AACDECODER_LIB_VL0 3 +#define AACDECODER_LIB_VL1 2 +#define AACDECODER_LIB_VL2 0 + /** * \brief AAC decoder error codes. */ diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index ef0515c..5319b7c 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -968,6 +968,8 @@ LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, return NULL; } + transportDec_SetParam(pIn, TPDEC_PARAM_IGNORE_BUFFERFULLNESS, 1); + /* Allocate AAC decoder core struct. */ aacDec = CAacDecoder_Open(transportFmt); diff --git a/libAACdec/src/usacdec_acelp.cpp b/libAACdec/src/usacdec_acelp.cpp index ca1a6a2..9769a07 100644 --- a/libAACdec/src/usacdec_acelp.cpp +++ b/libAACdec/src/usacdec_acelp.cpp @@ -267,9 +267,9 @@ static void D_gain2_plus(int index, FIXP_COD code[], FIXP_SGL *gain_pit, gcode0_e = gcode0_e + SF_MEAN_ENER_LG10 - (ener_code_e >> 1) + 1; i = index << 1; - *gain_pit = t_qua_gain7b[i]; /* adaptive codebook gain */ + *gain_pit = fdk_t_qua_gain7b[i]; /* adaptive codebook gain */ /* t_qua_gain[ind2p1] : fixed codebook gain correction factor */ - Ltmp = fMult(t_qua_gain7b[i + 1], gcode0); + Ltmp = fMult(fdk_t_qua_gain7b[i + 1], gcode0); *gain_code = scaleValue(Ltmp, gcode0_e - SF_GAIN_C + SF_QUA_GAIN7B); /* update bad frame handler */ diff --git a/libAACdec/src/usacdec_rom.cpp b/libAACdec/src/usacdec_rom.cpp index 519e992..ca3009e 100644 --- a/libAACdec/src/usacdec_rom.cpp +++ b/libAACdec/src/usacdec_rom.cpp @@ -1249,7 +1249,7 @@ const FIXP_LPC fdk_dec_dico_lsf_abs_8b[] = { adaptive codebook gain g_p (left column). Scaled by 2.0f. innovative codebook gain g_c (right column). Scaled by 16.0f. */ -const FIXP_SGL t_qua_gain7b[128 * 2] = { +const FIXP_SGL fdk_t_qua_gain7b[128 * 2] = { 204, 441, 464, 1977, 869, 1077, 1072, 3062, 1281, 4759, 1647, 1539, 1845, 7020, 1853, 634, 1995, 2336, 2351, 15400, 2661, 1165, 2702, 3900, 2710, 10133, 3195, 1752, 3498, 2624, 3663, 849, 3984, diff --git a/libAACdec/src/usacdec_rom.h b/libAACdec/src/usacdec_rom.h index 0ad4cb0..f969e90 100644 --- a/libAACdec/src/usacdec_rom.h +++ b/libAACdec/src/usacdec_rom.h @@ -132,7 +132,7 @@ extern const FIXP_LPC fdk_dec_dico_lsf_abs_8b[16 * 256]; /* ACELP tables */ #define SF_QUA_GAIN7B 4 -extern const FIXP_SGL t_qua_gain7b[128 * 2]; +extern const FIXP_SGL fdk_t_qua_gain7b[128 * 2]; extern const FIXP_SGL lsp_interpol_factor[2][NB_SUBFR]; /* For bass post filter */ diff --git a/libAACenc/include/aacenc_lib.h b/libAACenc/include/aacenc_lib.h index 4f8f223..902ba11 100644 --- a/libAACenc/include/aacenc_lib.h +++ b/libAACenc/include/aacenc_lib.h @@ -332,7 +332,7 @@ If the present library is configured with Metadata support, it is possible to insert meta data side info into the generated audio bitstream while encoding. To work with meta data the encoder instance has to be \ref encOpen "allocated" -with meta data support. The meta data mode must be be configured with the +with meta data support. The meta data mode must be configured with the ::AACENC_METADATA_MODE parameter and aacEncoder_SetParam() function. \code aacEncoder_SetParam(hAacEncoder, AACENC_METADATA_MODE, 0-3); \endcode diff --git a/libAACenc/src/aacenc.h b/libAACenc/src/aacenc.h index b7e0ef2..2d95abb 100644 --- a/libAACenc/src/aacenc.h +++ b/libAACenc/src/aacenc.h @@ -206,8 +206,9 @@ typedef enum { CH_ORDER_MPEG = 0, /*!< MPEG channel ordering (e. g. 5.1: C, L, R, SL, SR, LFE) */ - CH_ORDER_WAV /*!< WAV fileformat channel ordering (e. g. 5.1: L, R, C, LFE, - SL, SR) */ + CH_ORDER_WAV, /*!< WAV fileformat channel ordering (e. g. 5.1: L, R, C, LFE, + SL, SR) */ + CH_ORDER_WG4 /*!< WG4 fileformat channel ordering (e. g. 5.1: L, R, SL, SR, C, LFE) */ } CHANNEL_ORDER; diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index c11db27..ee7f918 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -2234,7 +2234,7 @@ AACENC_ERROR aacEncoder_SetParam(const HANDLE_AACENCODER hAacEncoder, break; case AACENC_CHANNELORDER: if (hAacEncoder->aacConfig.channelOrder != (CHANNEL_ORDER)value) { - if (!((value == 0) || (value == 1))) { + if (!((value == 0) || (value == 1) || (value == 2))) { err = AACENC_INVALID_CONFIG; break; } diff --git a/libAACenc/src/metadata_main.cpp b/libAACenc/src/metadata_main.cpp index edd3831..ada4502 100644 --- a/libAACenc/src/metadata_main.cpp +++ b/libAACenc/src/metadata_main.cpp @@ -491,10 +491,17 @@ FDK_METADATA_ERROR FDK_MetadataEnc_Init( FDK_channelMapDescr mapDescrPrev, mapDescr; int c, src[2] = {-1, -1}, dst[2] = {-1, -1}; - FDK_chMapDescr_init(&mapDescrPrev, NULL, 0, - (channelOrder == CH_ORDER_MPEG) ? 1 : 0); - FDK_chMapDescr_init(&mapDescr, NULL, 0, - (channelOrder == CH_ORDER_MPEG) ? 1 : 0); + if (channelOrder == CH_ORDER_WG4) { + FDK_chMapDescr_init(&mapDescrPrev, FDK_mapInfoTabWg4, + FDK_mapInfoTabLenWg4, 0); + FDK_chMapDescr_init(&mapDescr, FDK_mapInfoTabWg4, + FDK_mapInfoTabLenWg4, 0); + } else { + FDK_chMapDescr_init(&mapDescrPrev, NULL, 0, + (channelOrder == CH_ORDER_MPEG) ? 1 : 0); + FDK_chMapDescr_init(&mapDescr, NULL, 0, + (channelOrder == CH_ORDER_MPEG) ? 1 : 0); + } switch (channelMode) { case MODE_1: diff --git a/libFDK/include/FDK_archdef.h b/libFDK/include/FDK_archdef.h index 3d0cddf..2ece9a4 100644 --- a/libFDK/include/FDK_archdef.h +++ b/libFDK/include/FDK_archdef.h @@ -114,10 +114,14 @@ amm-info@iis.fraunhofer.de #define __x86__ #endif -#if defined(_M_ARM) && !defined(__arm__) || defined(__aarch64__) +#if defined(_M_ARM) && !defined(__arm__) || defined(__aarch64__) || defined(_M_ARM64) #define __arm__ #endif +#if defined(_ARCH_PPC) && !defined(__powerpc__) +#define __powerpc__ 1 +#endif + #if (__TARGET_ARCH_ARM == 5) || defined(__TARGET_FEATURE_DSPMUL) || \ (_M_ARM == 5) || defined(__ARM_ARCH_5TEJ__) || defined(__ARM_ARCH_7EM__) /* Define __ARM_ARCH_5TE__ if armv5te features are supported */ @@ -158,12 +162,11 @@ amm-info@iis.fraunhofer.de #define __ARM_ARCH_7EM__ #endif -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(_M_ARM64) #define __ARM_ARCH_8__ #endif #ifdef _M_ARM -#include "cmnintrin.h" #include "armintr.h" #endif @@ -226,6 +229,9 @@ amm-info@iis.fraunhofer.de #define LDCOEFF_16BIT #define WINDOWTABLE_16BIT +#elif defined(__powerpc__) +#define ARCH_PREFER_MULT_32x32 + #else #warning >>>> Please set architecture characterization defines for your platform (FDK_HIGH_PERFORMANCE)! <<<< diff --git a/libFDK/include/clz.h b/libFDK/include/clz.h index 6acdee6..df75618 100644 --- a/libFDK/include/clz.h +++ b/libFDK/include/clz.h @@ -115,6 +115,9 @@ amm-info@iis.fraunhofer.de #elif defined(__x86__) #include "x86/clz_x86.h" +#elif defined(__powerpc__) +#include "ppc/clz_ppc.h" + #endif /* all cores */ /************************************************************************* diff --git a/libFDK/include/common_fix.h b/libFDK/include/common_fix.h index 8d0dfde..7c08225 100644 --- a/libFDK/include/common_fix.h +++ b/libFDK/include/common_fix.h @@ -406,10 +406,6 @@ FDK_INLINE FIXP_SGL fMax(FIXP_SGL a, FIXP_SGL b) { return fixmax_S(a, b); } #if !defined(__LP64__) FDK_INLINE INT fMax(INT a, INT b) { return fixmax_I(a, b); } FDK_INLINE INT fMin(INT a, INT b) { return fixmin_I(a, b); } -#if !defined(_MSC_VER) && defined(__x86_64__) -FDK_INLINE SHORT fMax(SHORT a, SHORT b) { return fixmax_S(a, b); } -FDK_INLINE SHORT fMin(SHORT a, SHORT b) { return fixmin_S(a, b); } -#endif #endif inline UINT fMax(UINT a, UINT b) { return fixmax_UI(a, b); } diff --git a/libFDK/include/fft.h b/libFDK/include/fft.h index 3576ed3..4ef62b4 100644 --- a/libFDK/include/fft.h +++ b/libFDK/include/fft.h @@ -139,7 +139,7 @@ void ifft(int length, FIXP_DBL *pInput, INT *scalefactor); * bit scale headroom. The values are interleaved, real/imag pairs. */ LNK_SECTION_CODE_L1 -static void FDK_FORCEINLINE fft_4(FIXP_DBL *x) { +static inline void fft_4(FIXP_DBL *x) { FIXP_DBL a00, a10, a20, a30, tmp0, tmp1; a00 = (x[0] + x[4]) >> 1; /* Re A + Re B */ @@ -168,7 +168,7 @@ static void FDK_FORCEINLINE fft_4(FIXP_DBL *x) { #ifndef FUNCTION_fft_8 LNK_SECTION_CODE_L1 -static void FDK_FORCEINLINE fft_8(FIXP_DBL *x) { +static inline void fft_8(FIXP_DBL *x) { FIXP_SPK w_PiFOURTH = {{FIXP_SGL(0x5A82), FIXP_SGL(0x5A82)}}; FIXP_DBL a00, a10, a20, a30; diff --git a/libFDK/include/fixmul.h b/libFDK/include/fixmul.h index a51ca0c..8eeb7ab 100644 --- a/libFDK/include/fixmul.h +++ b/libFDK/include/fixmul.h @@ -115,6 +115,9 @@ amm-info@iis.fraunhofer.de #elif defined(__x86__) #include "x86/fixmul_x86.h" +#elif defined(__powerpc__) +#include "ppc/fixmul_ppc.h" + #endif /* all cores */ /************************************************************************* diff --git a/libFDK/include/mips/abs_mips.h b/libFDK/include/mips/abs_mips.h index dbb2063..5644bc0 100644 --- a/libFDK/include/mips/abs_mips.h +++ b/libFDK/include/mips/abs_mips.h @@ -107,7 +107,7 @@ amm-info@iis.fraunhofer.de #if defined(__GNUC__) && defined(__mips__) -#if defined(__mips_dsp) +#if defined(__mips_dsp) && !defined(__mips16) #define FUNCTION_fixabs_D #define FUNCTION_fixabs_I #define FUNCTION_fixabs_S diff --git a/libFDK/include/mips/cplx_mul_mips.h b/libFDK/include/mips/cplx_mul_mips.h index acae118..4ade3e5 100644 --- a/libFDK/include/mips/cplx_mul_mips.h +++ b/libFDK/include/mips/cplx_mul_mips.h @@ -103,7 +103,7 @@ amm-info@iis.fraunhofer.de #if !defined(CPLX_MUL_MIPS_H) #define CPLX_MUL_MIPS_H -#if defined(__GNUC__) && defined(__mips__) && __mips_isa_rev < 6 +#if defined(__GNUC__) && defined(__mips__) //#define FUNCTION_cplxMultDiv2_32x16 //#define FUNCTION_cplxMultDiv2_32x16X2 @@ -115,53 +115,16 @@ amm-info@iis.fraunhofer.de #if defined(FUNCTION_cplxMultDiv2_32x32X2) inline void cplxMultDiv2(FIXP_DBL *c_Re, FIXP_DBL *c_Im, FIXP_DBL a_Re, FIXP_DBL a_Im, FIXP_DBL b_Re, FIXP_DBL b_Im) { - INT result; - - __asm__( - "mult %[a_Re], %[b_Re];\n" - "msub %[a_Im], %[b_Im];\n" - "mfhi %[result];\n" - : [result] "=r"(result) - : [a_Re] "d"(a_Re), [b_Re] "d"(b_Re), [a_Im] "d"(a_Im), [b_Im] "d"(b_Im) - : "lo"); - - *c_Re = result; - - __asm__( - "mult %[a_Re], %[b_Im];\n" - "madd %[a_Im], %[b_Re];\n" - "mfhi %[result];\n" - : [result] "=r"(result) - : [a_Re] "r"(a_Re), [b_Im] "r"(b_Im), [a_Im] "r"(a_Im), [b_Re] "r"(b_Re) - : "lo"); - *c_Im = result; + *c_Re = (((long long)a_Re * (long long)b_Re) - ((long long)a_Im * (long long)b_Im))>>32; + *c_Im = (((long long)a_Re * (long long)b_Im) + ((long long)a_Im * (long long)b_Re))>>32; } #endif #if defined(FUNCTION_cplxMult_32x32X2) inline void cplxMult(FIXP_DBL *c_Re, FIXP_DBL *c_Im, FIXP_DBL a_Re, FIXP_DBL a_Im, FIXP_DBL b_Re, FIXP_DBL b_Im) { - INT result; - - __asm__( - "mult %[a_Re], %[b_Re];\n" - "msub %[a_Im], %[b_Im];\n" - "mfhi %[result];\n" - //"extr_w %[result], 31;\n" - : [result] "=r"(result) - : [a_Re] "r"(a_Re), [b_Re] "r"(b_Re), [a_Im] "r"(a_Im), [b_Im] "r"(b_Im) - : "lo"); - *c_Re = result << 1; - - __asm__( - "mult %[a_Re], %[b_Im];\n" - "madd %[a_Im], %[b_Re];\n" - "mfhi %[result];\n" - //"extr_w %[result], 31;\n" - : [result] "=r"(result) - : [a_Re] "r"(a_Re), [b_Im] "r"(b_Im), [a_Im] "r"(a_Im), [b_Re] "r"(b_Re) - : "lo"); - *c_Im = result << 1; + *c_Re = ((((long long)a_Re * (long long)b_Re) - ((long long)a_Im * (long long)b_Im))>>32)<<1; + *c_Im = ((((long long)a_Re * (long long)b_Im) + ((long long)a_Im * (long long)b_Re))>>32)<<1; } #endif diff --git a/libFDK/include/mips/scale_mips.h b/libFDK/include/mips/scale_mips.h index 3c141fc..882ef35 100644 --- a/libFDK/include/mips/scale_mips.h +++ b/libFDK/include/mips/scale_mips.h @@ -103,7 +103,7 @@ amm-info@iis.fraunhofer.de #ifndef SCALE_MIPS_H #define SCALE_MIPS_H -#if defined(__mips_dsp) +#if defined(__mips_dsp) && !defined(__mips16) /*! * diff --git a/libFDK/include/ppc/clz_ppc.h b/libFDK/include/ppc/clz_ppc.h new file mode 100644 index 0000000..bfd23c6 --- /dev/null +++ b/libFDK/include/ppc/clz_ppc.h @@ -0,0 +1,102 @@ + +/* ----------------------------------------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. + All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements +the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio. +This FDK AAC Codec software is intended to be used on a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual +audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by +independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part +of the MPEG specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer) +may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners +individually for the purpose of encoding or decoding bit streams in products that are compliant with +the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license +these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec +software may already be covered under those patent licenses when it is used for those licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality, +are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional +applications information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, are permitted without +payment of copyright license fees provided that you satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of the FDK AAC Codec or +your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation and/or other materials +provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form. +You must make available free of charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived from this library without +prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec +software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software +and the date of any change. For modified versions of the FDK AAC Codec, the term +"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term +"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer, +ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with +respect to this software. + +You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized +by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors +"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties +of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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), arising in any way out of the use of this software, even if +advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------------------------------------- */ + +/*************************** Fraunhofer IIS FDK Tools ********************** + + Author(s): + Description: fixed point intrinsics + +******************************************************************************/ + +#if defined(__powerpc__) && (defined(__GNUC__) || defined(__xlC__)) + +#define FUNCTION_fixnormz_D + +inline INT fixnormz_D(LONG value) +{ + INT result; + __asm__ ("cntlzw %0, %1" : "=r" (result) : "r" (value)); + return result; +} + +#endif /* __powerpc__ && (__GNUC__ || __xlC__) */ diff --git a/libFDK/include/ppc/fixmul_ppc.h b/libFDK/include/ppc/fixmul_ppc.h new file mode 100644 index 0000000..9e2745c --- /dev/null +++ b/libFDK/include/ppc/fixmul_ppc.h @@ -0,0 +1,115 @@ + +/* ----------------------------------------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. + All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements +the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio. +This FDK AAC Codec software is intended to be used on a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual +audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by +independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part +of the MPEG specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer) +may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners +individually for the purpose of encoding or decoding bit streams in products that are compliant with +the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license +these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec +software may already be covered under those patent licenses when it is used for those licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality, +are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional +applications information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, are permitted without +payment of copyright license fees provided that you satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of the FDK AAC Codec or +your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation and/or other materials +provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form. +You must make available free of charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived from this library without +prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec +software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software +and the date of any change. For modified versions of the FDK AAC Codec, the term +"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term +"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer, +ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with +respect to this software. + +You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized +by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors +"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties +of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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), arising in any way out of the use of this software, even if +advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------------------------------------- */ + +/*************************** Fraunhofer IIS FDK Tools ********************** + + Author(s): + Description: fixed point intrinsics + +******************************************************************************/ + +#if defined(__powerpc__) && (defined(__GNUC__) || defined(__xlC__)) + +#define FUNCTION_fixmuldiv2_DD + +#define FUNCTION_fixmuldiv2BitExact_DD +#define fixmuldiv2BitExact_DD(a,b) fixmuldiv2_DD(a,b) + +#define FUNCTION_fixmulBitExact_DD +#define fixmulBitExact_DD(a,b) fixmul_DD(a,b) + +#define FUNCTION_fixmuldiv2BitExact_DS +#define fixmuldiv2BitExact_DS(a,b) fixmuldiv2_DS(a,b) + +#define FUNCTION_fixmulBitExact_DS +#define fixmulBitExact_DS(a,b) fixmul_DS(a,b) + + +inline INT fixmuldiv2_DD (const INT a, const INT b) +{ + INT result; + __asm__ ("mulhw %0, %1, %2" : "=r" (result) : "r" (a), "r" (b)); + return result; +} + +#endif /* __powerpc__ && (__GNUC__ || __xlC__) */ diff --git a/libFDK/include/scramble.h b/libFDK/include/scramble.h index f07ebed..e7cead9 100644 --- a/libFDK/include/scramble.h +++ b/libFDK/include/scramble.h @@ -108,7 +108,7 @@ amm-info@iis.fraunhofer.de #if defined(__arm__) #include "arm/scramble_arm.h" -#elif defined(__mips__) && defined(__mips_dsp) +#elif defined(__mips__) && defined(__mips_dsp) && !defined(__mips16) #include "mips/scramble_mips.h" #endif diff --git a/libFDK/src/fft.cpp b/libFDK/src/fft.cpp index 4e6fdd2..c9ee784 100644 --- a/libFDK/src/fft.cpp +++ b/libFDK/src/fft.cpp @@ -170,7 +170,7 @@ amm-info@iis.fraunhofer.de /* Performs the FFT of length 2. Input vector unscaled, output vector scaled * with factor 0.5 */ -static FDK_FORCEINLINE void fft2(FIXP_DBL *RESTRICT pDat) { +static inline void fft2(FIXP_DBL *RESTRICT pDat) { FIXP_DBL r1, i1; FIXP_DBL r2, i2; @@ -196,7 +196,7 @@ static FDK_FORCEINLINE void fft2(FIXP_DBL *RESTRICT pDat) { #ifndef FUNCTION_fft3 /* Performs the FFT of length 3 according to the algorithm after winograd. */ -static FDK_FORCEINLINE void fft3(FIXP_DBL *RESTRICT pDat) { +static inline void fft3(FIXP_DBL *RESTRICT pDat) { FIXP_DBL r1, r2; FIXP_DBL s1, s2; FIXP_DBL pD; @@ -233,7 +233,7 @@ static FDK_FORCEINLINE void fft3(FIXP_DBL *RESTRICT pDat) { /* performs the FFT of length 5 according to the algorithm after winograd */ /* This version works with a prescale of 2 instead of 3 */ -static FDK_FORCEINLINE void fft5(FIXP_DBL *RESTRICT pDat) { +static inline void fft5(FIXP_DBL *RESTRICT pDat) { FIXP_DBL r1, r2, r3, r4; FIXP_DBL s1, s2, s3, s4; FIXP_DBL t; diff --git a/libFDK/src/fft_rad2.cpp b/libFDK/src/fft_rad2.cpp index 27f3aa0..f457f8b 100644 --- a/libFDK/src/fft_rad2.cpp +++ b/libFDK/src/fft_rad2.cpp @@ -109,7 +109,7 @@ amm-info@iis.fraunhofer.de #if defined(__arm__) #include "arm/fft_rad2_arm.cpp" -#elif defined(__GNUC__) && defined(__mips__) && defined(__mips_dsp) +#elif defined(__GNUC__) && defined(__mips__) && defined(__mips_dsp) && !defined(__mips16) #include "mips/fft_rad2_mips.cpp" #endif diff --git a/libFDK/src/mips/scale_mips.cpp b/libFDK/src/mips/scale_mips.cpp index 1a3d33c..ff295d9 100644 --- a/libFDK/src/mips/scale_mips.cpp +++ b/libFDK/src/mips/scale_mips.cpp @@ -100,7 +100,7 @@ amm-info@iis.fraunhofer.de *******************************************************************************/ -#if defined(__mips_dsp) +#if defined(__mips_dsp) && !defined(__mips16) #ifndef FUNCTION_getScalefactor_DBL #define FUNCTION_getScalefactor_DBL diff --git a/libSBRdec/src/hbe.cpp b/libSBRdec/src/hbe.cpp index f2452ea..9485823 100644 --- a/libSBRdec/src/hbe.cpp +++ b/libSBRdec/src/hbe.cpp @@ -641,7 +641,7 @@ static const FIXP_DBL invCubeRootCorrection[3] = {0x40000000, 0x50A28BE6, */ static #ifdef __arm__ - FIXP_DBL __attribute__((always_inline)) + FIXP_DBL FDK_FORCEINLINE invCubeRootNorm2(FIXP_DBL op_m, INT* op_e) #else FIXP_DBL @@ -763,7 +763,7 @@ static const FIXP_DBL invFourthRootCorrection[4] = {0x40000000, 0x4C1BF829, static #ifdef __arm__ - FIXP_DBL __attribute__((always_inline)) + FIXP_DBL FDK_FORCEINLINE invFourthRootNorm2(FIXP_DBL op_m, INT* op_e) #else FIXP_DBL @@ -879,7 +879,7 @@ static const FIXP_DBL inv3EigthRootCorrection[8] = { static #ifdef __arm__ - FIXP_DBL __attribute__((always_inline)) + FIXP_DBL FDK_FORCEINLINE inv3EigthRootNorm2(FIXP_DBL op_m, INT* op_e) #else FIXP_DBL diff --git a/libSYS/include/machine_type.h b/libSYS/include/machine_type.h index b66d5ad..bd97669 100644 --- a/libSYS/include/machine_type.h +++ b/libSYS/include/machine_type.h @@ -382,13 +382,22 @@ it. Hence, a fully platform-independant way to use alignment is not supported. /************************************************** * Macros regarding static code analysis **************************************************/ -#if defined(__clang__) +#ifdef __cplusplus +#if !defined(__has_cpp_attribute) +#define __has_cpp_attribute(x) 0 +#endif +#if defined(__clang__) && __has_cpp_attribute(clang::fallthrough) #define FDK_FALLTHROUGH [[clang::fallthrough]] -#elif defined(__GNUC__) && (__GNUC__ >= 7) +#endif +#endif + +#ifndef FDK_FALLTHROUGH +#if defined(__GNUC__) && (__GNUC__ >= 7) #define FDK_FALLTHROUGH __attribute__((fallthrough)) #else #define FDK_FALLTHROUGH #endif +#endif #ifdef _MSC_VER /* diff --git a/libSYS/include/syslib_channelMapDescr.h b/libSYS/include/syslib_channelMapDescr.h index 1c5737a..375a24d 100644 --- a/libSYS/include/syslib_channelMapDescr.h +++ b/libSYS/include/syslib_channelMapDescr.h @@ -189,6 +189,12 @@ UCHAR FDK_chMapDescr_getMapValue(const FDK_channelMapDescr* const pMapDescr, */ int FDK_chMapDescr_isValid(const FDK_channelMapDescr* const pMapDescr); +/** + * Extra variables for setting up Wg4 channel mapping. + */ +extern const CHANNEL_MAP_INFO FDK_mapInfoTabWg4[]; +extern const UINT FDK_mapInfoTabLenWg4; + #ifdef __cplusplus } #endif diff --git a/libSYS/src/syslib_channelMapDescr.cpp b/libSYS/src/syslib_channelMapDescr.cpp index e011f25..d22a30d 100644 --- a/libSYS/src/syslib_channelMapDescr.cpp +++ b/libSYS/src/syslib_channelMapDescr.cpp @@ -155,6 +155,37 @@ static const CHANNEL_MAP_INFO mapInfoTabDflt[DFLT_CH_MAP_TAB_LEN] = /* 13 */ {mapCfg13, 24}, /* 14 */ {mapCfg14, 8}}; + +static const UCHAR mapWg4Cfg1[] = {0, 1}; +static const UCHAR mapWg4Cfg2[] = {0, 1}; +static const UCHAR mapWg4Cfg3[] = {2, 0, 1}; +static const UCHAR mapWg4Cfg4[] = {3, 0, 1, 2}; +static const UCHAR mapWg4Cfg5[] = {4, 0, 1, 2, 3}; +static const UCHAR mapWg4Cfg6[] = {4, 0, 1, 2, 3, 5}; +static const UCHAR mapWg4Cfg7[] = {6, 0, 1, 2, 3, 4, 5, 7}; +static const UCHAR mapWg4Cfg14[] = {6, 0, 1, 2, 3, 4, 5, 7}; + +const CHANNEL_MAP_INFO FDK_mapInfoTabWg4[] = + {/* chCfg, map, numCh */ + /* 0 */ {mapFallback, 24}, + /* 1 */ {mapWg4Cfg1, 2}, + /* 2 */ {mapWg4Cfg2, 2}, + /* 3 */ {mapWg4Cfg3, 3}, + /* 4 */ {mapWg4Cfg4, 4}, + /* 5 */ {mapWg4Cfg5, 5}, + /* 6 */ {mapWg4Cfg6, 6}, + /* 7 */ {mapWg4Cfg7, 8}, + /* 8 */ {mapFallback, 24}, + /* 9 */ {mapFallback, 24}, + /* 10 */ {mapFallback, 24}, + /* 11 */ {mapFallback, 24}, // Unhandled for Wg4 yet + /* 12 */ {mapFallback, 24}, // Unhandled for Wg4 yet + /* 13 */ {mapFallback, 24}, // Unhandled for Wg4 yet + /* 14 */ {mapFallback, 24}}; // Unhandled for Wg4 yet + +const UINT FDK_mapInfoTabLenWg4 = sizeof(FDK_mapInfoTabWg4)/sizeof(FDK_mapInfoTabWg4[0]); + + /** * Get the mapping value for a specific channel and map index. */ diff --git a/m4/.gitkeep b/m4/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/m4/.gitkeep @@ -0,0 +1,399 @@ +/*! + * \copy + * Copyright (c) 1998, 2009 Paul E. Jones <paulej@packetizer.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER 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. + * + */ + +/* + * Description: + * This file implements the Secure Hashing Standard as defined + * in FIPS PUB 180-1 published April 17, 1995. + * + * The Secure Hashing Standard, which uses the Secure Hashing + * Algorithm (SHA), produces a 160-bit message digest for a + * given data stream. In theory, it is highly improbable that + * two messages will produce the same message digest. Therefore, + * this algorithm can serve as a means of providing a "fingerprint" + * for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code was + * written with the expectation that the processor has at least + * a 32-bit machine word size. If the machine word size is larger, + * the code should still function properly. One caveat to that + * is that the input functions taking characters and character + * arrays assume that only 8 bits of information are stored in each + * character. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated for + * messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is a + * multiple of the size of an 8-bit character. + * + */ + +#include "sha1.h" + +/* + * Define the circular shift macro + */ +#define SHA1CircularShift(bits,word) \ + ((((word) << (bits)) & 0xFFFFFFFF) | \ + ((word) >> (32-(bits)))) + +/* Function prototypes */ +void SHA1ProcessMessageBlock(SHA1Context *); +void SHA1PadMessage(SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1Reset(SHA1Context *context) +{ + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Message_Digest[0] = 0x67452301; + context->Message_Digest[1] = 0xEFCDAB89; + context->Message_Digest[2] = 0x98BADCFE; + context->Message_Digest[3] = 0x10325476; + context->Message_Digest[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * digest array provided as a parameter. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * digest: [out] + * An array of characters where the digest is written. + * + * Returns: + * 1 if successful, 0 if it failed. + * + * Comments: + * + */ +int SHA1Result(SHA1Context *context, unsigned char *digest) +{ + int i; + + if (context->Corrupted) + { + return 0; + } + + if (!context->Computed) + { + SHA1PadMessage(context); + context->Computed = 1; + } + + for (i = 0; i < SHA_DIGEST_LENGTH; i++) + digest[i] = context->Message_Digest[i / 4] >> (8 * (3 - (i % 4))); + + return 1; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion of + * the message. + * + * Parameters: + * context: [in/out] + * The SHA-1 context to update + * message_array: [in] + * An array of characters representing the next portion of the + * message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1Input( SHA1Context *context, + const unsigned char *message_array, + unsigned length) +{ + if (!length) + { + return; + } + + if (context->Computed || context->Corrupted) + { + context->Corrupted = 1; + return; + } + + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + context->Length_Low += 8; + /* Force it to 32 bits */ + context->Length_Low &= 0xFFFFFFFF; + if (context->Length_Low == 0) + { + context->Length_High++; + /* Force it to 32 bits */ + context->Length_High &= 0xFFFFFFFF; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in the SHAContext, especially the + * single character names, were used because those were the names + * used in the publication. + * + * + */ +void SHA1ProcessMessageBlock(SHA1Context *context) +{ + const unsigned K[] = /* Constants defined in SHA-1 */ + { + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + unsigned temp; /* Temporary word value */ + unsigned W[80]; /* Word sequence */ + unsigned A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = ((unsigned) context->Message_Block[t * 4]) << 24; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]); + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Message_Digest[0]; + B = context->Message_Digest[1]; + C = context->Message_Digest[2]; + D = context->Message_Digest[3]; + E = context->Message_Digest[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Message_Digest[0] = + (context->Message_Digest[0] + A) & 0xFFFFFFFF; + context->Message_Digest[1] = + (context->Message_Digest[1] + B) & 0xFFFFFFFF; + context->Message_Digest[2] = + (context->Message_Digest[2] + C) & 0xFFFFFFFF; + context->Message_Digest[3] = + (context->Message_Digest[3] + D) & 0xFFFFFFFF; + context->Message_Digest[4] = + (context->Message_Digest[4] + E) & 0xFFFFFFFF; + + context->Message_Block_Index = 0; +} + +/* + * SHA1PadMessage + * + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call SHA1ProcessMessageBlock() + * appropriately. When it returns, it can be assumed that the + * message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (context->Length_High >> 24) & 0xFF; + context->Message_Block[57] = (context->Length_High >> 16) & 0xFF; + context->Message_Block[58] = (context->Length_High >> 8) & 0xFF; + context->Message_Block[59] = (context->Length_High) & 0xFF; + context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF; + context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF; + context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF; + context->Message_Block[63] = (context->Length_Low) & 0xFF; + + SHA1ProcessMessageBlock(context); +} @@ -0,0 +1,85 @@ +/*! + * \copy + * Copyright (c) 1998, 2009 Paul E. Jones <paulej@packetizer.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER 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. + * + */ + +/* + * Description: + * This class implements the Secure Hashing Standard as defined + * in FIPS PUB 180-1 published April 17, 1995. + * + * Many of the variable names in the SHA1Context, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure will hold context information for the hashing + * operation + */ +typedef struct SHA1Context { + unsigned Message_Digest[5]; /* Message Digest (output) */ + + unsigned Length_Low; /* Message length in bits */ + unsigned Length_High; /* Message length in bits */ + + unsigned char Message_Block[64]; /* 512-bit message blocks */ + int Message_Block_Index; /* Index into message block array */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corruped? */ +} SHA1Context; + +/* + * Function Prototypes + */ +void SHA1Reset (SHA1Context*); +int SHA1Result (SHA1Context*, unsigned char*); +void SHA1Input (SHA1Context*, + const unsigned char*, + unsigned); + +#define SHA_DIGEST_LENGTH 20 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test-encode-decode.c b/test-encode-decode.c new file mode 100644 index 0000000..a216c18 --- /dev/null +++ b/test-encode-decode.c @@ -0,0 +1,383 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2017 Martin Storsjo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include "aacenc_lib.h" +#include "aacdecoder_lib.h" +#include "wavreader.h" +#include "sha1.h" + + +static int encoder_input_samples, encoder_input_size; +static int decoder_output_skip; +static int16_t *encoder_input; +static int max_diff; +static uint64_t diff_sum, diff_samples; +static SHA1Context encode_hash, decode_hash; + +static void init_encoder_input(void) { + encoder_input_samples = 0; + max_diff = 0; + diff_sum = diff_samples = 0; +} + +static void free_encoder_input(void) { + free(encoder_input); + encoder_input = NULL; + encoder_input_size = 0; +} + +static void append_encoder_input(const int16_t *input, int samples) { + if (encoder_input_samples + samples > encoder_input_size) { + int size = 2*(encoder_input_samples + samples); + int16_t *ptr = realloc(encoder_input, size * sizeof(*encoder_input)); + if (!ptr) + abort(); + encoder_input = ptr; + encoder_input_size = size; + } + memcpy(encoder_input + encoder_input_samples, input, samples * sizeof(*input)); + encoder_input_samples += samples; +} + +static void compare_decoder_output(const int16_t *output, int samples) { + int i; + // TODO: Stereo upconvert? + SHA1Input(&decode_hash, (const unsigned char*) output, samples * sizeof(*output)); + if (decoder_output_skip > 0) { + int n = samples; + if (n > decoder_output_skip) + n = decoder_output_skip; + output += n; + samples -= n; + decoder_output_skip -= n; + if (samples <= 0) + return; + } + if (samples > encoder_input_samples) + samples = encoder_input_samples; + for (i = 0; i < samples; i++) { + int diff = abs(encoder_input[i] - output[i]); + if (diff > max_diff) + max_diff = diff; + diff_sum += diff; + diff_samples++; + } + memmove(encoder_input, encoder_input + samples, (encoder_input_samples - samples) * sizeof(*encoder_input)); + encoder_input_samples -= samples; +} + +static int decode(HANDLE_AACDECODER decoder, const uint8_t *ptr, int size, uint8_t *decoder_buffer, int decoder_buffer_size, int channels) { + AAC_DECODER_ERROR err; + CStreamInfo *info; + UINT valid, buffer_size; + SHA1Input(&encode_hash, ptr, size); + do { + valid = buffer_size = size; + err = aacDecoder_Fill(decoder, (UCHAR**) &ptr, &buffer_size, &valid); + ptr += buffer_size - valid; + size -= buffer_size - valid; + if (err == AAC_DEC_NOT_ENOUGH_BITS) + continue; + if (err != AAC_DEC_OK) + break; + err = aacDecoder_DecodeFrame(decoder, (INT_PCM *) decoder_buffer, decoder_buffer_size / sizeof(INT_PCM), 0); + if (!ptr && err != AAC_DEC_OK) + break; + if (err == AAC_DEC_NOT_ENOUGH_BITS) + continue; + if (err != AAC_DEC_OK) { + fprintf(stderr, "Decoding failed\n"); + return 1; + } + info = aacDecoder_GetStreamInfo(decoder); + if (info->numChannels != channels) { + fprintf(stderr, "Mismatched number of channels, input %d, output %d\n", channels, info->numChannels); + return 1; + } + compare_decoder_output((int16_t*) decoder_buffer, info->numChannels * info->frameSize); + } while (size > 0); + return 0; +} + +static int test_encode_decode(const char *infile, int aot, int afterburner, int eld_sbr, int vbr, int bitrate, int adts) { + void *wav; + int format, sample_rate, channels, bits_per_sample; + int input_size; + uint8_t* input_buf; + int16_t* convert_buf; + HANDLE_AACENCODER encoder; + CHANNEL_MODE mode; + AACENC_InfoStruct info = { 0 }; + HANDLE_AACDECODER decoder; + int ret = 0; + int decoder_buffer_size = 2048 * 2 * 8; + uint8_t* decoder_buffer = malloc(decoder_buffer_size); + int avg_diff; + + fprintf(stderr, "Testing encoding with aot %d afterburner %d eld_sbr %d vbr %d bitrate %d adts %d\n", aot, afterburner, eld_sbr, vbr, bitrate, adts); + init_encoder_input(); + + wav = wav_read_open(infile); + if (!wav) { + fprintf(stderr, "Unable to open wav file %s\n", infile); + return 1; + } + if (!wav_get_header(wav, &format, &channels, &sample_rate, &bits_per_sample, NULL)) { + fprintf(stderr, "Bad wav file %s\n", infile); + return 1; + } + if (format != 1) { + fprintf(stderr, "Unsupported WAV format %d\n", format); + return 1; + } + if (bits_per_sample != 16) { + fprintf(stderr, "Unsupported WAV sample depth %d\n", bits_per_sample); + return 1; + } + switch (channels) { + case 1: mode = MODE_1; break; + case 2: mode = MODE_2; break; + case 3: mode = MODE_1_2; break; + case 4: mode = MODE_1_2_1; break; + case 5: mode = MODE_1_2_2; break; + case 6: mode = MODE_1_2_2_1; break; + default: + fprintf(stderr, "Unsupported WAV channels %d\n", channels); + return 1; + } + if (aacEncOpen(&encoder, 0, channels) != AACENC_OK) { + fprintf(stderr, "Unable to open encoder\n"); + return 1; + } + if (aacEncoder_SetParam(encoder, AACENC_AOT, aot) != AACENC_OK) { + fprintf(stderr, "Unable to set the AOT\n"); + return 1; + } + if (aot == 39 && eld_sbr) { + if (aacEncoder_SetParam(encoder, AACENC_SBR_MODE, 1) != AACENC_OK) { + fprintf(stderr, "Unable to set SBR mode for ELD\n"); + return 1; + } + } + if (aacEncoder_SetParam(encoder, AACENC_SAMPLERATE, sample_rate) != AACENC_OK) { + fprintf(stderr, "Unable to set the AOT\n"); + return 1; + } + if (aacEncoder_SetParam(encoder, AACENC_CHANNELMODE, mode) != AACENC_OK) { + fprintf(stderr, "Unable to set the channel mode\n"); + return 1; + } + if (aacEncoder_SetParam(encoder, AACENC_CHANNELORDER, 1) != AACENC_OK) { + fprintf(stderr, "Unable to set the wav channel order\n"); + return 1; + } + if (vbr) { + if (aacEncoder_SetParam(encoder, AACENC_BITRATEMODE, vbr) != AACENC_OK) { + fprintf(stderr, "Unable to set the VBR bitrate mode\n"); + return 1; + } + } else { + if (aacEncoder_SetParam(encoder, AACENC_BITRATE, bitrate) != AACENC_OK) { + fprintf(stderr, "Unable to set the bitrate\n"); + return 1; + } + } + if (aacEncoder_SetParam(encoder, AACENC_TRANSMUX, adts ? 2 : 0) != AACENC_OK) { + fprintf(stderr, "Unable to set the ADTS transmux\n"); + return 1; + } + if (aacEncoder_SetParam(encoder, AACENC_AFTERBURNER, afterburner) != AACENC_OK) { + fprintf(stderr, "Unable to set the afterburner mode\n"); + return 1; + } + if (aacEncEncode(encoder, NULL, NULL, NULL, NULL) != AACENC_OK) { + fprintf(stderr, "Unable to initialize the encoder\n"); + return 1; + } + if (aacEncInfo(encoder, &info) != AACENC_OK) { + fprintf(stderr, "Unable to get the encoder info\n"); + return 1; + } + + input_size = channels*2*info.frameLength; + input_buf = (uint8_t*) malloc(input_size); + convert_buf = (int16_t*) malloc(input_size); + + decoder_output_skip = channels * info.nDelay; + + decoder = aacDecoder_Open(adts ? TT_MP4_ADTS : TT_MP4_RAW, 1); + if (!adts) { + UCHAR *bufArray[] = { info.confBuf }; + if (aacDecoder_ConfigRaw(decoder, (UCHAR**) bufArray, &info.confSize) != AAC_DEC_OK) { + fprintf(stderr, "Unable to set ASC\n"); + ret = 1; + goto end; + } + } + aacDecoder_SetParam(decoder, AAC_CONCEAL_METHOD, 1); + aacDecoder_SetParam(decoder, AAC_PCM_LIMITER_ENABLE, 0); + while (1) { + AACENC_BufDesc in_buf = { 0 }, out_buf = { 0 }; + AACENC_InArgs in_args = { 0 }; + AACENC_OutArgs out_args = { 0 }; + int in_identifier = IN_AUDIO_DATA; + int in_size, in_elem_size; + int out_identifier = OUT_BITSTREAM_DATA; + int out_size, out_elem_size; + int read, i; + void *in_ptr, *out_ptr; + uint8_t outbuf[20480]; + AACENC_ERROR err; + + read = wav_read_data(wav, input_buf, input_size); + for (i = 0; i < read/2; i++) { + const uint8_t* in = &input_buf[2*i]; + convert_buf[i] = in[0] | (in[1] << 8); + } + in_ptr = convert_buf; + in_size = read; + in_elem_size = 2; + + in_buf.numBufs = 1; + in_buf.bufs = &in_ptr; + in_buf.bufferIdentifiers = &in_identifier; + in_buf.bufSizes = &in_size; + in_buf.bufElSizes = &in_elem_size; + + if (read <= 0) { + in_args.numInSamples = -1; + } else { + in_args.numInSamples = read/2; + append_encoder_input(convert_buf, in_args.numInSamples); + } + out_ptr = outbuf; + out_size = sizeof(outbuf); + out_elem_size = 1; + out_buf.numBufs = 1; + out_buf.bufs = &out_ptr; + out_buf.bufferIdentifiers = &out_identifier; + out_buf.bufSizes = &out_size; + out_buf.bufElSizes = &out_elem_size; + + if ((err = aacEncEncode(encoder, &in_buf, &out_buf, &in_args, &out_args)) != AACENC_OK) { + if (err == AACENC_ENCODE_EOF) + break; + fprintf(stderr, "Encoding failed\n"); + ret = 1; + goto end; + } + if (out_args.numOutBytes == 0) + continue; + + if (decode(decoder, outbuf, out_args.numOutBytes, decoder_buffer, decoder_buffer_size, channels)) { + ret = 1; + goto end; + } + } + + if (encoder_input_samples > 0) { + fprintf(stderr, "%d unmatched samples left at the end\n", encoder_input_samples); + ret = 1; + goto end; + } + avg_diff = 0; + if (diff_samples > 0) + avg_diff = diff_sum / diff_samples; + if (/*max_diff > 10000 ||*/ avg_diff > ((aot == 23) ? 2500 : (aot == 29) ? 1500 : 300)) { + fprintf(stderr, "max_diff %d, avg_diff %d\n", max_diff, avg_diff); + ret = 1; + goto end; + } + +end: + free(input_buf); + free(convert_buf); + wav_read_close(wav); + aacEncClose(&encoder); + free(decoder_buffer); + aacDecoder_Close(decoder); + + return ret; +} + +int main(int argc, char *argv[]) { + const char* infile; + void *wav; + int sample_rate, channels; + int failures = 0; + int i; + unsigned char encode_digest[SHA_DIGEST_LENGTH], decode_digest[SHA_DIGEST_LENGTH]; + if (argc < 2) { + printf("%s input.wav\n", argv[0]); + return 1; + } + infile = argv[1]; + + wav = wav_read_open(infile); + if (!wav) { + fprintf(stderr, "Unable to open wav file %s\n", infile); + return 1; + } + if (!wav_get_header(wav, NULL, &channels, &sample_rate, NULL, NULL)) { + fprintf(stderr, "Bad wav file %s\n", infile); + return 1; + } + wav_read_close(wav); + + SHA1Reset(&encode_hash); + SHA1Reset(&decode_hash); + + failures += test_encode_decode(infile, 2, 0, 0, 0, 64000, 0); // AAC-LC, without afterburner + for (i = 0; i < 2; i++) + failures += test_encode_decode(infile, 2, 1, 0, 0, 64000, i); // AAC-LC + for (i = 1; i <= 5; i++) + failures += test_encode_decode(infile, 2, 1, 0, i, 0, 0); // AAC-LC VBR + if (channels == 2) { + // HE-AACv2 only works for stereo; HE-AACv1 gets upconverted to stereo (which we don't match properly) + for (i = 0; i < 2; i++) + failures += test_encode_decode(infile, 5, 1, 0, 0, 64000, i); // HE-AAC + for (i = 1; i <= 5; i++) + failures += test_encode_decode(infile, 5, 1, 0, i, 0, 0); // HE-AAC VBR + for (i = 0; i < 2; i++) + failures += test_encode_decode(infile, 29, 1, 0, 0, 64000, i); // HE-AACv2 + for (i = 1; i <= 5; i++) + failures += test_encode_decode(infile, 29, 1, 0, i, 0, 0); // HE-AACv2 VBR + } + if (channels == 1) + failures += test_encode_decode(infile, 23, 1, 0, 0, 64000, 0); // AAC-LD + failures += test_encode_decode(infile, 39, 1, 0, 0, 64000, 0); // AAC-ELD + failures += test_encode_decode(infile, 39, 1, 1, 0, 64000, 0); // AAC-ELD with SBR + + free_encoder_input(); + fprintf(stderr, "%d failures\n", failures); + SHA1Result(&encode_hash, encode_digest); + SHA1Result(&decode_hash, decode_digest); + printf("encode hash: "); + for (i = 0; i < SHA_DIGEST_LENGTH; i++) + printf("%02x", encode_digest[i]); + printf("\n"); + printf("decode hash: "); + for (i = 0; i < SHA_DIGEST_LENGTH; i++) + printf("%02x", decode_digest[i]); + printf("\n"); + return failures; +} diff --git a/test/ref-mono.txt b/test/ref-mono.txt new file mode 100644 index 0000000..22a84f2 --- /dev/null +++ b/test/ref-mono.txt @@ -0,0 +1,2 @@ +encode hash: 516e51016cbba6068f1aa285a8fdd55b00ada6b0 +decode hash: 3b3b3a17cc5ba50ade75b3ef1a37f96017935fe5 diff --git a/test/ref-stereo.txt b/test/ref-stereo.txt new file mode 100644 index 0000000..3de5276 --- /dev/null +++ b/test/ref-stereo.txt @@ -0,0 +1,2 @@ +encode hash: 1179940ca3a5c62de45b6823efbdbe42fce11de2 +decode hash: 85f2a154b46cc6cfa2792ff95c67b4200ce4463b diff --git a/test/run-test.sh b/test/run-test.sh new file mode 100755 index 0000000..b2ef548 --- /dev/null +++ b/test/run-test.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +set -e +set -o pipefail + +if [ ! -f Sample01_4.wav ]; then + curl -LO https://media.xiph.org/audio/HA_2011/Sample01_4.wav +fi + +if [ "$(md5sum Sample01_4.wav | awk '{print $1}')" != "a5c105544c64ce92c6c5c06d280e6b9c" ]; then + echo Incorrect checksum for Sample01_4.wav + exit 1 +fi + +if [ ! -f Sample01_4-mono.wav ]; then + ffmpeg -i Sample01_4.wav -ac 1 -fflags +bitexact -y Sample01_4-mono.wav +fi + +if [ "$(md5sum Sample01_4-mono.wav | awk '{print $1}')" != "3bfccac9f2e527ba3ef888874f09a409" ]; then + echo Incorrect checksum for Sample01_4-mono.wav + exit 1 +fi + +./test-encode-decode Sample01_4.wav | tee log-stereo.txt +./test-encode-decode Sample01_4-mono.wav | tee log-mono.txt + +diff -u log-stereo.txt $(dirname $0)/ref-stereo.txt +diff -u log-mono.txt $(dirname $0)/ref-mono.txt diff --git a/wavreader.c b/wavreader.c new file mode 100644 index 0000000..898eb9c --- /dev/null +++ b/wavreader.c @@ -0,0 +1,193 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2009 Martin Storsjo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#include "wavreader.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +#define TAG(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) + +struct wav_reader { + FILE *wav; + uint32_t data_length; + + int format; + int sample_rate; + int bits_per_sample; + int channels; + int byte_rate; + int block_align; + + int streamed; +}; + +static uint32_t read_tag(struct wav_reader* wr) { + uint32_t tag = 0; + tag = (tag << 8) | fgetc(wr->wav); + tag = (tag << 8) | fgetc(wr->wav); + tag = (tag << 8) | fgetc(wr->wav); + tag = (tag << 8) | fgetc(wr->wav); + return tag; +} + +static uint32_t read_int32(struct wav_reader* wr) { + uint32_t value = 0; + value |= fgetc(wr->wav) << 0; + value |= fgetc(wr->wav) << 8; + value |= fgetc(wr->wav) << 16; + value |= fgetc(wr->wav) << 24; + return value; +} + +static uint16_t read_int16(struct wav_reader* wr) { + uint16_t value = 0; + value |= fgetc(wr->wav) << 0; + value |= fgetc(wr->wav) << 8; + return value; +} + +static void skip(FILE *f, int n) { + int i; + for (i = 0; i < n; i++) + fgetc(f); +} + +void* wav_read_open(const char *filename) { + struct wav_reader* wr = (struct wav_reader*) malloc(sizeof(*wr)); + long data_pos = 0; + memset(wr, 0, sizeof(*wr)); + + if (!strcmp(filename, "-")) + wr->wav = stdin; + else + wr->wav = fopen(filename, "rb"); + if (wr->wav == NULL) { + free(wr); + return NULL; + } + + while (1) { + uint32_t tag, tag2, length; + tag = read_tag(wr); + if (feof(wr->wav)) + break; + length = read_int32(wr); + if (!length || length >= 0x7fff0000) { + wr->streamed = 1; + length = ~0; + } + if (tag != TAG('R', 'I', 'F', 'F') || length < 4) { + fseek(wr->wav, length, SEEK_CUR); + continue; + } + tag2 = read_tag(wr); + length -= 4; + if (tag2 != TAG('W', 'A', 'V', 'E')) { + fseek(wr->wav, length, SEEK_CUR); + continue; + } + // RIFF chunk found, iterate through it + while (length >= 8) { + uint32_t subtag, sublength; + subtag = read_tag(wr); + if (feof(wr->wav)) + break; + sublength = read_int32(wr); + length -= 8; + if (length < sublength) + break; + if (subtag == TAG('f', 'm', 't', ' ')) { + if (sublength < 16) { + // Insufficient data for 'fmt ' + break; + } + wr->format = read_int16(wr); + wr->channels = read_int16(wr); + wr->sample_rate = read_int32(wr); + wr->byte_rate = read_int32(wr); + wr->block_align = read_int16(wr); + wr->bits_per_sample = read_int16(wr); + if (wr->format == 0xfffe) { + if (sublength < 28) { + // Insufficient data for waveformatex + break; + } + skip(wr->wav, 8); + wr->format = read_int32(wr); + skip(wr->wav, sublength - 28); + } else { + skip(wr->wav, sublength - 16); + } + } else if (subtag == TAG('d', 'a', 't', 'a')) { + data_pos = ftell(wr->wav); + wr->data_length = sublength; + if (!wr->data_length || wr->streamed) { + wr->streamed = 1; + return wr; + } + fseek(wr->wav, sublength, SEEK_CUR); + } else { + skip(wr->wav, sublength); + } + length -= sublength; + } + if (length > 0) { + // Bad chunk? + fseek(wr->wav, length, SEEK_CUR); + } + } + fseek(wr->wav, data_pos, SEEK_SET); + return wr; +} + +void wav_read_close(void* obj) { + struct wav_reader* wr = (struct wav_reader*) obj; + if (wr->wav != stdin) + fclose(wr->wav); + free(wr); +} + +int wav_get_header(void* obj, int* format, int* channels, int* sample_rate, int* bits_per_sample, unsigned int* data_length) { + struct wav_reader* wr = (struct wav_reader*) obj; + if (format) + *format = wr->format; + if (channels) + *channels = wr->channels; + if (sample_rate) + *sample_rate = wr->sample_rate; + if (bits_per_sample) + *bits_per_sample = wr->bits_per_sample; + if (data_length) + *data_length = wr->data_length; + return wr->format && wr->sample_rate; +} + +int wav_read_data(void* obj, unsigned char* data, unsigned int length) { + struct wav_reader* wr = (struct wav_reader*) obj; + int n; + if (wr->wav == NULL) + return -1; + if (length > wr->data_length && !wr->streamed) + length = wr->data_length; + n = fread(data, 1, length, wr->wav); + wr->data_length -= length; + return n; +} + diff --git a/wavreader.h b/wavreader.h new file mode 100644 index 0000000..57a13ff --- /dev/null +++ b/wavreader.h @@ -0,0 +1,37 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2009 Martin Storsjo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#ifndef WAVREADER_H +#define WAVREADER_H + +#ifdef __cplusplus +extern "C" { +#endif + +void* wav_read_open(const char *filename); +void wav_read_close(void* obj); + +int wav_get_header(void* obj, int* format, int* channels, int* sample_rate, int* bits_per_sample, unsigned int* data_length); +int wav_read_data(void* obj, unsigned char* data, unsigned int length); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/win32/getopt.h b/win32/getopt.h new file mode 100644 index 0000000..7402521 --- /dev/null +++ b/win32/getopt.h @@ -0,0 +1,904 @@ +#ifndef __GETOPT_H__ +/** + * DISCLAIMER + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * + * The mingw-w64 runtime package and its code is distributed in the hope that it + * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR + * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to + * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ +/* + * Implementation of the `getopt', `getopt_long' and `getopt_long_only' + * APIs, for inclusion in the MinGW runtime library. + * + * This file is part of the MinGW32 package set. + * + * Written by Keith Marshall <keithmarshall@users.sourceforge.net> + * Copyright (C) 2008, 2009, 2011, 2012, MinGW.org Project. + * + * --------------------------------------------------------------------------- + * + * 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, this permission notice, and the following + * disclaimer 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. + * + * --------------------------------------------------------------------------- + * + */ + +#define __GETOPT_H__ + +/* All the headers include this file. */ +#include <crtdefs.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern int optind; /* index of first non-option in argv */ +extern int optopt; /* single option character, as parsed */ +extern int opterr; /* flag to enable built-in diagnostics... */ + /* (user may set to zero, to suppress) */ + +extern char *optarg; /* pointer to argument of current option */ + +/* Identify how to get the calling program name, for use in messages... + */ +#ifdef __CYGWIN__ +/* + * CYGWIN uses this DLL reference... + */ +# define PROGNAME __progname +extern char __declspec(dllimport) *__progname; +#else +/* + * ...while elsewhere, we simply use the first argument passed. + */ +# define PROGNAME *argv +#endif + +extern int getopt(int nargc, char * const *nargv, const char *options); + +#ifdef _BSD_SOURCE +/* + * BSD adds the non-standard `optreset' feature, for reinitialisation + * of `getopt' parsing. We support this feature, for applications which + * proclaim their BSD heritage, before including this header; however, + * to maintain portability, developers are advised to avoid it. + */ +# define optreset __mingw_optreset +extern int optreset; +#endif +#ifdef __cplusplus +} +#endif +/* + * POSIX requires the `getopt' API to be specified in `unistd.h'; + * thus, `unistd.h' includes this header. However, we do not want + * to expose the `getopt_long' or `getopt_long_only' APIs, when + * included in this manner. Thus, close the standard __GETOPT_H__ + * declarations block, and open an additional __GETOPT_LONG_H__ + * specific block, only when *not* __UNISTD_H_SOURCED__, in which + * to declare the extended API. + */ +#endif /* !defined(__GETOPT_H__) */ + +#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) +#define __GETOPT_LONG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct option /* specification for a long form option... */ +{ + const char *name; /* option name, without leading hyphens */ + int has_arg; /* does it take an argument? */ + int *flag; /* where to save its status, or NULL */ + int val; /* its associated status value */ +}; + +enum /* permitted values for its `has_arg' field... */ +{ + no_argument = 0, /* option never takes an argument */ + required_argument, /* option always requires an argument */ + optional_argument /* option may take an argument */ +}; + +extern int getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx); +extern int getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx); +/* + * Previous MinGW implementation had... + */ +#ifndef HAVE_DECL_GETOPT +/* + * ...for the long form API only; keep this for compatibility. + */ +# define HAVE_DECL_GETOPT 1 +#endif + + + +/* Identify how to get the calling program name, for use in messages... + */ +#ifdef __CYGWIN__ +/* + * CYGWIN uses this DLL reference... + */ +# define PROGNAME __progname +extern char __declspec(dllimport) *__progname; +#else +/* + * ...while elsewhere, we simply use the first argument passed. + */ +# define PROGNAME *argv +#endif + +/* Initialise the public variables. */ + +int optind = 1; /* index for first non-option arg */ +int opterr = 1; /* enable built-in error messages */ + +char *optarg = NULL; /* pointer to current option argument */ + +#define CHAR char /* argument type selector */ + +#define getopt_switchar '-' /* option prefix character in argv */ +#define getopt_pluschar '+' /* prefix for POSIX mode in optstring */ +#define getopt_takes_argument ':' /* marker for optarg in optstring */ +#define getopt_arg_assign '=' /* longopt argument field separator */ +#define getopt_unknown '?' /* return code for unmatched option */ +#define getopt_ordered 1 /* return code for ordered non-option */ + +#define getopt_all_done -1 /* return code to indicate completion */ + +enum +{ /* All `getopt' API functions are implemented via calls to the + * common static function `getopt_parse()'; these `mode' selectors + * determine the behaviour of `getopt_parse()', to deliver the + * appropriate result in each case. + */ + getopt_mode_standard = 0, /* getopt() */ + getopt_mode_long, /* getopt_long() */ + getopt_mode_long_only /* getopt_long_only() */ +}; + +enum +{ /* When attempting to match a command line argument to a long form option, + * these indicate the status of the match. + */ + getopt_no_match = 0, /* no successful match */ + getopt_abbreviated_match, /* argument is an abbreviation for an option */ + getopt_exact_match /* argument matches the full option name */ +}; + +int optopt = getopt_unknown; /* return value for option being evaluated */ + +/* Some BSD applications expect to be able to reinitialise `getopt' parsing + * by setting a global variable called `optreset'. We provide an obfuscated + * API, which allows applications to emulate this brain damage; however, any + * use of this is non-portable, and is strongly discouraged. + */ +#define optreset __mingw_optreset +int optreset = 0; + +static +int getopt_missing_arg( const CHAR *optstring ) +{ + /* Helper function to determine the appropriate return value, + * for the case where a required option argument is missing. + */ + if( (*optstring == getopt_pluschar) || (*optstring == getopt_switchar) ) + ++optstring; + return (*optstring == getopt_takes_argument) + ? getopt_takes_argument + : getopt_unknown; +} + +/* `complain' macro facilitates the generation of simple built-in + * error messages, displayed on various fault conditions, provided + * `opterr' is non-zero. + */ +#define complain( MSG, ARG ) if( opterr ) \ + fprintf( stderr, "%s: "MSG"\n", PROGNAME, ARG ) + +static +int getopt_argerror( int mode, char *fmt, CHAR *prog, struct option *opt, int retval ) +{ + /* Helper function, to generate more complex built-in error + * messages, for invalid arguments to long form options ... + */ + if( opterr ) + { + /* ... but, displayed only if `opterr' is non-zero. + */ + char flag[] = "--"; + if( mode != getopt_mode_long ) + /* + * only display one hyphen, for implicit long form options, + * improperly resolved by `getopt_long_only()'. + */ + flag[1] = 0; + /* + * always preface the program name ... + */ + fprintf( stderr, "%s: ", prog ); + /* + * to the appropriate, option specific message. + */ + fprintf( stderr, fmt, flag, opt->name ); + } + /* Whether displaying the message, or not, always set `optopt' + * to identify the faulty option ... + */ + optopt = opt->val; + /* + * and return the `invalid option' indicator. + */ + return retval; +} + +/* `getopt_conventions' establish behavioural options, to control + * the operation of `getopt_parse()', e.g. to select between POSIX + * and GNU style argument parsing behaviour. + */ +#define getopt_set_conventions 0x1000 +#define getopt_posixly_correct 0x0010 + +static +int getopt_conventions( int flags ) +{ + static int conventions = 0; + + if( (conventions == 0) && ((flags & getopt_set_conventions) == 0) ) + { + /* default conventions have not yet been established; + * initialise them now! + */ + conventions = getopt_set_conventions; + if( flags == getopt_pluschar ) + conventions |= getopt_posixly_correct; + } + + else if( flags & getopt_set_conventions ) + /* + * default conventions may have already been established, + * but this is a specific request to augment them. + */ + conventions |= flags; + + /* in any event, return the currently established conventions. + */ + return conventions; +} + +static +int is_switchar( CHAR flag ) +{ + /* A simple helper function, used to identify the switch character + * introducing an optional command line argument. + */ + return flag == getopt_switchar; +} + +static +const CHAR *getopt_match( CHAR lookup, const CHAR *opt_string ) +{ + /* Helper function, used to identify short form options. + */ + if( (*opt_string == getopt_pluschar) || (*opt_string == getopt_switchar) ) + ++opt_string; + if( *opt_string == getopt_takes_argument ) + ++opt_string; + do if( lookup == *opt_string ) return opt_string; + while( *++opt_string ); + return NULL; +} + +static +int getopt_match_long( const CHAR *nextchar, const CHAR *optname ) +{ + /* Helper function, used to identify potential matches for + * long form options. + */ + CHAR matchchar; + while( (matchchar = *nextchar++) && (matchchar == *optname) ) + /* + * skip over initial substring which DOES match. + */ + ++optname; + + if( matchchar ) + { + /* did NOT match the entire argument to an initial substring + * of a defined option name ... + */ + if( matchchar != getopt_arg_assign ) + /* + * ... and didn't stop at an `=' internal field separator, + * so this is NOT a possible match. + */ + return getopt_no_match; + + /* DID stop at an `=' internal field separator, + * so this IS a possible match, and what follows is an + * argument to the possibly matched option. + */ + optarg = (char *)(nextchar); + } + return *optname + /* + * if we DIDN'T match the ENTIRE text of the option name, + * then it's a possible abbreviated match ... + */ + ? getopt_abbreviated_match + /* + * but if we DID match the entire option name, + * then it's a DEFINITE EXACT match. + */ + : getopt_exact_match; +} + +static +int getopt_resolved( int mode, int argc, CHAR *const *argv, int *argind, +struct option *opt, int index, int *retindex, const CHAR *optstring ) +{ + /* Helper function to establish appropriate return conditions, + * on resolution of a long form option. + */ + if( retindex != NULL ) + *retindex = index; + + /* On return, `optind' should normally refer to the argument, if any, + * which follows the current one; it is convenient to set this, before + * checking for the presence of any `optarg'. + */ + optind = *argind + 1; + + if( optarg && (opt[index].has_arg == no_argument) ) + /* + * it is an error for the user to specify an option specific argument + * with an option which doesn't expect one! + */ + return getopt_argerror( mode, "option `%s%s' doesn't accept an argument\n", + PROGNAME, opt + index, getopt_unknown ); + + else if( (optarg == NULL) && (opt[index].has_arg == required_argument) ) + { + /* similarly, it is an error if no argument is specified + * with an option which requires one ... + */ + if( optind < argc ) + /* + * ... except that the requirement may be satisfied from + * the following command line argument, if any ... + */ + optarg = argv[*argind = optind++]; + + else + /* so fail this case, only if no such argument exists! + */ + return getopt_argerror( mode, "option `%s%s' requires an argument\n", + PROGNAME, opt + index, getopt_missing_arg( optstring ) ); + } + + /* when the caller has provided a return buffer ... + */ + if( opt[index].flag != NULL ) + { + /* ... then we place the proper return value there, + * and return a status code of zero ... + */ + *(opt[index].flag) = opt[index].val; + return 0; + } + /* ... otherwise, the return value becomes the status code. + */ + return opt[index].val; +} + +static +int getopt_verify( const CHAR *nextchar, const CHAR *optstring ) +{ + /* Helper function, called by getopt_parse() when invoked + * by getopt_long_only(), to verify when an unmatched or an + * ambiguously matched long form option string is valid as + * a short form option specification. + */ + if( ! (nextchar && *nextchar && optstring && *optstring) ) + /* + * There are no characters to be matched, or there are no + * valid short form option characters to which they can be + * matched, so this can never be valid. + */ + return 0; + + while( *nextchar ) + { + /* For each command line character in turn ... + */ + const CHAR *test; + if( (test = getopt_match( *nextchar++, optstring )) == NULL ) + /* + * ... there is no short form option to match the current + * candidate, so the entire argument fails. + */ + return 0; + + if( test[1] == getopt_takes_argument ) + /* + * The current candidate is valid, and it matches an option + * which takes an argument, so this command line argument is + * a valid short form option specification; accept it. + */ + return 1; + } + /* If we get to here, then every character in the command line + * argument was valid as a short form option; accept it. + */ + return 1; +} + +static +#define getopt_std_args int argc, CHAR *const argv[], const CHAR *optstring +int getopt_parse( int mode, getopt_std_args, ... ) +{ + /* Common core implementation for ALL `getopt' functions. + */ + static int argind = 0; + static int optbase = 0; + static const CHAR *nextchar = NULL; + static int optmark = 0; + + if( (optreset |= (optind < 1)) || (optind < optbase) ) + { + /* POSIX does not prescribe any definitive mechanism for restarting + * a `getopt' scan, but some applications may require such capability. + * We will support it, by allowing the caller to adjust the value of + * `optind' downwards, (nominally setting it to zero). Since POSIX + * wants `optind' to have an initial value of one, but we want all + * of our internal place holders to be initialised to zero, when we + * are called for the first time, we will handle such a reset by + * adjusting all of the internal place holders to one less than + * the adjusted `optind' value, (but never to less than zero). + */ + if( optreset ) + { + /* User has explicitly requested reinitialisation... + * We need to reset `optind' to it's normal initial value of 1, + * to avoid a potential infinitely recursive loop; by doing this + * up front, we also ensure that the remaining place holders + * will be correctly reinitialised to no less than zero. + */ + optind = 1; + + /* We also need to clear the `optreset' request... + */ + optreset = 0; + } + + /* Now, we may safely reinitialise the internal place holders, to + * one less than `optind', without fear of making them negative. + */ + optmark = optbase = argind = optind - 1; + nextchar = NULL; + } + + /* From a POSIX perspective, the following is `undefined behaviour'; + * we implement it thus, for compatibility with GNU and BSD getopt. + */ + else if( optind > (argind + 1) ) + { + /* Some applications expect to be able to manipulate `optind', + * causing `getopt' to skip over one or more elements of `argv'; + * POSIX doesn't require us to support this brain-damaged concept; + * (indeed, POSIX defines no particular behaviour, in the event of + * such usage, so it must be considered a bug for an application + * to rely on any particular outcome); nonetheless, Mac-OS-X and + * BSD actually provide *documented* support for this capability, + * so we ensure that our internal place holders keep track of + * external `optind' increments; (`argind' must lag by one). + */ + argind = optind - 1; + + /* When `optind' is misused, in this fashion, we also abandon any + * residual text in the argument we had been parsing; this is done + * without any further processing of such abandoned text, assuming + * that the caller is equipped to handle it appropriately. + */ + nextchar = NULL; + } + + if( nextchar && *nextchar ) + { + /* we are parsing a standard, or short format, option argument ... + */ + const CHAR *optchar; + if( (optchar = getopt_match( optopt = *nextchar++, optstring )) != NULL ) + { + /* we have identified it as valid ... + */ + if( optchar[1] == getopt_takes_argument ) + { + /* and determined that it requires an associated argument ... + */ + if( ! *(optarg = (char *)(nextchar)) ) + { + /* the argument is NOT attached ... + */ + if( optchar[2] == getopt_takes_argument ) + /* + * but this GNU extension marks it as optional, + * so we don't provide one on this occasion. + */ + optarg = NULL; + + /* otherwise this option takes a mandatory argument, + * so, provided there is one available ... + */ + else if( (argc - argind) > 1 ) + /* + * we take the following command line argument, + * as the appropriate option argument. + */ + optarg = argv[++argind]; + + /* but if no further argument is available, + * then there is nothing we can do, except for + * issuing the requisite diagnostic message. + */ + else + { + complain( "option requires an argument -- %c", optopt ); + return getopt_missing_arg( optstring ); + } + } + optind = argind + 1; + nextchar = NULL; + } + else + optarg = NULL; + optind = (nextchar && *nextchar) ? argind : argind + 1; + return optopt; + } + /* if we didn't find a valid match for the specified option character, + * then we fall through to here, so take appropriate diagnostic action. + */ + if( mode == getopt_mode_long_only ) + { + complain( "unrecognised option `-%s'", --nextchar ); + nextchar = NULL; + optopt = 0; + } + else + complain( "invalid option -- %c", optopt ); + optind = (nextchar && *nextchar) ? argind : argind + 1; + return getopt_unknown; + } + + if( optmark > optbase ) + { + /* This can happen, in GNU parsing mode ONLY, when we have + * skipped over non-option arguments, and found a subsequent + * option argument; in this case we permute the arguments. + */ + int index; + /* + * `optspan' specifies the number of contiguous arguments + * which are spanned by the current option, and so must be + * moved together during permutation. + */ + const int optspan = argind - optmark + 1; + /* + * we use `this_arg' to store these temporarily. + */ + CHAR **this_arg = malloc(sizeof(CHAR*) * optspan); + /* + * we cannot manipulate `argv' directly, since the `getopt' + * API prototypes it as `read-only'; this cast to `arglist' + * allows us to work around that restriction. + */ + CHAR **arglist = (char **)(argv); + + /* save temporary copies of the arguments which are associated + * with the current option ... + */ + for( index = 0; index < optspan; ++index ) + this_arg[index] = arglist[optmark + index]; + + /* move all preceding non-option arguments to the right, + * overwriting these saved arguments, while making space + * to replace them in their permuted location. + */ + for( --optmark; optmark >= optbase; --optmark ) + arglist[optmark + optspan] = arglist[optmark]; + + /* restore the temporarily saved option arguments to + * their permuted location. + */ + for( index = 0; index < optspan; ++index ) + arglist[optbase + index] = this_arg[index]; + + /* adjust `optbase', to account for the relocated option. + */ + optbase += optspan; + + free(this_arg); + } + + else + /* no permutation occurred ... + * simply adjust `optbase' for all options parsed so far. + */ + optbase = argind + 1; + + /* enter main parsing loop ... + */ + while( argc > ++argind ) + { + /* inspect each argument in turn, identifying possible options ... + */ + if( is_switchar( *(nextchar = argv[optmark = argind]) ) && *++nextchar ) + { + /* we've found a candidate option argument ... */ + + if( is_switchar( *nextchar ) ) + { + /* it's a double hyphen argument ... */ + + const CHAR *refchar = nextchar; + if( *++refchar ) + { + /* and it looks like a long format option ... + * `getopt_long' mode must be active to accept it as such, + * `getopt_long_only' also qualifies, but we must downgrade + * it to force explicit handling as a long format option. + */ + if( mode >= getopt_mode_long ) + { + nextchar = refchar; + mode = getopt_mode_long; + } + } + else + { + /* this is an explicit `--' end of options marker, so wrap up now! + */ + if( optmark > optbase ) + { + /* permuting the argument list as necessary ... + * (note use of `this_arg' and `arglist', as above). + */ + CHAR *this_arg = argv[optmark]; + CHAR **arglist = (CHAR **)(argv); + + /* move all preceding non-option arguments to the right ... + */ + do arglist[optmark] = arglist[optmark - 1]; + while( optmark-- > optbase ); + + /* reinstate the `--' marker, in its permuted location. + */ + arglist[optbase] = this_arg; + } + /* ... before finally bumping `optbase' past the `--' marker, + * and returning the `all done' completion indicator. + */ + optind = ++optbase; + return getopt_all_done; + } + } + else if( mode < getopt_mode_long_only ) + { + /* it's not an explicit long option, and `getopt_long_only' isn't active, + * so we must explicitly try to match it as a short option. + */ + mode = getopt_mode_standard; + } + + if( mode >= getopt_mode_long ) + { + /* the current argument is a long form option, (either explicitly, + * introduced by a double hyphen, or implicitly because we were called + * by `getopt_long_only'); this is where we parse it. + */ + int lookup; + int matched = -1; + + /* we need to fetch the `extra' function arguments, which are + * specified for the `getopt_long' APIs. + */ + va_list refptr; + struct option *longopts; + int *optindex; + va_start( refptr, optstring ); + longopts = va_arg( refptr, struct option * ); + optindex = va_arg( refptr, int * ); + va_end( refptr ); + + /* ensuring that `optarg' does not inherit any junk, from parsing + * preceding arguments ... + */ + optarg = NULL; + for( lookup = 0; longopts && longopts[lookup].name; ++lookup ) + { + /* scan the list of defined long form options ... + */ + switch( getopt_match_long( nextchar, longopts[lookup].name ) ) + { + /* looking for possible matches for the current argument. + */ + case getopt_exact_match: + /* + * when an exact match is found, + * return it immediately, setting `nextchar' to NULL, + * to ensure we don't mistakenly try to match any + * subsequent characters as short form options. + */ + nextchar = NULL; + return getopt_resolved( mode, argc, argv, &argind, + longopts, lookup, optindex, optstring ); + + case getopt_abbreviated_match: + /* + * but, for a partial (initial substring) match ... + */ + if( matched >= 0 ) + { + /* if this is not the first, then we have an ambiguity ... + */ + if( (mode == getopt_mode_long_only) + /* + * However, in the case of getopt_long_only(), if + * the entire ambiguously matched string represents + * a valid short option specification, then we may + * proceed to interpret it as such. + */ + && getopt_verify( nextchar, optstring ) ) + return getopt_parse( mode, argc, argv, optstring ); + + /* If we get to here, then the ambiguously matched + * partial long option isn't valid for short option + * evaluation; reset parser context to resume with + * the following command line argument, diagnose + * ambiguity, and bail out. + */ + optopt = 0; + nextchar = NULL; + optind = argind + 1; + complain( "option `%s' is ambiguous", argv[argind] ); + return getopt_unknown; + } + /* otherwise just note that we've found a possible match ... + */ + matched = lookup; + } + } + if( matched >= 0 ) + { + /* if we get to here, then we found exactly one partial match, + * so return it, as for an exact match. + */ + nextchar = NULL; + return getopt_resolved( mode, argc, argv, &argind, + longopts, matched, optindex, optstring ); + } + /* if here, then we had what SHOULD have been a long form option, + * but it is unmatched ... + */ + if( (mode < getopt_mode_long_only) + /* + * ... although paradoxically, `mode == getopt_mode_long_only' + * allows us to still try to match it as a short form option. + */ + || (getopt_verify( nextchar, optstring ) == 0) ) + { + /* When it cannot be matched, reset the parsing context to + * resume from the next argument, diagnose the failed match, + * and bail out. + */ + optopt = 0; + nextchar = NULL; + optind = argind + 1; + complain( "unrecognised option `%s'", argv[argind] ); + return getopt_unknown; + } + } + /* fall through to handle standard short form options... + * when the option argument format is neither explictly identified + * as long, nor implicitly matched as such, and the argument isn't + * just a bare hyphen, (which isn't an option), then we make one + * recursive call to explicitly interpret it as short format. + */ + if( *nextchar ) + return getopt_parse( mode, argc, argv, optstring ); + } + /* if we get to here, then we've parsed a non-option argument ... + * in GNU compatibility mode, we step over it, so we can permute + * any subsequent option arguments, but ... + */ + if( *optstring == getopt_switchar ) + { + /* if `optstring' begins with a `-' character, this special + * GNU specific behaviour requires us to return the non-option + * arguments in strict order, as pseudo-arguments to a special + * option, with return value defined as `getopt_ordered'. + */ + nextchar = NULL; + optind = argind + 1; + optarg = argv[argind]; + return getopt_ordered; + } + if( getopt_conventions( *optstring ) & getopt_posixly_correct ) + /* + * otherwise ... + * for POSIXLY_CORRECT behaviour, or if `optstring' begins with + * a `+' character, then we break out of the parsing loop, so that + * the scan ends at the current argument, with no permutation. + */ + break; + } + /* fall through when all arguments have been evaluated, + */ + optind = optbase; + return getopt_all_done; +} + +/* All three public API entry points are trivially defined, + * in terms of the internal `getopt_parse' function. + */ +int getopt( getopt_std_args ) +{ + return getopt_parse( getopt_mode_standard, argc, argv, optstring ); +} + +int getopt_long( getopt_std_args, const struct option *opts, int *index ) +{ + return getopt_parse( getopt_mode_long, argc, argv, optstring, opts, index ); +} + +int getopt_long_only( getopt_std_args, const struct option *opts, int *index ) +{ + return getopt_parse( getopt_mode_long_only, argc, argv, optstring, opts, index ); +} + +#ifdef __weak_alias +/* + * These Microsnot style uglified aliases are provided for compatibility + * with the previous MinGW implementation of the getopt API. + */ +__weak_alias( getopt, _getopt ) +__weak_alias( getopt_long, _getopt_long ) +__weak_alias( getopt_long_only, _getopt_long_only ) +#endif + + + + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ |