diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e18b6840 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "code/dep_external/src/oar-private"] + path = code/dep_external/src/oar-private + url = https://github.com/AOMediaCodec/oar-private diff --git a/code/AUTHORS.TXT b/code/AUTHORS.TXT index c0df4b9a..35127cca 100755 --- a/code/AUTHORS.TXT +++ b/code/AUTHORS.TXT @@ -3,9 +3,9 @@ Jungkyu Kim Kyungrae Kim Sunghee Hwang Yongmin Kwon +Wonbeen Jo Yoonjae Son Chaebin Im Woohyun Nam Yilun Zhang Jingbo Hou -Yiming Dong diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 905d8232..3c5c41a6 100755 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,157 +1,133 @@ -cmake_minimum_required(VERSION 3.6) +cmake_minimum_required(VERSION 3.28) project (iamf) -message(STATUS "start build iamf") +message(STATUS "Start build libiamf") -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Werror=unused-variable") -SET(CMAKE_POSITION_INDEPENDENT_CODE ON) - -option(BUILD_SHARED_LIBS "Build shared library" ON) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") +if(NOT MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=unused-variable") +endif() +set(CMAKE_POSITION_INDEPENDENT_CODE ON) -set(CODEC_LIB_DIR "${PROJECT_SOURCE_DIR}/dep_codecs/lib") -set(CODEC_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/dep_codecs/include") -set(EXTER_LIB_DIR "${PROJECT_SOURCE_DIR}/dep_external/lib") -set(EXTER_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/dep_external/include") +set(DEP_CODECS_DIR "${PROJECT_SOURCE_DIR}/dep_codecs") +set(DEP_EXTERNAL_DIR "${PROJECT_SOURCE_DIR}/dep_external") +option(IAMF_BUILD_SHARED_LIB "Build shared library" ON) +option(IAMF_ENABLE_BINAURALIZER "Enable binaural rendering" ON) +option(ENABLE_BUILD_CODECS "Build all codecs" ON) +option(IAMF_TEST_TOOL "IAMF test tool" OFF) option(SUPPORT_VERIFIER "Output vlogging file" OFF) + if (SUPPORT_VERIFIER) - message(STATUS "Output vlogging file") - add_definitions(-DSUPPORT_VERIFIER=1) + message(STATUS "Output vlogging file") + add_definitions(-DSUPPORT_VERIFIER=1) endif() -option(CODEC_CAP "Codec capability check" ON) -option(MULTICHANNEL_BINAURALIZER "Enable multichannel binaural rendering" OFF) -option(HOA_BINAURALIZER "Enable HOA binaural rendering" OFF) - if (CMAKE_BUILD_TYPE) - string(TOLOWER ${CMAKE_BUILD_TYPE} BUILD_TYPE) - if ("${BUILD_TYPE}" STREQUAL "debug") - add_definitions(-DIA_DBG) - message(STATUS "Debug mode.") - endif() -endif() - -if(MULTICHANNEL_BINAURALIZER) - message(STATUS "Enable multichannel binaural rendering") - add_definitions(-DENABLE_MULTICHANNEL_TO_BINAURAL=1) + string(TOLOWER ${CMAKE_BUILD_TYPE} BUILD_TYPE) + if ("${BUILD_TYPE}" STREQUAL "debug") + add_definitions(-DIA_DBG) + message(STATUS "Debug mode") + endif() endif() -if(HOA_BINAURALIZER) - message(STATUS "Enable HOA binaural rendering") - add_definitions(-DENABLE_HOA_TO_BINAURAL=1) -endif() - -if(CODEC_CAP) - unset(find_opus CACHE) - find_library(find_opus NAMES opus PATHS ${CODEC_LIB_DIR} NO_DEFAULT_PATH) - if(${find_opus} STREQUAL "find_opus-NOTFOUND") - message(WARNING "the opus library was not found") - else() - add_definitions(-DCONFIG_OPUS_CODEC) - endif() - - unset(find_aac CACHE) - find_library(find_aac NAMES fdk-aac PATHS ${CODEC_LIB_DIR} NO_DEFAULT_PATH) - if(${find_aac} STREQUAL "find_aac-NOTFOUND") - message(WARNING "the fdk-aac library was not found") - else() - add_definitions(-DCONFIG_AAC_CODEC) - endif() - - unset(find_flac CACHE) - find_library(find_flac NAMES FLAC PATHS ${CODEC_LIB_DIR} NO_DEFAULT_PATH) - if(${find_flac} STREQUAL "find_flac-NOTFOUND") - message(WARNING "the FLAC library was not found") - else() - add_definitions(-DCONFIG_FLAC_CODEC) - if(CMAKE_SYSTEM_NAME MATCHES "Windows") +if (ENABLE_BUILD_CODECS) + add_subdirectory(dep_codecs) + add_definitions(-DCONFIG_OPUS_CODEC -DCONFIG_AAC_CODEC -DCONFIG_FLAC_CODEC) + if(MSVC) add_definitions(-DFLAC__NO_DLL) - endif() - endif() + endif() +else() + unset(find_opus CACHE) + find_library(find_opus NAMES opus PATHS ${DEP_CODECS_DIR}/lib NO_DEFAULT_PATH) + if(${find_opus} STREQUAL "find_opus-NOTFOUND") + message(STATUS "The opus library was not found") + else() + add_definitions(-DCONFIG_OPUS_CODEC) + endif() + + unset(find_aac CACHE) + find_library(find_aac NAMES fdk-aac PATHS ${DEP_CODECS_DIR}/lib NO_DEFAULT_PATH) + if(${find_aac} STREQUAL "find_aac-NOTFOUND") + message(STATUS "The aac library was not found") + else() + add_definitions(-DCONFIG_AAC_CODEC) + endif() + + unset(find_flac CACHE) + find_library(find_flac NAMES FLAC PATHS ${DEP_CODECS_DIR}/lib NO_DEFAULT_PATH) + if(${find_flac} STREQUAL "find_flac-NOTFOUND") + message(STATUS "The flac library was not found") + else() + add_definitions(-DCONFIG_FLAC_CODEC) + if(MSVC) + add_definitions(-DFLAC__NO_DLL) + endif() + endif() endif() -include_directories (include) -aux_source_directory (dep_external/src/wav DIR_DEP_EXTERNAL_WAV) -aux_source_directory (src/common DIR_IAMF_COMMON) -aux_source_directory (src/iamf_dec DIR_IAMF_DEC) -aux_source_directory (src/iamf_dec/arch DIR_IAMF_DEC_ARCH) -aux_source_directory (src/iamf_dec/arch/arm DIR_IAMF_DEC_ARCH_ARM) -aux_source_directory (src/iamf_dec/arch/x86 DIR_IAMF_DEC_ARCH_X86) -if(NOT ${find_opus} STREQUAL "find_opus-NOTFOUND") - aux_source_directory (src/iamf_dec/opus DIR_IAMF_DEC_OPUS) -endif() -if(NOT ${find_aac} STREQUAL "find_aac-NOTFOUND") - aux_source_directory (src/iamf_dec/aac DIR_IAMF_DEC_AAC) -endif() -if(NOT ${find_flac} STREQUAL "find_flac-NOTFOUND") - aux_source_directory (src/iamf_dec/flac DIR_IAMF_DEC_FLAC) +if (IAMF_ENABLE_BINAURALIZER) + set(OAR_ENABLE_BINAURALIZER ON) +else() + set(OAR_ENABLE_BINAURALIZER OFF) endif() -aux_source_directory (src/iamf_dec/pcm DIR_IAMF_DEC_PCM) - +set(OAR_BUILD_SHARED_LIBRARY OFF) +add_subdirectory(dep_external/src/oar-private/liboar) +file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/dep_external/src/wav/*.c") include_directories( - ${CODEC_INCLUDE_DIR} - ${EXTER_INCLUDE_DIR} - ${PROJECT_SOURCE_DIR}/src/common + include + ${DEP_CODECS_DIR}/include + ${DEP_EXTERNAL_DIR}/include + ${DEP_EXTERNAL_DIR}/src/oar-private/liboar/include + ${DEP_EXTERNAL_DIR}/src/oar-private/liboar/src/common ${PROJECT_SOURCE_DIR}/src/iamf_dec - ${PROJECT_SOURCE_DIR}/src/iamf_dec/arch - ${PROJECT_SOURCE_DIR}/src/iamf_dec/arch/arm - ${PROJECT_SOURCE_DIR}/src/iamf_dec/arch/x86 - ${PROJECT_SOURCE_DIR}/src/iamf_dec/opus - ${PROJECT_SOURCE_DIR}/src/iamf_dec/aac - ${PROJECT_SOURCE_DIR}/src/iamf_dec/flac + ${PROJECT_SOURCE_DIR}/src/iamf_dec/codec + ${PROJECT_SOURCE_DIR}/src/iamf_dec/codec/opus + ${PROJECT_SOURCE_DIR}/src/iamf_dec/codec/aac + ${PROJECT_SOURCE_DIR}/src/iamf_dec/codec/flac + ${PROJECT_SOURCE_DIR}/src/iamf_dec/common + ${PROJECT_SOURCE_DIR}/src/iamf_dec/obu ) + link_directories ( - ${CODEC_LIB_DIR} + ${DEP_CODECS_DIR}/lib ) -if(MULTICHANNEL_BINAURALIZER OR HOA_BINAURALIZER) -link_directories( - ${EXTER_LIB_DIR}/binaural -) +if(IAMF_BUILD_SHARED_LIB) + add_library(${PROJECT_NAME} SHARED ${sources}) +else() + add_library(${PROJECT_NAME} STATIC ${sources}) endif() - -if(BUILD_SHARED_LIBS) - add_library(${PROJECT_NAME} SHARED ${DIR_DEP_EXTERNAL_WAV} ${DIR_IAMF_COMMON} - ${DIR_IAMF_DEC_OPUS} ${DIR_IAMF_DEC_AAC} ${DIR_IAMF_DEC_FLAC} ${DIR_IAMF_DEC_PCM} ${DIR_IAMF_DEC} - ${DIR_IAMF_DEC_ARCH} ${DIR_IAMF_DEC_ARCH_ARM} ${DIR_IAMF_DEC_ARCH_X86}) - - if(NOT ${find_opus} STREQUAL "find_opus-NOTFOUND") - target_link_libraries (${PROJECT_NAME} opus) - endif() - - if(NOT ${find_aac} STREQUAL "find_aac-NOTFOUND") - target_link_libraries (${PROJECT_NAME} fdk-aac) - endif() - - if(NOT ${find_flac} STREQUAL "find_flac-NOTFOUND") - target_link_libraries (${PROJECT_NAME} FLAC) - endif() - - if(MULTICHANNEL_BINAURALIZER) - target_link_libraries (${PROJECT_NAME} iamf2bear) - endif() - if(HOA_BINAURALIZER) - target_link_libraries (${PROJECT_NAME} iamf2resonance) - endif() - target_link_libraries (${PROJECT_NAME} m) +if (ENABLE_BUILD_CODECS) + add_dependencies(${PROJECT_NAME} dep_opus dep_aac dep_flac) + target_link_libraries (${PROJECT_NAME} opus fdk-aac FLAC) else() - add_library(${PROJECT_NAME} STATIC ${DIR_DEP_EXTERNAL_WAV} ${DIR_IAMF_COMMON} - ${DIR_IAMF_DEC_OPUS} ${DIR_IAMF_DEC_AAC} ${DIR_IAMF_DEC_PCM} - ${DIR_IAMF_DEC_FLAC} ${DIR_IAMF_DEC} ${DIR_IAMF_DEC_ARCH} ${DIR_IAMF_DEC_ARCH_ARM} - ${DIR_IAMF_DEC_ARCH_X86}) + if(NOT ${find_opus} STREQUAL "find_opus-NOTFOUND") + target_link_libraries (${PROJECT_NAME} opus) + endif() + if(NOT ${find_aac} STREQUAL "find_aac-NOTFOUND") + target_link_libraries (${PROJECT_NAME} fdk-aac) + endif() + if(NOT ${find_flac} STREQUAL "find_flac-NOTFOUND") + target_link_libraries (${PROJECT_NAME} FLAC) + endif() endif() +if(NOT MSVC) + target_link_libraries (${PROJECT_NAME} m) +endif() +target_link_libraries (${PROJECT_NAME} oar) +if(IAMF_TEST_TOOL) + add_subdirectory(test/tools/iamfdec) +endif() - -set(IAMF_PUBLIC_HEADER - ${CMAKE_CURRENT_SOURCE_DIR}/include/IAMF_decoder.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/IAMF_defines.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/vlogging_tool_sr.h - ) -set_target_properties(iamf PROPERTIES PUBLIC_HEADER "${IAMF_PUBLIC_HEADER}") - +file(GLOB iamf_public_headers CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/include/*") +set_target_properties(iamf PROPERTIES PUBLIC_HEADER "${iamf_public_headers}") set(prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix ${CMAKE_INSTALL_PREFIX}) @@ -159,20 +135,15 @@ set(libdir ${CMAKE_INSTALL_PREFIX}/lib) set(includedir ${CMAKE_INSTALL_PREFIX}/include) configure_file(iamf.pc.in iamf.pc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/iamf.pc - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig) + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig) -if(BUILD_SHARED_LIBS) - install(TARGETS ${PROJECT_NAME} +if(IAMF_BUILD_SHARED_LIB) + install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/iamf) else() - install(TARGETS ${PROJECT_NAME} + install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/iamf) endif() -if(MULTICHANNEL_BINAURALIZER OR HOA_BINAURALIZER) - install(DIRECTORY ${EXTER_LIB_DIR}/binaural - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) -endif() - diff --git a/code/README.md b/code/README.md index 0f2164a0..aa23dde0 100755 --- a/code/README.md +++ b/code/README.md @@ -1,33 +1,11 @@ -README.md -========= # [IAMF](https://aomediacodec.github.io/iamf/) Library -## Contents -1. [Building the lib](#Building-the-library) - - [Prerequisites](#Prerequisites) - - [Get the code](#Get-the-code) - - [Basics](#Basic-build) - - [Configuration options](#Configuration-options) - - [Dylib builds](#Dylib-builds) - - [Cross compiling](#Cross-compiling) - - [MSVC builds](#Microsoft-Visual-Studio-builds) - - [MacOS builds](#MacOS-builds) -2. [Testing the library](#Testing-the-IAMF) - - [Build application](#1-Build-application) - - [Decoder tests](#2-Decoder-tests) -3. [Coding style](#Coding-style) -4. [Bug reports](#Bug-reports) -5. [License](#License) - - ## Building the library ### Prerequisites - 1. [CMake](https://cmake.org) version 3.6 or higher. + 1. [CMake](https://cmake.org) version 3.28 or higher. 2. [Git](https://git-scm.com/). - 3. Building the libiamf requires dependent audio codec libraries: [opus](https://downloads.xiph.org/releases/opus/opus-1.4.tar.gz) [fdk-aac](https://people.freedesktop.org/~wtay/fdk-aac-free-2.0.0.tar.gz) [flac](https://downloads.xiph.org/releases/flac/flac-1.4.2.tar.xz) - 4. Enabling the binaural rendering in libiamf requires external libraries: [bear](https://github.com/ebu/bear) [resonance-audio](https://github.com/resonance-audio/resonance-audio) - + ### Get the code The IAMF library source code is stored in the Alliance for Open Media Git @@ -35,138 +13,119 @@ repository: ~~~ $ git clone https://github.com/AOMediaCodec/libiamf + $ git submodule update --init --recursive # By default, the above command stores the source in the libiamf/code directory: $ cd libiamf/code ~~~ ### Basic build -"build.sh" is an example to build, you can run it directly at your side. -(dependent [codec libraries](dep_codecs/lib) and [external libraries](dep_external/lib/binaural) complied under x64 linux have been provided in advance, -if compile other platform versions, please refer to [dependent codecs](dep_codecs/README.md) and [dependent externals](dep_external/src/binaural/README.md)) - -CMake replaces the configure step typical of many projects. Running CMake will -produce configuration and build files for the currently selected CMake -generator. For most systems the default generator is Unix Makefiles. The basic -form of a makefile build is the following: - ~~~ - $ cmake . - $ make + $ cmake -B build + $ cmake --build build ~~~ ### Configuration options -The IAMF library has few configuration options, There are one option which is used to enable binaural rendering: - Build binaural rendering configuration options. These have the form `MULTICHANNEL_BINAURALIZER` and `HOA_BINAURALIZER`. - (If binaural rendering is not enabled, there is no need to provide external libraries) +The IAMF library has few configuration options. +1. Build binaural rendering options. These have the form `IAMF_ENABLE_BINAURALIZER`. ~~~ - $ cmake ./ -DMULTICHANNEL_BINAURALIZER=ON -DHOA_BINAURALIZER=ON - $ make + $ cmake -B build -DIAMF_ENABLE_BINAURALIZER=OFF ~~~ - -### Dylib builds - -A dylib (shared object) build of the IAMF library is enabled by default. +2. Build dependent codec libraries options. These have the form `ENABLE_BUILD_CODECS`. +The dependent codec libraries are downloaded and built by default, if they are installed in `code/dep_codecs` already, this option can be used to disable building again. ~~~ - $ cmake . - $ make + $ cmake -B build -DENABLE_BUILD_CODECS=OFF ~~~ -### Cross compiling - -For the purposes of building the codec and applications and relative to the -scope of this guide, all builds for architectures differing from the native host -architecture will be considered cross compiles. The CMake build handles -cross compiling via the use of toolchain files included in the repository. -The toolchain files available at the time of this writing are: - - - arm64-ios.cmake - - arm64-linux.cmake - - x86_64-mingw.cmake - - x86-macos.cmake - -Please note that all [dependent codecs](dep_codecs/README.md) and [dependent externals](dep_external/src/binaural/README.md) should have been cross compiled already. - -The following example demonstrates use of the x86-macos.cmake toolchain file on -a x86\_64 MacOS host: +### Dylib builds +A dylib (shared object) build of the IAMF library is enabled by default. ~~~ - $ cmake ./ -DCMAKE_TOOLCHAIN_FILE=build/cmake/toolchains/x86-macos.cmake - $ make + $ cmake -B build + $ cmake --build build ~~~ ### Microsoft Visual Studio builds -Building the IAMF library in Microsoft Visual Studio is supported. Visual -Studio 2022(v143) solution has been provided. +Building the IAMF library in Microsoft Visual Studio is supported. +The following example demonstrates generating projects and a solution for the Microsoft IDE: +~~~ + # This does not require a bash shell; Command Prompt (cmd.exe) is fine. + # This assumes the build host is a Windows x64 computer. -Open win64/VS2022/iamf.sln directly. + # To create a Visual Studio 2022 solution for the x64 target: + $ cmake -B build -DIAMF_TEST_TOOL=ON -DIAMF_BUILD_SHARED_LIB=OFF -G "Visual Studio 17 2022" + $ cmake --build build +~~~ -### MacOS builds -Please note that all [dependent codecs](dep_codecs/README.md) and [dependent externals](dep_external/src/binaural/README.md) should have been MacOS compiled already. +### Cross compiling +CMake build handles cross compiling via the use of toolchain files +The following example demonstrates use of an available x86-macos.cmake toolchain file on the x86_64 MacOS host: ~~~ - $ cmake . - $ make + $ cmake -B build -DCMAKE_TOOLCHAIN_FILE=x86-macos.cmake + $ cmake --build build ~~~ ## Testing the IAMF The iamfdec is a test application to decode an IAMF bitstream or mp4 file with IAMF encapsulation. -### 1. Build application - -~~~ - $ cd test/tools/iamfdec - - $ cmake -DCMAKE_INSTALL_PREFIX=${BUILD_LIBS} . - # ${BUILD_LIBS} is the iamf library and header files installing directory. - # If enable binaural rendering, add option `MULTICHANNEL_BINAURALIZER` and `HOA_BINAURALIZER` - - $ make -~~~ - -### 2. Decoder tests - -To produce binaural output, please download the following file and place it in your working directory [default.tf](https://github.com/ebu/bear/releases/download/v0.0.1-pre/default.tf). -~~~ - ./iamfdec - options: - -i[0-1] 0 : IAMF bitstream input.(default) - 1 : MP4 input. - -o[2-3] 2 : WAVE output, same path as binary.(default) - 3 [path] - : WAVE output, user setting path. - -r [rate] : Audio signal sampling rate, 48000 is the default. - -s[0~11,b] : Output layout, the sound system A~J and extensions (Upper + Middle + Bottom). - 0 : Sound system A (0+2+0) - 1 : Sound system B (0+5+0) - 2 : Sound system C (2+5+0) - 3 : Sound system D (4+5+0) - 4 : Sound system E (4+5+1) - 5 : Sound system F (3+7+0) - 6 : Sound system G (4+9+0) - 7 : Sound system H (9+10+3) - 8 : Sound system I (0+7+0) - 9 : Sound system J (4+7+0) - 10 : Sound system extension 712 (2+7+0) - 11 : Sound system extension 312 (2+3+0) - 12 : Sound system mono (0+1+0) - 13 : Sound system extension 916 (6+9+0) - b : Binaural. - -p [dB] : Peak threshold in dB. - -l [LKFS] : Normalization loudness(<0) in LKFS. - -d [bit] : Bit depth of WAVE output. - -mp [id] : Set mix presentation id. - -m : Generate a metadata file with the suffix .met. - -disable_limiter - : Disable peak limiter. - - Example: ./iamfdec -o2 -s9 simple_profile.iamf - ./iamfdec -i1 -o2 -s9 simple_profile.mp4 - ./iamfdec -i1 -o3 /tmp/out.wav -s9 simple_profile.mp4 -~~~ +Please add the compile option `-DIAMF_TEST_TOOL=ON` if you wish to use this tool. + +### iamfdec +This tool aims to decode IA bitstream and dump to wav file. + +```sh +./iamfdec +options: +-i[0-1] 0 : IAMF bitstream input.(default) + 1 : MP4 input. +-o[1-3] 1 : Output IAMF stream info. + 2 : WAVE output, same path as binary.(default) + 3 [path] + : WAVE output, user setting path. +-r [rate] : Audio signal sampling rate, 48000 is the default. +-s[0~14,b] : Output layout, the sound system A~J and extensions (Upper + Middle + Bottom). + 0 : Sound system A (0+2+0) + 1 : Sound system B (0+5+0) + 2 : Sound system C (2+5+0) + 3 : Sound system D (4+5+0) + 4 : Sound system E (4+5+1) + 5 : Sound system F (3+7+0) + 6 : Sound system G (4+9+0) + 7 : Sound system H (9+10+3) + 8 : Sound system I (0+7+0) + 9 : Sound system J (4+7+0) + 10 : Sound system extension 712 (2+7+0) + 11 : Sound system extension 312 (2+3+0) + 12 : Sound system mono (0+1+0) + 13 : Sound system extension 916 (6+9+0) + 14 : Sound system extension 7154 (5+7+4) + b : Binaural. +-p [dB] : Peak threshold in dB. +-l [LKFS] : Normalization loudness(<0) in LKFS. +-d [bits] : Bit depth of pcm output. +-mp [id] : Set mix presentation id. +-disable_limiter + : Disable peak limiter. +-profile [n] : Set IAMF profile (0=SIMPLE, 1=BASE, 2=BASE_ENHANCED, 3=BASE_ADVANCED, 4=ADVANCED_1, 5=ADVANCED_2). +-ego id1:gain1,id2:gain2,... + : Set element gain offsets in dB for multiple audio elements. +-ht : Enable head tracking. +-hr w,x,y,z : Set head rotation quaternion. + +Example: ./iamfdec -o2 -s9 simple_profile.iamf + ./iamfdec -i1 -o2 -s9 simple_profile.mp4 + ./iamfdec -i1 -o3 out.wav -s9 simple_profile.mp4 + +``` + +### Channel ordering + +The ordering of channel from IAMF decoder is based on the related [ITU-2051-3](https://www.itu.int/rec/R-REC-BS.2051) layout. +Please refer to the [Output WAV files](https://github.com/AOMediaCodec/libiamf/blob/main/tests/README.md#output-wav-files) in `test` directory, or liboar's [loudspeaker ordering](https://github.com/AOMediaCodec/oar-private/blob/main/liboar/doc/loudspeaker_layout_channel_order.md) documentation ## Coding style diff --git a/code/build.sh b/code/build.sh deleted file mode 100755 index 35274025..00000000 --- a/code/build.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -BUILD_LIBS=$PWD/build_libs -#1, build libiamf -make clean -cmake -DCMAKE_INSTALL_PREFIX=${BUILD_LIBS} -DMULTICHANNEL_BINAURALIZER=ON -DHOA_BINAURALIZER=ON . -make -make install - -#2, build test/tools/iamfdec - -cd test/tools/iamfdec -make clean -cmake -DCMAKE_INSTALL_PREFIX=${BUILD_LIBS} -DMULTICHANNEL_BINAURALIZER=ON -DHOA_BINAURALIZER=ON . -make -cd - diff --git a/code/build/cmake/toolchains/arm64-ios.cmake b/code/build/cmake/toolchains/arm64-ios.cmake deleted file mode 100755 index 660bd80c..00000000 --- a/code/build/cmake/toolchains/arm64-ios.cmake +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2024, Alliance for Open Media. All rights reserved -# -# This source code is subject to the terms of the BSD 3-Clause Clear License -# and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear -# License was not distributed with this source code in the LICENSE file, you -# can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the -# Alliance for Open Media Patent License 1.0 was not distributed with this -# source code in the PATENTS file, you can obtain it at -# www.aomedia.org/license/patent. -# - -set(CMAKE_SYSTEM_PROCESSOR "arm64") -set(CMAKE_SYSTEM_NAME "Darwin") - -if("${CROSS}" STREQUAL "") - set(CROSS arm64-apple-darwin20.4-) -endif() -set(CMAKE_C_COMPILER ${CROSS}clang) -set(CMAKE_CXX_COMPILER ${CROSS}clang++) \ No newline at end of file diff --git a/code/build/cmake/toolchains/arm64-linux.cmake b/code/build/cmake/toolchains/arm64-linux.cmake deleted file mode 100755 index 5576f8fb..00000000 --- a/code/build/cmake/toolchains/arm64-linux.cmake +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2024, Alliance for Open Media. All rights reserved -# -# This source code is subject to the terms of the BSD 3-Clause Clear License -# and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear -# License was not distributed with this source code in the LICENSE file, you -# can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the -# Alliance for Open Media Patent License 1.0 was not distributed with this -# source code in the PATENTS file, you can obtain it at -# www.aomedia.org/license/patent. -# - -set(CMAKE_SYSTEM_PROCESSOR "arm64") -set(CMAKE_SYSTEM_NAME "Linux") - -if("${CROSS}" STREQUAL "") - set(CROSS aarch64-linux-gnu-) -endif() -set(CMAKE_C_COMPILER ${CROSS}gcc) -set(CMAKE_CXX_COMPILER ${CROSS}g++) diff --git a/code/build/cmake/toolchains/x86-macos.cmake b/code/build/cmake/toolchains/x86-macos.cmake deleted file mode 100755 index f1e720a1..00000000 --- a/code/build/cmake/toolchains/x86-macos.cmake +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2024, Alliance for Open Media. All rights reserved -# -# This source code is subject to the terms of the BSD 3-Clause Clear License -# and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear -# License was not distributed with this source code in the LICENSE file, you -# can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the -# Alliance for Open Media Patent License 1.0 was not distributed with this -# source code in the PATENTS file, you can obtain it at -# www.aomedia.org/license/patent. -# - -set(CMAKE_SYSTEM_PROCESSOR "x86") -set(CMAKE_SYSTEM_NAME "Darwin") - -if("${CROSS}" STREQUAL "") - set(CROSS x86_64-apple-darwin20.4-) -endif() -set(CMAKE_C_COMPILER ${CROSS}clang) -set(CMAKE_CXX_COMPILER ${CROSS}clang++) - diff --git a/code/build/cmake/toolchains/x86_64-mingw.cmake b/code/build/cmake/toolchains/x86_64-mingw.cmake deleted file mode 100755 index 8cdfc3f4..00000000 --- a/code/build/cmake/toolchains/x86_64-mingw.cmake +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2024, Alliance for Open Media. All rights reserved -# -# This source code is subject to the terms of the BSD 3-Clause Clear License -# and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear -# License was not distributed with this source code in the LICENSE file, you -# can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the -# Alliance for Open Media Patent License 1.0 was not distributed with this -# source code in the PATENTS file, you can obtain it at -# www.aomedia.org/license/patent. -# - -set(CMAKE_SYSTEM_PROCESSOR "x86_64") -set(CMAKE_SYSTEM_NAME "Windows") - -if("${CROSS}" STREQUAL "") - set(CROSS x86_64-w64-mingw32-) -endif() - -set(CMAKE_C_COMPILER ${CROSS}gcc) -set(CMAKE_CXX_COMPILER ${CROSS}g++) -set(CMAKE_RC_COMPILER ${CROSS}windres) -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) \ No newline at end of file diff --git a/code/dep_codecs/CMakeLists.txt b/code/dep_codecs/CMakeLists.txt new file mode 100755 index 00000000..70a78de7 --- /dev/null +++ b/code/dep_codecs/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.28) + +project (dep_codecs) + +# Fetch opus library +include(ExternalProject) +ExternalProject_Add( + dep_opus + URL https://downloads.xiph.org/releases/opus/opus-1.4.tar.gz + CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${DEP_CODECS_DIR} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} +) + +# Fetch fdk-aac(2.0.3) library +include(ExternalProject) +ExternalProject_Add( + dep_aac + GIT_REPOSITORY https://github.com/mstorsjo/fdk-aac.git + GIT_TAG 716f4394641d53f0d79c9ddac3fa93b03a49f278 + CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${DEP_CODECS_DIR} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} +) + +# Fetch flac library +include(ExternalProject) +ExternalProject_Add( + dep_flac + URL https://downloads.xiph.org/releases/flac/flac-1.4.2.tar.xz + CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DWITH_OGG=OFF -DBUILD_CXXLIBS=OFF -DINSTALL_MANPAGES=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${DEP_CODECS_DIR} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} +) diff --git a/code/dep_codecs/README.md b/code/dep_codecs/README.md deleted file mode 100755 index d968fc9f..00000000 --- a/code/dep_codecs/README.md +++ /dev/null @@ -1,53 +0,0 @@ -README.md -========= -# Dependent Codec Libraries - -## Contents -1. [Downloading the opensource](#Downloading-the-opensource) -2. [Building the libraries](#Building-the-libraries) - - [Prerequisites](#Prerequisites) - - [Basic build](#Basic-build) - - [Cross compiling](#Cross-compiling) - - -## Downloading the opensource - 1. [opus](https://downloads.xiph.org/releases/opus/opus-1.4.tar.gz) - 2. [fdk-aac](https://people.freedesktop.org/~wtay/fdk-aac-free-2.0.0.tar.gz) - 3. [flac](https://downloads.xiph.org/releases/flac/flac-1.4.2.tar.xz) - -Please download the opensource and unzip to directory separately as following: -~~~ - opus/opus-1.4 - aac/fdk-aac-free-2.0.0 - flac/flac-1.4.2 -~~~ - -## Building the libraries - -### Prerequisites - 1. [CMake](https://cmake.org) version 3.6 or higher. - 2. Tool chains if need cross compiling. - - -### Basic build -"build.sh" is an example to build, you can run it directly at your side. - - -### Cross compiling -For the purposes of building the codec and applications and relative to the -scope of this guide, all builds for architectures differing from the native host -architecture will be considered cross compiles. The CMake build handles -cross compiling via the use of toolchain files included in the repository. -The toolchain files available at the time of this writing are: - - - arm64-ios.cmake - - arm64-linux.cmake - - x86_64-mingw.cmake - - x86-macos.cmake - -The following example demonstrates use of the x86-macos.cmake toolchain file on -a x86\_64 MacOS host: - -~~~ - $ ./build.sh --x86-macos_toolchain -~~~ diff --git a/code/dep_codecs/build.sh b/code/dep_codecs/build.sh deleted file mode 100755 index 74dbba22..00000000 --- a/code/dep_codecs/build.sh +++ /dev/null @@ -1,290 +0,0 @@ -# Copyright (c) 2024, Alliance for Open Media. All rights reserved -# -# This source code is subject to the terms of the BSD 3-Clause Clear License -# and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear -# License was not distributed with this source code in the LICENSE file, you -# can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the -# Alliance for Open Media Patent License 1.0 was not distributed with this -# source code in the PATENTS file, you can obtain it at -# www.aomedia.org/license/patent. -# - -set -e - -run () -{ - if [ "$VERBOSE" = "yes" ] ; then - echo "##### NEW COMMAND" - echo "$@" - $@ 2>&1 - else - if [ -n "$TMPLOG" ] ; then - echo "##### NEW COMMAND" >> $TMPLOG - echo "$@" >> $TMPLOG - $@ 2>&1 | tee -a $TMPLOG - else - $@ > /dev/null 2>&1 - fi - fi -} - -pattern_match () -{ - echo "$2" | grep -q -E -e "$1" -} - -# Find if a given shell program is available. -# -# $1: variable name -# $2: program name -# -# Result: set $1 to the full path of the corresponding command -# or to the empty/undefined string if not available -# -find_program () -{ - eval $1=`command -v $2` -} - -prepare_download () -{ - find_program CMD_WGET wget - find_program CMD_CURL curl - find_program CMD_SCRP scp -} - -# Download a file with either 'curl', 'wget' or 'scp' -# -# $1: source URL (e.g. http://foo.com, ssh://blah, /some/path) -# $2: target file -download_file () -{ - # Is this HTTP, HTTPS or FTP ? - if pattern_match "^(http|https|ftp):.*" "$1"; then - if [ -n "$CMD_WGET" ] ; then - run $CMD_WGET -O $2 $1 - elif [ -n "$CMD_CURL" ] ; then - run $CMD_CURL -L -o $2 $1 - else - echo "Please install wget or curl on this machine" - exit 1 - fi - return - fi - - # Is this SSH ? - # Accept both ssh:// or : - # - if pattern_match "^(ssh|[^:]+):.*" "$1"; then - if [ -n "$CMD_SCP" ] ; then - scp_src=`echo $1 | sed -e s%ssh://%%g` - run $CMD_SCP $scp_src $2 - else - echo "Please install scp on this machine" - exit 1 - fi - return - fi - - # Is this a file copy ? - # Accept both file:// or / - # - if pattern_match "^(file://|/).*" "$1"; then - cp_src=`echo $1 | sed -e s%^file://%%g` - run cp -f $cp_src $2 - return - fi -} - -OPUS_DIR="$( cd "$(dirname "$0")" ; pwd -P )/opus" -AAC_DIR="$( cd "$(dirname "$0")" ; pwd -P )/aac" -FLAC_DIR="$( cd "$(dirname "$0")" ; pwd -P )/flac" -CODECS_DIR="$( cd "$(dirname "$0")" ; pwd -P )" -OPUS_TAR="opus-1.4.tar.gz" -AAC_TAR="fdk-aac-free-2.0.0.tar.gz" -FLAC_TAR="flac-1.4.2.tar.xz" - -declare -a CONFIG_FLAGS_OPUS -declare -a CONFIG_FLAGS_AAC -declare -a CONFIG_FLAGS_FLAC -CONFIG_FLAGS_OPUS="-DCMAKE_POSITION_INDEPENDENT_CODE=ON" -CONFIG_FLAGS_AAC="--enable-static --disable-shared --with-pic" -CONFIG_FLAGS_FLAC="-DWITH_OGG=OFF -DBUILD_CXXLIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON" - -OPUS_DOWNLOAD_LINK="https://downloads.xiph.org/releases/opus/opus-1.4.tar.gz" -AAC_DOWNLOAD_LINK="https://people.freedesktop.org/~wtay/fdk-aac-free-2.0.0.tar.gz" -FLAC_DOWNLOAD_LINK="https://downloads.xiph.org/releases/flac/flac-1.4.2.tar.xz" - - -function show_help() -{ - cat <>>>>>>>>>>>>>>>>>>>>>>>>>>Codec Download<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" - -CLEAN=yes -DOWNLOAD=yes - -if [ $CLEAN = yes ] ; then - echo "Cleaning: $OPUS_DIR" - rm -f -r $OPUS_DIR - - echo "Cleaning: $AAC_DIR" - rm -f -r $AAC_DIR - - echo "Cleaning: $FLAC_DIR" - rm -f -r $FLAC_DIR - - mkdir $OPUS_DIR - mkdir $AAC_DIR - mkdir $FLAC_DIR - [ "$DOWNLOAD" = "yes" ] || exit 0 -fi - -#Download OPUS -if [ ! -f $OPUS_DIR/$OPUS_TAR ] -then - echo "Downloading opus please wait..." - prepare_download - download_file $OPUS_DOWNLOAD_LINK $OPUS_DIR/$OPUS_TAR -fi - -if [ ! -f $OPUS_DIR/$OPUS_TAR ] -then - echo "Failed to download opus! Please download manually\nand save it in this directory as $OPUS_TAR" - exit 1 -fi - -if [ -f $OPUS_DIR/$OPUS_TAR ] -then - echo "Unpacking opus" - tar -zxf $OPUS_DIR/$OPUS_TAR -C $OPUS_DIR -fi - -#Download AAC -if [ ! -f $AAC_DIR/$AAC_TAR ] -then - echo "Downloading aac please wait..." - prepare_download - download_file $AAC_DOWNLOAD_LINK $AAC_DIR/$AAC_TAR -fi - -if [ ! -f $AAC_DIR/$AAC_TAR ] -then - echo "Failed to download aac! Please download manually\nand save it in this directory as $AAC_TAR" - exit 1 -fi - -if [ -f $AAC_DIR/$AAC_TAR ] -then - echo "Unpacking aac" - tar -zxf $AAC_DIR/$AAC_TAR -C $AAC_DIR -fi - -#Download FLAC -if [ ! -f $FLAC_DIR/$FLAC_TAR ] -then - echo "Downloading flac please wait..." - prepare_download - download_file $FLAC_DOWNLOAD_LINK $FLAC_DIR/$FLAC_TAR -fi - -if [ ! -f $FLAC_DIR/$FLAC_TAR ] -then - echo "Failed to download flac! Please download manually\nand save it in this directory as $FLAC_TAR" - exit 1 -fi - -if [ -f $FLAC_DIR/$FLAC_TAR ] -then - echo "Unpacking flac" - tar -xf $FLAC_DIR/$FLAC_TAR -C $FLAC_DIR -fi - -echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>OPUS Compile<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" -cd $OPUS_DIR/opus-1.4 -rm -rf build -cmake -B build ./ $CONFIG_FLAGS_OPUS -cmake --build build --clean-first -cmake --install build --prefix $CODECS_DIR - -echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>AAC Compile<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" -cd $AAC_DIR/fdk-aac-free-2.0.0 -rm -rf build -mkdir build -cd build -../configure $CONFIG_FLAGS_AAC --prefix=$CODECS_DIR -make -make install - -echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>FLAC Compile<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" -cd $FLAC_DIR/flac-1.4.2 -rm -rf build -cmake -B build ./ $CONFIG_FLAGS_FLAC -cmake --build build --clean-first -cmake --install build --prefix $CODECS_DIR diff --git a/code/dep_codecs/include/FLAC/all.h b/code/dep_codecs/include/FLAC/all.h deleted file mode 100755 index a6a012fc..00000000 --- a/code/dep_codecs/include/FLAC/all.h +++ /dev/null @@ -1,450 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2022 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__ALL_H -#define FLAC__ALL_H - -#include "export.h" - -#include "assert.h" -#include "callback.h" -#include "format.h" -#include "metadata.h" -#include "ordinals.h" -#include "stream_decoder.h" -#include "stream_encoder.h" - -/** \mainpage - * - * \section intro Introduction - * - * This is the documentation for the FLAC C and C++ APIs. It is - * highly interconnected; this introduction should give you a top - * level idea of the structure and how to find the information you - * need. As a prerequisite you should have at least a basic - * knowledge of the FLAC format, documented - * here. - * - * \section c_api FLAC C API - * - * The FLAC C API is the interface to libFLAC, a set of structures - * describing the components of FLAC streams, and functions for - * encoding and decoding streams, as well as manipulating FLAC - * metadata in files. The public include files will be installed - * in your include area (for example /usr/include/FLAC/...). - * - * By writing a little code and linking against libFLAC, it is - * relatively easy to add FLAC support to another program. The - * library is licensed under Xiph's BSD license. - * Complete source code of libFLAC as well as the command-line - * encoder and plugins is available and is a useful source of - * examples. - * - * Aside from encoders and decoders, libFLAC provides a powerful - * metadata interface for manipulating metadata in FLAC files. It - * allows the user to add, delete, and modify FLAC metadata blocks - * and it can automatically take advantage of PADDING blocks to avoid - * rewriting the entire FLAC file when changing the size of the - * metadata. - * - * libFLAC usually only requires the standard C library and C math - * library. In particular, threading is not used so there is no - * dependency on a thread library. However, libFLAC does not use - * global variables and should be thread-safe. - * - * libFLAC also supports encoding to and decoding from Ogg FLAC. - * However the metadata editing interfaces currently have limited - * read-only support for Ogg FLAC files. - * - * \section cpp_api FLAC C++ API - * - * The FLAC C++ API is a set of classes that encapsulate the - * structures and functions in libFLAC. They provide slightly more - * functionality with respect to metadata but are otherwise - * equivalent. For the most part, they share the same usage as - * their counterparts in libFLAC, and the FLAC C API documentation - * can be used as a supplement. The public include files - * for the C++ API will be installed in your include area (for - * example /usr/include/FLAC++/...). - * - * libFLAC++ is also licensed under - * Xiph's BSD license. - * - * \section getting_started Getting Started - * - * A good starting point for learning the API is to browse through - * the modules. Modules are logical - * groupings of related functions or classes, which correspond roughly - * to header files or sections of header files. Each module includes a - * detailed description of the general usage of its functions or - * classes. - * - * From there you can go on to look at the documentation of - * individual functions. You can see different views of the individual - * functions through the links in top bar across this page. - * - * If you prefer a more hands-on approach, you can jump right to some - * example code. - * - * \section porting_guide Porting Guide - * - * Starting with FLAC 1.1.3 a \link porting Porting Guide \endlink - * has been introduced which gives detailed instructions on how to - * port your code to newer versions of FLAC. - * - * \section embedded_developers Embedded Developers - * - * libFLAC has grown larger over time as more functionality has been - * included, but much of it may be unnecessary for a particular embedded - * implementation. Unused parts may be pruned by some simple editing of - * src/libFLAC/Makefile.am. In general, the decoders, encoders, and - * metadata interface are all independent from each other. - * - * It is easiest to just describe the dependencies: - * - * - All modules depend on the \link flac_format Format \endlink module. - * - The decoders and encoders depend on the bitbuffer. - * - The decoder is independent of the encoder. The encoder uses the - * decoder because of the verify feature, but this can be removed if - * not needed. - * - Parts of the metadata interface require the stream decoder (but not - * the encoder). - * - Ogg support is selectable through the compile time macro - * \c FLAC__HAS_OGG. - * - * For example, if your application only requires the stream decoder, no - * encoder, and no metadata interface, you can remove the stream encoder - * and the metadata interface, which will greatly reduce the size of the - * library. - * - * Also, there are several places in the libFLAC code with comments marked - * with "OPT:" where a \#define can be changed to enable code that might be - * faster on a specific platform. Experimenting with these can yield faster - * binaries. - */ - -/** \defgroup porting Porting Guide for New Versions - * - * This module describes differences in the library interfaces from - * version to version. It assists in the porting of code that uses - * the libraries to newer versions of FLAC. - * - * One simple facility for making porting easier that has been added - * in FLAC 1.1.3 is a set of \#defines in \c export.h of each - * library's includes (e.g. \c include/FLAC/export.h). The - * \#defines mirror the libraries' - * libtool version numbers, - * e.g. in libFLAC there are \c FLAC_API_VERSION_CURRENT, - * \c FLAC_API_VERSION_REVISION, and \c FLAC_API_VERSION_AGE. - * These can be used to support multiple versions of an API during the - * transition phase, e.g. - * - * \code - * #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7 - * legacy code - * #else - * new code - * #endif - * \endcode - * - * The source will work for multiple versions and the legacy code can - * easily be removed when the transition is complete. - * - * Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in - * include/FLAC/export.h), which can be used to determine whether or not - * the library has been compiled with support for Ogg FLAC. This is - * simpler than trying to call an Ogg init function and catching the - * error. - */ - -/** \defgroup porting_1_1_2_to_1_1_3 Porting from FLAC 1.1.2 to 1.1.3 - * \ingroup porting - * - * \brief - * This module describes porting from FLAC 1.1.2 to FLAC 1.1.3. - * - * The main change between the APIs in 1.1.2 and 1.1.3 is that they have - * been simplified. First, libOggFLAC has been merged into libFLAC and - * libOggFLAC++ has been merged into libFLAC++. Second, both the three - * decoding layers and three encoding layers have been merged into a - * single stream decoder and stream encoder. That is, the functionality - * of FLAC__SeekableStreamDecoder and FLAC__FileDecoder has been merged - * into FLAC__StreamDecoder, and FLAC__SeekableStreamEncoder and - * FLAC__FileEncoder into FLAC__StreamEncoder. Only the - * FLAC__StreamDecoder and FLAC__StreamEncoder remain. What this means - * is there is now a single API that can be used to encode or decode - * streams to/from native FLAC or Ogg FLAC and the single API can work - * on both seekable and non-seekable streams. - * - * Instead of creating an encoder or decoder of a certain layer, now the - * client will always create a FLAC__StreamEncoder or - * FLAC__StreamDecoder. The old layers are now differentiated by the - * initialization function. For example, for the decoder, - * FLAC__stream_decoder_init() has been replaced by - * FLAC__stream_decoder_init_stream(). This init function takes - * callbacks for the I/O, and the seeking callbacks are optional. This - * allows the client to use the same object for seekable and - * non-seekable streams. For decoding a FLAC file directly, the client - * can use FLAC__stream_decoder_init_file() and pass just a filename - * and fewer callbacks; most of the other callbacks are supplied - * internally. For situations where fopen()ing by filename is not - * possible (e.g. Unicode filenames on Windows) the client can instead - * open the file itself and supply the FILE* to - * FLAC__stream_decoder_init_FILE(). The init functions now returns a - * FLAC__StreamDecoderInitStatus instead of FLAC__StreamDecoderState. - * Since the callbacks and client data are now passed to the init - * function, the FLAC__stream_decoder_set_*_callback() functions and - * FLAC__stream_decoder_set_client_data() are no longer needed. The - * rest of the calls to the decoder are the same as before. - * - * There are counterpart init functions for Ogg FLAC, e.g. - * FLAC__stream_decoder_init_ogg_stream(). All the rest of the calls - * and callbacks are the same as for native FLAC. - * - * As an example, in FLAC 1.1.2 a seekable stream decoder would have - * been set up like so: - * - * \code - * FLAC__SeekableStreamDecoder *decoder = FLAC__seekable_stream_decoder_new(); - * if(decoder == NULL) do_something; - * FLAC__seekable_stream_decoder_set_md5_checking(decoder, true); - * [... other settings ...] - * FLAC__seekable_stream_decoder_set_read_callback(decoder, my_read_callback); - * FLAC__seekable_stream_decoder_set_seek_callback(decoder, my_seek_callback); - * FLAC__seekable_stream_decoder_set_tell_callback(decoder, my_tell_callback); - * FLAC__seekable_stream_decoder_set_length_callback(decoder, my_length_callback); - * FLAC__seekable_stream_decoder_set_eof_callback(decoder, my_eof_callback); - * FLAC__seekable_stream_decoder_set_write_callback(decoder, my_write_callback); - * FLAC__seekable_stream_decoder_set_metadata_callback(decoder, my_metadata_callback); - * FLAC__seekable_stream_decoder_set_error_callback(decoder, my_error_callback); - * FLAC__seekable_stream_decoder_set_client_data(decoder, my_client_data); - * if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) do_something; - * \endcode - * - * In FLAC 1.1.3 it is like this: - * - * \code - * FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new(); - * if(decoder == NULL) do_something; - * FLAC__stream_decoder_set_md5_checking(decoder, true); - * [... other settings ...] - * if(FLAC__stream_decoder_init_stream( - * decoder, - * my_read_callback, - * my_seek_callback, // or NULL - * my_tell_callback, // or NULL - * my_length_callback, // or NULL - * my_eof_callback, // or NULL - * my_write_callback, - * my_metadata_callback, // or NULL - * my_error_callback, - * my_client_data - * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; - * \endcode - * - * or you could do; - * - * \code - * [...] - * FILE *file = fopen("somefile.flac","rb"); - * if(file == NULL) do_somthing; - * if(FLAC__stream_decoder_init_FILE( - * decoder, - * file, - * my_write_callback, - * my_metadata_callback, // or NULL - * my_error_callback, - * my_client_data - * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; - * \endcode - * - * or just: - * - * \code - * [...] - * if(FLAC__stream_decoder_init_file( - * decoder, - * "somefile.flac", - * my_write_callback, - * my_metadata_callback, // or NULL - * my_error_callback, - * my_client_data - * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; - * \endcode - * - * Another small change to the decoder is in how it handles unparseable - * streams. Before, when the decoder found an unparseable stream - * (reserved for when the decoder encounters a stream from a future - * encoder that it can't parse), it changed the state to - * \c FLAC__STREAM_DECODER_UNPARSEABLE_STREAM. Now the decoder instead - * drops sync and calls the error callback with a new error code - * \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM. This is - * more robust. If your error callback does not discriminate on the the - * error state, your code does not need to be changed. - * - * The encoder now has a new setting: - * FLAC__stream_encoder_set_apodization(). This is for setting the - * method used to window the data before LPC analysis. You only need to - * add a call to this function if the default is not suitable. There - * are also two new convenience functions that may be useful: - * FLAC__metadata_object_cuesheet_calculate_cddb_id() and - * FLAC__metadata_get_cuesheet(). - * - * The \a bytes parameter to FLAC__StreamDecoderReadCallback, - * FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback - * is now \c size_t instead of \c uint32_t. - */ - -/** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4 - * \ingroup porting - * - * \brief - * This module describes porting from FLAC 1.1.3 to FLAC 1.1.4. - * - * There were no changes to any of the interfaces from 1.1.3 to 1.1.4. - * There was a slight change in the implementation of - * FLAC__stream_encoder_set_metadata(); the function now makes a copy - * of the \a metadata array of pointers so the client no longer needs - * to maintain it after the call. The objects themselves that are - * pointed to by the array are still not copied though and must be - * maintained until the call to FLAC__stream_encoder_finish(). - */ - -/** \defgroup porting_1_1_4_to_1_2_0 Porting from FLAC 1.1.4 to 1.2.0 - * \ingroup porting - * - * \brief - * This module describes porting from FLAC 1.1.4 to FLAC 1.2.0. - * - * There were only very minor changes to the interfaces from 1.1.4 to 1.2.0. - * In libFLAC, \c FLAC__format_sample_rate_is_subset() was added. - * In libFLAC++, \c FLAC::Decoder::Stream::get_decode_position() was added. - * - * Finally, value of the constant \c FLAC__FRAME_HEADER_RESERVED_LEN - * has changed to reflect the conversion of one of the reserved bits - * into active use. It used to be \c 2 and now is \c 1. However the - * FLAC frame header length has not changed, so to skip the proper - * number of bits, use \c FLAC__FRAME_HEADER_RESERVED_LEN + - * \c FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN - */ - -/** \defgroup porting_1_3_4_to_1_4_0 Porting from FLAC 1.3.4 to 1.4.0 - * \ingroup porting - * - * \brief - * This module describes porting from FLAC 1.3.4 to FLAC 1.4.0. - * - * \section porting_1_3_4_to_1_4_0_summary Summary - * - * Between FLAC 1.3.4 and FLAC 1.4.0, there have four breaking changes - * - the function get_client_data_from_decoder has been renamed to - * FLAC__get_decoder_client_data - * - some data types in the FLAC__Frame struct have changed - * - all functions resizing metadata blocks now return the object - * untouched if memory allocation fails, whereas previously the - * handling varied and was more or less undefined - * - all functions accepting a filename now take UTF-8 encoded filenames - * on Windows instead of filenames in the current codepage - * - * Furthermore, there have been the following additions - * - the functions FLAC__stream_encoder_set_limit_min_bitrate, - * FLAC__stream_encoder_get_limit_min_bitrate, - * FLAC::encoder::file::set_limit_min_bitrate() and - * FLAC::encoder::file::get_limit_min_bitrate() have been added - * - Added FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA to the - * FLAC__StreamDecoderErrorStatus enum - * - * \section porting_1_3_4_to_1_4_0_breaking Breaking changes - * - * The function \b get_client_data_from_decoder was added in FLAC 1.3.3 - * but did not follow the API naming convention and was not properly - * exported. The function is now renamed and properly integrated as - * FLAC__stream_decoder_get_client_data - * - * To accomodate encoding and decoding 32-bit int PCM, some data types - * in the \b FLAC__frame struct were changed. Specifically, warmup - * in both the FLAC__Subframe_Fixed struc and the FLAC__Subframe_LPC - * struct is changed from FLAC__int32 to FLAC__int64. Also, value - * in the FLAC__Subframe_Constant is changed from FLAC__int32 to - * FLAC__int64. Finally, in FLAC__Subframe_Verbatim struct data is - * changes from a FLAC__int32 array to a union containing a FLAC__int32 - * array and a FLAC__int64 array. Also, a new member is added, - * data_type, which clarifies whether the FLAC__int32 or FLAC__int64 - * array is in use. - * - * Furthermore, the following functions now return the object untouched - * if memory allocation fails, whereas previously the handling varied - * and was more or less undefined - * - * - FLAC__metadata_object_seektable_resize_points - * - FLAC__metadata_object_vorbiscomment_resize_comments - * - FLAC__metadata_object_cuesheet_track_resize_indices - * - FLAC__metadata_object_cuesheet_resize_tracks - * - * The last breaking change is that all API functions taking a filename - * as an argument now, on Windows, must be supplied with that filename - * in the UTF-8 character encoding instead of using the current code - * page. libFLAC internally translates these UTF-8 encoded filenames to - * an appropriate representation to use with _wfopen. On all other - * systems, filename is passed to fopen without any translation, as it - * in libFLAC 1.3.4 and earlier. - * - * \section porting_1_3_4_to_1_4_0_additions Additions - * - * To aid in creating properly streamable FLAC files, a set of functions - * was added to make it possible to enfore a minimum bitrate to files - * created through libFLAC's stream_encoder.h interface. With this - * function enabled the resulting FLAC files have a minimum bitrate of - * 1bit/sample independent of the number of channels, i.e. 48kbit/s for - * 48kHz. This can be beneficial for streaming, as very low bitrates for - * silent sections compressed with 'constant' subframes can result in a - * bitrate of 1kbit/s, creating problems with clients that aren't aware - * of this possibility and buffer too much data. - * - * Finally, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA was added to - * the FLAC__StreamDecoderErrorStatus enum to signal that the decoder - * encountered unreadable metadata. - * - */ - -/** \defgroup flac FLAC C API - * - * The FLAC C API is the interface to libFLAC, a set of structures - * describing the components of FLAC streams, and functions for - * encoding and decoding streams, as well as manipulating FLAC - * metadata in files. - * - * You should start with the format components as all other modules - * are dependent on it. - */ - -#endif diff --git a/code/dep_codecs/include/FLAC/assert.h b/code/dep_codecs/include/FLAC/assert.h deleted file mode 100755 index aee23c8c..00000000 --- a/code/dep_codecs/include/FLAC/assert.h +++ /dev/null @@ -1,46 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2022 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__ASSERT_H -#define FLAC__ASSERT_H - -/* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */ -#ifndef NDEBUG -#include -#define FLAC__ASSERT(x) assert(x) -#define FLAC__ASSERT_DECLARATION(x) x -#else -#define FLAC__ASSERT(x) -#define FLAC__ASSERT_DECLARATION(x) -#endif - -#endif diff --git a/code/dep_codecs/include/FLAC/callback.h b/code/dep_codecs/include/FLAC/callback.h deleted file mode 100755 index d00878b6..00000000 --- a/code/dep_codecs/include/FLAC/callback.h +++ /dev/null @@ -1,185 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2004-2009 Josh Coalson - * Copyright (C) 2011-2022 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__CALLBACK_H -#define FLAC__CALLBACK_H - -#include "ordinals.h" -#include /* for size_t */ - -/** \file include/FLAC/callback.h - * - * \brief - * This module defines the structures for describing I/O callbacks - * to the other FLAC interfaces. - * - * See the detailed documentation for callbacks in the - * \link flac_callbacks callbacks \endlink module. - */ - -/** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures - * \ingroup flac - * - * \brief - * This module defines the structures for describing I/O callbacks - * to the other FLAC interfaces. - * - * The purpose of the I/O callback functions is to create a common way - * for the metadata interfaces to handle I/O. - * - * Originally the metadata interfaces required filenames as the way of - * specifying FLAC files to operate on. This is problematic in some - * environments so there is an additional option to specify a set of - * callbacks for doing I/O on the FLAC file, instead of the filename. - * - * In addition to the callbacks, a FLAC__IOHandle type is defined as an - * opaque structure for a data source. - * - * The callback function prototypes are similar (but not identical) to the - * stdio functions fread, fwrite, fseek, ftell, feof, and fclose. If you use - * stdio streams to implement the callbacks, you can pass fread, fwrite, and - * fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or - * FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle - * is required. \warning You generally CANNOT directly use fseek or ftell - * for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems - * these use 32-bit offsets and FLAC requires 64-bit offsets to deal with - * large files. You will have to find an equivalent function (e.g. ftello), - * or write a wrapper. The same is true for feof() since this is usually - * implemented as a macro, not as a function whose address can be taken. - * - * \{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** This is the opaque handle type used by the callbacks. Typically - * this is a \c FILE* or address of a file descriptor. - */ -typedef void* FLAC__IOHandle; - -/** Signature for the read callback. - * The signature and semantics match POSIX fread() implementations - * and can generally be used interchangeably. - * - * \param ptr The address of the read buffer. - * \param size The size of the records to be read. - * \param nmemb The number of records to be read. - * \param handle The handle to the data source. - * \retval size_t - * The number of records read. - */ -typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); - -/** Signature for the write callback. - * The signature and semantics match POSIX fwrite() implementations - * and can generally be used interchangeably. - * - * \param ptr The address of the write buffer. - * \param size The size of the records to be written. - * \param nmemb The number of records to be written. - * \param handle The handle to the data source. - * \retval size_t - * The number of records written. - */ -typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); - -/** Signature for the seek callback. - * The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT - * EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long' - * and 32-bits wide. - * - * \param handle The handle to the data source. - * \param offset The new position, relative to \a whence - * \param whence \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END - * \retval int - * \c 0 on success, \c -1 on error. - */ -typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence); - -/** Signature for the tell callback. - * The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT - * EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long' - * and 32-bits wide. - * - * \param handle The handle to the data source. - * \retval FLAC__int64 - * The current position on success, \c -1 on error. - */ -typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle); - -/** Signature for the EOF callback. - * The signature and semantics mostly match POSIX feof() but WATCHOUT: - * on many systems, feof() is a macro, so in this case a wrapper function - * must be provided instead. - * - * \param handle The handle to the data source. - * \retval int - * \c 0 if not at end of file, nonzero if at end of file. - */ -typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle); - -/** Signature for the close callback. - * The signature and semantics match POSIX fclose() implementations - * and can generally be used interchangeably. - * - * \param handle The handle to the data source. - * \retval int - * \c 0 on success, \c EOF on error. - */ -typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle); - -/** A structure for holding a set of callbacks. - * Each FLAC interface that requires a FLAC__IOCallbacks structure will - * describe which of the callbacks are required. The ones that are not - * required may be set to NULL. - * - * If the seek requirement for an interface is optional, you can signify that - * a data source is not seekable by setting the \a seek field to \c NULL. - */ -typedef struct { - FLAC__IOCallback_Read read; /**< See FLAC__IOCallbacks */ - FLAC__IOCallback_Write write; /**< See FLAC__IOCallbacks */ - FLAC__IOCallback_Seek seek; /**< See FLAC__IOCallbacks */ - FLAC__IOCallback_Tell tell; /**< See FLAC__IOCallbacks */ - FLAC__IOCallback_Eof eof; /**< See FLAC__IOCallbacks */ - FLAC__IOCallback_Close close; /**< See FLAC__IOCallbacks */ -} FLAC__IOCallbacks; - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/code/dep_codecs/include/FLAC/export.h b/code/dep_codecs/include/FLAC/export.h deleted file mode 100755 index 983f13b1..00000000 --- a/code/dep_codecs/include/FLAC/export.h +++ /dev/null @@ -1,115 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2022 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__EXPORT_H -#define FLAC__EXPORT_H - -/** \file include/FLAC/export.h - * - * \brief - * This module contains \#defines and symbols for exporting function - * calls, and providing version information and compiled-in features. - * - * See the \link flac_export export \endlink module. - */ - -/** \defgroup flac_export FLAC/export.h: export symbols - * \ingroup flac - * - * \brief - * This module contains \#defines and symbols for exporting function - * calls, and providing version information and compiled-in features. - * - * If you are compiling for Windows (with Visual Studio or MinGW for - * example) and will link to the static library (libFLAC++.lib) you - * should define FLAC__NO_DLL in your project to make sure the symbols - * are exported properly. - * - * \{ - */ - -/** This \#define is used internally in libFLAC and its headers to make - * sure the correct symbols are exported when working with shared - * libraries. On Windows, this \#define is set to __declspec(dllexport) - * when compiling libFLAC into a library and to __declspec(dllimport) - * when the headers are used to link to that DLL. On non-Windows systems - * it is used to set symbol visibility. - * - * Because of this, the define FLAC__NO_DLL must be defined when linking - * to libFLAC statically or linking will fail. - */ -/* This has grown quite complicated. FLAC__NO_DLL is used by MSVC sln - * files and CMake, which build either static or shared. autotools can - * build static, shared or **both**. Therefore, DLL_EXPORT, which is set - * by libtool, must override FLAC__NO_DLL on building shared components - */ -#if defined(_WIN32) - -#if defined(FLAC__NO_DLL) && !(defined(DLL_EXPORT)) -#define FLAC_API -#else -#ifdef FLAC_API_EXPORTS -#define FLAC_API __declspec(dllexport) -#else -#define FLAC_API __declspec(dllimport) -#endif -#endif - -#elif defined(FLAC__USE_VISIBILITY_ATTR) -#define FLAC_API __attribute__ ((visibility ("default"))) - -#else -#define FLAC_API - -#endif - -/** These \#defines will mirror the libtool-based library version number, see - * http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning - */ -#define FLAC_API_VERSION_CURRENT 12 -#define FLAC_API_VERSION_REVISION 0 /**< see above */ -#define FLAC_API_VERSION_AGE 0 /**< see above */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \c 1 if the library has been compiled with support for Ogg FLAC, else \c 0. */ -extern FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC; - -#ifdef __cplusplus -} -#endif - -/* \} */ - -#endif diff --git a/code/dep_codecs/include/FLAC/format.h b/code/dep_codecs/include/FLAC/format.h deleted file mode 100755 index 2d548437..00000000 --- a/code/dep_codecs/include/FLAC/format.h +++ /dev/null @@ -1,1032 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2022 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__FORMAT_H -#define FLAC__FORMAT_H - -#include "export.h" -#include "ordinals.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** \file include/FLAC/format.h - * - * \brief - * This module contains structure definitions for the representation - * of FLAC format components in memory. These are the basic - * structures used by the rest of the interfaces. - * - * See the detailed documentation in the - * \link flac_format format \endlink module. - */ - -/** \defgroup flac_format FLAC/format.h: format components - * \ingroup flac - * - * \brief - * This module contains structure definitions for the representation - * of FLAC format components in memory. These are the basic - * structures used by the rest of the interfaces. - * - * First, you should be familiar with the - * FLAC format. Many of the values here - * follow directly from the specification. As a user of libFLAC, the - * interesting parts really are the structures that describe the frame - * header and metadata blocks. - * - * The format structures here are very primitive, designed to store - * information in an efficient way. Reading information from the - * structures is easy but creating or modifying them directly is - * more complex. For the most part, as a user of a library, editing - * is not necessary; however, for metadata blocks it is, so there are - * convenience functions provided in the \link flac_metadata metadata - * module \endlink to simplify the manipulation of metadata blocks. - * - * \note - * It's not the best convention, but symbols ending in _LEN are in bits - * and _LENGTH are in bytes. _LENGTH symbols are \#defines instead of - * global variables because they are usually used when declaring byte - * arrays and some compilers require compile-time knowledge of array - * sizes when declared on the stack. - * - * \{ - */ - - -/* - Most of the values described in this file are defined by the FLAC - format specification. There is nothing to tune here. -*/ - -/** The largest legal metadata type code. */ -#define FLAC__MAX_METADATA_TYPE_CODE (126u) - -/** The minimum block size, in samples, permitted by the format. */ -#define FLAC__MIN_BLOCK_SIZE (16u) - -/** The maximum block size, in samples, permitted by the format. */ -#define FLAC__MAX_BLOCK_SIZE (65535u) - -/** The maximum block size, in samples, permitted by the FLAC subset for - * sample rates up to 48kHz. */ -#define FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ (4608u) - -/** The maximum number of channels permitted by the format. */ -#define FLAC__MAX_CHANNELS (8u) - -/** The minimum sample resolution permitted by the format. */ -#define FLAC__MIN_BITS_PER_SAMPLE (4u) - -/** The maximum sample resolution permitted by the format. */ -#define FLAC__MAX_BITS_PER_SAMPLE (32u) - -/** The maximum sample resolution permitted by libFLAC. - * - * FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format. However, - * the reference encoder/decoder used to be limited to 24 bits. This - * value was used to signal that limit. - */ -#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (32u) - -/** The maximum sample rate permitted by the format. The value is - * ((2 ^ 20) - 1) - */ -#define FLAC__MAX_SAMPLE_RATE (1048575u) - -/** The maximum LPC order permitted by the format. */ -#define FLAC__MAX_LPC_ORDER (32u) - -/** The maximum LPC order permitted by the FLAC subset for sample rates - * up to 48kHz. */ -#define FLAC__SUBSET_MAX_LPC_ORDER_48000HZ (12u) - -/** The minimum quantized linear predictor coefficient precision - * permitted by the format. - */ -#define FLAC__MIN_QLP_COEFF_PRECISION (5u) - -/** The maximum quantized linear predictor coefficient precision - * permitted by the format. - */ -#define FLAC__MAX_QLP_COEFF_PRECISION (15u) - -/** The maximum order of the fixed predictors permitted by the format. */ -#define FLAC__MAX_FIXED_ORDER (4u) - -/** The maximum Rice partition order permitted by the format. */ -#define FLAC__MAX_RICE_PARTITION_ORDER (15u) - -/** The maximum Rice partition order permitted by the FLAC Subset. */ -#define FLAC__SUBSET_MAX_RICE_PARTITION_ORDER (8u) - -/** The version string of the release, stamped onto the libraries and binaries. - * - * \note - * This does not correspond to the shared library version number, which - * is used to determine binary compatibility. - */ -extern FLAC_API const char *FLAC__VERSION_STRING; - -/** The vendor string inserted by the encoder into the VORBIS_COMMENT block. - * This is a NUL-terminated ASCII string; when inserted into the - * VORBIS_COMMENT the trailing null is stripped. - */ -extern FLAC_API const char *FLAC__VENDOR_STRING; - -/** The byte string representation of the beginning of a FLAC stream. */ -extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */ - -/** The 32-bit integer big-endian representation of the beginning of - * a FLAC stream. - */ -extern FLAC_API const uint32_t FLAC__STREAM_SYNC; /* = 0x664C6143 */ - -/** The length of the FLAC signature in bits. */ -extern FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN; /* = 32 bits */ - -/** The length of the FLAC signature in bytes. */ -#define FLAC__STREAM_SYNC_LENGTH (4u) - - -/***************************************************************************** - * - * Subframe structures - * - *****************************************************************************/ - -/*****************************************************************************/ - -/** An enumeration of the available entropy coding methods. */ -typedef enum { - FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0, - /**< Residual is coded by partitioning into contexts, each with it's own - * 4-bit Rice parameter. */ - - FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 = 1 - /**< Residual is coded by partitioning into contexts, each with it's own - * 5-bit Rice parameter. */ -} FLAC__EntropyCodingMethodType; - -/** Maps a FLAC__EntropyCodingMethodType to a C string. - * - * Using a FLAC__EntropyCodingMethodType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[]; - - -/** Contents of a Rice partitioned residual - */ -typedef struct { - - uint32_t *parameters; - /**< The Rice parameters for each context. */ - - uint32_t *raw_bits; - /**< Widths for escape-coded partitions. Will be non-zero for escaped - * partitions and zero for unescaped partitions. - */ - - uint32_t capacity_by_order; - /**< The capacity of the \a parameters and \a raw_bits arrays - * specified as an order, i.e. the number of array elements - * allocated is 2 ^ \a capacity_by_order. - */ -} FLAC__EntropyCodingMethod_PartitionedRiceContents; - -/** Header for a Rice partitioned residual. (c.f. format specification) - */ -typedef struct { - - uint32_t order; - /**< The partition order, i.e. # of contexts = 2 ^ \a order. */ - - const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents; - /**< The context's Rice parameters and/or raw bits. */ - -} FLAC__EntropyCodingMethod_PartitionedRice; - -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */ -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */ - -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; -/**< == (1<format specification) - */ -typedef struct { - FLAC__EntropyCodingMethodType type; - union { - FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice; - } data; -} FLAC__EntropyCodingMethod; - -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */ - -/*****************************************************************************/ - -/** An enumeration of the available subframe types. */ -typedef enum { - FLAC__SUBFRAME_TYPE_CONSTANT = 0, /**< constant signal */ - FLAC__SUBFRAME_TYPE_VERBATIM = 1, /**< uncompressed signal */ - FLAC__SUBFRAME_TYPE_FIXED = 2, /**< fixed polynomial prediction */ - FLAC__SUBFRAME_TYPE_LPC = 3 /**< linear prediction */ -} FLAC__SubframeType; - -/** Maps a FLAC__SubframeType to a C string. - * - * Using a FLAC__SubframeType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__SubframeTypeString[]; - - -/** CONSTANT subframe. (c.f. format specification) - */ -typedef struct { - FLAC__int64 value; /**< The constant signal value. */ -} FLAC__Subframe_Constant; - -/** An enumeration of the possible verbatim subframe data types. */ -typedef enum { - FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32, /**< verbatim subframe has 32-bit int */ - FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT64 /**< verbatim subframe has 64-bit int */ -} FLAC__VerbatimSubframeDataType; - - -/** VERBATIM subframe. (c.f. format specification) - */ -typedef struct { - union { - const FLAC__int32 *int32; /**< A FLAC__int32 pointer to verbatim signal. */ - const FLAC__int64 *int64; /**< A FLAC__int64 pointer to verbatim signal. */ - } data; - FLAC__VerbatimSubframeDataType data_type; -} FLAC__Subframe_Verbatim; - - -/** FIXED subframe. (c.f. format specification) - */ -typedef struct { - FLAC__EntropyCodingMethod entropy_coding_method; - /**< The residual coding method. */ - - uint32_t order; - /**< The polynomial order. */ - - FLAC__int64 warmup[FLAC__MAX_FIXED_ORDER]; - /**< Warmup samples to prime the predictor, length == order. */ - - const FLAC__int32 *residual; - /**< The residual signal, length == (blocksize minus order) samples. */ -} FLAC__Subframe_Fixed; - - -/** LPC subframe. (c.f. format specification) - */ -typedef struct { - FLAC__EntropyCodingMethod entropy_coding_method; - /**< The residual coding method. */ - - uint32_t order; - /**< The FIR order. */ - - uint32_t qlp_coeff_precision; - /**< Quantized FIR filter coefficient precision in bits. */ - - int quantization_level; - /**< The qlp coeff shift needed. */ - - FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; - /**< FIR filter coefficients. */ - - FLAC__int64 warmup[FLAC__MAX_LPC_ORDER]; - /**< Warmup samples to prime the predictor, length == order. */ - - const FLAC__int32 *residual; - /**< The residual signal, length == (blocksize minus order) samples. */ -} FLAC__Subframe_LPC; - -extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */ - - -/** FLAC subframe structure. (c.f. format specification) - */ -typedef struct { - FLAC__SubframeType type; - union { - FLAC__Subframe_Constant constant; - FLAC__Subframe_Fixed fixed; - FLAC__Subframe_LPC lpc; - FLAC__Subframe_Verbatim verbatim; - } data; - uint32_t wasted_bits; -} FLAC__Subframe; - -/** == 1 (bit) - * - * This used to be a zero-padding bit (hence the name - * FLAC__SUBFRAME_ZERO_PAD_LEN) but is now a reserved bit. It still has a - * mandatory value of \c 0 but in the future may take on the value \c 0 or \c 1 - * to mean something else. - */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN; -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */ - -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */ - -/*****************************************************************************/ - - -/***************************************************************************** - * - * Frame structures - * - *****************************************************************************/ - -/** An enumeration of the available channel assignments. */ -typedef enum { - FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, /**< independent channels */ - FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, /**< left+side stereo */ - FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, /**< right+side stereo */ - FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 /**< mid+side stereo */ -} FLAC__ChannelAssignment; - -/** Maps a FLAC__ChannelAssignment to a C string. - * - * Using a FLAC__ChannelAssignment as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__ChannelAssignmentString[]; - -/** An enumeration of the possible frame numbering methods. */ -typedef enum { - FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER, /**< number contains the frame number */ - FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER /**< number contains the sample number of first sample in frame */ -} FLAC__FrameNumberType; - -/** Maps a FLAC__FrameNumberType to a C string. - * - * Using a FLAC__FrameNumberType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__FrameNumberTypeString[]; - - -/** FLAC frame header structure. (c.f. format specification) - */ -typedef struct { - uint32_t blocksize; - /**< The number of samples per subframe. */ - - uint32_t sample_rate; - /**< The sample rate in Hz. */ - - uint32_t channels; - /**< The number of channels (== number of subframes). */ - - FLAC__ChannelAssignment channel_assignment; - /**< The channel assignment for the frame. */ - - uint32_t bits_per_sample; - /**< The sample resolution. */ - - FLAC__FrameNumberType number_type; - /**< The numbering scheme used for the frame. As a convenience, the - * decoder will always convert a frame number to a sample number because - * the rules are complex. */ - - union { - FLAC__uint32 frame_number; - FLAC__uint64 sample_number; - } number; - /**< The frame number or sample number of first sample in frame; - * use the \a number_type value to determine which to use. */ - - FLAC__uint8 crc; - /**< CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0) - * of the raw frame header bytes, meaning everything before the CRC byte - * including the sync code. - */ -} FLAC__FrameHeader; - -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */ - - -/** FLAC frame footer structure. (c.f. format specification) - */ -typedef struct { - FLAC__uint16 crc; - /**< CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with - * 0) of the bytes before the crc, back to and including the frame header - * sync code. - */ -} FLAC__FrameFooter; - -extern FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */ - - -/** FLAC frame structure. (c.f. format specification) - */ -typedef struct { - FLAC__FrameHeader header; - FLAC__Subframe subframes[FLAC__MAX_CHANNELS]; - FLAC__FrameFooter footer; -} FLAC__Frame; - -/*****************************************************************************/ - - -/***************************************************************************** - * - * Meta-data structures - * - *****************************************************************************/ - -/** An enumeration of the available metadata block types. */ -typedef enum { - - FLAC__METADATA_TYPE_STREAMINFO = 0, - /**< STREAMINFO block */ - - FLAC__METADATA_TYPE_PADDING = 1, - /**< PADDING block */ - - FLAC__METADATA_TYPE_APPLICATION = 2, - /**< APPLICATION block */ - - FLAC__METADATA_TYPE_SEEKTABLE = 3, - /**< SEEKTABLE block */ - - FLAC__METADATA_TYPE_VORBIS_COMMENT = 4, - /**< VORBISCOMMENT block (a.k.a. FLAC tags) */ - - FLAC__METADATA_TYPE_CUESHEET = 5, - /**< CUESHEET block */ - - FLAC__METADATA_TYPE_PICTURE = 6, - /**< PICTURE block */ - - FLAC__METADATA_TYPE_UNDEFINED = 7, - /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */ - - FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE, - /**< No type will ever be greater than this. There is not enough room in the protocol block. */ -} FLAC__MetadataType; - -/** Maps a FLAC__MetadataType to a C string. - * - * Using a FLAC__MetadataType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__MetadataTypeString[]; - - -/** FLAC STREAMINFO structure. (c.f. format specification) - */ -typedef struct { - uint32_t min_blocksize, max_blocksize; - uint32_t min_framesize, max_framesize; - uint32_t sample_rate; - uint32_t channels; - uint32_t bits_per_sample; - FLAC__uint64 total_samples; - FLAC__byte md5sum[16]; -} FLAC__StreamMetadata_StreamInfo; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */ - -/** The total stream length of the STREAMINFO block in bytes. */ -#define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u) - -/** FLAC PADDING structure. (c.f. format specification) - */ -typedef struct { - int dummy; - /**< Conceptually this is an empty struct since we don't store the - * padding bytes. Empty structs are not allowed by some C compilers, - * hence the dummy. - */ -} FLAC__StreamMetadata_Padding; - - -/** FLAC APPLICATION structure. (c.f. format specification) - */ -typedef struct { - FLAC__byte id[4]; - FLAC__byte *data; -} FLAC__StreamMetadata_Application; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */ - -/** SeekPoint structure used in SEEKTABLE blocks. (c.f. format specification) - */ -typedef struct { - FLAC__uint64 sample_number; - /**< The sample number of the target frame. */ - - FLAC__uint64 stream_offset; - /**< The offset, in bytes, of the target frame with respect to - * beginning of the first frame. */ - - uint32_t frame_samples; - /**< The number of samples in the target frame. */ -} FLAC__StreamMetadata_SeekPoint; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */ - -/** The total stream length of a seek point in bytes. */ -#define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u) - -/** The value used in the \a sample_number field of - * FLAC__StreamMetadataSeekPoint used to indicate a placeholder - * point (== 0xffffffffffffffff). - */ -extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; - - -/** FLAC SEEKTABLE structure. (c.f. format specification) - * - * \note From the format specification: - * - The seek points must be sorted by ascending sample number. - * - Each seek point's sample number must be the first sample of the - * target frame. - * - Each seek point's sample number must be unique within the table. - * - Existence of a SEEKTABLE block implies a correct setting of - * total_samples in the stream_info block. - * - Behavior is undefined when more than one SEEKTABLE block is - * present in a stream. - */ -typedef struct { - uint32_t num_points; - FLAC__StreamMetadata_SeekPoint *points; -} FLAC__StreamMetadata_SeekTable; - - -/** Vorbis comment entry structure used in VORBIS_COMMENT blocks. (c.f. format specification) - * - * For convenience, the APIs maintain a trailing NUL character at the end of - * \a entry which is not counted toward \a length, i.e. - * \code strlen(entry) == length \endcode - */ -typedef struct { - FLAC__uint32 length; - FLAC__byte *entry; -} FLAC__StreamMetadata_VorbisComment_Entry; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */ - - -/** FLAC VORBIS_COMMENT structure. (c.f. format specification) - */ -typedef struct { - FLAC__StreamMetadata_VorbisComment_Entry vendor_string; - FLAC__uint32 num_comments; - FLAC__StreamMetadata_VorbisComment_Entry *comments; -} FLAC__StreamMetadata_VorbisComment; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */ - - -/** FLAC CUESHEET track index structure. (See the - * format specification for - * the full description of each field.) - */ -typedef struct { - FLAC__uint64 offset; - /**< Offset in samples, relative to the track offset, of the index - * point. - */ - - FLAC__byte number; - /**< The index point number. */ -} FLAC__StreamMetadata_CueSheet_Index; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */ - - -/** FLAC CUESHEET track structure. (See the - * format specification for - * the full description of each field.) - */ -typedef struct { - FLAC__uint64 offset; - /**< Track offset in samples, relative to the beginning of the FLAC audio stream. */ - - FLAC__byte number; - /**< The track number. */ - - char isrc[13]; - /**< Track ISRC. This is a 12-digit alphanumeric code plus a trailing \c NUL byte */ - - uint32_t type:1; - /**< The track type: 0 for audio, 1 for non-audio. */ - - uint32_t pre_emphasis:1; - /**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */ - - FLAC__byte num_indices; - /**< The number of track index points. */ - - FLAC__StreamMetadata_CueSheet_Index *indices; - /**< NULL if num_indices == 0, else pointer to array of index points. */ - -} FLAC__StreamMetadata_CueSheet_Track; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */ - - -/** FLAC CUESHEET structure. (See the - * format specification - * for the full description of each field.) - */ -typedef struct { - char media_catalog_number[129]; - /**< Media catalog number, in ASCII printable characters 0x20-0x7e. In - * general, the media catalog number may be 0 to 128 bytes long; any - * unused characters should be right-padded with NUL characters. - */ - - FLAC__uint64 lead_in; - /**< The number of lead-in samples. */ - - FLAC__bool is_cd; - /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */ - - uint32_t num_tracks; - /**< The number of tracks. */ - - FLAC__StreamMetadata_CueSheet_Track *tracks; - /**< NULL if num_tracks == 0, else pointer to array of tracks. */ - -} FLAC__StreamMetadata_CueSheet; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */ - - -/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */ -typedef enum { - FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */ - FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */ - FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */ - FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */ - FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */ - FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */ - FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */ - FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */ - FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */ - FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */ - FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */ - FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */ - FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */ - FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */ - FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED -} FLAC__StreamMetadata_Picture_Type; - -/** Maps a FLAC__StreamMetadata_Picture_Type to a C string. - * - * Using a FLAC__StreamMetadata_Picture_Type as the index to this array - * will give the string equivalent. The contents should not be - * modified. - */ -extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[]; - -/** FLAC PICTURE structure. (See the - * format specification - * for the full description of each field.) - */ -typedef struct { - FLAC__StreamMetadata_Picture_Type type; - /**< The kind of picture stored. */ - - char *mime_type; - /**< Picture data's MIME type, in ASCII printable characters - * 0x20-0x7e, NUL terminated. For best compatibility with players, - * use picture data of MIME type \c image/jpeg or \c image/png. A - * MIME type of '-->' is also allowed, in which case the picture - * data should be a complete URL. In file storage, the MIME type is - * stored as a 32-bit length followed by the ASCII string with no NUL - * terminator, but is converted to a plain C string in this structure - * for convenience. - */ - - FLAC__byte *description; - /**< Picture's description in UTF-8, NUL terminated. In file storage, - * the description is stored as a 32-bit length followed by the UTF-8 - * string with no NUL terminator, but is converted to a plain C string - * in this structure for convenience. - */ - - FLAC__uint32 width; - /**< Picture's width in pixels. */ - - FLAC__uint32 height; - /**< Picture's height in pixels. */ - - FLAC__uint32 depth; - /**< Picture's color depth in bits-per-pixel. */ - - FLAC__uint32 colors; - /**< For indexed palettes (like GIF), picture's number of colors (the - * number of palette entries), or \c 0 for non-indexed (i.e. 2^depth). - */ - - FLAC__uint32 data_length; - /**< Length of binary picture data in bytes. */ - - FLAC__byte *data; - /**< Binary picture data. */ - -} FLAC__StreamMetadata_Picture; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */ - - -/** Structure that is used when a metadata block of unknown type is loaded. - * The contents are opaque. The structure is used only internally to - * correctly handle unknown metadata. - */ -typedef struct { - FLAC__byte *data; -} FLAC__StreamMetadata_Unknown; - - -/** FLAC metadata block structure. (c.f. format specification) - */ -typedef struct FLAC__StreamMetadata { - FLAC__MetadataType type; - /**< The type of the metadata block; used determine which member of the - * \a data union to dereference. If type >= FLAC__METADATA_TYPE_UNDEFINED - * then \a data.unknown must be used. */ - - FLAC__bool is_last; - /**< \c true if this metadata block is the last, else \a false */ - - uint32_t length; - /**< Length, in bytes, of the block data as it appears in the stream. */ - - union { - FLAC__StreamMetadata_StreamInfo stream_info; - FLAC__StreamMetadata_Padding padding; - FLAC__StreamMetadata_Application application; - FLAC__StreamMetadata_SeekTable seek_table; - FLAC__StreamMetadata_VorbisComment vorbis_comment; - FLAC__StreamMetadata_CueSheet cue_sheet; - FLAC__StreamMetadata_Picture picture; - FLAC__StreamMetadata_Unknown unknown; - } data; - /**< Polymorphic block data; use the \a type value to determine which - * to use. */ -} FLAC__StreamMetadata; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */ - -/** The total stream length of a metadata block header in bytes. */ -#define FLAC__STREAM_METADATA_HEADER_LENGTH (4u) - -/*****************************************************************************/ - - -/***************************************************************************** - * - * Utility functions - * - *****************************************************************************/ - -/** Tests that a sample rate is valid for FLAC. - * - * \param sample_rate The sample rate to test for compliance. - * \retval FLAC__bool - * \c true if the given sample rate conforms to the specification, else - * \c false. - */ -FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(uint32_t sample_rate); - -/** Tests that a blocksize at the given sample rate is valid for the FLAC - * subset. - * - * \param blocksize The blocksize to test for compliance. - * \param sample_rate The sample rate is needed, since the valid subset - * blocksize depends on the sample rate. - * \retval FLAC__bool - * \c true if the given blocksize conforms to the specification for the - * subset at the given sample rate, else \c false. - */ -FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate); - -/** Tests that a sample rate is valid for the FLAC subset. The subset rules - * for valid sample rates are slightly more complex since the rate has to - * be expressible completely in the frame header. - * - * \param sample_rate The sample rate to test for compliance. - * \retval FLAC__bool - * \c true if the given sample rate conforms to the specification for the - * subset, else \c false. - */ -FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate); - -/** Check a Vorbis comment entry name to see if it conforms to the Vorbis - * comment specification. - * - * Vorbis comment names must be composed only of characters from - * [0x20-0x3C,0x3E-0x7D]. - * - * \param name A NUL-terminated string to be checked. - * \assert - * \code name != NULL \endcode - * \retval FLAC__bool - * \c false if entry name is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name); - -/** Check a Vorbis comment entry value to see if it conforms to the Vorbis - * comment specification. - * - * Vorbis comment values must be valid UTF-8 sequences. - * - * \param value A string to be checked. - * \param length A the length of \a value in bytes. May be - * \c (uint32_t)(-1) to indicate that \a value is a plain - * UTF-8 NUL-terminated string. - * \assert - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if entry name is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length); - -/** Check a Vorbis comment entry to see if it conforms to the Vorbis - * comment specification. - * - * Vorbis comment entries must be of the form 'name=value', and 'name' and - * 'value' must be legal according to - * FLAC__format_vorbiscomment_entry_name_is_legal() and - * FLAC__format_vorbiscomment_entry_value_is_legal() respectively. - * - * \param entry An entry to be checked. - * \param length The length of \a entry in bytes. - * \assert - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if entry name is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length); - -/** Check a seek table to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * seek table. - * - * \param seek_table A pointer to a seek table to be checked. - * \assert - * \code seek_table != NULL \endcode - * \retval FLAC__bool - * \c false if seek table is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table); - -/** Sort a seek table's seek points according to the format specification. - * This includes a "unique-ification" step to remove duplicates, i.e. - * seek points with identical \a sample_number values. Duplicate seek - * points are converted into placeholder points and sorted to the end of - * the table. - * - * \param seek_table A pointer to a seek table to be sorted. - * \assert - * \code seek_table != NULL \endcode - * \retval uint32_t - * The number of duplicate seek points converted into placeholders. - */ -FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table); - -/** Check a cue sheet to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * cue sheet. - * - * \param cue_sheet A pointer to an existing cue sheet to be checked. - * \param check_cd_da_subset If \c true, check CUESHEET against more - * stringent requirements for a CD-DA (audio) disc. - * \param violation Address of a pointer to a string. If there is a - * violation, a pointer to a string explanation of the - * violation will be returned here. \a violation may be - * \c NULL if you don't need the returned string. Do not - * free the returned string; it will always point to static - * data. - * \assert - * \code cue_sheet != NULL \endcode - * \retval FLAC__bool - * \c false if cue sheet is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation); - -/** Check picture data to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * PICTURE block. - * - * \param picture A pointer to existing picture data to be checked. - * \param violation Address of a pointer to a string. If there is a - * violation, a pointer to a string explanation of the - * violation will be returned here. \a violation may be - * \c NULL if you don't need the returned string. Do not - * free the returned string; it will always point to static - * data. - * \assert - * \code picture != NULL \endcode - * \retval FLAC__bool - * \c false if picture data is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/code/dep_codecs/include/FLAC/metadata.h b/code/dep_codecs/include/FLAC/metadata.h deleted file mode 100755 index 651b7405..00000000 --- a/code/dep_codecs/include/FLAC/metadata.h +++ /dev/null @@ -1,2206 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2022 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__METADATA_H -#define FLAC__METADATA_H - -#include /* for off_t */ -#include "export.h" -#include "callback.h" -#include "format.h" - -/* -------------------------------------------------------------------- - (For an example of how all these routines are used, see the source - code for the unit tests in src/test_libFLAC/metadata_*.c, or - metaflac in src/metaflac/) - ------------------------------------------------------------------*/ - -/** \file include/FLAC/metadata.h - * - * \brief - * This module provides functions for creating and manipulating FLAC - * metadata blocks in memory, and three progressively more powerful - * interfaces for traversing and editing metadata in FLAC files. - * - * See the detailed documentation for each interface in the - * \link flac_metadata metadata \endlink module. - */ - -/** \defgroup flac_metadata FLAC/metadata.h: metadata interfaces - * \ingroup flac - * - * \brief - * This module provides functions for creating and manipulating FLAC - * metadata blocks in memory, and three progressively more powerful - * interfaces for traversing and editing metadata in native FLAC files. - * Note that currently only the Chain interface (level 2) supports Ogg - * FLAC files, and it is read-only i.e. no writing back changed - * metadata to file. - * - * There are three metadata interfaces of increasing complexity: - * - * Level 0: - * Read-only access to the STREAMINFO, VORBIS_COMMENT, CUESHEET, and - * PICTURE blocks. - * - * Level 1: - * Read-write access to all metadata blocks. This level is write- - * efficient in most cases (more on this below), and uses less memory - * than level 2. - * - * Level 2: - * Read-write access to all metadata blocks. This level is write- - * efficient in all cases, but uses more memory since all metadata for - * the whole file is read into memory and manipulated before writing - * out again. - * - * What do we mean by efficient? Since FLAC metadata appears at the - * beginning of the file, when writing metadata back to a FLAC file - * it is possible to grow or shrink the metadata such that the entire - * file must be rewritten. However, if the size remains the same during - * changes or PADDING blocks are utilized, only the metadata needs to be - * overwritten, which is much faster. - * - * Efficient means the whole file is rewritten at most one time, and only - * when necessary. Level 1 is not efficient only in the case that you - * cause more than one metadata block to grow or shrink beyond what can - * be accommodated by padding. In this case you should probably use level - * 2, which allows you to edit all the metadata for a file in memory and - * write it out all at once. - * - * All levels know how to skip over and not disturb an ID3v2 tag at the - * front of the file. - * - * All levels access files via their filenames. In addition, level 2 - * has additional alternative read and write functions that take an I/O - * handle and callbacks, for situations where access by filename is not - * possible. - * - * In addition to the three interfaces, this module defines functions for - * creating and manipulating various metadata objects in memory. As we see - * from the Format module, FLAC metadata blocks in memory are very primitive - * structures for storing information in an efficient way. Reading - * information from the structures is easy but creating or modifying them - * directly is more complex. The metadata object routines here facilitate - * this by taking care of the consistency and memory management drudgery. - * - * Unless you will be using the level 1 or 2 interfaces to modify existing - * metadata however, you will not probably not need these. - * - * From a dependency standpoint, none of the encoders or decoders require - * the metadata module. This is so that embedded users can strip out the - * metadata module from libFLAC to reduce the size and complexity. - */ - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \defgroup flac_metadata_level0 FLAC/metadata.h: metadata level 0 interface - * \ingroup flac_metadata - * - * \brief - * The level 0 interface consists of individual routines to read the - * STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring - * only a filename. - * - * On Windows, filename must be a UTF-8 encoded filename, which libFLAC - * internally translates to an appropriate representation to use with - * _wfopen. On all other systems, filename is passed to fopen without - * any translation. - * - * They try to skip any ID3v2 tag at the head of the file. - * - * \{ - */ - -/** Read the STREAMINFO metadata block of the given FLAC file. This function - * will try to skip any ID3v2 tag at the head of the file. - * - * \param filename The path to the FLAC file to read. - * \param streaminfo A pointer to space for the STREAMINFO block. Since - * FLAC__StreamMetadata is a simple structure with no - * memory allocation involved, you pass the address of - * an existing structure. It need not be initialized. - * \assert - * \code filename != NULL \endcode - * \code streaminfo != NULL \endcode - * \retval FLAC__bool - * \c true if a valid STREAMINFO block was read from \a filename. Returns - * \c false if there was a memory allocation error, a file decoder error, - * or the file contained no STREAMINFO block. (A memory allocation error - * is possible because this function must set up a file decoder.) - */ -FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo); - -/** Read the VORBIS_COMMENT metadata block of the given FLAC file. This - * function will try to skip any ID3v2 tag at the head of the file. - * - * \param filename The path to the FLAC file to read. - * \param tags The address where the returned pointer will be - * stored. The \a tags object must be deleted by - * the caller using FLAC__metadata_object_delete(). - * \assert - * \code filename != NULL \endcode - * \code tags != NULL \endcode - * \retval FLAC__bool - * \c true if a valid VORBIS_COMMENT block was read from \a filename, - * and \a *tags will be set to the address of the metadata structure. - * Returns \c false if there was a memory allocation error, a file - * decoder error, or the file contained no VORBIS_COMMENT block, and - * \a *tags will be set to \c NULL. - */ -FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags); - -/** Read the CUESHEET metadata block of the given FLAC file. This - * function will try to skip any ID3v2 tag at the head of the file. - * - * \param filename The path to the FLAC file to read. - * \param cuesheet The address where the returned pointer will be - * stored. The \a cuesheet object must be deleted by - * the caller using FLAC__metadata_object_delete(). - * \assert - * \code filename != NULL \endcode - * \code cuesheet != NULL \endcode - * \retval FLAC__bool - * \c true if a valid CUESHEET block was read from \a filename, - * and \a *cuesheet will be set to the address of the metadata - * structure. Returns \c false if there was a memory allocation - * error, a file decoder error, or the file contained no CUESHEET - * block, and \a *cuesheet will be set to \c NULL. - */ -FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet); - -/** Read a PICTURE metadata block of the given FLAC file. This - * function will try to skip any ID3v2 tag at the head of the file. - * Since there can be more than one PICTURE block in a file, this - * function takes a number of parameters that act as constraints to - * the search. The PICTURE block with the largest area matching all - * the constraints will be returned, or \a *picture will be set to - * \c NULL if there was no such block. - * - * \param filename The path to the FLAC file to read. - * \param picture The address where the returned pointer will be - * stored. The \a picture object must be deleted by - * the caller using FLAC__metadata_object_delete(). - * \param type The desired picture type. Use \c -1 to mean - * "any type". - * \param mime_type The desired MIME type, e.g. "image/jpeg". The - * string will be matched exactly. Use \c NULL to - * mean "any MIME type". - * \param description The desired description. The string will be - * matched exactly. Use \c NULL to mean "any - * description". - * \param max_width The maximum width in pixels desired. Use - * \c (uint32_t)(-1) to mean "any width". - * \param max_height The maximum height in pixels desired. Use - * \c (uint32_t)(-1) to mean "any height". - * \param max_depth The maximum color depth in bits-per-pixel desired. - * Use \c (uint32_t)(-1) to mean "any depth". - * \param max_colors The maximum number of colors desired. Use - * \c (uint32_t)(-1) to mean "any number of colors". - * \assert - * \code filename != NULL \endcode - * \code picture != NULL \endcode - * \retval FLAC__bool - * \c true if a valid PICTURE block was read from \a filename, - * and \a *picture will be set to the address of the metadata - * structure. Returns \c false if there was a memory allocation - * error, a file decoder error, or the file contained no PICTURE - * block, and \a *picture will be set to \c NULL. - */ -FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors); - -/* \} */ - - -/** \defgroup flac_metadata_level1 FLAC/metadata.h: metadata level 1 interface - * \ingroup flac_metadata - * - * \brief - * The level 1 interface provides read-write access to FLAC file metadata and - * operates directly on the FLAC file. - * - * The general usage of this interface is: - * - * - Create an iterator using FLAC__metadata_simple_iterator_new() - * - Attach it to a file using FLAC__metadata_simple_iterator_init() and check - * the exit code. Call FLAC__metadata_simple_iterator_is_writable() to - * see if the file is writable, or only read access is allowed. - * - Use FLAC__metadata_simple_iterator_next() and - * FLAC__metadata_simple_iterator_prev() to traverse the blocks. - * This is does not read the actual blocks themselves. - * FLAC__metadata_simple_iterator_next() is relatively fast. - * FLAC__metadata_simple_iterator_prev() is slower since it needs to search - * forward from the front of the file. - * - Use FLAC__metadata_simple_iterator_get_block_type() or - * FLAC__metadata_simple_iterator_get_block() to access the actual data at - * the current iterator position. The returned object is yours to modify - * and free. - * - Use FLAC__metadata_simple_iterator_set_block() to write a modified block - * back. You must have write permission to the original file. Make sure to - * read the whole comment to FLAC__metadata_simple_iterator_set_block() - * below. - * - Use FLAC__metadata_simple_iterator_insert_block_after() to add new blocks. - * Use the object creation functions from - * \link flac_metadata_object here \endlink to generate new objects. - * - Use FLAC__metadata_simple_iterator_delete_block() to remove the block - * currently referred to by the iterator, or replace it with padding. - * - Destroy the iterator with FLAC__metadata_simple_iterator_delete() when - * finished. - * - * \note - * The FLAC file remains open the whole time between - * FLAC__metadata_simple_iterator_init() and - * FLAC__metadata_simple_iterator_delete(), so make sure you are not altering - * the file during this time. - * - * \note - * Do not modify the \a is_last, \a length, or \a type fields of returned - * FLAC__StreamMetadata objects. These are managed automatically. - * - * \note - * If any of the modification functions - * (FLAC__metadata_simple_iterator_set_block(), - * FLAC__metadata_simple_iterator_delete_block(), - * FLAC__metadata_simple_iterator_insert_block_after(), etc.) return \c false, - * you should delete the iterator as it may no longer be valid. - * - * \{ - */ - -struct FLAC__Metadata_SimpleIterator; -/** The opaque structure definition for the level 1 iterator type. - * See the - * \link flac_metadata_level1 metadata level 1 module \endlink - * for a detailed description. - */ -typedef struct FLAC__Metadata_SimpleIterator FLAC__Metadata_SimpleIterator; - -/** Status type for FLAC__Metadata_SimpleIterator. - * - * The iterator's current status can be obtained by calling FLAC__metadata_simple_iterator_status(). - */ -typedef enum { - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK = 0, - /**< The iterator is in the normal OK state */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, - /**< The data passed into a function violated the function's usage criteria */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE, - /**< The iterator could not open the target file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE, - /**< The iterator could not find the FLAC signature at the start of the file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE, - /**< The iterator tried to write to a file that was not writable */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA, - /**< The iterator encountered input that does not conform to the FLAC metadata specification */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR, - /**< The iterator encountered an error while reading the FLAC file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, - /**< The iterator encountered an error while seeking in the FLAC file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR, - /**< The iterator encountered an error while writing the FLAC file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR, - /**< The iterator encountered an error renaming the FLAC file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR, - /**< The iterator encountered an error removing the temporary file */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR, - /**< Memory allocation failed */ - - FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR - /**< The caller violated an assertion or an unexpected error occurred */ - -} FLAC__Metadata_SimpleIteratorStatus; - -/** Maps a FLAC__Metadata_SimpleIteratorStatus to a C string. - * - * Using a FLAC__Metadata_SimpleIteratorStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[]; - - -/** Create a new iterator instance. - * - * \retval FLAC__Metadata_SimpleIterator* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void); - -/** Free an iterator instance. Deletes the object pointed to by \a iterator. - * - * \param iterator A pointer to an existing iterator. - * \assert - * \code iterator != NULL \endcode - */ -FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator); - -/** Get the current status of the iterator. Call this after a function - * returns \c false to get the reason for the error. Also resets the status - * to FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK. - * - * \param iterator A pointer to an existing iterator. - * \assert - * \code iterator != NULL \endcode - * \retval FLAC__Metadata_SimpleIteratorStatus - * The current status of the iterator. - */ -FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator); - -/** Initialize the iterator to point to the first metadata block in the - * given FLAC file. - * - * On Windows, filename must be a UTF-8 encoded filename, which libFLAC - * internally translates to an appropriate representation to use with - * _wfopen. On all other systems, filename is passed to fopen without - * any translation. - * - * \param iterator A pointer to an existing iterator. - * \param filename The path to the FLAC file. - * \param read_only If \c true, the FLAC file will be opened - * in read-only mode; if \c false, the FLAC - * file will be opened for edit even if no - * edits are performed. - * \param preserve_file_stats If \c true, the owner and modification - * time will be preserved even if the FLAC - * file is written to. - * \assert - * \code iterator != NULL \endcode - * \code filename != NULL \endcode - * \retval FLAC__bool - * \c false if a memory allocation error occurs, the file can't be - * opened, or another error occurs, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats); - -/** Returns \c true if the FLAC file is writable. If \c false, calls to - * FLAC__metadata_simple_iterator_set_block() and - * FLAC__metadata_simple_iterator_insert_block_after() will fail. - * - * \param iterator A pointer to an existing iterator. - * \assert - * \code iterator != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator); - -/** Moves the iterator forward one metadata block, returning \c false if - * already at the end. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__bool - * \c false if already at the last metadata block of the chain, else - * \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator); - -/** Moves the iterator backward one metadata block, returning \c false if - * already at the beginning. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__bool - * \c false if already at the first metadata block of the chain, else - * \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator); - -/** Returns a flag telling if the current metadata block is the last. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__bool - * \c true if the current metadata block is the last in the file, - * else \c false. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator); - -/** Get the offset of the metadata block at the current position. This - * avoids reading the actual block data which can save time for large - * blocks. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval off_t - * The offset of the metadata block at the current iterator position. - * This is the byte offset relative to the beginning of the file of - * the current metadata block's header. - */ -FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator); - -/** Get the type of the metadata block at the current position. This - * avoids reading the actual block data which can save time for large - * blocks. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__MetadataType - * The type of the metadata block at the current iterator position. - */ -FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator); - -/** Get the length of the metadata block at the current position. This - * avoids reading the actual block data which can save time for large - * blocks. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval uint32_t - * The length of the metadata block at the current iterator position. - * The is same length as that in the - * metadata block header, - * i.e. the length of the metadata body that follows the header. - */ -FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator); - -/** Get the application ID of the \c APPLICATION block at the current - * position. This avoids reading the actual block data which can save - * time for large blocks. - * - * \param iterator A pointer to an existing initialized iterator. - * \param id A pointer to a buffer of at least \c 4 bytes where - * the ID will be stored. - * \assert - * \code iterator != NULL \endcode - * \code id != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__bool - * \c true if the ID was successfully read, else \c false, in which - * case you should check FLAC__metadata_simple_iterator_status() to - * find out why. If the status is - * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, then the - * current metadata block is not an \c APPLICATION block. Otherwise - * if the status is - * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR or - * \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, an I/O error - * occurred and the iterator can no longer be used. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id); - -/** Get the metadata block at the current position. You can modify the - * block but must use FLAC__metadata_simple_iterator_set_block() to - * write it back to the FLAC file. - * - * You must call FLAC__metadata_object_delete() on the returned object - * when you are finished with it. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__StreamMetadata* - * The current metadata block, or \c NULL if there was a memory - * allocation error. - */ -FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator); - -/** Write a block back to the FLAC file. This function tries to be - * as efficient as possible; how the block is actually written is - * shown by the following: - * - * Existing block is a STREAMINFO block and the new block is a - * STREAMINFO block: the new block is written in place. Make sure - * you know what you're doing when changing the values of a - * STREAMINFO block. - * - * Existing block is a STREAMINFO block and the new block is a - * not a STREAMINFO block: this is an error since the first block - * must be a STREAMINFO block. Returns \c false without altering the - * file. - * - * Existing block is not a STREAMINFO block and the new block is a - * STREAMINFO block: this is an error since there may be only one - * STREAMINFO block. Returns \c false without altering the file. - * - * Existing block and new block are the same length: the existing - * block will be replaced by the new block, written in place. - * - * Existing block is longer than new block: if use_padding is \c true, - * the existing block will be overwritten in place with the new - * block followed by a PADDING block, if possible, to make the total - * size the same as the existing block. Remember that a padding - * block requires at least four bytes so if the difference in size - * between the new block and existing block is less than that, the - * entire file will have to be rewritten, using the new block's - * exact size. If use_padding is \c false, the entire file will be - * rewritten, replacing the existing block by the new block. - * - * Existing block is shorter than new block: if use_padding is \c true, - * the function will try and expand the new block into the following - * PADDING block, if it exists and doing so won't shrink the PADDING - * block to less than 4 bytes. If there is no following PADDING - * block, or it will shrink to less than 4 bytes, or use_padding is - * \c false, the entire file is rewritten, replacing the existing block - * with the new block. Note that in this case any following PADDING - * block is preserved as is. - * - * After writing the block, the iterator will remain in the same - * place, i.e. pointing to the new block. - * - * \param iterator A pointer to an existing initialized iterator. - * \param block The block to set. - * \param use_padding See above. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \code block != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding); - -/** This is similar to FLAC__metadata_simple_iterator_set_block() - * except that instead of writing over an existing block, it appends - * a block after the existing block. \a use_padding is again used to - * tell the function to try an expand into following padding in an - * attempt to avoid rewriting the entire file. - * - * This function will fail and return \c false if given a STREAMINFO - * block. - * - * After writing the block, the iterator will be pointing to the - * new block. - * - * \param iterator A pointer to an existing initialized iterator. - * \param block The block to set. - * \param use_padding See above. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \code block != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding); - -/** Deletes the block at the current position. This will cause the - * entire FLAC file to be rewritten, unless \a use_padding is \c true, - * in which case the block will be replaced by an equal-sized PADDING - * block. The iterator will be left pointing to the block before the - * one just deleted. - * - * You may not delete the STREAMINFO block. - * - * \param iterator A pointer to an existing initialized iterator. - * \param use_padding See above. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_simple_iterator_init() - * \retval FLAC__bool - * \c true if successful, else \c false. - */ -FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding); - -/* \} */ - - -/** \defgroup flac_metadata_level2 FLAC/metadata.h: metadata level 2 interface - * \ingroup flac_metadata - * - * \brief - * The level 2 interface provides read-write access to FLAC file metadata; - * all metadata is read into memory, operated on in memory, and then written - * to file, which is more efficient than level 1 when editing multiple blocks. - * - * Currently Ogg FLAC is supported for read only, via - * FLAC__metadata_chain_read_ogg() but a subsequent - * FLAC__metadata_chain_write() will fail. - * - * The general usage of this interface is: - * - * - Create a new chain using FLAC__metadata_chain_new(). A chain is a - * linked list of FLAC metadata blocks. - * - Read all metadata into the chain from a FLAC file using - * FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and - * check the status. - * - Optionally, consolidate the padding using - * FLAC__metadata_chain_merge_padding() or - * FLAC__metadata_chain_sort_padding(). - * - Create a new iterator using FLAC__metadata_iterator_new() - * - Initialize the iterator to point to the first element in the chain - * using FLAC__metadata_iterator_init() - * - Traverse the chain using FLAC__metadata_iterator_next and - * FLAC__metadata_iterator_prev(). - * - Get a block for reading or modification using - * FLAC__metadata_iterator_get_block(). The pointer to the object - * inside the chain is returned, so the block is yours to modify. - * Changes will be reflected in the FLAC file when you write the - * chain. You can also add and delete blocks (see functions below). - * - When done, write out the chain using FLAC__metadata_chain_write(). - * Make sure to read the whole comment to the function below. - * - Delete the chain using FLAC__metadata_chain_delete(). - * - * \note - * Even though the FLAC file is not open while the chain is being - * manipulated, you must not alter the file externally during - * this time. The chain assumes the FLAC file will not change - * between the time of FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg() - * and FLAC__metadata_chain_write(). - * - * \note - * Do not modify the is_last, length, or type fields of returned - * FLAC__StreamMetadata objects. These are managed automatically. - * - * \note - * The metadata objects returned by FLAC__metadata_iterator_get_block() - * are owned by the chain; do not FLAC__metadata_object_delete() them. - * In the same way, blocks passed to FLAC__metadata_iterator_set_block() - * become owned by the chain and they will be deleted when the chain is - * deleted. - * - * \{ - */ - -struct FLAC__Metadata_Chain; -/** The opaque structure definition for the level 2 chain type. - */ -typedef struct FLAC__Metadata_Chain FLAC__Metadata_Chain; - -struct FLAC__Metadata_Iterator; -/** The opaque structure definition for the level 2 iterator type. - */ -typedef struct FLAC__Metadata_Iterator FLAC__Metadata_Iterator; - -typedef enum { - FLAC__METADATA_CHAIN_STATUS_OK = 0, - /**< The chain is in the normal OK state */ - - FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT, - /**< The data passed into a function violated the function's usage criteria */ - - FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE, - /**< The chain could not open the target file */ - - FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE, - /**< The chain could not find the FLAC signature at the start of the file */ - - FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE, - /**< The chain tried to write to a file that was not writable */ - - FLAC__METADATA_CHAIN_STATUS_BAD_METADATA, - /**< The chain encountered input that does not conform to the FLAC metadata specification */ - - FLAC__METADATA_CHAIN_STATUS_READ_ERROR, - /**< The chain encountered an error while reading the FLAC file */ - - FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR, - /**< The chain encountered an error while seeking in the FLAC file */ - - FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR, - /**< The chain encountered an error while writing the FLAC file */ - - FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR, - /**< The chain encountered an error renaming the FLAC file */ - - FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR, - /**< The chain encountered an error removing the temporary file */ - - FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR, - /**< Memory allocation failed */ - - FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR, - /**< The caller violated an assertion or an unexpected error occurred */ - - FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS, - /**< One or more of the required callbacks was NULL */ - - FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH, - /**< FLAC__metadata_chain_write() was called on a chain read by - * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), - * or - * FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile() - * was called on a chain read by - * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). - * Matching read/write methods must always be used. */ - - FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL - /**< FLAC__metadata_chain_write_with_callbacks() was called when the - * chain write requires a tempfile; use - * FLAC__metadata_chain_write_with_callbacks_and_tempfile() instead. - * Or, FLAC__metadata_chain_write_with_callbacks_and_tempfile() was - * called when the chain write does not require a tempfile; use - * FLAC__metadata_chain_write_with_callbacks() instead. - * Always check FLAC__metadata_chain_check_if_tempfile_needed() - * before writing via callbacks. */ - -} FLAC__Metadata_ChainStatus; - -/** Maps a FLAC__Metadata_ChainStatus to a C string. - * - * Using a FLAC__Metadata_ChainStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__Metadata_ChainStatusString[]; - -/*********** FLAC__Metadata_Chain ***********/ - -/** Create a new chain instance. - * - * \retval FLAC__Metadata_Chain* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void); - -/** Free a chain instance. Deletes the object pointed to by \a chain. - * - * \param chain A pointer to an existing chain. - * \assert - * \code chain != NULL \endcode - */ -FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain); - -/** Get the current status of the chain. Call this after a function - * returns \c false to get the reason for the error. Also resets the - * status to FLAC__METADATA_CHAIN_STATUS_OK. - * - * \param chain A pointer to an existing chain. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__Metadata_ChainStatus - * The current status of the chain. - */ -FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain); - -/** Read all metadata from a FLAC file into the chain. - * - * On Windows, filename must be a UTF-8 encoded filename, which libFLAC - * internally translates to an appropriate representation to use with - * _wfopen. On all other systems, filename is passed to fopen without - * any translation. - * - * \param chain A pointer to an existing chain. - * \param filename The path to the FLAC file to read. - * \assert - * \code chain != NULL \endcode - * \code filename != NULL \endcode - * \retval FLAC__bool - * \c true if a valid list of metadata blocks was read from - * \a filename, else \c false. On failure, check the status with - * FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename); - -/** Read all metadata from an Ogg FLAC file into the chain. - * - * On Windows, filename must be a UTF-8 encoded filename, which libFLAC - * internally translates to an appropriate representation to use with - * _wfopen. On all other systems, filename is passed to fopen without - * any translation. - * - * \note Ogg FLAC metadata data writing is not supported yet and - * FLAC__metadata_chain_write() will fail. - * - * \param chain A pointer to an existing chain. - * \param filename The path to the Ogg FLAC file to read. - * \assert - * \code chain != NULL \endcode - * \code filename != NULL \endcode - * \retval FLAC__bool - * \c true if a valid list of metadata blocks was read from - * \a filename, else \c false. On failure, check the status with - * FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename); - -/** Read all metadata from a FLAC stream into the chain via I/O callbacks. - * - * The \a handle need only be open for reading, but must be seekable. - * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" - * for Windows). - * - * \param chain A pointer to an existing chain. - * \param handle The I/O handle of the FLAC stream to read. The - * handle will NOT be closed after the metadata is read; - * that is the duty of the caller. - * \param callbacks - * A set of callbacks to use for I/O. The mandatory - * callbacks are \a read, \a seek, and \a tell. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if a valid list of metadata blocks was read from - * \a handle, else \c false. On failure, check the status with - * FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); - -/** Read all metadata from an Ogg FLAC stream into the chain via I/O callbacks. - * - * The \a handle need only be open for reading, but must be seekable. - * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" - * for Windows). - * - * \note Ogg FLAC metadata data writing is not supported yet and - * FLAC__metadata_chain_write() will fail. - * - * \param chain A pointer to an existing chain. - * \param handle The I/O handle of the Ogg FLAC stream to read. The - * handle will NOT be closed after the metadata is read; - * that is the duty of the caller. - * \param callbacks - * A set of callbacks to use for I/O. The mandatory - * callbacks are \a read, \a seek, and \a tell. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if a valid list of metadata blocks was read from - * \a handle, else \c false. On failure, check the status with - * FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); - -/** Checks if writing the given chain would require the use of a - * temporary file, or if it could be written in place. - * - * Under certain conditions, padding can be utilized so that writing - * edited metadata back to the FLAC file does not require rewriting the - * entire file. If rewriting is required, then a temporary workfile is - * required. When writing metadata using callbacks, you must check - * this function to know whether to call - * FLAC__metadata_chain_write_with_callbacks() or - * FLAC__metadata_chain_write_with_callbacks_and_tempfile(). When - * writing with FLAC__metadata_chain_write(), the temporary file is - * handled internally. - * - * \param chain A pointer to an existing chain. - * \param use_padding - * Whether or not padding will be allowed to be used - * during the write. The value of \a use_padding given - * here must match the value later passed to - * FLAC__metadata_chain_write_with_callbacks() or - * FLAC__metadata_chain_write_with_callbacks_with_tempfile(). - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if writing the current chain would require a tempfile, or - * \c false if metadata can be written in place. - */ -FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding); - -/** Write all metadata out to the FLAC file. This function tries to be as - * efficient as possible; how the metadata is actually written is shown by - * the following: - * - * If the current chain is the same size as the existing metadata, the new - * data is written in place. - * - * If the current chain is longer than the existing metadata, and - * \a use_padding is \c true, and the last block is a PADDING block of - * sufficient length, the function will truncate the final padding block - * so that the overall size of the metadata is the same as the existing - * metadata, and then just rewrite the metadata. Otherwise, if not all of - * the above conditions are met, the entire FLAC file must be rewritten. - * If you want to use padding this way it is a good idea to call - * FLAC__metadata_chain_sort_padding() first so that you have the maximum - * amount of padding to work with, unless you need to preserve ordering - * of the PADDING blocks for some reason. - * - * If the current chain is shorter than the existing metadata, and - * \a use_padding is \c true, and the final block is a PADDING block, the padding - * is extended to make the overall size the same as the existing data. If - * \a use_padding is \c true and the last block is not a PADDING block, a new - * PADDING block is added to the end of the new data to make it the same - * size as the existing data (if possible, see the note to - * FLAC__metadata_simple_iterator_set_block() about the four byte limit) - * and the new data is written in place. If none of the above apply or - * \a use_padding is \c false, the entire FLAC file is rewritten. - * - * If \a preserve_file_stats is \c true, the owner and modification time will - * be preserved even if the FLAC file is written. - * - * For this write function to be used, the chain must have been read with - * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(), not - * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(). - * - * \param chain A pointer to an existing chain. - * \param use_padding See above. - * \param preserve_file_stats See above. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if the write succeeded, else \c false. On failure, - * check the status with FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats); - -/** Write all metadata out to a FLAC stream via callbacks. - * - * (See FLAC__metadata_chain_write() for the details on how padding is - * used to write metadata in place if possible.) - * - * The \a handle must be open for updating and be seekable. The - * equivalent minimum stdio fopen() file mode is \c "r+" (or \c "r+b" - * for Windows). - * - * For this write function to be used, the chain must have been read with - * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), - * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). - * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned - * \c false. - * - * \param chain A pointer to an existing chain. - * \param use_padding See FLAC__metadata_chain_write() - * \param handle The I/O handle of the FLAC stream to write. The - * handle will NOT be closed after the metadata is - * written; that is the duty of the caller. - * \param callbacks A set of callbacks to use for I/O. The mandatory - * callbacks are \a write and \a seek. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if the write succeeded, else \c false. On failure, - * check the status with FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks); - -/** Write all metadata out to a FLAC stream via callbacks. - * - * (See FLAC__metadata_chain_write() for the details on how padding is - * used to write metadata in place if possible.) - * - * This version of the write-with-callbacks function must be used when - * FLAC__metadata_chain_check_if_tempfile_needed() returns true. In - * this function, you must supply an I/O handle corresponding to the - * FLAC file to edit, and a temporary handle to which the new FLAC - * file will be written. It is the caller's job to move this temporary - * FLAC file on top of the original FLAC file to complete the metadata - * edit. - * - * The \a handle must be open for reading and be seekable. The - * equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb" - * for Windows). - * - * The \a temp_handle must be open for writing. The - * equivalent minimum stdio fopen() file mode is \c "w" (or \c "wb" - * for Windows). It should be an empty stream, or at least positioned - * at the start-of-file (in which case it is the caller's duty to - * truncate it on return). - * - * For this write function to be used, the chain must have been read with - * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(), - * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(). - * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned - * \c true. - * - * \param chain A pointer to an existing chain. - * \param use_padding See FLAC__metadata_chain_write() - * \param handle The I/O handle of the original FLAC stream to read. - * The handle will NOT be closed after the metadata is - * written; that is the duty of the caller. - * \param callbacks A set of callbacks to use for I/O on \a handle. - * The mandatory callbacks are \a read, \a seek, and - * \a eof. - * \param temp_handle The I/O handle of the FLAC stream to write. The - * handle will NOT be closed after the metadata is - * written; that is the duty of the caller. - * \param temp_callbacks - * A set of callbacks to use for I/O on temp_handle. - * The only mandatory callback is \a write. - * \assert - * \code chain != NULL \endcode - * \retval FLAC__bool - * \c true if the write succeeded, else \c false. On failure, - * check the status with FLAC__metadata_chain_status(). - */ -FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks); - -/** Merge adjacent PADDING blocks into a single block. - * - * \note This function does not write to the FLAC file, it only - * modifies the chain. - * - * \warning Any iterator on the current chain will become invalid after this - * call. You should delete the iterator and get a new one. - * - * \param chain A pointer to an existing chain. - * \assert - * \code chain != NULL \endcode - */ -FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain); - -/** This function will move all PADDING blocks to the end on the metadata, - * then merge them into a single block. - * - * \note This function does not write to the FLAC file, it only - * modifies the chain. - * - * \warning Any iterator on the current chain will become invalid after this - * call. You should delete the iterator and get a new one. - * - * \param chain A pointer to an existing chain. - * \assert - * \code chain != NULL \endcode - */ -FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain); - - -/*********** FLAC__Metadata_Iterator ***********/ - -/** Create a new iterator instance. - * - * \retval FLAC__Metadata_Iterator* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void); - -/** Free an iterator instance. Deletes the object pointed to by \a iterator. - * - * \param iterator A pointer to an existing iterator. - * \assert - * \code iterator != NULL \endcode - */ -FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator); - -/** Initialize the iterator to point to the first metadata block in the - * given chain. - * - * \param iterator A pointer to an existing iterator. - * \param chain A pointer to an existing and initialized (read) chain. - * \assert - * \code iterator != NULL \endcode - * \code chain != NULL \endcode - */ -FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain); - -/** Moves the iterator forward one metadata block, returning \c false if - * already at the end. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__bool - * \c false if already at the last metadata block of the chain, else - * \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator); - -/** Moves the iterator backward one metadata block, returning \c false if - * already at the beginning. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__bool - * \c false if already at the first metadata block of the chain, else - * \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator); - -/** Get the type of the metadata block at the current position. - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__MetadataType - * The type of the metadata block at the current iterator position. - */ -FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator); - -/** Get the metadata block at the current position. You can modify - * the block in place but must write the chain before the changes - * are reflected to the FLAC file. You do not need to call - * FLAC__metadata_iterator_set_block() to reflect the changes; - * the pointer returned by FLAC__metadata_iterator_get_block() - * points directly into the chain. - * - * \warning - * Do not call FLAC__metadata_object_delete() on the returned object; - * to delete a block use FLAC__metadata_iterator_delete_block(). - * - * \param iterator A pointer to an existing initialized iterator. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__StreamMetadata* - * The current metadata block. - */ -FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator); - -/** Set the metadata block at the current position, replacing the existing - * block. The new block passed in becomes owned by the chain and it will be - * deleted when the chain is deleted. - * - * \param iterator A pointer to an existing initialized iterator. - * \param block A pointer to a metadata block. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \code block != NULL \endcode - * \retval FLAC__bool - * \c false if the conditions in the above description are not met, or - * a memory allocation error occurs, otherwise \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); - -/** Removes the current block from the chain. If \a replace_with_padding is - * \c true, the block will instead be replaced with a padding block of equal - * size. You can not delete the STREAMINFO block. The iterator will be - * left pointing to the block before the one just "deleted", even if - * \a replace_with_padding is \c true. - * - * \param iterator A pointer to an existing initialized iterator. - * \param replace_with_padding See above. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__bool - * \c false if the conditions in the above description are not met, - * otherwise \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding); - -/** Insert a new block before the current block. You cannot insert a block - * before the first STREAMINFO block. You cannot insert a STREAMINFO block - * as there can be only one, the one that already exists at the head when you - * read in a chain. The chain takes ownership of the new block and it will be - * deleted when the chain is deleted. The iterator will be left pointing to - * the new block. - * - * \param iterator A pointer to an existing initialized iterator. - * \param block A pointer to a metadata block to insert. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__bool - * \c false if the conditions in the above description are not met, or - * a memory allocation error occurs, otherwise \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); - -/** Insert a new block after the current block. You cannot insert a STREAMINFO - * block as there can be only one, the one that already exists at the head when - * you read in a chain. The chain takes ownership of the new block and it will - * be deleted when the chain is deleted. The iterator will be left pointing to - * the new block. - * - * \param iterator A pointer to an existing initialized iterator. - * \param block A pointer to a metadata block to insert. - * \assert - * \code iterator != NULL \endcode - * \a iterator has been successfully initialized with - * FLAC__metadata_iterator_init() - * \retval FLAC__bool - * \c false if the conditions in the above description are not met, or - * a memory allocation error occurs, otherwise \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block); - -/* \} */ - - -/** \defgroup flac_metadata_object FLAC/metadata.h: metadata object methods - * \ingroup flac_metadata - * - * \brief - * This module contains methods for manipulating FLAC metadata objects. - * - * Since many are variable length we have to be careful about the memory - * management. We decree that all pointers to data in the object are - * owned by the object and memory-managed by the object. - * - * Use the FLAC__metadata_object_new() and FLAC__metadata_object_delete() - * functions to create all instances. When using the - * FLAC__metadata_object_set_*() functions to set pointers to data, set - * \a copy to \c true to have the function make it's own copy of the data, or - * to \c false to give the object ownership of your data. In the latter case - * your pointer must be freeable by free() and will be free()d when the object - * is FLAC__metadata_object_delete()d. It is legal to pass a null pointer as - * the data pointer to a FLAC__metadata_object_set_*() function as long as - * the length argument is 0 and the \a copy argument is \c false. - * - * The FLAC__metadata_object_new() and FLAC__metadata_object_clone() function - * will return \c NULL in the case of a memory allocation error, otherwise a new - * object. The FLAC__metadata_object_set_*() functions return \c false in the - * case of a memory allocation error. - * - * We don't have the convenience of C++ here, so note that the library relies - * on you to keep the types straight. In other words, if you pass, for - * example, a FLAC__StreamMetadata* that represents a STREAMINFO block to - * FLAC__metadata_object_application_set_data(), you will get an assertion - * failure. - * - * For convenience the FLAC__metadata_object_vorbiscomment_*() functions - * maintain a trailing NUL on each Vorbis comment entry. This is not counted - * toward the length or stored in the stream, but it can make working with plain - * comments (those that don't contain embedded-NULs in the value) easier. - * Entries passed into these functions have trailing NULs added if missing, and - * returned entries are guaranteed to have a trailing NUL. - * - * The FLAC__metadata_object_vorbiscomment_*() functions that take a Vorbis - * comment entry/name/value will first validate that it complies with the Vorbis - * comment specification and return false if it does not. - * - * There is no need to recalculate the length field on metadata blocks you - * have modified. They will be calculated automatically before they are - * written back to a file. - * - * \{ - */ - - -/** Create a new metadata object instance of the given type. - * - * The object will be "empty"; i.e. values and data pointers will be \c 0, - * with the exception of FLAC__METADATA_TYPE_VORBIS_COMMENT, which will have - * the vendor string set (but zero comments). - * - * Do not pass in a value greater than or equal to - * \a FLAC__METADATA_TYPE_UNDEFINED unless you really know what you're - * doing. - * - * \param type Type of object to create - * \retval FLAC__StreamMetadata* - * \c NULL if there was an error allocating memory or the type code is - * greater than FLAC__MAX_METADATA_TYPE_CODE, else the new instance. - */ -FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type); - -/** Create a copy of an existing metadata object. - * - * The copy is a "deep" copy, i.e. dynamically allocated data within the - * object is also copied. The caller takes ownership of the new block and - * is responsible for freeing it with FLAC__metadata_object_delete(). - * - * \param object Pointer to object to copy. - * \assert - * \code object != NULL \endcode - * \retval FLAC__StreamMetadata* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object); - -/** Free a metadata object. Deletes the object pointed to by \a object. - * - * The delete is a "deep" delete, i.e. dynamically allocated data within the - * object is also deleted. - * - * \param object A pointer to an existing object. - * \assert - * \code object != NULL \endcode - */ -FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object); - -/** Compares two metadata objects. - * - * The compare is "deep", i.e. dynamically allocated data within the - * object is also compared. - * - * \param block1 A pointer to an existing object. - * \param block2 A pointer to an existing object. - * \assert - * \code block1 != NULL \endcode - * \code block2 != NULL \endcode - * \retval FLAC__bool - * \c true if objects are identical, else \c false. - */ -FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2); - -/** Sets the application data of an APPLICATION block. - * - * If \a copy is \c true, a copy of the data is stored; otherwise, the object - * takes ownership of the pointer. The existing data will be freed if this - * function is successful, otherwise the original data will remain if \a copy - * is \c true and malloc() fails. - * - * \note It is safe to pass a const pointer to \a data if \a copy is \c true. - * - * \param object A pointer to an existing APPLICATION object. - * \param data A pointer to the data to set. - * \param length The length of \a data in bytes. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_APPLICATION \endcode - * \code (data != NULL && length > 0) || - * (data == NULL && length == 0 && copy == false) \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy); - -/** Resize the seekpoint array. - * - * If the size shrinks, elements will truncated; if it grows, new placeholder - * points will be added to the end. If this function returns false, the - * object is left untouched. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param new_num_points The desired length of the array; may be \c 0. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code (object->data.seek_table.points == NULL && object->data.seek_table.num_points == 0) || - * (object->data.seek_table.points != NULL && object->data.seek_table.num_points > 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points); - -/** Set a seekpoint in a seektable. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param point_num Index into seekpoint array to set. - * \param point The point to set. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code object->data.seek_table.num_points > point_num \endcode - */ -FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point); - -/** Insert a seekpoint into a seektable. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param point_num Index into seekpoint array to set. - * \param point The point to set. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code object->data.seek_table.num_points >= point_num \endcode - * \retval FLAC__bool - * \c false if memory allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point); - -/** Delete a seekpoint from a seektable. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param point_num Index into seekpoint array to set. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code object->data.seek_table.num_points > point_num \endcode - * \retval FLAC__bool - * \c false if memory allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num); - -/** Check a seektable to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * seektable. - * - * \param object A pointer to an existing SEEKTABLE object. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \retval FLAC__bool - * \c false if seek table is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object); - -/** Append a number of placeholder points to the end of a seek table. - * - * \note - * As with the other ..._seektable_template_... functions, you should - * call FLAC__metadata_object_seektable_template_sort() when finished - * to make the seek table legal. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param num The number of placeholder points to append. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num); - -/** Append a specific seek point template to the end of a seek table. - * - * \note - * As with the other ..._seektable_template_... functions, you should - * call FLAC__metadata_object_seektable_template_sort() when finished - * to make the seek table legal. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param sample_number The sample number of the seek point template. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number); - -/** Append specific seek point templates to the end of a seek table. - * - * \note - * As with the other ..._seektable_template_... functions, you should - * call FLAC__metadata_object_seektable_template_sort() when finished - * to make the seek table legal. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param sample_numbers An array of sample numbers for the seek points. - * \param num The number of seek point templates to append. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num); - -/** Append a set of evenly-spaced seek point templates to the end of a - * seek table. - * - * \note - * As with the other ..._seektable_template_... functions, you should - * call FLAC__metadata_object_seektable_template_sort() when finished - * to make the seek table legal. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param num The number of placeholder points to append. - * \param total_samples The total number of samples to be encoded; - * the seekpoints will be spaced approximately - * \a total_samples / \a num samples apart. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code total_samples > 0 \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples); - -/** Append a set of evenly-spaced seek point templates to the end of a - * seek table. - * - * \note - * As with the other ..._seektable_template_... functions, you should - * call FLAC__metadata_object_seektable_template_sort() when finished - * to make the seek table legal. - * - * \param object A pointer to an existing SEEKTABLE object. - * \param samples The number of samples apart to space the placeholder - * points. The first point will be at sample \c 0, the - * second at sample \a samples, then 2*\a samples, and - * so on. As long as \a samples and \a total_samples - * are greater than \c 0, there will always be at least - * one seekpoint at sample \c 0. - * \param total_samples The total number of samples to be encoded; - * the seekpoints will be spaced - * \a samples samples apart. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \code samples > 0 \endcode - * \code total_samples > 0 \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples); - -/** Sort a seek table's seek points according to the format specification, - * removing duplicates. - * - * \param object A pointer to a seek table to be sorted. - * \param compact If \c false, behaves like FLAC__format_seektable_sort(). - * If \c true, duplicates are deleted and the seek table is - * shrunk appropriately; the number of placeholder points - * present in the seek table will be the same after the call - * as before. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact); - -/** Sets the vendor string in a VORBIS_COMMENT block. - * - * For convenience, a trailing NUL is added to the entry if it doesn't have - * one already. - * - * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry.entry pointer. - * - * \note If this function returns \c false, the caller still owns the - * pointer. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param entry The entry to set the vendor string to. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code (entry.entry != NULL && entry.length > 0) || - * (entry.entry == NULL && entry.length == 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); - -/** Resize the comment array. - * - * If the size shrinks, elements will truncated; if it grows, new empty - * fields will be added to the end. If this function returns false, the - * object is left untouched. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param new_num_comments The desired length of the array; may be \c 0. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code (object->data.vorbis_comment.comments == NULL && object->data.vorbis_comment.num_comments == 0) || - * (object->data.vorbis_comment.comments != NULL && object->data.vorbis_comment.num_comments > 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments); - -/** Sets a comment in a VORBIS_COMMENT block. - * - * For convenience, a trailing NUL is added to the entry if it doesn't have - * one already. - * - * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry.entry pointer. - * - * \note If this function returns \c false, the caller still owns the - * pointer. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param comment_num Index into comment array to set. - * \param entry The entry to set the comment to. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code comment_num < object->data.vorbis_comment.num_comments \endcode - * \code (entry.entry != NULL && entry.length > 0) || - * (entry.entry == NULL && entry.length == 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); - -/** Insert a comment in a VORBIS_COMMENT block at the given index. - * - * For convenience, a trailing NUL is added to the entry if it doesn't have - * one already. - * - * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry.entry pointer. - * - * \note If this function returns \c false, the caller still owns the - * pointer. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param comment_num The index at which to insert the comment. The comments - * at and after \a comment_num move right one position. - * To append a comment to the end, set \a comment_num to - * \c object->data.vorbis_comment.num_comments . - * \param entry The comment to insert. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code object->data.vorbis_comment.num_comments >= comment_num \endcode - * \code (entry.entry != NULL && entry.length > 0) || - * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); - -/** Appends a comment to a VORBIS_COMMENT block. - * - * For convenience, a trailing NUL is added to the entry if it doesn't have - * one already. - * - * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry.entry pointer. - * - * \note If this function returns \c false, the caller still owns the - * pointer. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param entry The comment to insert. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code (entry.entry != NULL && entry.length > 0) || - * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy); - -/** Replaces comments in a VORBIS_COMMENT block with a new one. - * - * For convenience, a trailing NUL is added to the entry if it doesn't have - * one already. - * - * Depending on the value of \a all, either all or just the first comment - * whose field name(s) match the given entry's name will be replaced by the - * given entry. If no comments match, \a entry will simply be appended. - * - * If \a copy is \c true, a copy of the entry is stored; otherwise, the object - * takes ownership of the \c entry.entry pointer. - * - * \note If this function returns \c false, the caller still owns the - * pointer. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param entry The comment to insert. - * \param all If \c true, all comments whose field name matches - * \a entry's field name will be removed, and \a entry will - * be inserted at the position of the first matching - * comment. If \c false, only the first comment whose - * field name matches \a entry's field name will be - * replaced with \a entry. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code (entry.entry != NULL && entry.length > 0) || - * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy); - -/** Delete a comment in a VORBIS_COMMENT block at the given index. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param comment_num The index of the comment to delete. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code object->data.vorbis_comment.num_comments > comment_num \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num); - -/** Creates a Vorbis comment entry from NUL-terminated name and value strings. - * - * On return, the filled-in \a entry->entry pointer will point to malloc()ed - * memory and shall be owned by the caller. For convenience the entry will - * have a terminating NUL. - * - * \param entry A pointer to a Vorbis comment entry. The entry's - * \c entry pointer should not point to allocated - * memory as it will be overwritten. - * \param field_name The field name in ASCII, \c NUL terminated. - * \param field_value The field value in UTF-8, \c NUL terminated. - * \assert - * \code entry != NULL \endcode - * \code field_name != NULL \endcode - * \code field_value != NULL \endcode - * \retval FLAC__bool - * \c false if malloc() fails, or if \a field_name or \a field_value does - * not comply with the Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value); - -/** Splits a Vorbis comment entry into NUL-terminated name and value strings. - * - * The returned pointers to name and value will be allocated by malloc() - * and shall be owned by the caller. - * - * \param entry An existing Vorbis comment entry. - * \param field_name The address of where the returned pointer to the - * field name will be stored. - * \param field_value The address of where the returned pointer to the - * field value will be stored. - * \assert - * \code (entry.entry != NULL && entry.length > 0) \endcode - * \code memchr(entry.entry, '=', entry.length) != NULL \endcode - * \code field_name != NULL \endcode - * \code field_value != NULL \endcode - * \retval FLAC__bool - * \c false if memory allocation fails or \a entry does not comply with the - * Vorbis comment specification, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value); - -/** Check if the given Vorbis comment entry's field name matches the given - * field name. - * - * \param entry An existing Vorbis comment entry. - * \param field_name The field name to check. - * \param field_name_length The length of \a field_name, not including the - * terminating \c NUL. - * \assert - * \code (entry.entry != NULL && entry.length > 0) \endcode - * \retval FLAC__bool - * \c true if the field names match, else \c false - */ -FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length); - -/** Find a Vorbis comment with the given field name. - * - * The search begins at entry number \a offset; use an offset of 0 to - * search from the beginning of the comment array. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param offset The offset into the comment array from where to start - * the search. - * \param field_name The field name of the comment to find. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \code field_name != NULL \endcode - * \retval int - * The offset in the comment array of the first comment whose field - * name matches \a field_name, or \c -1 if no match was found. - */ -FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name); - -/** Remove first Vorbis comment matching the given field name. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param field_name The field name of comment to delete. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \retval int - * \c -1 for memory allocation error, \c 0 for no matching entries, - * \c 1 for one matching entry deleted. - */ -FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name); - -/** Remove all Vorbis comments matching the given field name. - * - * \param object A pointer to an existing VORBIS_COMMENT object. - * \param field_name The field name of comments to delete. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode - * \retval int - * \c -1 for memory allocation error, \c 0 for no matching entries, - * else the number of matching entries deleted. - */ -FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name); - -/** Create a new CUESHEET track instance. - * - * The object will be "empty"; i.e. values and data pointers will be \c 0. - * - * \retval FLAC__StreamMetadata_CueSheet_Track* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void); - -/** Create a copy of an existing CUESHEET track object. - * - * The copy is a "deep" copy, i.e. dynamically allocated data within the - * object is also copied. The caller takes ownership of the new object and - * is responsible for freeing it with - * FLAC__metadata_object_cuesheet_track_delete(). - * - * \param object Pointer to object to copy. - * \assert - * \code object != NULL \endcode - * \retval FLAC__StreamMetadata_CueSheet_Track* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object); - -/** Delete a CUESHEET track object - * - * \param object A pointer to an existing CUESHEET track object. - * \assert - * \code object != NULL \endcode - */ -FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object); - -/** Resize a track's index point array. - * - * If the size shrinks, elements will truncated; if it grows, new blank - * indices will be added to the end. If this function returns false, the - * track object is left untouched. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index of the track to modify. NOTE: this is not - * necessarily the same as the track's \a number field. - * \param new_num_indices The desired length of the array; may be \c 0. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks > track_num \endcode - * \code (object->data.cue_sheet.tracks[track_num].indices == NULL && object->data.cue_sheet.tracks[track_num].num_indices == 0) || - * (object->data.cue_sheet.tracks[track_num].indices != NULL && object->data.cue_sheet.tracks[track_num].num_indices > 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices); - -/** Insert an index point in a CUESHEET track at the given index. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index of the track to modify. NOTE: this is not - * necessarily the same as the track's \a number field. - * \param index_num The index into the track's index array at which to - * insert the index point. NOTE: this is not necessarily - * the same as the index point's \a number field. The - * indices at and after \a index_num move right one - * position. To append an index point to the end, set - * \a index_num to - * \c object->data.cue_sheet.tracks[track_num].num_indices . - * \param index The index point to insert. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks > track_num \endcode - * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index index); - -/** Insert a blank index point in a CUESHEET track at the given index. - * - * A blank index point is one in which all field values are zero. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index of the track to modify. NOTE: this is not - * necessarily the same as the track's \a number field. - * \param index_num The index into the track's index array at which to - * insert the index point. NOTE: this is not necessarily - * the same as the index point's \a number field. The - * indices at and after \a index_num move right one - * position. To append an index point to the end, set - * \a index_num to - * \c object->data.cue_sheet.tracks[track_num].num_indices . - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks > track_num \endcode - * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num); - -/** Delete an index point in a CUESHEET track at the given index. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index into the track array of the track to - * modify. NOTE: this is not necessarily the same - * as the track's \a number field. - * \param index_num The index into the track's index array of the index - * to delete. NOTE: this is not necessarily the same - * as the index's \a number field. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks > track_num \endcode - * \code object->data.cue_sheet.tracks[track_num].num_indices > index_num \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num); - -/** Resize the track array. - * - * If the size shrinks, elements will truncated; if it grows, new blank - * tracks will be added to the end. If this function returns false, the - * object is left untouched. - * - * \param object A pointer to an existing CUESHEET object. - * \param new_num_tracks The desired length of the array; may be \c 0. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code (object->data.cue_sheet.tracks == NULL && object->data.cue_sheet.num_tracks == 0) || - * (object->data.cue_sheet.tracks != NULL && object->data.cue_sheet.num_tracks > 0) \endcode - * \retval FLAC__bool - * \c false if memory allocation error, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks); - -/** Sets a track in a CUESHEET block. - * - * If \a copy is \c true, a copy of the track is stored; otherwise, the object - * takes ownership of the \a track pointer. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num Index into track array to set. NOTE: this is not - * necessarily the same as the track's \a number field. - * \param track The track to set the track to. You may safely pass in - * a const pointer if \a copy is \c true. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code track_num < object->data.cue_sheet.num_tracks \endcode - * \code (track->indices != NULL && track->num_indices > 0) || - * (track->indices == NULL && track->num_indices == 0) \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy); - -/** Insert a track in a CUESHEET block at the given index. - * - * If \a copy is \c true, a copy of the track is stored; otherwise, the object - * takes ownership of the \a track pointer. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index at which to insert the track. NOTE: this - * is not necessarily the same as the track's \a number - * field. The tracks at and after \a track_num move right - * one position. To append a track to the end, set - * \a track_num to \c object->data.cue_sheet.num_tracks . - * \param track The track to insert. You may safely pass in a const - * pointer if \a copy is \c true. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks >= track_num \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy); - -/** Insert a blank track in a CUESHEET block at the given index. - * - * A blank track is one in which all field values are zero. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index at which to insert the track. NOTE: this - * is not necessarily the same as the track's \a number - * field. The tracks at and after \a track_num move right - * one position. To append a track to the end, set - * \a track_num to \c object->data.cue_sheet.num_tracks . - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks >= track_num \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num); - -/** Delete a track in a CUESHEET block at the given index. - * - * \param object A pointer to an existing CUESHEET object. - * \param track_num The index into the track array of the track to - * delete. NOTE: this is not necessarily the same - * as the track's \a number field. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \code object->data.cue_sheet.num_tracks > track_num \endcode - * \retval FLAC__bool - * \c false if realloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num); - -/** Check a cue sheet to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * cue sheet. - * - * \param object A pointer to an existing CUESHEET object. - * \param check_cd_da_subset If \c true, check CUESHEET against more - * stringent requirements for a CD-DA (audio) disc. - * \param violation Address of a pointer to a string. If there is a - * violation, a pointer to a string explanation of the - * violation will be returned here. \a violation may be - * \c NULL if you don't need the returned string. Do not - * free the returned string; it will always point to static - * data. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \retval FLAC__bool - * \c false if cue sheet is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation); - -/** Calculate and return the CDDB/freedb ID for a cue sheet. The function - * assumes the cue sheet corresponds to a CD; the result is undefined - * if the cuesheet's is_cd bit is not set. - * - * \param object A pointer to an existing CUESHEET object. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode - * \retval FLAC__uint32 - * The unsigned integer representation of the CDDB/freedb ID - */ -FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object); - -/** Sets the MIME type of a PICTURE block. - * - * If \a copy is \c true, a copy of the string is stored; otherwise, the object - * takes ownership of the pointer. The existing string will be freed if this - * function is successful, otherwise the original string will remain if \a copy - * is \c true and malloc() fails. - * - * \note It is safe to pass a const pointer to \a mime_type if \a copy is \c true. - * - * \param object A pointer to an existing PICTURE object. - * \param mime_type A pointer to the MIME type string. The string must be - * ASCII characters 0x20-0x7e, NUL-terminated. No validation - * is done. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode - * \code (mime_type != NULL) \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy); - -/** Sets the description of a PICTURE block. - * - * If \a copy is \c true, a copy of the string is stored; otherwise, the object - * takes ownership of the pointer. The existing string will be freed if this - * function is successful, otherwise the original string will remain if \a copy - * is \c true and malloc() fails. - * - * \note It is safe to pass a const pointer to \a description if \a copy is \c true. - * - * \param object A pointer to an existing PICTURE object. - * \param description A pointer to the description string. The string must be - * valid UTF-8, NUL-terminated. No validation is done. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode - * \code (description != NULL) \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy); - -/** Sets the picture data of a PICTURE block. - * - * If \a copy is \c true, a copy of the data is stored; otherwise, the object - * takes ownership of the pointer. Also sets the \a data_length field of the - * metadata object to what is passed in as the \a length parameter. The - * existing data will be freed if this function is successful, otherwise the - * original data and data_length will remain if \a copy is \c true and - * malloc() fails. - * - * \note It is safe to pass a const pointer to \a data if \a copy is \c true. - * - * \param object A pointer to an existing PICTURE object. - * \param data A pointer to the data to set. - * \param length The length of \a data in bytes. - * \param copy See above. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode - * \code (data != NULL && length > 0) || - * (data == NULL && length == 0 && copy == false) \endcode - * \retval FLAC__bool - * \c false if \a copy is \c true and malloc() fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy); - -/** Check a PICTURE block to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * PICTURE block. - * - * \param object A pointer to existing PICTURE block to be checked. - * \param violation Address of a pointer to a string. If there is a - * violation, a pointer to a string explanation of the - * violation will be returned here. \a violation may be - * \c NULL if you don't need the returned string. Do not - * free the returned string; it will always point to static - * data. - * \assert - * \code object != NULL \endcode - * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode - * \retval FLAC__bool - * \c false if PICTURE block is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/code/dep_codecs/include/FLAC/ordinals.h b/code/dep_codecs/include/FLAC/ordinals.h deleted file mode 100755 index 77757d66..00000000 --- a/code/dep_codecs/include/FLAC/ordinals.h +++ /dev/null @@ -1,85 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2022 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__ORDINALS_H -#define FLAC__ORDINALS_H - -#if defined(_MSC_VER) && _MSC_VER < 1600 - -/* Microsoft Visual Studio earlier than the 2010 version did not provide - * the 1999 ISO C Standard header file . - */ - -typedef signed __int8 FLAC__int8; -typedef signed __int16 FLAC__int16; -typedef signed __int32 FLAC__int32; -typedef signed __int64 FLAC__int64; -typedef unsigned __int8 FLAC__uint8; -typedef unsigned __int16 FLAC__uint16; -typedef unsigned __int32 FLAC__uint32; -typedef unsigned __int64 FLAC__uint64; - -#else - -/* For MSVC 2010 and everything else which provides . */ - -#include - -typedef int8_t FLAC__int8; -typedef uint8_t FLAC__uint8; - -typedef int16_t FLAC__int16; -typedef int32_t FLAC__int32; -typedef int64_t FLAC__int64; -typedef uint16_t FLAC__uint16; -typedef uint32_t FLAC__uint32; -typedef uint64_t FLAC__uint64; - -#endif - -typedef int FLAC__bool; - -typedef FLAC__uint8 FLAC__byte; - - -#ifdef true -#undef true -#endif -#ifdef false -#undef false -#endif -#ifndef __cplusplus -#define true 1 -#define false 0 -#endif - -#endif diff --git a/code/dep_codecs/include/FLAC/stream_decoder.h b/code/dep_codecs/include/FLAC/stream_decoder.h deleted file mode 100755 index f4e16488..00000000 --- a/code/dep_codecs/include/FLAC/stream_decoder.h +++ /dev/null @@ -1,1584 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2022 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__STREAM_DECODER_H -#define FLAC__STREAM_DECODER_H - -#include /* for FILE */ -#include "export.h" -#include "format.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \file include/FLAC/stream_decoder.h - * - * \brief - * This module contains the functions which implement the stream - * decoder. - * - * See the detailed documentation in the - * \link flac_stream_decoder stream decoder \endlink module. - */ - -/** \defgroup flac_decoder FLAC/ \*_decoder.h: decoder interfaces - * \ingroup flac - * - * \brief - * This module describes the decoder layers provided by libFLAC. - * - * The stream decoder can be used to decode complete streams either from - * the client via callbacks, or directly from a file, depending on how - * it is initialized. When decoding via callbacks, the client provides - * callbacks for reading FLAC data and writing decoded samples, and - * handling metadata and errors. If the client also supplies seek-related - * callback, the decoder function for sample-accurate seeking within the - * FLAC input is also available. When decoding from a file, the client - * needs only supply a filename or open \c FILE* and write/metadata/error - * callbacks; the rest of the callbacks are supplied internally. For more - * info see the \link flac_stream_decoder stream decoder \endlink module. - */ - -/** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface - * \ingroup flac_decoder - * - * \brief - * This module contains the functions which implement the stream - * decoder. - * - * The stream decoder can decode native FLAC, and optionally Ogg FLAC - * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files. - * - * The basic usage of this decoder is as follows: - * - The program creates an instance of a decoder using - * FLAC__stream_decoder_new(). - * - The program overrides the default settings using - * FLAC__stream_decoder_set_*() functions. - * - The program initializes the instance to validate the settings and - * prepare for decoding using - * - FLAC__stream_decoder_init_stream() or FLAC__stream_decoder_init_FILE() - * or FLAC__stream_decoder_init_file() for native FLAC, - * - FLAC__stream_decoder_init_ogg_stream() or FLAC__stream_decoder_init_ogg_FILE() - * or FLAC__stream_decoder_init_ogg_file() for Ogg FLAC - * - The program calls the FLAC__stream_decoder_process_*() functions - * to decode data, which subsequently calls the callbacks. - * - The program finishes the decoding with FLAC__stream_decoder_finish(), - * which flushes the input and output and resets the decoder to the - * uninitialized state. - * - The instance may be used again or deleted with - * FLAC__stream_decoder_delete(). - * - * In more detail, the program will create a new instance by calling - * FLAC__stream_decoder_new(), then call FLAC__stream_decoder_set_*() - * functions to override the default decoder options, and call - * one of the FLAC__stream_decoder_init_*() functions. - * - * There are three initialization functions for native FLAC, one for - * setting up the decoder to decode FLAC data from the client via - * callbacks, and two for decoding directly from a FLAC file. - * - * For decoding via callbacks, use FLAC__stream_decoder_init_stream(). - * You must also supply several callbacks for handling I/O. Some (like - * seeking) are optional, depending on the capabilities of the input. - * - * For decoding directly from a file, use FLAC__stream_decoder_init_FILE() - * or FLAC__stream_decoder_init_file(). Then you must only supply an open - * \c FILE* or filename and fewer callbacks; the decoder will handle - * the other callbacks internally. - * - * There are three similarly-named init functions for decoding from Ogg - * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the - * library has been built with Ogg support. - * - * Once the decoder is initialized, your program will call one of several - * functions to start the decoding process: - * - * - FLAC__stream_decoder_process_single() - Tells the decoder to process at - * most one metadata block or audio frame and return, calling either the - * metadata callback or write callback, respectively, once. If the decoder - * loses sync it will return with only the error callback being called. - * - FLAC__stream_decoder_process_until_end_of_metadata() - Tells the decoder - * to process the stream from the current location and stop upon reaching - * the first audio frame. The client will get one metadata, write, or error - * callback per metadata block, audio frame, or sync error, respectively. - * - FLAC__stream_decoder_process_until_end_of_stream() - Tells the decoder - * to process the stream from the current location until the read callback - * returns FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM or - * FLAC__STREAM_DECODER_READ_STATUS_ABORT. The client will get one metadata, - * write, or error callback per metadata block, audio frame, or sync error, - * respectively. - * - * When the decoder has finished decoding (normally or through an abort), - * the instance is finished by calling FLAC__stream_decoder_finish(), which - * ensures the decoder is in the correct state and frees memory. Then the - * instance may be deleted with FLAC__stream_decoder_delete() or initialized - * again to decode another stream. - * - * Seeking is exposed through the FLAC__stream_decoder_seek_absolute() method. - * At any point after the stream decoder has been initialized, the client can - * call this function to seek to an exact sample within the stream. - * Subsequently, the first time the write callback is called it will be - * passed a (possibly partial) block starting at that sample. - * - * If the client cannot seek via the callback interface provided, but still - * has another way of seeking, it can flush the decoder using - * FLAC__stream_decoder_flush() and start feeding data from the new position - * through the read callback. - * - * The stream decoder also provides MD5 signature checking. If this is - * turned on before initialization, FLAC__stream_decoder_finish() will - * report when the decoded MD5 signature does not match the one stored - * in the STREAMINFO block. MD5 checking is automatically turned off - * (until the next FLAC__stream_decoder_reset()) if there is no signature - * in the STREAMINFO block or when a seek is attempted. - * - * The FLAC__stream_decoder_set_metadata_*() functions deserve special - * attention. By default, the decoder only calls the metadata_callback for - * the STREAMINFO block. These functions allow you to tell the decoder - * explicitly which blocks to parse and return via the metadata_callback - * and/or which to skip. Use a FLAC__stream_decoder_set_metadata_respond_all(), - * FLAC__stream_decoder_set_metadata_ignore() ... or FLAC__stream_decoder_set_metadata_ignore_all(), - * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify - * which blocks to return. Remember that metadata blocks can potentially - * be big (for example, cover art) so filtering out the ones you don't - * use can reduce the memory requirements of the decoder. Also note the - * special forms FLAC__stream_decoder_set_metadata_respond_application(id) - * and FLAC__stream_decoder_set_metadata_ignore_application(id) for - * filtering APPLICATION blocks based on the application ID. - * - * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but - * they still can legally be filtered from the metadata_callback. - * - * \note - * The "set" functions may only be called when the decoder is in the - * state FLAC__STREAM_DECODER_UNINITIALIZED, i.e. after - * FLAC__stream_decoder_new() or FLAC__stream_decoder_finish(), but - * before FLAC__stream_decoder_init_*(). If this is the case they will - * return \c true, otherwise \c false. - * - * \note - * FLAC__stream_decoder_finish() resets all settings to the constructor - * defaults, including the callbacks. - * - * \{ - */ - - -/** State values for a FLAC__StreamDecoder - * - * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state(). - */ -typedef enum { - - FLAC__STREAM_DECODER_SEARCH_FOR_METADATA = 0, - /**< The decoder is ready to search for metadata. */ - - FLAC__STREAM_DECODER_READ_METADATA, - /**< The decoder is ready to or is in the process of reading metadata. */ - - FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC, - /**< The decoder is ready to or is in the process of searching for the - * frame sync code. - */ - - FLAC__STREAM_DECODER_READ_FRAME, - /**< The decoder is ready to or is in the process of reading a frame. */ - - FLAC__STREAM_DECODER_END_OF_STREAM, - /**< The decoder has reached the end of the stream. */ - - FLAC__STREAM_DECODER_OGG_ERROR, - /**< An error occurred in the underlying Ogg layer. */ - - FLAC__STREAM_DECODER_SEEK_ERROR, - /**< An error occurred while seeking. The decoder must be flushed - * with FLAC__stream_decoder_flush() or reset with - * FLAC__stream_decoder_reset() before decoding can continue. - */ - - FLAC__STREAM_DECODER_ABORTED, - /**< The decoder was aborted by the read or write callback. */ - - FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR, - /**< An error occurred allocating memory. The decoder is in an invalid - * state and can no longer be used. - */ - - FLAC__STREAM_DECODER_UNINITIALIZED - /**< The decoder is in the uninitialized state; one of the - * FLAC__stream_decoder_init_*() functions must be called before samples - * can be processed. - */ - -} FLAC__StreamDecoderState; - -/** Maps a FLAC__StreamDecoderState to a C string. - * - * Using a FLAC__StreamDecoderState as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderStateString[]; - - -/** Possible return values for the FLAC__stream_decoder_init_*() functions. - */ -typedef enum { - - FLAC__STREAM_DECODER_INIT_STATUS_OK = 0, - /**< Initialization was successful. */ - - FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER, - /**< The library was not compiled with support for the given container - * format. - */ - - FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS, - /**< A required callback was not supplied. */ - - FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR, - /**< An error occurred allocating memory. */ - - FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE, - /**< fopen() failed in FLAC__stream_decoder_init_file() or - * FLAC__stream_decoder_init_ogg_file(). */ - - FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED - /**< FLAC__stream_decoder_init_*() was called when the decoder was - * already initialized, usually because - * FLAC__stream_decoder_finish() was not called. - */ - -} FLAC__StreamDecoderInitStatus; - -/** Maps a FLAC__StreamDecoderInitStatus to a C string. - * - * Using a FLAC__StreamDecoderInitStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderInitStatusString[]; - - -/** Return values for the FLAC__StreamDecoder read callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, - /**< The read was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM, - /**< The read was attempted while at the end of the stream. Note that - * the client must only return this value when the read callback was - * called when already at the end of the stream. Otherwise, if the read - * itself moves to the end of the stream, the client should still return - * the data and \c FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, and then on - * the next read callback it should return - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM with a byte count - * of \c 0. - */ - - FLAC__STREAM_DECODER_READ_STATUS_ABORT - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - -} FLAC__StreamDecoderReadStatus; - -/** Maps a FLAC__StreamDecoderReadStatus to a C string. - * - * Using a FLAC__StreamDecoderReadStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[]; - - -/** Return values for the FLAC__StreamDecoder seek callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_SEEK_STATUS_OK, - /**< The seek was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_SEEK_STATUS_ERROR, - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - - FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED - /**< Client does not support seeking. */ - -} FLAC__StreamDecoderSeekStatus; - -/** Maps a FLAC__StreamDecoderSeekStatus to a C string. - * - * Using a FLAC__StreamDecoderSeekStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[]; - - -/** Return values for the FLAC__StreamDecoder tell callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_TELL_STATUS_OK, - /**< The tell was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_TELL_STATUS_ERROR, - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - - FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED - /**< Client does not support telling the position. */ - -} FLAC__StreamDecoderTellStatus; - -/** Maps a FLAC__StreamDecoderTellStatus to a C string. - * - * Using a FLAC__StreamDecoderTellStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderTellStatusString[]; - - -/** Return values for the FLAC__StreamDecoder length callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_LENGTH_STATUS_OK, - /**< The length call was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR, - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - - FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED - /**< Client does not support reporting the length. */ - -} FLAC__StreamDecoderLengthStatus; - -/** Maps a FLAC__StreamDecoderLengthStatus to a C string. - * - * Using a FLAC__StreamDecoderLengthStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[]; - - -/** Return values for the FLAC__StreamDecoder write callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE, - /**< The write was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_WRITE_STATUS_ABORT - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - -} FLAC__StreamDecoderWriteStatus; - -/** Maps a FLAC__StreamDecoderWriteStatus to a C string. - * - * Using a FLAC__StreamDecoderWriteStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[]; - - -/** Possible values passed back to the FLAC__StreamDecoder error callback. - * \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC is the generic catch- - * all. The rest could be caused by bad sync (false synchronization on - * data that is not the start of a frame) or corrupted data. The error - * itself is the decoder's best guess at what happened assuming a correct - * sync. For example \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER - * could be caused by a correct sync on the start of a frame, but some - * data in the frame header was corrupted. Or it could be the result of - * syncing on a point the stream that looked like the starting of a frame - * but was not. \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM - * could be because the decoder encountered a valid frame made by a future - * version of the encoder which it cannot parse, or because of a false - * sync making it appear as though an encountered frame was generated by - * a future encoder. \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA is - * caused by finding data that doesn't fit a metadata block (too large - * or too small) or finding inconsistencies in the metadata, for example - * a PICTURE block with an image that exceeds the size of the metadata - * block. - */ -typedef enum { - - FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, - /**< An error in the stream caused the decoder to lose synchronization. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, - /**< The decoder encountered a corrupted frame header. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH, - /**< The frame's data did not match the CRC in the footer. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM, - /**< The decoder encountered reserved fields in use in the stream. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA - /**< The decoder encountered a corrupted metadata block. */ - -} FLAC__StreamDecoderErrorStatus; - -/** Maps a FLAC__StreamDecoderErrorStatus to a C string. - * - * Using a FLAC__StreamDecoderErrorStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[]; - - -/*********************************************************************** - * - * class FLAC__StreamDecoder - * - ***********************************************************************/ - -struct FLAC__StreamDecoderProtected; -struct FLAC__StreamDecoderPrivate; -/** The opaque structure definition for the stream decoder type. - * See the \link flac_stream_decoder stream decoder module \endlink - * for a detailed description. - */ -typedef struct { - struct FLAC__StreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */ - struct FLAC__StreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */ -} FLAC__StreamDecoder; - -/** Signature for the read callback. - * - * A function pointer matching this signature must be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder needs more input data. The address of the - * buffer to be filled is supplied, along with the number of bytes the - * buffer can hold. The callback may choose to supply less data and - * modify the byte count but must be careful not to overflow the buffer. - * The callback then returns a status code chosen from - * FLAC__StreamDecoderReadStatus. - * - * Here is an example of a read callback for stdio streams: - * \code - * FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * if(*bytes > 0) { - * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file); - * if(ferror(file)) - * return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - * else if(*bytes == 0) - * return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - * else - * return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - * } - * else - * return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param buffer A pointer to a location for the callee to store - * data to be decoded. - * \param bytes A pointer to the size of the buffer. On entry - * to the callback, it contains the maximum number - * of bytes that may be stored in \a buffer. The - * callee must set it to the actual number of bytes - * stored (0 in case of error or end-of-stream) before - * returning. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderReadStatus - * The callee's return status. Note that the callback should return - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM if and only if - * zero bytes were read and there is no more data to be read. - */ -typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); - -/** Signature for the seek callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder needs to seek the input stream. The decoder - * will pass the absolute byte offset to seek to, 0 meaning the - * beginning of the stream. - * - * Here is an example of a seek callback for stdio streams: - * \code - * FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * if(file == stdin) - * return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; - * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0) - * return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; - * else - * return FLAC__STREAM_DECODER_SEEK_STATUS_OK; - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param absolute_byte_offset The offset from the beginning of the stream - * to seek to. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderSeekStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderSeekStatus (*FLAC__StreamDecoderSeekCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); - -/** Signature for the tell callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder wants to know the current position of the - * stream. The callback should return the byte offset from the - * beginning of the stream. - * - * Here is an example of a tell callback for stdio streams: - * \code - * FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * off_t pos; - * if(file == stdin) - * return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED; - * else if((pos = ftello(file)) < 0) - * return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; - * else { - * *absolute_byte_offset = (FLAC__uint64)pos; - * return FLAC__STREAM_DECODER_TELL_STATUS_OK; - * } - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param absolute_byte_offset A pointer to storage for the current offset - * from the beginning of the stream. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderTellStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderTellStatus (*FLAC__StreamDecoderTellCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); - -/** Signature for the length callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder wants to know the total length of the stream - * in bytes. - * - * Here is an example of a length callback for stdio streams: - * \code - * FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * struct stat filestats; - * - * if(file == stdin) - * return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; - * else if(fstat(fileno(file), &filestats) != 0) - * return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; - * else { - * *stream_length = (FLAC__uint64)filestats.st_size; - * return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; - * } - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param stream_length A pointer to storage for the length of the stream - * in bytes. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderLengthStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderLengthStatus (*FLAC__StreamDecoderLengthCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); - -/** Signature for the EOF callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder needs to know if the end of the stream has - * been reached. - * - * Here is an example of a EOF callback for stdio streams: - * FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data) - * \code - * { - * FILE *file = ((MyClientData*)client_data)->file; - * return feof(file)? true : false; - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__bool - * \c true if the currently at the end of the stream, else \c false. - */ -typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *decoder, void *client_data); - -/** Signature for the write callback. - * - * A function pointer matching this signature must be passed to one of - * the FLAC__stream_decoder_init_*() functions. - * The supplied function will be called when the decoder has decoded a - * single audio frame. The decoder will pass the frame metadata as well - * as an array of pointers (one for each channel) pointing to the - * decoded audio. - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param frame The description of the decoded frame. See - * FLAC__Frame. - * \param buffer An array of pointers to decoded channels of data. - * Each pointer will point to an array of signed - * samples of length \a frame->header.blocksize. - * Channels will be ordered according to the FLAC - * specification; see the documentation for the - * frame header. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderWriteStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderWriteStatus (*FLAC__StreamDecoderWriteCallback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); - -/** Signature for the metadata callback. - * - * A function pointer matching this signature must be passed to one of - * the FLAC__stream_decoder_init_*() functions. - * The supplied function will be called when the decoder has decoded a - * metadata block. In a valid FLAC file there will always be one - * \c STREAMINFO block, followed by zero or more other metadata blocks. - * These will be supplied by the decoder in the same order as they - * appear in the stream and always before the first audio frame (i.e. - * write callback). The metadata block that is passed in must not be - * modified, and it doesn't live beyond the callback, so you should make - * a copy of it with FLAC__metadata_object_clone() if you will need it - * elsewhere. Since metadata blocks can potentially be large, by - * default the decoder only calls the metadata callback for the - * \c STREAMINFO block; you can instruct the decoder to pass or filter - * other blocks with FLAC__stream_decoder_set_metadata_*() calls. - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param metadata The decoded metadata block. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - */ -typedef void (*FLAC__StreamDecoderMetadataCallback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); - -/** Signature for the error callback. - * - * A function pointer matching this signature must be passed to one of - * the FLAC__stream_decoder_init_*() functions. - * The supplied function will be called whenever an error occurs during - * decoding. - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param status The error encountered by the decoder. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - */ -typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); - - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -/** Create a new stream decoder instance. The instance is created with - * default settings; see the individual FLAC__stream_decoder_set_*() - * functions for each setting's default. - * - * \retval FLAC__StreamDecoder* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void); - -/** Free a decoder instance. Deletes the object pointed to by \a decoder. - * - * \param decoder A pointer to an existing decoder. - * \assert - * \code decoder != NULL \endcode - */ -FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder); - - -/*********************************************************************** - * - * Public class method prototypes - * - ***********************************************************************/ - -/** Set the serial number for the FLAC stream within the Ogg container. - * The default behavior is to use the serial number of the first Ogg - * page. Setting a serial number here will explicitly specify which - * stream is to be decoded. - * - * \note - * This does not need to be set for native FLAC decoding. - * - * \default \c use serial number of first page - * \param decoder A decoder instance to set. - * \param serial_number See above. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number); - -/** Set the "MD5 signature checking" flag. If \c true, the decoder will - * compute the MD5 signature of the unencoded audio data while decoding - * and compare it to the signature from the STREAMINFO block, if it - * exists, during FLAC__stream_decoder_finish(). - * - * MD5 signature checking will be turned off (until the next - * FLAC__stream_decoder_reset()) if there is no signature in the - * STREAMINFO block or when a seek is attempted. - * - * Clients that do not use the MD5 check should leave this off to speed - * up decoding. - * - * \default \c false - * \param decoder A decoder instance to set. - * \param value Flag value (see above). - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value); - -/** Direct the decoder to pass on all metadata blocks of type \a type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param type See above. - * \assert - * \code decoder != NULL \endcode - * \a type is valid - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type); - -/** Direct the decoder to pass on all APPLICATION metadata blocks of the - * given \a id. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param id See above. - * \assert - * \code decoder != NULL \endcode - * \code id != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]); - -/** Direct the decoder to pass on all metadata blocks of any type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder); - -/** Direct the decoder to filter out all metadata blocks of type \a type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param type See above. - * \assert - * \code decoder != NULL \endcode - * \a type is valid - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type); - -/** Direct the decoder to filter out all APPLICATION metadata blocks of - * the given \a id. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param id See above. - * \assert - * \code decoder != NULL \endcode - * \code id != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]); - -/** Direct the decoder to filter out all metadata blocks of any type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder); - -/** Get the current decoder state. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderState - * The current decoder state. - */ -FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder); - -/** Get the current decoder state as a C string. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval const char * - * The decoder state as a C string. Do not modify the contents. - */ -FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder); - -/** Get the "MD5 signature checking" flag. - * This is the value of the setting, not whether or not the decoder is - * currently checking the MD5 (remember, it can be turned off automatically - * by a seek). When the decoder is reset the flag will be restored to the - * value returned by this function. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder); - -/** Get the total number of samples in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the \c STREAMINFO block. A value of \c 0 means "unknown". - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder); - -/** Get the current number of channels in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder); - -/** Get the current channel assignment in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__ChannelAssignment - * See above. - */ -FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder); - -/** Get the current sample resolution in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder); - -/** Get the current sample rate in Hz of the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder); - -/** Get the current blocksize of the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder); - -/** Returns the decoder's current read position within the stream. - * The position is the byte offset from the start of the stream. - * Bytes before this position have been fully decoded. Note that - * there may still be undecoded bytes in the decoder's read FIFO. - * The returned position is correct even after a seek. - * - * \warning This function currently only works for native FLAC, - * not Ogg FLAC streams. - * - * \param decoder A decoder instance to query. - * \param position Address at which to return the desired position. - * \assert - * \code decoder != NULL \endcode - * \code position != NULL \endcode - * \retval FLAC__bool - * \c true if successful, \c false if the stream is not native FLAC, - * or there was an error from the 'tell' callback or it returned - * \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position); - -/** Return client_data from decoder. - * The data pointed to by the pointer should not be modified. - * - * \param decoder A decoder instance. - * \retval const void * - * The callee's client data set through FLAC__stream_decoder_init_*(). - * Do not modify the contents. - */ -FLAC_API const void *FLAC__stream_decoder_get_client_data(FLAC__StreamDecoder *decoder); - -/** Initialize the decoder instance to decode native FLAC streams. - * - * This flavor of initialization sets up the decoder to decode from a - * native FLAC stream. I/O is performed via callbacks to the client. - * For decoding from a plain file via filename or open FILE*, - * FLAC__stream_decoder_init_file() and FLAC__stream_decoder_init_FILE() - * provide a simpler interface. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \param decoder An uninitialized decoder instance. - * \param read_callback See FLAC__StreamDecoderReadCallback. This - * pointer must not be \c NULL. - * \param seek_callback See FLAC__StreamDecoderSeekCallback. This - * pointer may be \c NULL if seeking is not - * supported. If \a seek_callback is not \c NULL then a - * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied. - * Alternatively, a dummy seek callback that just - * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param tell_callback See FLAC__StreamDecoderTellCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a tell_callback must also be supplied. - * Alternatively, a dummy tell callback that just - * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param length_callback See FLAC__StreamDecoderLengthCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a length_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param eof_callback See FLAC__StreamDecoderEofCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a eof_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c false - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode Ogg FLAC streams. - * - * This flavor of initialization sets up the decoder to decode from a - * FLAC stream in an Ogg container. I/O is performed via callbacks to the - * client. For decoding from a plain file via filename or open FILE*, - * FLAC__stream_decoder_init_ogg_file() and FLAC__stream_decoder_init_ogg_FILE() - * provide a simpler interface. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \note Support for Ogg FLAC in the library is optional. If this - * library has been built without support for Ogg FLAC, this function - * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. - * - * \param decoder An uninitialized decoder instance. - * \param read_callback See FLAC__StreamDecoderReadCallback. This - * pointer must not be \c NULL. - * \param seek_callback See FLAC__StreamDecoderSeekCallback. This - * pointer may be \c NULL if seeking is not - * supported. If \a seek_callback is not \c NULL then a - * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied. - * Alternatively, a dummy seek callback that just - * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param tell_callback See FLAC__StreamDecoderTellCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a tell_callback must also be supplied. - * Alternatively, a dummy tell callback that just - * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param length_callback See FLAC__StreamDecoderLengthCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a length_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param eof_callback See FLAC__StreamDecoderEofCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a eof_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c false - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode native FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a - * plain native FLAC file. For non-stdio streams, you must use - * FLAC__stream_decoder_init_stream() and provide callbacks for the I/O. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \param decoder An uninitialized decoder instance. - * \param file An open FLAC file. The file should have been - * opened with mode \c "rb" and rewound. The file - * becomes owned by the decoder and should not be - * manipulated by the client while decoding. - * Unless \a file is \c stdin, it will be closed - * when FLAC__stream_decoder_finish() is called. - * Note however that seeking will not work when - * decoding from \c stdin since it is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \code file != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode Ogg FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a - * plain Ogg FLAC file. For non-stdio streams, you must use - * FLAC__stream_decoder_init_ogg_stream() and provide callbacks for the I/O. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \note Support for Ogg FLAC in the library is optional. If this - * library has been built without support for Ogg FLAC, this function - * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. - * - * \param decoder An uninitialized decoder instance. - * \param file An open FLAC file. The file should have been - * opened with mode \c "rb" and rewound. The file - * becomes owned by the decoder and should not be - * manipulated by the client while decoding. - * Unless \a file is \c stdin, it will be closed - * when FLAC__stream_decoder_finish() is called. - * Note however that seeking will not work when - * decoding from \c stdin since it is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \code file != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode native FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a plain - * native FLAC file. If POSIX fopen() semantics are not sufficient, you must - * use FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream() - * and provide callbacks for the I/O. - * - * On Windows, filename must be a UTF-8 encoded filename, which libFLAC - * internally translates to an appropriate representation to use with - * _wfopen. On all other systems, filename is passed to fopen without - * any translation. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \param decoder An uninitialized decoder instance. - * \param filename The name of the file to decode from. The file will - * be opened with fopen(). Use \c NULL to decode from - * \c stdin. Note that \c stdin is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode Ogg FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a plain - * Ogg FLAC file. If POSIX fopen() semantics are not sufficient, you must use - * FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream() - * and provide callbacks for the I/O. - * - * On Windows, filename must be a UTF-8 encoded filename, which libFLAC - * internally translates to an appropriate representation to use with - * _wfopen. On all other systems, filename is passed to fopen without - * any translation. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \note Support for Ogg FLAC in the library is optional. If this - * library has been built without support for Ogg FLAC, this function - * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. - * - * \param decoder An uninitialized decoder instance. - * \param filename The name of the file to decode from. The file will - * be opened with fopen(). Use \c NULL to decode from - * \c stdin. Note that \c stdin is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Finish the decoding process. - * Flushes the decoding buffer, releases resources, resets the decoder - * settings to their defaults, and returns the decoder state to - * FLAC__STREAM_DECODER_UNINITIALIZED. - * - * In the event of a prematurely-terminated decode, it is not strictly - * necessary to call this immediately before FLAC__stream_decoder_delete() - * but it is good practice to match every FLAC__stream_decoder_init_*() - * with a FLAC__stream_decoder_finish(). - * - * \param decoder An uninitialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if MD5 checking is on AND a STREAMINFO block was available - * AND the MD5 signature in the STREAMINFO block was non-zero AND the - * signature does not match the one computed by the decoder; else - * \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder); - -/** Flush the stream input. - * The decoder's input buffer will be cleared and the state set to - * \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC. This will also turn - * off MD5 checking. - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false if a memory allocation - * error occurs (in which case the state will be set to - * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder); - -/** Reset the decoding process. - * The decoder's input buffer will be cleared and the state set to - * \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA. This is similar to - * FLAC__stream_decoder_finish() except that the settings are - * preserved; there is no need to call FLAC__stream_decoder_init_*() - * before decoding again. MD5 checking will be restored to its original - * setting. - * - * If the decoder is seekable, or was initialized with - * FLAC__stream_decoder_init*_FILE() or FLAC__stream_decoder_init*_file(), - * the decoder will also attempt to seek to the beginning of the file. - * If this rewind fails, this function will return \c false. It follows - * that FLAC__stream_decoder_reset() cannot be used when decoding from - * \c stdin. - * - * If the decoder was initialized with FLAC__stream_encoder_init*_stream() - * and is not seekable (i.e. no seek callback was provided or the seek - * callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it - * is the duty of the client to start feeding data from the beginning of - * the stream on the next FLAC__stream_decoder_process_*() call. - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false if a memory allocation occurs - * (in which case the state will be set to - * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) or a seek error - * occurs (the state will be unchanged). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder); - -/** Decode one metadata block or audio frame. - * This version instructs the decoder to decode a either a single metadata - * block or a single frame and stop, unless the callbacks return a fatal - * error or the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. - * - * As the decoder needs more input it will call the read callback. - * Depending on what was decoded, the metadata or write callback will be - * called with the decoded metadata block or audio frame. - * - * Unless there is a fatal read error or end of stream, this function - * will return once one whole frame is decoded. In other words, if the - * stream is not synchronized or points to a corrupt frame header, the - * decoder will continue to try and resync until it gets to a valid - * frame, then decode one frame, then return. If the decoder points to - * a frame whose frame CRC in the frame footer does not match the - * computed frame CRC, this function will issue a - * FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the - * error callback, and return, having decoded one complete, although - * corrupt, frame. (Such corrupted frames are sent as silence of the - * correct length to the write callback.) - * - * \param decoder An initialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder); - -/** Decode until the end of the metadata. - * This version instructs the decoder to decode from the current position - * and continue until all the metadata has been read, or until the - * callbacks return a fatal error or the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. - * - * As the decoder needs more input it will call the read callback. - * As each metadata block is decoded, the metadata callback will be called - * with the decoded metadata. - * - * \param decoder An initialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder); - -/** Decode until the end of the stream. - * This version instructs the decoder to decode from the current position - * and continue until the end of stream (the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM), or until the - * callbacks return a fatal error. - * - * As the decoder needs more input it will call the read callback. - * As each metadata block and frame is decoded, the metadata or write - * callback will be called with the decoded metadata or frame. - * - * \param decoder An initialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder); - -/** Skip one audio frame. - * This version instructs the decoder to 'skip' a single frame and stop, - * unless the callbacks return a fatal error or the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. - * - * The decoding flow is the same as what occurs when - * FLAC__stream_decoder_process_single() is called to process an audio - * frame, except that this function does not decode the parsed data into - * PCM or call the write callback. The integrity of the frame is still - * checked the same way as in the other process functions. - * - * This function will return once one whole frame is skipped, in the - * same way that FLAC__stream_decoder_process_single() will return once - * one whole frame is decoded. - * - * This function can be used in more quickly determining FLAC frame - * boundaries when decoding of the actual data is not needed, for - * example when an application is separating a FLAC stream into frames - * for editing or storing in a container. To do this, the application - * can use FLAC__stream_decoder_skip_single_frame() to quickly advance - * to the next frame, then use - * FLAC__stream_decoder_get_decode_position() to find the new frame - * boundary. - * - * This function should only be called when the stream has advanced - * past all the metadata, otherwise it will return \c false. - * - * \param decoder An initialized decoder instance not in a metadata - * state. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), or if the decoder - * is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or - * FLAC__STREAM_DECODER_READ_METADATA state, else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder); - -/** Flush the input and seek to an absolute sample. - * Decoding will resume at the given sample. Note that because of - * this, the next write callback may contain a partial block. The - * client must support seeking the input or this function will fail - * and return \c false. Furthermore, if the decoder state is - * \c FLAC__STREAM_DECODER_SEEK_ERROR, then the decoder must be flushed - * with FLAC__stream_decoder_flush() or reset with - * FLAC__stream_decoder_reset() before decoding can continue. - * - * \param decoder A decoder instance. - * \param sample The target sample number to seek to. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/code/dep_codecs/include/FLAC/stream_encoder.h b/code/dep_codecs/include/FLAC/stream_encoder.h deleted file mode 100755 index 4ab4dce4..00000000 --- a/code/dep_codecs/include/FLAC/stream_encoder.h +++ /dev/null @@ -1,1837 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2022 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__STREAM_ENCODER_H -#define FLAC__STREAM_ENCODER_H - -#include /* for FILE */ -#include "export.h" -#include "format.h" -#include "stream_decoder.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \file include/FLAC/stream_encoder.h - * - * \brief - * This module contains the functions which implement the stream - * encoder. - * - * See the detailed documentation in the - * \link flac_stream_encoder stream encoder \endlink module. - */ - -/** \defgroup flac_encoder FLAC/ \*_encoder.h: encoder interfaces - * \ingroup flac - * - * \brief - * This module describes the encoder layers provided by libFLAC. - * - * The stream encoder can be used to encode complete streams either to the - * client via callbacks, or directly to a file, depending on how it is - * initialized. When encoding via callbacks, the client provides a write - * callback which will be called whenever FLAC data is ready to be written. - * If the client also supplies a seek callback, the encoder will also - * automatically handle the writing back of metadata discovered while - * encoding, like stream info, seek points offsets, etc. When encoding to - * a file, the client needs only supply a filename or open \c FILE* and an - * optional progress callback for periodic notification of progress; the - * write and seek callbacks are supplied internally. For more info see the - * \link flac_stream_encoder stream encoder \endlink module. - */ - -/** \defgroup flac_stream_encoder FLAC/stream_encoder.h: stream encoder interface - * \ingroup flac_encoder - * - * \brief - * This module contains the functions which implement the stream - * encoder. - * - * The stream encoder can encode to native FLAC, and optionally Ogg FLAC - * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files. - * - * The basic usage of this encoder is as follows: - * - The program creates an instance of an encoder using - * FLAC__stream_encoder_new(). - * - The program overrides the default settings using - * FLAC__stream_encoder_set_*() functions. At a minimum, the following - * functions should be called: - * - FLAC__stream_encoder_set_channels() - * - FLAC__stream_encoder_set_bits_per_sample() - * - FLAC__stream_encoder_set_sample_rate() - * - FLAC__stream_encoder_set_ogg_serial_number() (if encoding to Ogg FLAC) - * - FLAC__stream_encoder_set_total_samples_estimate() (if known) - * - If the application wants to control the compression level or set its own - * metadata, then the following should also be called: - * - FLAC__stream_encoder_set_compression_level() - * - FLAC__stream_encoder_set_verify() - * - FLAC__stream_encoder_set_metadata() - * - The rest of the set functions should only be called if the client needs - * exact control over how the audio is compressed; thorough understanding - * of the FLAC format is necessary to achieve good results. - * - The program initializes the instance to validate the settings and - * prepare for encoding using - * - FLAC__stream_encoder_init_stream() or FLAC__stream_encoder_init_FILE() - * or FLAC__stream_encoder_init_file() for native FLAC - * - FLAC__stream_encoder_init_ogg_stream() or FLAC__stream_encoder_init_ogg_FILE() - * or FLAC__stream_encoder_init_ogg_file() for Ogg FLAC - * - The program calls FLAC__stream_encoder_process() or - * FLAC__stream_encoder_process_interleaved() to encode data, which - * subsequently calls the callbacks when there is encoder data ready - * to be written. - * - The program finishes the encoding with FLAC__stream_encoder_finish(), - * which causes the encoder to encode any data still in its input pipe, - * update the metadata with the final encoding statistics if output - * seeking is possible, and finally reset the encoder to the - * uninitialized state. - * - The instance may be used again or deleted with - * FLAC__stream_encoder_delete(). - * - * In more detail, the stream encoder functions similarly to the - * \link flac_stream_decoder stream decoder \endlink, but has fewer - * callbacks and more options. Typically the client will create a new - * instance by calling FLAC__stream_encoder_new(), then set the necessary - * parameters with FLAC__stream_encoder_set_*(), and initialize it by - * calling one of the FLAC__stream_encoder_init_*() functions. - * - * Unlike the decoders, the stream encoder has many options that can - * affect the speed and compression ratio. When setting these parameters - * you should have some basic knowledge of the format (see the - * user-level documentation - * or the formal description). The - * FLAC__stream_encoder_set_*() functions themselves do not validate the - * values as many are interdependent. The FLAC__stream_encoder_init_*() - * functions will do this, so make sure to pay attention to the state - * returned by FLAC__stream_encoder_init_*() to make sure that it is - * FLAC__STREAM_ENCODER_INIT_STATUS_OK. Any parameters that are not set - * before FLAC__stream_encoder_init_*() will take on the defaults from - * the constructor. - * - * There are three initialization functions for native FLAC, one for - * setting up the encoder to encode FLAC data to the client via - * callbacks, and two for encoding directly to a file. - * - * For encoding via callbacks, use FLAC__stream_encoder_init_stream(). - * You must also supply a write callback which will be called anytime - * there is raw encoded data to write. If the client can seek the output - * it is best to also supply seek and tell callbacks, as this allows the - * encoder to go back after encoding is finished to write back - * information that was collected while encoding, like seek point offsets, - * frame sizes, etc. - * - * For encoding directly to a file, use FLAC__stream_encoder_init_FILE() - * or FLAC__stream_encoder_init_file(). Then you must only supply a - * filename or open \c FILE*; the encoder will handle all the callbacks - * internally. You may also supply a progress callback for periodic - * notification of the encoding progress. - * - * There are three similarly-named init functions for encoding to Ogg - * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the - * library has been built with Ogg support. - * - * The call to FLAC__stream_encoder_init_*() currently will also immediately - * call the write callback several times, once with the \c fLaC signature, - * and once for each encoded metadata block. Note that for Ogg FLAC - * encoding you will usually get at least twice the number of callbacks than - * with native FLAC, one for the Ogg page header and one for the page body. - * - * After initializing the instance, the client may feed audio data to the - * encoder in one of two ways: - * - * - Channel separate, through FLAC__stream_encoder_process() - The client - * will pass an array of pointers to buffers, one for each channel, to - * the encoder, each of the same length. The samples need not be - * block-aligned, but each channel should have the same number of samples. - * - Channel interleaved, through - * FLAC__stream_encoder_process_interleaved() - The client will pass a single - * pointer to data that is channel-interleaved (i.e. channel0_sample0, - * channel1_sample0, ... , channelN_sample0, channel0_sample1, ...). - * Again, the samples need not be block-aligned but they must be - * sample-aligned, i.e. the first value should be channel0_sample0 and - * the last value channelN_sampleM. - * - * Note that for either process call, each sample in the buffers should be a - * signed integer, right-justified to the resolution set by - * FLAC__stream_encoder_set_bits_per_sample(). For example, if the resolution - * is 16 bits per sample, the samples should all be in the range [-32768,32767]. - * - * When the client is finished encoding data, it calls - * FLAC__stream_encoder_finish(), which causes the encoder to encode any - * data still in its input pipe, and call the metadata callback with the - * final encoding statistics. Then the instance may be deleted with - * FLAC__stream_encoder_delete() or initialized again to encode another - * stream. - * - * For programs that write their own metadata, but that do not know the - * actual metadata until after encoding, it is advantageous to instruct - * the encoder to write a PADDING block of the correct size, so that - * instead of rewriting the whole stream after encoding, the program can - * just overwrite the PADDING block. If only the maximum size of the - * metadata is known, the program can write a slightly larger padding - * block, then split it after encoding. - * - * Make sure you understand how lengths are calculated. All FLAC metadata - * blocks have a 4 byte header which contains the type and length. This - * length does not include the 4 bytes of the header. See the format page - * for the specification of metadata blocks and their lengths. - * - * \note - * If you are writing the FLAC data to a file via callbacks, make sure it - * is open for update (e.g. mode "w+" for stdio streams). This is because - * after the first encoding pass, the encoder will try to seek back to the - * beginning of the stream, to the STREAMINFO block, to write some data - * there. (If using FLAC__stream_encoder_init*_file() or - * FLAC__stream_encoder_init*_FILE(), the file is managed internally.) - * - * \note - * The "set" functions may only be called when the encoder is in the - * state FLAC__STREAM_ENCODER_UNINITIALIZED, i.e. after - * FLAC__stream_encoder_new() or FLAC__stream_encoder_finish(), but - * before FLAC__stream_encoder_init_*(). If this is the case they will - * return \c true, otherwise \c false. - * - * \note - * FLAC__stream_encoder_finish() resets all settings to the constructor - * defaults. - * - * \{ - */ - - -/** State values for a FLAC__StreamEncoder. - * - * The encoder's state can be obtained by calling FLAC__stream_encoder_get_state(). - * - * If the encoder gets into any other state besides \c FLAC__STREAM_ENCODER_OK - * or \c FLAC__STREAM_ENCODER_UNINITIALIZED, it becomes invalid for encoding and - * must be deleted with FLAC__stream_encoder_delete(). - */ -typedef enum { - - FLAC__STREAM_ENCODER_OK = 0, - /**< The encoder is in the normal OK state and samples can be processed. */ - - FLAC__STREAM_ENCODER_UNINITIALIZED, - /**< The encoder is in the uninitialized state; one of the - * FLAC__stream_encoder_init_*() functions must be called before samples - * can be processed. - */ - - FLAC__STREAM_ENCODER_OGG_ERROR, - /**< An error occurred in the underlying Ogg layer. */ - - FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR, - /**< An error occurred in the underlying verify stream decoder; - * check FLAC__stream_encoder_get_verify_decoder_state(). - */ - - FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA, - /**< The verify decoder detected a mismatch between the original - * audio signal and the decoded audio signal. - */ - - FLAC__STREAM_ENCODER_CLIENT_ERROR, - /**< One of the callbacks returned a fatal error. */ - - FLAC__STREAM_ENCODER_IO_ERROR, - /**< An I/O error occurred while opening/reading/writing a file. - * Check \c errno. - */ - - FLAC__STREAM_ENCODER_FRAMING_ERROR, - /**< An error occurred while writing the stream; usually, the - * write_callback returned an error. - */ - - FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR - /**< Memory allocation failed. */ - -} FLAC__StreamEncoderState; - -/** Maps a FLAC__StreamEncoderState to a C string. - * - * Using a FLAC__StreamEncoderState as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderStateString[]; - - -/** Possible return values for the FLAC__stream_encoder_init_*() functions. - */ -typedef enum { - - FLAC__STREAM_ENCODER_INIT_STATUS_OK = 0, - /**< Initialization was successful. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR, - /**< General failure to set up encoder; call FLAC__stream_encoder_get_state() for cause. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER, - /**< The library was not compiled with support for the given container - * format. - */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS, - /**< A required callback was not supplied. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS, - /**< The encoder has an invalid setting for number of channels. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE, - /**< The encoder has an invalid setting for bits-per-sample. - * FLAC supports 4-32 bps. - */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE, - /**< The encoder has an invalid setting for the input sample rate. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE, - /**< The encoder has an invalid setting for the block size. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER, - /**< The encoder has an invalid setting for the maximum LPC order. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION, - /**< The encoder has an invalid setting for the precision of the quantized linear predictor coefficients. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER, - /**< The specified block size is less than the maximum LPC order. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE, - /**< The encoder is bound to the Subset but other settings violate it. */ - - FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA, - /**< The metadata input to the encoder is invalid, in one of the following ways: - * - FLAC__stream_encoder_set_metadata() was called with a null pointer but a block count > 0 - * - One of the metadata blocks contains an undefined type - * - It contains an illegal CUESHEET as checked by FLAC__format_cuesheet_is_legal() - * - It contains an illegal SEEKTABLE as checked by FLAC__format_seektable_is_legal() - * - It contains more than one SEEKTABLE block or more than one VORBIS_COMMENT block - */ - - FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED - /**< FLAC__stream_encoder_init_*() was called when the encoder was - * already initialized, usually because - * FLAC__stream_encoder_finish() was not called. - */ - -} FLAC__StreamEncoderInitStatus; - -/** Maps a FLAC__StreamEncoderInitStatus to a C string. - * - * Using a FLAC__StreamEncoderInitStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderInitStatusString[]; - - -/** Return values for the FLAC__StreamEncoder read callback. - */ -typedef enum { - - FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE, - /**< The read was OK and decoding can continue. */ - - FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM, - /**< The read was attempted at the end of the stream. */ - - FLAC__STREAM_ENCODER_READ_STATUS_ABORT, - /**< An unrecoverable error occurred. */ - - FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED - /**< Client does not support reading back from the output. */ - -} FLAC__StreamEncoderReadStatus; - -/** Maps a FLAC__StreamEncoderReadStatus to a C string. - * - * Using a FLAC__StreamEncoderReadStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderReadStatusString[]; - - -/** Return values for the FLAC__StreamEncoder write callback. - */ -typedef enum { - - FLAC__STREAM_ENCODER_WRITE_STATUS_OK = 0, - /**< The write was OK and encoding can continue. */ - - FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR - /**< An unrecoverable error occurred. The encoder will return from the process call. */ - -} FLAC__StreamEncoderWriteStatus; - -/** Maps a FLAC__StreamEncoderWriteStatus to a C string. - * - * Using a FLAC__StreamEncoderWriteStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[]; - - -/** Return values for the FLAC__StreamEncoder seek callback. - */ -typedef enum { - - FLAC__STREAM_ENCODER_SEEK_STATUS_OK, - /**< The seek was OK and encoding can continue. */ - - FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR, - /**< An unrecoverable error occurred. */ - - FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED - /**< Client does not support seeking. */ - -} FLAC__StreamEncoderSeekStatus; - -/** Maps a FLAC__StreamEncoderSeekStatus to a C string. - * - * Using a FLAC__StreamEncoderSeekStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[]; - - -/** Return values for the FLAC__StreamEncoder tell callback. - */ -typedef enum { - - FLAC__STREAM_ENCODER_TELL_STATUS_OK, - /**< The tell was OK and encoding can continue. */ - - FLAC__STREAM_ENCODER_TELL_STATUS_ERROR, - /**< An unrecoverable error occurred. */ - - FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED - /**< Client does not support seeking. */ - -} FLAC__StreamEncoderTellStatus; - -/** Maps a FLAC__StreamEncoderTellStatus to a C string. - * - * Using a FLAC__StreamEncoderTellStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamEncoderTellStatusString[]; - - -/*********************************************************************** - * - * class FLAC__StreamEncoder - * - ***********************************************************************/ - -struct FLAC__StreamEncoderProtected; -struct FLAC__StreamEncoderPrivate; -/** The opaque structure definition for the stream encoder type. - * See the \link flac_stream_encoder stream encoder module \endlink - * for a detailed description. - */ -typedef struct { - struct FLAC__StreamEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */ - struct FLAC__StreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */ -} FLAC__StreamEncoder; - -/** Signature for the read callback. - * - * A function pointer matching this signature must be passed to - * FLAC__stream_encoder_init_ogg_stream() if seeking is supported. - * The supplied function will be called when the encoder needs to read back - * encoded data. This happens during the metadata callback, when the encoder - * has to read, modify, and rewrite the metadata (e.g. seekpoints) gathered - * while encoding. The address of the buffer to be filled is supplied, along - * with the number of bytes the buffer can hold. The callback may choose to - * supply less data and modify the byte count but must be careful not to - * overflow the buffer. The callback then returns a status code chosen from - * FLAC__StreamEncoderReadStatus. - * - * Here is an example of a read callback for stdio streams: - * \code - * FLAC__StreamEncoderReadStatus read_cb(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * if(*bytes > 0) { - * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file); - * if(ferror(file)) - * return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; - * else if(*bytes == 0) - * return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM; - * else - * return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE; - * } - * else - * return FLAC__STREAM_ENCODER_READ_STATUS_ABORT; - * } - * \endcode - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param buffer A pointer to a location for the callee to store - * data to be encoded. - * \param bytes A pointer to the size of the buffer. On entry - * to the callback, it contains the maximum number - * of bytes that may be stored in \a buffer. The - * callee must set it to the actual number of bytes - * stored (0 in case of error or end-of-stream) before - * returning. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_set_client_data(). - * \retval FLAC__StreamEncoderReadStatus - * The callee's return status. - */ -typedef FLAC__StreamEncoderReadStatus (*FLAC__StreamEncoderReadCallback)(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data); - -/** Signature for the write callback. - * - * A function pointer matching this signature must be passed to - * FLAC__stream_encoder_init*_stream(). The supplied function will be called - * by the encoder anytime there is raw encoded data ready to write. It may - * include metadata mixed with encoded audio frames and the data is not - * guaranteed to be aligned on frame or metadata block boundaries. - * - * The only duty of the callback is to write out the \a bytes worth of data - * in \a buffer to the current position in the output stream. The arguments - * \a samples and \a current_frame are purely informational. If \a samples - * is greater than \c 0, then \a current_frame will hold the current frame - * number that is being written; otherwise it indicates that the write - * callback is being called to write metadata. - * - * \note - * Unlike when writing to native FLAC, when writing to Ogg FLAC the - * write callback will be called twice when writing each audio - * frame; once for the page header, and once for the page body. - * When writing the page header, the \a samples argument to the - * write callback will be \c 0. - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param buffer An array of encoded data of length \a bytes. - * \param bytes The byte length of \a buffer. - * \param samples The number of samples encoded by \a buffer. - * \c 0 has a special meaning; see above. - * \param current_frame The number of the current frame being encoded. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_init_*(). - * \retval FLAC__StreamEncoderWriteStatus - * The callee's return status. - */ -typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data); - -/** Signature for the seek callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_encoder_init*_stream(). The supplied function will be called - * when the encoder needs to seek the output stream. The encoder will pass - * the absolute byte offset to seek to, 0 meaning the beginning of the stream. - * - * Here is an example of a seek callback for stdio streams: - * \code - * FLAC__StreamEncoderSeekStatus seek_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * if(file == stdin) - * return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED; - * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0) - * return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; - * else - * return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; - * } - * \endcode - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param absolute_byte_offset The offset from the beginning of the stream - * to seek to. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_init_*(). - * \retval FLAC__StreamEncoderSeekStatus - * The callee's return status. - */ -typedef FLAC__StreamEncoderSeekStatus (*FLAC__StreamEncoderSeekCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); - -/** Signature for the tell callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_encoder_init*_stream(). The supplied function will be called - * when the encoder needs to know the current position of the output stream. - * - * \warning - * The callback must return the true current byte offset of the output to - * which the encoder is writing. If you are buffering the output, make - * sure and take this into account. If you are writing directly to a - * FILE* from your write callback, ftell() is sufficient. If you are - * writing directly to a file descriptor from your write callback, you - * can use lseek(fd, SEEK_CUR, 0). The encoder may later seek back to - * these points to rewrite metadata after encoding. - * - * Here is an example of a tell callback for stdio streams: - * \code - * FLAC__StreamEncoderTellStatus tell_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * off_t pos; - * if(file == stdin) - * return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED; - * else if((pos = ftello(file)) < 0) - * return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; - * else { - * *absolute_byte_offset = (FLAC__uint64)pos; - * return FLAC__STREAM_ENCODER_TELL_STATUS_OK; - * } - * } - * \endcode - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param absolute_byte_offset The address at which to store the current - * position of the output. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_init_*(). - * \retval FLAC__StreamEncoderTellStatus - * The callee's return status. - */ -typedef FLAC__StreamEncoderTellStatus (*FLAC__StreamEncoderTellCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); - -/** Signature for the metadata callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_encoder_init*_stream(). The supplied function will be called - * once at the end of encoding with the populated STREAMINFO structure. This - * is so the client can seek back to the beginning of the file and write the - * STREAMINFO block with the correct statistics after encoding (like - * minimum/maximum frame size and total samples). - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param metadata The final populated STREAMINFO block. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_init_*(). - */ -typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data); - -/** Signature for the progress callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE(). - * The supplied function will be called when the encoder has finished - * writing a frame. The \c total_frames_estimate argument to the - * callback will be based on the value from - * FLAC__stream_encoder_set_total_samples_estimate(). - * - * \note In general, FLAC__StreamEncoder functions which change the - * state should not be called on the \a encoder while in the callback. - * - * \param encoder The encoder instance calling the callback. - * \param bytes_written Bytes written so far. - * \param samples_written Samples written so far. - * \param frames_written Frames written so far. - * \param total_frames_estimate The estimate of the total number of - * frames to be written. - * \param client_data The callee's client data set through - * FLAC__stream_encoder_init_*(). - */ -typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data); - - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -/** Create a new stream encoder instance. The instance is created with - * default settings; see the individual FLAC__stream_encoder_set_*() - * functions for each setting's default. - * - * \retval FLAC__StreamEncoder* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void); - -/** Free an encoder instance. Deletes the object pointed to by \a encoder. - * - * \param encoder A pointer to an existing encoder. - * \assert - * \code encoder != NULL \endcode - */ -FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder); - - -/*********************************************************************** - * - * Public class method prototypes - * - ***********************************************************************/ - -/** Set the serial number for the FLAC stream to use in the Ogg container. - * - * \note - * This does not need to be set for native FLAC encoding. - * - * \note - * It is recommended to set a serial number explicitly as the default of '0' - * may collide with other streams. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param serial_number See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long serial_number); - -/** Set the "verify" flag. If \c true, the encoder will verify it's own - * encoded output by feeding it through an internal decoder and comparing - * the original signal against the decoded signal. If a mismatch occurs, - * the process call will return \c false. Note that this will slow the - * encoding process by the extra time required for decoding and comparison. - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value Flag value (see above). - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value); - -/** Set the Subset flag. If \c true, - * the encoder will comply with the Subset and will check the - * settings during FLAC__stream_encoder_init_*() to see if all settings - * comply. If \c false, the settings may take advantage of the full - * range that the format allows. - * - * Make sure you know what it entails before setting this to \c false. - * - * \default \c true - * \param encoder An encoder instance to set. - * \param value Flag value (see above). - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value); - -/** Set the number of channels to be encoded. - * - * \default \c 2 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set the sample resolution of the input to be encoded. - * - * \warning - * Do not feed the encoder data that is wider than the value you - * set here or you will generate an invalid stream. - * - * \default \c 16 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set the sample rate (in Hz) of the input to be encoded. - * - * \default \c 44100 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set the compression level - * - * The compression level is roughly proportional to the amount of effort - * the encoder expends to compress the file. A higher level usually - * means more computation but higher compression. The default level is - * suitable for most applications. - * - * Currently the levels range from \c 0 (fastest, least compression) to - * \c 8 (slowest, most compression). A value larger than \c 8 will be - * treated as \c 8. - * - * This function automatically calls the following other \c _set_ - * functions with appropriate values, so the client does not need to - * unless it specifically wants to override them: - * - FLAC__stream_encoder_set_do_mid_side_stereo() - * - FLAC__stream_encoder_set_loose_mid_side_stereo() - * - FLAC__stream_encoder_set_apodization() - * - FLAC__stream_encoder_set_max_lpc_order() - * - FLAC__stream_encoder_set_qlp_coeff_precision() - * - FLAC__stream_encoder_set_do_qlp_coeff_prec_search() - * - FLAC__stream_encoder_set_do_escape_coding() - * - FLAC__stream_encoder_set_do_exhaustive_model_search() - * - FLAC__stream_encoder_set_min_residual_partition_order() - * - FLAC__stream_encoder_set_max_residual_partition_order() - * - FLAC__stream_encoder_set_rice_parameter_search_dist() - * - * The actual values set for each level are: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
leveldo mid-side stereoloose mid-side stereoapodizationmax lpc orderqlp coeff precisionqlp coeff prec searchescape codingexhaustive model searchmin residual partition ordermax residual partition orderrice parameter search dist
0 false false tukey(0.5) 0 0 false false false 0 3 0
1 true true tukey(0.5) 0 0 false false false 0 3 0
2 true false tukey(0.5) 0 0 false false false 0 3 0
3 false false tukey(0.5) 6 0 false false false 0 4 0
4 true true tukey(0.5) 8 0 false false false 0 4 0
5 true false tukey(0.5) 8 0 false false false 0 5 0
6 true false subdivide_tukey(2) 8 0 false false false 0 6 0
7 true false subdivide_tukey(2) 12 0 false false false 0 6 0
8 true false subdivide_tukey(2) 12 0 false false false 0 6 0
- * - * \default \c 5 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set the blocksize to use while encoding. - * - * The number of samples to use per frame. Use \c 0 to let the encoder - * estimate a blocksize; this is usually best. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set to \c true to enable mid-side encoding on stereo input. The - * number of channels must be 2 for this to have any effect. Set to - * \c false to use only independent channel coding. - * - * \default \c true - * \param encoder An encoder instance to set. - * \param value Flag value (see above). - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value); - -/** Set to \c true to enable adaptive switching between mid-side and - * left-right encoding on stereo input. Set to \c false to use - * exhaustive searching. Setting this to \c true requires - * FLAC__stream_encoder_set_do_mid_side_stereo() to also be set to - * \c true in order to have any effect. - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value Flag value (see above). - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value); - -/** Sets the apodization function(s) the encoder will use when windowing - * audio data for LPC analysis. - * - * The \a specification is a plain ASCII string which specifies exactly - * which functions to use. There may be more than one (up to 32), - * separated by \c ';' characters. Some functions take one or more - * comma-separated arguments in parentheses. - * - * The available functions are \c bartlett, \c bartlett_hann, - * \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop, - * \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall, - * \c rectangle, \c triangle, \c tukey(P), \c partial_tukey(n[/ov[/P]]), - * \c punchout_tukey(n[/ov[/P]]), \c subdivide_tukey(n[/P]), \c welch. - * - * For \c gauss(STDDEV), STDDEV specifies the standard deviation - * (0blocksize / (2 ^ order). - * - * Set both min and max values to \c 0 to force a single context, - * whose Rice parameter is based on the residual signal variance. - * Otherwise, set a min and max order, and the encoder will search - * all orders, using the mean of each context for its Rice parameter, - * and use the best. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set the maximum partition order to search when coding the residual. - * This is used in tandem with - * FLAC__stream_encoder_set_min_residual_partition_order(). - * - * The partition order determines the context size in the residual. - * The context size will be approximately blocksize / (2 ^ order). - * - * Set both min and max values to \c 0 to force a single context, - * whose Rice parameter is based on the residual signal variance. - * Otherwise, set a min and max order, and the encoder will search - * all orders, using the mean of each context for its Rice parameter, - * and use the best. - * - * \default \c 5 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Deprecated. Setting this value has no effect. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, uint32_t value); - -/** Set an estimate of the total samples that will be encoded. - * This is merely an estimate and may be set to \c 0 if unknown. - * This value will be written to the STREAMINFO block before encoding, - * and can remove the need for the caller to rewrite the value later - * if the value is known before encoding. - * - * \default \c 0 - * \param encoder An encoder instance to set. - * \param value See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value); - -/** Set the metadata blocks to be emitted to the stream before encoding. - * A value of \c NULL, \c 0 implies no metadata; otherwise, supply an - * array of pointers to metadata blocks. The array is non-const since - * the encoder may need to change the \a is_last flag inside them, and - * in some cases update seek point offsets. Otherwise, the encoder will - * not modify or free the blocks. It is up to the caller to free the - * metadata blocks after encoding finishes. - * - * \note - * The encoder stores only copies of the pointers in the \a metadata array; - * the metadata blocks themselves must survive at least until after - * FLAC__stream_encoder_finish() returns. Do not free the blocks until then. - * - * \note - * The STREAMINFO block is always written and no STREAMINFO block may - * occur in the supplied array. - * - * \note - * By default the encoder does not create a SEEKTABLE. If one is supplied - * in the \a metadata array, but the client has specified that it does not - * support seeking, then the SEEKTABLE will be written verbatim. However - * by itself this is not very useful as the client will not know the stream - * offsets for the seekpoints ahead of time. In order to get a proper - * seektable the client must support seeking. See next note. - * - * \note - * SEEKTABLE blocks are handled specially. Since you will not know - * the values for the seek point stream offsets, you should pass in - * a SEEKTABLE 'template', that is, a SEEKTABLE object with the - * required sample numbers (or placeholder points), with \c 0 for the - * \a frame_samples and \a stream_offset fields for each point. If the - * client has specified that it supports seeking by providing a seek - * callback to FLAC__stream_encoder_init_stream() or both seek AND read - * callback to FLAC__stream_encoder_init_ogg_stream() (or by using - * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE()), - * then while it is encoding the encoder will fill the stream offsets in - * for you and when encoding is finished, it will seek back and write the - * real values into the SEEKTABLE block in the stream. There are helper - * routines for manipulating seektable template blocks; see metadata.h: - * FLAC__metadata_object_seektable_template_*(). If the client does - * not support seeking, the SEEKTABLE will have inaccurate offsets which - * will slow down or remove the ability to seek in the FLAC stream. - * - * \note - * The encoder instance \b will modify the first \c SEEKTABLE block - * as it transforms the template to a valid seektable while encoding, - * but it is still up to the caller to free all metadata blocks after - * encoding. - * - * \note - * A VORBIS_COMMENT block may be supplied. The vendor string in it - * will be ignored. libFLAC will use it's own vendor string. libFLAC - * will not modify the passed-in VORBIS_COMMENT's vendor string, it - * will simply write it's own into the stream. If no VORBIS_COMMENT - * block is present in the \a metadata array, libFLAC will write an - * empty one, containing only the vendor string. - * - * \note The Ogg FLAC mapping requires that the VORBIS_COMMENT block be - * the second metadata block of the stream. The encoder already supplies - * the STREAMINFO block automatically. If \a metadata does not contain a - * VORBIS_COMMENT block, the encoder will supply that too. Otherwise, if - * \a metadata does contain a VORBIS_COMMENT block and it is not the - * first, the init function will reorder \a metadata by moving the - * VORBIS_COMMENT block to the front; the relative ordering of the other - * blocks will remain as they were. - * - * \note The Ogg FLAC mapping limits the number of metadata blocks per - * stream to \c 65535. If \a num_blocks exceeds this the function will - * return \c false. - * - * \default \c NULL, 0 - * \param encoder An encoder instance to set. - * \param metadata See above. - * \param num_blocks See above. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - * \c false if the encoder is already initialized, or if - * \a num_blocks > 65535 if encoding to Ogg FLAC, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, uint32_t num_blocks); - -/** Set to \c true to make the encoder not output frames which contain - * only constant subframes. This is beneficial for streaming - * applications: very small frames can cause problems with buffering - * as bitrates can drop as low 1kbit/s for CDDA audio encoded within - * subset. The minimum bitrate for a FLAC file encoded with this - * function used is raised to 1bit/sample (i.e. 48kbit/s for 48kHz - * material). - * - * \default \c false - * \param encoder An encoder instance to set. - * \param value Flag value (see above). - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if the encoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_set_limit_min_bitrate(FLAC__StreamEncoder *encoder, FLAC__bool value); - -/** Get the current encoder state. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamEncoderState - * The current encoder state. - */ -FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder); - -/** Get the state of the verify stream decoder. - * Useful when the stream encoder state is - * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamDecoderState - * The verify stream decoder state. - */ -FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder); - -/** Get the current encoder state as a C string. - * This version automatically resolves - * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR by getting the - * verify decoder's state. - * - * \param encoder A encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval const char * - * The encoder state as a C string. Do not modify the contents. - */ -FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder); - -/** Get relevant values about the nature of a verify decoder error. - * Useful when the stream encoder state is - * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. The arguments should - * be addresses in which the stats will be returned, or NULL if value - * is not desired. - * - * \param encoder An encoder instance to query. - * \param absolute_sample The absolute sample number of the mismatch. - * \param frame_number The number of the frame in which the mismatch occurred. - * \param channel The channel in which the mismatch occurred. - * \param sample The number of the sample (relative to the frame) in - * which the mismatch occurred. - * \param expected The expected value for the sample in question. - * \param got The actual value returned by the decoder. - * \assert - * \code encoder != NULL \endcode - */ -FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got); - -/** Get the "verify" flag. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__stream_encoder_set_verify(). - */ -FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder); - -/** Get the Subset flag. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__stream_encoder_set_streamable_subset(). - */ -FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder); - -/** Get the number of input channels being processed. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval uint32_t - * See FLAC__stream_encoder_set_channels(). - */ -FLAC_API uint32_t FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder); - -/** Get the input sample resolution setting. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval uint32_t - * See FLAC__stream_encoder_set_bits_per_sample(). - */ -FLAC_API uint32_t FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder); - -/** Get the input sample rate setting. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval uint32_t - * See FLAC__stream_encoder_set_sample_rate(). - */ -FLAC_API uint32_t FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder); - -/** Get the blocksize setting. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval uint32_t - * See FLAC__stream_encoder_set_blocksize(). - */ -FLAC_API uint32_t FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder); - -/** Get the "mid/side stereo coding" flag. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__stream_encoder_get_do_mid_side_stereo(). - */ -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder); - -/** Get the "adaptive mid/side switching" flag. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__stream_encoder_set_loose_mid_side_stereo(). - */ -FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder); - -/** Get the maximum LPC order setting. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval uint32_t - * See FLAC__stream_encoder_set_max_lpc_order(). - */ -FLAC_API uint32_t FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder); - -/** Get the quantized linear predictor coefficient precision setting. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval uint32_t - * See FLAC__stream_encoder_set_qlp_coeff_precision(). - */ -FLAC_API uint32_t FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder); - -/** Get the qlp coefficient precision search flag. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__stream_encoder_set_do_qlp_coeff_prec_search(). - */ -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder); - -/** Get the "escape coding" flag. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__stream_encoder_set_do_escape_coding(). - */ -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder); - -/** Get the exhaustive model search flag. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__stream_encoder_set_do_exhaustive_model_search(). - */ -FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder); - -/** Get the minimum residual partition order setting. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval uint32_t - * See FLAC__stream_encoder_set_min_residual_partition_order(). - */ -FLAC_API uint32_t FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder); - -/** Get maximum residual partition order setting. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval uint32_t - * See FLAC__stream_encoder_set_max_residual_partition_order(). - */ -FLAC_API uint32_t FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder); - -/** Get the Rice parameter search distance setting. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval uint32_t - * See FLAC__stream_encoder_set_rice_parameter_search_dist(). - */ -FLAC_API uint32_t FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder); - -/** Get the previously set estimate of the total samples to be encoded. - * The encoder merely mimics back the value given to - * FLAC__stream_encoder_set_total_samples_estimate() since it has no - * other way of knowing how many samples the client will encode. - * - * \param encoder An encoder instance to set. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__uint64 - * See FLAC__stream_encoder_get_total_samples_estimate(). - */ -FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder); - -/** Get the "limit_min_bitrate" flag. - * - * \param encoder An encoder instance to query. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * See FLAC__stream_encoder_set_limit_min_bitrate(). - */ -FLAC_API FLAC__bool FLAC__stream_encoder_get_limit_min_bitrate(const FLAC__StreamEncoder *encoder); - -/** Initialize the encoder instance to encode native FLAC streams. - * - * This flavor of initialization sets up the encoder to encode to a - * native FLAC stream. I/O is performed via callbacks to the client. - * For encoding to a plain file via filename or open \c FILE*, - * FLAC__stream_encoder_init_file() and FLAC__stream_encoder_init_FILE() - * provide a simpler interface. - * - * This function should be called after FLAC__stream_encoder_new() and - * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() - * or FLAC__stream_encoder_process_interleaved(). - * initialization succeeded. - * - * The call to FLAC__stream_encoder_init_stream() currently will also - * immediately call the write callback several times, once with the \c fLaC - * signature, and once for each encoded metadata block. - * - * \param encoder An uninitialized encoder instance. - * \param write_callback See FLAC__StreamEncoderWriteCallback. This - * pointer must not be \c NULL. - * \param seek_callback See FLAC__StreamEncoderSeekCallback. This - * pointer may be \c NULL if seeking is not - * supported. The encoder uses seeking to go back - * and write some some stream statistics to the - * STREAMINFO block; this is recommended but not - * necessary to create a valid FLAC stream. If - * \a seek_callback is not \c NULL then a - * \a tell_callback must also be supplied. - * Alternatively, a dummy seek callback that just - * returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the encoder. - * \param tell_callback See FLAC__StreamEncoderTellCallback. This - * pointer may be \c NULL if seeking is not - * supported. If \a seek_callback is \c NULL then - * this argument will be ignored. If - * \a seek_callback is not \c NULL then a - * \a tell_callback must also be supplied. - * Alternatively, a dummy tell callback that just - * returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the encoder. - * \param metadata_callback See FLAC__StreamEncoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. If the client provides a seek callback, - * this function is not necessary as the encoder - * will automatically seek back and update the - * STREAMINFO block. It may also be \c NULL if the - * client does not support seeking, since it will - * have no way of going back to update the - * STREAMINFO. However the client can still supply - * a callback if it would like to know the details - * from the STREAMINFO. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamEncoderInitStatus - * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamEncoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data); - -/** Initialize the encoder instance to encode Ogg FLAC streams. - * - * This flavor of initialization sets up the encoder to encode to a FLAC - * stream in an Ogg container. I/O is performed via callbacks to the - * client. For encoding to a plain file via filename or open \c FILE*, - * FLAC__stream_encoder_init_ogg_file() and FLAC__stream_encoder_init_ogg_FILE() - * provide a simpler interface. - * - * This function should be called after FLAC__stream_encoder_new() and - * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() - * or FLAC__stream_encoder_process_interleaved(). - * initialization succeeded. - * - * The call to FLAC__stream_encoder_init_ogg_stream() currently will also - * immediately call the write callback several times to write the metadata - * packets. - * - * \param encoder An uninitialized encoder instance. - * \param read_callback See FLAC__StreamEncoderReadCallback. This - * pointer must not be \c NULL if \a seek_callback - * is non-NULL since they are both needed to be - * able to write data back to the Ogg FLAC stream - * in the post-encode phase. - * \param write_callback See FLAC__StreamEncoderWriteCallback. This - * pointer must not be \c NULL. - * \param seek_callback See FLAC__StreamEncoderSeekCallback. This - * pointer may be \c NULL if seeking is not - * supported. The encoder uses seeking to go back - * and write some some stream statistics to the - * STREAMINFO block; this is recommended but not - * necessary to create a valid FLAC stream. If - * \a seek_callback is not \c NULL then a - * \a tell_callback must also be supplied. - * Alternatively, a dummy seek callback that just - * returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the encoder. - * \param tell_callback See FLAC__StreamEncoderTellCallback. This - * pointer may be \c NULL if seeking is not - * supported. If \a seek_callback is \c NULL then - * this argument will be ignored. If - * \a seek_callback is not \c NULL then a - * \a tell_callback must also be supplied. - * Alternatively, a dummy tell callback that just - * returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the encoder. - * \param metadata_callback See FLAC__StreamEncoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. If the client provides a seek callback, - * this function is not necessary as the encoder - * will automatically seek back and update the - * STREAMINFO block. It may also be \c NULL if the - * client does not support seeking, since it will - * have no way of going back to update the - * STREAMINFO. However the client can still supply - * a callback if it would like to know the details - * from the STREAMINFO. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamEncoderInitStatus - * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamEncoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderReadCallback read_callback, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data); - -/** Initialize the encoder instance to encode native FLAC files. - * - * This flavor of initialization sets up the encoder to encode to a - * plain native FLAC file. For non-stdio streams, you must use - * FLAC__stream_encoder_init_stream() and provide callbacks for the I/O. - * - * This function should be called after FLAC__stream_encoder_new() and - * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() - * or FLAC__stream_encoder_process_interleaved(). - * initialization succeeded. - * - * \param encoder An uninitialized encoder instance. - * \param file An open file. The file should have been opened - * with mode \c "w+b" and rewound. The file - * becomes owned by the encoder and should not be - * manipulated by the client while encoding. - * Unless \a file is \c stdout, it will be closed - * when FLAC__stream_encoder_finish() is called. - * Note however that a proper SEEKTABLE cannot be - * created when encoding to \c stdout since it is - * not seekable. - * \param progress_callback See FLAC__StreamEncoderProgressCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code encoder != NULL \endcode - * \code file != NULL \endcode - * \retval FLAC__StreamEncoderInitStatus - * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamEncoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); - -/** Initialize the encoder instance to encode Ogg FLAC files. - * - * This flavor of initialization sets up the encoder to encode to a - * plain Ogg FLAC file. For non-stdio streams, you must use - * FLAC__stream_encoder_init_ogg_stream() and provide callbacks for the I/O. - * - * This function should be called after FLAC__stream_encoder_new() and - * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() - * or FLAC__stream_encoder_process_interleaved(). - * initialization succeeded. - * - * \param encoder An uninitialized encoder instance. - * \param file An open file. The file should have been opened - * with mode \c "w+b" and rewound. The file - * becomes owned by the encoder and should not be - * manipulated by the client while encoding. - * Unless \a file is \c stdout, it will be closed - * when FLAC__stream_encoder_finish() is called. - * Note however that a proper SEEKTABLE cannot be - * created when encoding to \c stdout since it is - * not seekable. - * \param progress_callback See FLAC__StreamEncoderProgressCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code encoder != NULL \endcode - * \code file != NULL \endcode - * \retval FLAC__StreamEncoderInitStatus - * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamEncoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); - -/** Initialize the encoder instance to encode native FLAC files. - * - * This flavor of initialization sets up the encoder to encode to a plain - * FLAC file. If POSIX fopen() semantics are not sufficient you must use - * FLAC__stream_encoder_init_FILE(), or FLAC__stream_encoder_init_stream() - * and provide callbacks for the I/O. - * - * On Windows, filename must be a UTF-8 encoded filename, which libFLAC - * internally translates to an appropriate representation to use with - * _wfopen. On all other systems, filename is passed to fopen without - * any translation. - * - * This function should be called after FLAC__stream_encoder_new() and - * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() - * or FLAC__stream_encoder_process_interleaved(). - * initialization succeeded. - * - * \param encoder An uninitialized encoder instance. - * \param filename The name of the file to encode to. The file will - * be opened with fopen(). Use \c NULL to encode to - * \c stdout. Note however that a proper SEEKTABLE - * cannot be created when encoding to \c stdout since - * it is not seekable. - * \param progress_callback See FLAC__StreamEncoderProgressCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamEncoderInitStatus - * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamEncoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); - -/** Initialize the encoder instance to encode Ogg FLAC files. - * - * This flavor of initialization sets up the encoder to encode to a plain - * Ogg FLAC file. If POSIX fopen() semantics are not sufficient, you must use - * FLAC__stream_encoder_init_ogg_FILE(), or FLAC__stream_encoder_init_ogg_stream() - * and provide callbacks for the I/O. - * - * On Windows, filename must be a UTF-8 encoded filename, which libFLAC - * internally translates to an appropriate representation to use with - * _wfopen. On all other systems, filename is passed to fopen without - * any translation. - * - * This function should be called after FLAC__stream_encoder_new() and - * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process() - * or FLAC__stream_encoder_process_interleaved(). - * initialization succeeded. - * - * \param encoder An uninitialized encoder instance. - * \param filename The name of the file to encode to. The file will - * be opened with fopen(). Use \c NULL to encode to - * \c stdout. Note however that a proper SEEKTABLE - * cannot be created when encoding to \c stdout since - * it is not seekable. - * \param progress_callback See FLAC__StreamEncoderProgressCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__StreamEncoderInitStatus - * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamEncoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data); - -/** Finish the encoding process. - * Flushes the encoding buffer, releases resources, resets the encoder - * settings to their defaults, and returns the encoder state to - * FLAC__STREAM_ENCODER_UNINITIALIZED. Note that this can generate - * one or more write callbacks before returning, and will generate - * a metadata callback. - * - * Note that in the course of processing the last frame, errors can - * occur, so the caller should be sure to check the return value to - * ensure the file was encoded properly. - * - * In the event of a prematurely-terminated encode, it is not strictly - * necessary to call this immediately before FLAC__stream_encoder_delete() - * but it is good practice to match every FLAC__stream_encoder_init_*() - * with a FLAC__stream_encoder_finish(). - * - * \param encoder An uninitialized encoder instance. - * \assert - * \code encoder != NULL \endcode - * \retval FLAC__bool - * \c false if an error occurred processing the last frame; or if verify - * mode is set (see FLAC__stream_encoder_set_verify()), there was a - * verify mismatch; else \c true. If \c false, caller should check the - * state with FLAC__stream_encoder_get_state() for more information - * about the error. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder); - -/** Submit data for encoding. - * This version allows you to supply the input data via an array of - * pointers, each pointer pointing to an array of \a samples samples - * representing one channel. The samples need not be block-aligned, - * but each channel should have the same number of samples. Each sample - * should be a signed integer, right-justified to the resolution set by - * FLAC__stream_encoder_set_bits_per_sample(). For example, if the - * resolution is 16 bits per sample, the samples should all be in the - * range [-32768,32767]. - * - * For applications where channel order is important, channels must - * follow the order as described in the - * frame header. - * - * \param encoder An initialized encoder instance in the OK state. - * \param buffer An array of pointers to each channel's signal. - * \param samples The number of samples in one channel. - * \assert - * \code encoder != NULL \endcode - * \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode - * \retval FLAC__bool - * \c true if successful, else \c false; in this case, check the - * encoder state with FLAC__stream_encoder_get_state() to see what - * went wrong. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], uint32_t samples); - -/** Submit data for encoding. - * This version allows you to supply the input data where the channels - * are interleaved into a single array (i.e. channel0_sample0, - * channel1_sample0, ... , channelN_sample0, channel0_sample1, ...). - * The samples need not be block-aligned but they must be - * sample-aligned, i.e. the first value should be channel0_sample0 - * and the last value channelN_sampleM. Each sample should be a signed - * integer, right-justified to the resolution set by - * FLAC__stream_encoder_set_bits_per_sample(). For example, if the - * resolution is 16 bits per sample, the samples should all be in the - * range [-32768,32767]. - * - * For applications where channel order is important, channels must - * follow the order as described in the - * frame header. - * - * \param encoder An initialized encoder instance in the OK state. - * \param buffer An array of channel-interleaved data (see above). - * \param samples The number of samples in one channel, the same as for - * FLAC__stream_encoder_process(). For example, if - * encoding two channels, \c 1000 \a samples corresponds - * to a \a buffer of 2000 values. - * \assert - * \code encoder != NULL \endcode - * \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode - * \retval FLAC__bool - * \c true if successful, else \c false; in this case, check the - * encoder state with FLAC__stream_encoder_get_state() to see what - * went wrong. - */ -FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], uint32_t samples); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/code/dep_codecs/include/fdk-aac/FDK_audio.h b/code/dep_codecs/include/fdk-aac/FDK_audio.h deleted file mode 100755 index 0e440c9e..00000000 --- a/code/dep_codecs/include/fdk-aac/FDK_audio.h +++ /dev/null @@ -1,813 +0,0 @@ -/* ----------------------------------------------------------------------------- -Software License for The Fraunhofer FDK AAC Codec Library for Android - -© Copyright 1995 - 2018 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 ------------------------------------------------------------------------------ */ - -/************************* System integration library ************************** - - Author(s): Manuel Jander - - Description: - -*******************************************************************************/ - -/** \file FDK_audio.h - * \brief Global audio struct and constant definitions. - */ - -#ifndef FDK_AUDIO_H -#define FDK_AUDIO_H - -#include "machine_type.h" -#include "genericStds.h" -#include "syslib_channelMapDescr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * File format identifiers. - */ -typedef enum { - FF_UNKNOWN = -1, /**< Unknown format. */ - FF_RAW = 0, /**< No container, bit stream data conveyed "as is". */ - - FF_MP4_3GPP = 3, /**< 3GPP file format. */ - FF_MP4_MP4F = 4, /**< MPEG-4 File format. */ - - FF_RAWPACKETS = 5 /**< Proprietary raw packet file. */ - -} FILE_FORMAT; - -/** - * Transport type identifiers. - */ -typedef enum { - TT_UNKNOWN = -1, /**< Unknown format. */ - TT_MP4_RAW = 0, /**< "as is" access units (packet based since there is - obviously no sync layer) */ - TT_MP4_ADIF = 1, /**< ADIF bitstream format. */ - TT_MP4_ADTS = 2, /**< ADTS bitstream format. */ - - TT_MP4_LATM_MCP1 = 6, /**< Audio Mux Elements with muxConfigPresent = 1 */ - TT_MP4_LATM_MCP0 = 7, /**< Audio Mux Elements with muxConfigPresent = 0, out - of band StreamMuxConfig */ - - TT_MP4_LOAS = 10, /**< Audio Sync Stream. */ - - TT_DRM = 12 /**< Digital Radio Mondial (DRM30/DRM+) bitstream format. */ - -} TRANSPORT_TYPE; - -#define TT_IS_PACKET(x) \ - (((x) == TT_MP4_RAW) || ((x) == TT_DRM) || ((x) == TT_MP4_LATM_MCP0) || \ - ((x) == TT_MP4_LATM_MCP1)) - -/** - * Audio Object Type definitions. - */ -typedef enum { - AOT_NONE = -1, - AOT_NULL_OBJECT = 0, - AOT_AAC_MAIN = 1, /**< Main profile */ - AOT_AAC_LC = 2, /**< Low Complexity object */ - AOT_AAC_SSR = 3, - AOT_AAC_LTP = 4, - AOT_SBR = 5, - AOT_AAC_SCAL = 6, - AOT_TWIN_VQ = 7, - AOT_CELP = 8, - AOT_HVXC = 9, - AOT_RSVD_10 = 10, /**< (reserved) */ - AOT_RSVD_11 = 11, /**< (reserved) */ - AOT_TTSI = 12, /**< TTSI Object */ - AOT_MAIN_SYNTH = 13, /**< Main Synthetic object */ - AOT_WAV_TAB_SYNTH = 14, /**< Wavetable Synthesis object */ - AOT_GEN_MIDI = 15, /**< General MIDI object */ - AOT_ALG_SYNTH_AUD_FX = 16, /**< Algorithmic Synthesis and Audio FX object */ - AOT_ER_AAC_LC = 17, /**< Error Resilient(ER) AAC Low Complexity */ - AOT_RSVD_18 = 18, /**< (reserved) */ - AOT_ER_AAC_LTP = 19, /**< Error Resilient(ER) AAC LTP object */ - AOT_ER_AAC_SCAL = 20, /**< Error Resilient(ER) AAC Scalable object */ - AOT_ER_TWIN_VQ = 21, /**< Error Resilient(ER) TwinVQ object */ - AOT_ER_BSAC = 22, /**< Error Resilient(ER) BSAC object */ - AOT_ER_AAC_LD = 23, /**< Error Resilient(ER) AAC LowDelay object */ - AOT_ER_CELP = 24, /**< Error Resilient(ER) CELP object */ - AOT_ER_HVXC = 25, /**< Error Resilient(ER) HVXC object */ - AOT_ER_HILN = 26, /**< Error Resilient(ER) HILN object */ - AOT_ER_PARA = 27, /**< Error Resilient(ER) Parametric object */ - AOT_RSVD_28 = 28, /**< might become SSC */ - AOT_PS = 29, /**< PS, Parametric Stereo (includes SBR) */ - AOT_MPEGS = 30, /**< MPEG Surround */ - - AOT_ESCAPE = 31, /**< Signal AOT uses more than 5 bits */ - - AOT_MP3ONMP4_L1 = 32, /**< MPEG-Layer1 in mp4 */ - AOT_MP3ONMP4_L2 = 33, /**< MPEG-Layer2 in mp4 */ - AOT_MP3ONMP4_L3 = 34, /**< MPEG-Layer3 in mp4 */ - AOT_RSVD_35 = 35, /**< might become DST */ - AOT_RSVD_36 = 36, /**< might become ALS */ - AOT_AAC_SLS = 37, /**< AAC + SLS */ - AOT_SLS = 38, /**< SLS */ - AOT_ER_AAC_ELD = 39, /**< AAC Enhanced Low Delay */ - - AOT_USAC = 42, /**< USAC */ - AOT_SAOC = 43, /**< SAOC */ - AOT_LD_MPEGS = 44, /**< Low Delay MPEG Surround */ - - /* Pseudo AOTs */ - AOT_MP2_AAC_LC = 129, /**< Virtual AOT MP2 Low Complexity profile */ - AOT_MP2_SBR = 132, /**< Virtual AOT MP2 Low Complexity Profile with SBR */ - - AOT_DRM_AAC = 143, /**< Virtual AOT for DRM (ER-AAC-SCAL without SBR) */ - AOT_DRM_SBR = 144, /**< Virtual AOT for DRM (ER-AAC-SCAL with SBR) */ - AOT_DRM_MPEG_PS = - 145, /**< Virtual AOT for DRM (ER-AAC-SCAL with SBR and MPEG-PS) */ - AOT_DRM_SURROUND = - 146, /**< Virtual AOT for DRM Surround (ER-AAC-SCAL (+SBR) +MPS) */ - AOT_DRM_USAC = 147 /**< Virtual AOT for DRM with USAC */ - -} AUDIO_OBJECT_TYPE; - -#define CAN_DO_PS(aot) \ - ((aot) == AOT_AAC_LC || (aot) == AOT_SBR || (aot) == AOT_PS || \ - (aot) == AOT_ER_BSAC || (aot) == AOT_DRM_AAC) - -#define IS_USAC(aot) ((aot) == AOT_USAC) - -#define IS_LOWDELAY(aot) ((aot) == AOT_ER_AAC_LD || (aot) == AOT_ER_AAC_ELD) - -/** Channel Mode ( 1-7 equals MPEG channel configurations, others are - * arbitrary). */ -typedef enum { - MODE_INVALID = -1, - MODE_UNKNOWN = 0, - MODE_1 = 1, /**< C */ - MODE_2 = 2, /**< L+R */ - MODE_1_2 = 3, /**< C, L+R */ - MODE_1_2_1 = 4, /**< C, L+R, Rear */ - MODE_1_2_2 = 5, /**< C, L+R, LS+RS */ - MODE_1_2_2_1 = 6, /**< C, L+R, LS+RS, LFE */ - MODE_1_2_2_2_1 = 7, /**< C, LC+RC, L+R, LS+RS, LFE */ - - MODE_6_1 = 11, /**< C, L+R, LS+RS, Crear, LFE */ - MODE_7_1_BACK = 12, /**< C, L+R, LS+RS, Lrear+Rrear, LFE */ - MODE_7_1_TOP_FRONT = 14, /**< C, L+R, LS+RS, LFE, Ltop+Rtop */ - - MODE_7_1_REAR_SURROUND = 33, /**< C, L+R, LS+RS, Lrear+Rrear, LFE */ - MODE_7_1_FRONT_CENTER = 34, /**< C, LC+RC, L+R, LS+RS, LFE */ - - MODE_212 = 128 /**< 212 configuration, used in ELDv2 */ - -} CHANNEL_MODE; - -/** - * Speaker description tags. - * Do not change the enumeration values unless it keeps the following - * segmentation: - * - Bit 0-3: Horizontal postion (0: none, 1: front, 2: side, 3: back, 4: lfe) - * - Bit 4-7: Vertical position (0: normal, 1: top, 2: bottom) - */ -typedef enum { - ACT_NONE = 0x00, - ACT_FRONT = 0x01, /*!< Front speaker position (at normal height) */ - ACT_SIDE = 0x02, /*!< Side speaker position (at normal height) */ - ACT_BACK = 0x03, /*!< Back speaker position (at normal height) */ - ACT_LFE = 0x04, /*!< Low frequency effect speaker postion (front) */ - - ACT_TOP = - 0x10, /*!< Top speaker area (for combination with speaker positions) */ - ACT_FRONT_TOP = 0x11, /*!< Top front speaker = (ACT_FRONT|ACT_TOP) */ - ACT_SIDE_TOP = 0x12, /*!< Top side speaker = (ACT_SIDE |ACT_TOP) */ - ACT_BACK_TOP = 0x13, /*!< Top back speaker = (ACT_BACK |ACT_TOP) */ - - ACT_BOTTOM = - 0x20, /*!< Bottom speaker area (for combination with speaker positions) */ - ACT_FRONT_BOTTOM = 0x21, /*!< Bottom front speaker = (ACT_FRONT|ACT_BOTTOM) */ - ACT_SIDE_BOTTOM = 0x22, /*!< Bottom side speaker = (ACT_SIDE |ACT_BOTTOM) */ - ACT_BACK_BOTTOM = 0x23 /*!< Bottom back speaker = (ACT_BACK |ACT_BOTTOM) */ - -} AUDIO_CHANNEL_TYPE; - -typedef enum { - SIG_UNKNOWN = -1, - SIG_IMPLICIT = 0, - SIG_EXPLICIT_BW_COMPATIBLE = 1, - SIG_EXPLICIT_HIERARCHICAL = 2 - -} SBR_PS_SIGNALING; - -/** - * Audio Codec flags. - */ -#define AC_ER_VCB11 \ - 0x000001 /*!< aacSectionDataResilienceFlag flag (from ASC): 1 means use \ - virtual codebooks */ -#define AC_ER_RVLC \ - 0x000002 /*!< aacSpectralDataResilienceFlag flag (from ASC): 1 means use \ - huffman codeword reordering */ -#define AC_ER_HCR \ - 0x000004 /*!< aacSectionDataResilienceFlag flag (from ASC): 1 means use \ - virtual codebooks */ -#define AC_SCALABLE 0x000008 /*!< AAC Scalable*/ -#define AC_ELD 0x000010 /*!< AAC-ELD */ -#define AC_LD 0x000020 /*!< AAC-LD */ -#define AC_ER 0x000040 /*!< ER syntax */ -#define AC_BSAC 0x000080 /*!< BSAC */ -#define AC_USAC 0x000100 /*!< USAC */ -#define AC_RSV603DA 0x000200 /*!< RSVD60 3D audio */ -#define AC_HDAAC 0x000400 /*!< HD-AAC */ -#define AC_RSVD50 0x004000 /*!< Rsvd50 */ -#define AC_SBR_PRESENT 0x008000 /*!< SBR present flag (from ASC) */ -#define AC_SBRCRC \ - 0x010000 /*!< SBR CRC present flag. Only relevant for AAC-ELD for now. */ -#define AC_PS_PRESENT 0x020000 /*!< PS present flag (from ASC or implicit) */ -#define AC_MPS_PRESENT \ - 0x040000 /*!< MPS present flag (from ASC or implicit) \ - */ -#define AC_DRM 0x080000 /*!< DRM bit stream syntax */ -#define AC_INDEP 0x100000 /*!< Independency flag */ -#define AC_MPEGD_RES 0x200000 /*!< MPEG-D residual individual channel data. */ -#define AC_SAOC_PRESENT 0x400000 /*!< SAOC Present Flag */ -#define AC_DAB 0x800000 /*!< DAB bit stream syntax */ -#define AC_ELD_DOWNSCALE 0x1000000 /*!< ELD Downscaled playout */ -#define AC_LD_MPS 0x2000000 /*!< Low Delay MPS. */ -#define AC_DRC_PRESENT \ - 0x4000000 /*!< Dynamic Range Control (DRC) data found. \ - */ -#define AC_USAC_SCFGI3 \ - 0x8000000 /*!< USAC flag: If stereoConfigIndex is 3 the flag is set. */ -/** - * Audio Codec flags (reconfiguration). - */ -#define AC_CM_DET_CFG_CHANGE \ - 0x000001 /*!< Config mode signalizes the callback to work in config change \ - detection mode */ -#define AC_CM_ALLOC_MEM \ - 0x000002 /*!< Config mode signalizes the callback to work in memory \ - allocation mode */ - -/** - * Audio Codec flags (element specific). - */ -#define AC_EL_USAC_TW 0x000001 /*!< USAC time warped filter bank is active */ -#define AC_EL_USAC_NOISE 0x000002 /*!< USAC noise filling is active */ -#define AC_EL_USAC_ITES 0x000004 /*!< USAC SBR inter-TES tool is active */ -#define AC_EL_USAC_PVC \ - 0x000008 /*!< USAC SBR predictive vector coding tool is active */ -#define AC_EL_USAC_MPS212 0x000010 /*!< USAC MPS212 tool is active */ -#define AC_EL_USAC_LFE 0x000020 /*!< USAC element is LFE */ -#define AC_EL_USAC_CP_POSSIBLE \ - 0x000040 /*!< USAC may use Complex Stereo Prediction in this channel element \ - */ -#define AC_EL_ENHANCED_NOISE 0x000080 /*!< Enhanced noise filling*/ -#define AC_EL_IGF_AFTER_TNS 0x000100 /*!< IGF after TNS */ -#define AC_EL_IGF_INDEP_TILING 0x000200 /*!< IGF independent tiling */ -#define AC_EL_IGF_USE_ENF 0x000400 /*!< IGF use enhanced noise filling */ -#define AC_EL_FULLBANDLPD 0x000800 /*!< enable fullband LPD tools */ -#define AC_EL_LPDSTEREOIDX 0x001000 /*!< LPD-stereo-tool stereo index */ -#define AC_EL_LFE 0x002000 /*!< The element is of type LFE. */ - -/* CODER_CONFIG::flags */ -#define CC_MPEG_ID 0x00100000 -#define CC_IS_BASELAYER 0x00200000 -#define CC_PROTECTION 0x00400000 -#define CC_SBR 0x00800000 -#define CC_SBRCRC 0x00010000 -#define CC_SAC 0x00020000 -#define CC_RVLC 0x01000000 -#define CC_VCB11 0x02000000 -#define CC_HCR 0x04000000 -#define CC_PSEUDO_SURROUND 0x08000000 -#define CC_USAC_NOISE 0x10000000 -#define CC_USAC_TW 0x20000000 -#define CC_USAC_HBE 0x40000000 - -/** Generic audio coder configuration structure. */ -typedef struct { - AUDIO_OBJECT_TYPE aot; /**< Audio Object Type (AOT). */ - AUDIO_OBJECT_TYPE extAOT; /**< Extension Audio Object Type (SBR). */ - CHANNEL_MODE channelMode; /**< Channel mode. */ - UCHAR channelConfigZero; /**< Use channel config zero + pce although a - standard channel config could be signaled. */ - INT samplingRate; /**< Sampling rate. */ - INT extSamplingRate; /**< Extended samplerate (SBR). */ - INT downscaleSamplingRate; /**< Downscale sampling rate (ELD downscaled mode) - */ - INT bitRate; /**< Average bitrate. */ - int samplesPerFrame; /**< Number of PCM samples per codec frame and audio - channel. */ - int noChannels; /**< Number of audio channels. */ - int bitsFrame; - int nSubFrames; /**< Amount of encoder subframes. 1 means no subframing. */ - int BSACnumOfSubFrame; /**< The number of the sub-frames which are grouped and - transmitted in a super-frame (BSAC). */ - int BSAClayerLength; /**< The average length of the large-step layers in bytes - (BSAC). */ - UINT flags; /**< flags */ - UCHAR matrixMixdownA; /**< Matrix mixdown index to put into PCE. Default value - 0 means no mixdown coefficient, valid values are 1-4 - which correspond to matrix_mixdown_idx 0-3. */ - UCHAR headerPeriod; /**< Frame period for sending in band configuration - buffers in the transport layer. */ - - UCHAR stereoConfigIndex; /**< USAC MPS stereo mode */ - UCHAR sbrMode; /**< USAC SBR mode */ - SBR_PS_SIGNALING sbrSignaling; /**< 0: implicit signaling, 1: backwards - compatible explicit signaling, 2: - hierarcical explicit signaling */ - - UCHAR rawConfig[64]; /**< raw codec specific config as bit stream */ - int rawConfigBits; /**< Size of rawConfig in bits */ - - UCHAR sbrPresent; - UCHAR psPresent; -} CODER_CONFIG; - -#define USAC_ID_BIT 16 /** USAC element IDs start at USAC_ID_BIT */ - -/** MP4 Element IDs. */ -typedef enum { - /* mp4 element IDs */ - ID_NONE = -1, /**< Invalid Element helper ID. */ - ID_SCE = 0, /**< Single Channel Element. */ - ID_CPE = 1, /**< Channel Pair Element. */ - ID_CCE = 2, /**< Coupling Channel Element. */ - ID_LFE = 3, /**< LFE Channel Element. */ - ID_DSE = 4, /**< Currently one Data Stream Element for ancillary data is - supported. */ - ID_PCE = 5, /**< Program Config Element. */ - ID_FIL = 6, /**< Fill Element. */ - ID_END = 7, /**< Arnie (End Element = Terminator). */ - ID_EXT = 8, /**< Extension Payload (ER only). */ - ID_SCAL = 9, /**< AAC scalable element (ER only). */ - /* USAC element IDs */ - ID_USAC_SCE = 0 + USAC_ID_BIT, /**< Single Channel Element. */ - ID_USAC_CPE = 1 + USAC_ID_BIT, /**< Channel Pair Element. */ - ID_USAC_LFE = 2 + USAC_ID_BIT, /**< LFE Channel Element. */ - ID_USAC_EXT = 3 + USAC_ID_BIT, /**< Extension Element. */ - ID_USAC_END = 4 + USAC_ID_BIT, /**< Arnie (End Element = Terminator). */ - ID_LAST -} MP4_ELEMENT_ID; - -/* usacConfigExtType q.v. ISO/IEC DIS 23008-3 Table 52 and ISO/IEC FDIS - * 23003-3:2011(E) Table 74*/ -typedef enum { - /* USAC and RSVD60 3DA */ - ID_CONFIG_EXT_FILL = 0, - /* RSVD60 3DA */ - ID_CONFIG_EXT_DOWNMIX = 1, - ID_CONFIG_EXT_LOUDNESS_INFO = 2, - ID_CONFIG_EXT_AUDIOSCENE_INFO = 3, - ID_CONFIG_EXT_HOA_MATRIX = 4, - ID_CONFIG_EXT_SIG_GROUP_INFO = 6 - /* 5-127 => reserved for ISO use */ - /* > 128 => reserved for use outside of ISO scope */ -} CONFIG_EXT_ID; - -#define IS_CHANNEL_ELEMENT(elementId) \ - ((elementId) == ID_SCE || (elementId) == ID_CPE || (elementId) == ID_LFE || \ - (elementId) == ID_USAC_SCE || (elementId) == ID_USAC_CPE || \ - (elementId) == ID_USAC_LFE) - -#define IS_MP4_CHANNEL_ELEMENT(elementId) \ - ((elementId) == ID_SCE || (elementId) == ID_CPE || (elementId) == ID_LFE) - -#define EXT_ID_BITS 4 /**< Size in bits of extension payload type tags. */ - -/** Extension payload types. */ -typedef enum { - EXT_FIL = 0x00, - EXT_FILL_DATA = 0x01, - EXT_DATA_ELEMENT = 0x02, - EXT_DATA_LENGTH = 0x03, - EXT_UNI_DRC = 0x04, - EXT_LDSAC_DATA = 0x09, - EXT_SAOC_DATA = 0x0a, - EXT_DYNAMIC_RANGE = 0x0b, - EXT_SAC_DATA = 0x0c, - EXT_SBR_DATA = 0x0d, - EXT_SBR_DATA_CRC = 0x0e -} EXT_PAYLOAD_TYPE; - -#define IS_USAC_CHANNEL_ELEMENT(elementId) \ - ((elementId) == ID_USAC_SCE || (elementId) == ID_USAC_CPE || \ - (elementId) == ID_USAC_LFE) - -/** MPEG-D USAC & RSVD60 3D audio Extension Element Types. */ -typedef enum { - /* usac */ - ID_EXT_ELE_FILL = 0x00, - ID_EXT_ELE_MPEGS = 0x01, - ID_EXT_ELE_SAOC = 0x02, - ID_EXT_ELE_AUDIOPREROLL = 0x03, - ID_EXT_ELE_UNI_DRC = 0x04, - /* rsv603da */ - ID_EXT_ELE_OBJ_METADATA = 0x05, - ID_EXT_ELE_SAOC_3D = 0x06, - ID_EXT_ELE_HOA = 0x07, - ID_EXT_ELE_FMT_CNVRTR = 0x08, - ID_EXT_ELE_MCT = 0x09, - ID_EXT_ELE_ENHANCED_OBJ_METADATA = 0x0d, - /* reserved for use outside of ISO scope */ - ID_EXT_ELE_VR_METADATA = 0x81, - ID_EXT_ELE_UNKNOWN = 0xFF -} USAC_EXT_ELEMENT_TYPE; - -/** - * Proprietary raw packet file configuration data type identifier. - */ -typedef enum { - TC_NOTHING = 0, /* No configuration available -> in-band configuration. */ - TC_RAW_ADTS = 2, /* Transfer type is ADTS. */ - TC_RAW_LATM_MCP1 = 6, /* Transfer type is LATM with SMC present. */ - TC_RAW_SDC = 21 /* Configuration data field is Drm SDC. */ - -} TP_CONFIG_TYPE; - -/* - * ############################################################################################## - * Library identification and error handling - * ############################################################################################## - */ -/* \cond */ - -typedef enum { - FDK_NONE = 0, - FDK_TOOLS = 1, - FDK_SYSLIB = 2, - FDK_AACDEC = 3, - FDK_AACENC = 4, - FDK_SBRDEC = 5, - FDK_SBRENC = 6, - FDK_TPDEC = 7, - FDK_TPENC = 8, - FDK_MPSDEC = 9, - FDK_MPEGFILEREAD = 10, - FDK_MPEGFILEWRITE = 11, - FDK_PCMDMX = 31, - FDK_MPSENC = 34, - FDK_TDLIMIT = 35, - FDK_UNIDRCDEC = 38, - - FDK_MODULE_LAST - -} FDK_MODULE_ID; - -/* AAC capability flags */ -#define CAPF_AAC_LC 0x00000001 /**< Support flag for AAC Low Complexity. */ -#define CAPF_ER_AAC_LD \ - 0x00000002 /**< Support flag for AAC Low Delay with Error Resilience tools. \ - */ -#define CAPF_ER_AAC_SCAL 0x00000004 /**< Support flag for AAC Scalable. */ -#define CAPF_ER_AAC_LC \ - 0x00000008 /**< Support flag for AAC Low Complexity with Error Resilience \ - tools. */ -#define CAPF_AAC_480 \ - 0x00000010 /**< Support flag for AAC with 480 framelength. */ -#define CAPF_AAC_512 \ - 0x00000020 /**< Support flag for AAC with 512 framelength. */ -#define CAPF_AAC_960 \ - 0x00000040 /**< Support flag for AAC with 960 framelength. */ -#define CAPF_AAC_1024 \ - 0x00000080 /**< Support flag for AAC with 1024 framelength. */ -#define CAPF_AAC_HCR \ - 0x00000100 /**< Support flag for AAC with Huffman Codeword Reordering. */ -#define CAPF_AAC_VCB11 \ - 0x00000200 /**< Support flag for AAC Virtual Codebook 11. */ -#define CAPF_AAC_RVLC \ - 0x00000400 /**< Support flag for AAC Reversible Variable Length Coding. */ -#define CAPF_AAC_MPEG4 0x00000800 /**< Support flag for MPEG file format. */ -#define CAPF_AAC_DRC \ - 0x00001000 /**< Support flag for AAC Dynamic Range Control. */ -#define CAPF_AAC_CONCEALMENT \ - 0x00002000 /**< Support flag for AAC concealment. */ -#define CAPF_AAC_DRM_BSFORMAT \ - 0x00004000 /**< Support flag for AAC DRM bistream format. */ -#define CAPF_ER_AAC_ELD \ - 0x00008000 /**< Support flag for AAC Enhanced Low Delay with Error \ - Resilience tools. */ -#define CAPF_ER_AAC_BSAC \ - 0x00010000 /**< Support flag for AAC BSAC. */ -#define CAPF_AAC_ELD_DOWNSCALE \ - 0x00040000 /**< Support flag for AAC-ELD Downscaling */ -#define CAPF_AAC_USAC_LP \ - 0x00100000 /**< Support flag for USAC low power mode. */ -#define CAPF_AAC_USAC \ - 0x00200000 /**< Support flag for Unified Speech and Audio Coding (USAC). */ -#define CAPF_ER_AAC_ELDV2 \ - 0x00800000 /**< Support flag for AAC Enhanced Low Delay with MPS 212. */ -#define CAPF_AAC_UNIDRC \ - 0x01000000 /**< Support flag for MPEG-D Dynamic Range Control (uniDrc). */ - -/* Transport capability flags */ -#define CAPF_ADTS \ - 0x00000001 /**< Support flag for ADTS transport format. */ -#define CAPF_ADIF \ - 0x00000002 /**< Support flag for ADIF transport format. */ -#define CAPF_LATM \ - 0x00000004 /**< Support flag for LATM transport format. */ -#define CAPF_LOAS \ - 0x00000008 /**< Support flag for LOAS transport format. */ -#define CAPF_RAWPACKETS \ - 0x00000010 /**< Support flag for RAW PACKETS transport format. */ -#define CAPF_DRM \ - 0x00000020 /**< Support flag for DRM/DRM+ transport format. */ -#define CAPF_RSVD50 \ - 0x00000040 /**< Support flag for RSVD50 transport format */ - -/* SBR capability flags */ -#define CAPF_SBR_LP \ - 0x00000001 /**< Support flag for SBR Low Power mode. */ -#define CAPF_SBR_HQ \ - 0x00000002 /**< Support flag for SBR High Quality mode. */ -#define CAPF_SBR_DRM_BS \ - 0x00000004 /**< Support flag for */ -#define CAPF_SBR_CONCEALMENT \ - 0x00000008 /**< Support flag for SBR concealment. */ -#define CAPF_SBR_DRC \ - 0x00000010 /**< Support flag for SBR Dynamic Range Control. */ -#define CAPF_SBR_PS_MPEG \ - 0x00000020 /**< Support flag for MPEG Parametric Stereo. */ -#define CAPF_SBR_PS_DRM \ - 0x00000040 /**< Support flag for DRM Parametric Stereo. */ -#define CAPF_SBR_ELD_DOWNSCALE \ - 0x00000080 /**< Support flag for ELD reduced delay mode */ -#define CAPF_SBR_HBEHQ \ - 0x00000100 /**< Support flag for HQ HBE */ - -/* PCM utils capability flags */ -#define CAPF_DMX_BLIND \ - 0x00000001 /**< Support flag for blind downmixing. */ -#define CAPF_DMX_PCE \ - 0x00000002 /**< Support flag for guided downmix with data from MPEG-2/4 \ - Program Config Elements (PCE). */ -#define CAPF_DMX_ARIB \ - 0x00000004 /**< Support flag for PCE guided downmix with slightly different \ - equations and levels to fulfill ARIB standard. */ -#define CAPF_DMX_DVB \ - 0x00000008 /**< Support flag for guided downmix with data from DVB ancillary \ - data fields. */ -#define CAPF_DMX_CH_EXP \ - 0x00000010 /**< Support flag for simple upmixing by dublicating channels or \ - adding zero channels. */ -#define CAPF_DMX_6_CH \ - 0x00000020 /**< Support flag for 5.1 channel configuration (input and \ - output). */ -#define CAPF_DMX_8_CH \ - 0x00000040 /**< Support flag for 6 and 7.1 channel configurations (input and \ - output). */ -#define CAPF_DMX_24_CH \ - 0x00000080 /**< Support flag for 22.2 channel configuration (input and \ - output). */ -#define CAPF_LIMITER \ - 0x00002000 /**< Support flag for signal level limiting. \ - */ - -/* MPEG Surround capability flags */ -#define CAPF_MPS_STD \ - 0x00000001 /**< Support flag for MPEG Surround. */ -#define CAPF_MPS_LD \ - 0x00000002 /**< Support flag for Low Delay MPEG Surround. \ - */ -#define CAPF_MPS_USAC \ - 0x00000004 /**< Support flag for USAC MPEG Surround. */ -#define CAPF_MPS_HQ \ - 0x00000010 /**< Support flag indicating if high quality processing is \ - supported */ -#define CAPF_MPS_LP \ - 0x00000020 /**< Support flag indicating if partially complex (low power) \ - processing is supported */ -#define CAPF_MPS_BLIND \ - 0x00000040 /**< Support flag indicating if blind processing is supported */ -#define CAPF_MPS_BINAURAL \ - 0x00000080 /**< Support flag indicating if binaural output is possible */ -#define CAPF_MPS_2CH_OUT \ - 0x00000100 /**< Support flag indicating if 2ch output is possible */ -#define CAPF_MPS_6CH_OUT \ - 0x00000200 /**< Support flag indicating if 6ch output is possible */ -#define CAPF_MPS_8CH_OUT \ - 0x00000400 /**< Support flag indicating if 8ch output is possible */ -#define CAPF_MPS_1CH_IN \ - 0x00001000 /**< Support flag indicating if 1ch dmx input is possible */ -#define CAPF_MPS_2CH_IN \ - 0x00002000 /**< Support flag indicating if 2ch dmx input is possible */ -#define CAPF_MPS_6CH_IN \ - 0x00004000 /**< Support flag indicating if 5ch dmx input is possible */ - -/* \endcond */ - -/* - * ############################################################################################## - * Library versioning - * ############################################################################################## - */ - -/** - * Convert each member of version numbers to one single numeric version - * representation. - * \param lev0 1st level of version number. - * \param lev1 2nd level of version number. - * \param lev2 3rd level of version number. - */ -#define LIB_VERSION(lev0, lev1, lev2) \ - ((lev0 << 24 & 0xff000000) | (lev1 << 16 & 0x00ff0000) | \ - (lev2 << 8 & 0x0000ff00)) - -/** - * Build text string of version. - */ -#define LIB_VERSION_STRING(info) \ - FDKsprintf((info)->versionStr, "%d.%d.%d", (((info)->version >> 24) & 0xff), \ - (((info)->version >> 16) & 0xff), \ - (((info)->version >> 8) & 0xff)) - -/** - * Library information. - */ -typedef struct LIB_INFO { - const char* title; - const char* build_date; - const char* build_time; - FDK_MODULE_ID module_id; - INT version; - UINT flags; - char versionStr[32]; -} LIB_INFO; - -#ifdef __cplusplus -#define FDK_AUDIO_INLINE inline -#else -#define FDK_AUDIO_INLINE -#endif - -/** Initialize library info. */ -static FDK_AUDIO_INLINE void FDKinitLibInfo(LIB_INFO* info) { - int i; - - for (i = 0; i < FDK_MODULE_LAST; i++) { - info[i].module_id = FDK_NONE; - } -} - -/** Aquire supported features of library. */ -static FDK_AUDIO_INLINE UINT -FDKlibInfo_getCapabilities(const LIB_INFO* info, FDK_MODULE_ID module_id) { - int i; - - for (i = 0; i < FDK_MODULE_LAST; i++) { - if (info[i].module_id == module_id) { - return info[i].flags; - } - } - return 0; -} - -/** Search for next free tab. */ -static FDK_AUDIO_INLINE INT FDKlibInfo_lookup(const LIB_INFO* info, - FDK_MODULE_ID module_id) { - int i = -1; - - for (i = 0; i < FDK_MODULE_LAST; i++) { - if (info[i].module_id == module_id) return -1; - if (info[i].module_id == FDK_NONE) break; - } - if (i == FDK_MODULE_LAST) return -1; - - return i; -} - -/* - * ############################################################################################## - * Buffer description - * ############################################################################################## - */ - -/** - * I/O buffer descriptor. - */ -typedef struct FDK_bufDescr { - void** ppBase; /*!< Pointer to an array containing buffer base addresses. - Set to NULL for buffer requirement info. */ - UINT* pBufSize; /*!< Pointer to an array containing the number of elements - that can be placed in the specific buffer. */ - UINT* pEleSize; /*!< Pointer to an array containing the element size for each - buffer in bytes. That is mostly the number returned by the - sizeof() operator for the data type used for the specific - buffer. */ - UINT* - pBufType; /*!< Pointer to an array of bit fields containing a description - for each buffer. See XXX below for more details. */ - UINT numBufs; /*!< Total number of buffers. */ - -} FDK_bufDescr; - -/** - * Buffer type description field. - */ -#define FDK_BUF_TYPE_MASK_IO ((UINT)0x03 << 30) -#define FDK_BUF_TYPE_MASK_DESCR ((UINT)0x3F << 16) -#define FDK_BUF_TYPE_MASK_ID ((UINT)0xFF) - -#define FDK_BUF_TYPE_INPUT ((UINT)0x1 << 30) -#define FDK_BUF_TYPE_OUTPUT ((UINT)0x2 << 30) - -#define FDK_BUF_TYPE_PCM_DATA ((UINT)0x1 << 16) -#define FDK_BUF_TYPE_ANC_DATA ((UINT)0x2 << 16) -#define FDK_BUF_TYPE_BS_DATA ((UINT)0x4 << 16) - -#ifdef __cplusplus -} -#endif - -#endif /* FDK_AUDIO_H */ diff --git a/code/dep_codecs/include/fdk-aac/aacdecoder_lib.h b/code/dep_codecs/include/fdk-aac/aacdecoder_lib.h deleted file mode 100755 index 5f0dd025..00000000 --- a/code/dep_codecs/include/fdk-aac/aacdecoder_lib.h +++ /dev/null @@ -1,1090 +0,0 @@ -/* ----------------------------------------------------------------------------- -Software License for The Fraunhofer FDK AAC Codec Library for Android - -© Copyright 1995 - 2018 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 ------------------------------------------------------------------------------ */ - -/**************************** AAC decoder library ****************************** - - Author(s): Manuel Jander - - Description: - -*******************************************************************************/ - -#ifndef AACDECODER_LIB_H -#define AACDECODER_LIB_H - -/** - * \file aacdecoder_lib.h - * \brief FDK AAC decoder library interface header file. - * - -\page INTRO Introduction - - -\section SCOPE Scope - -This document describes the high-level application interface and usage of the -ISO/MPEG-2/4 AAC Decoder library developed by the Fraunhofer Institute for -Integrated Circuits (IIS). Depending on the library configuration, decoding of -AAC-LC (Low-Complexity), HE-AAC (High-Efficiency AAC v1 and v2), AAC-LD -(Low-Delay) and AAC-ELD (Enhanced Low-Delay) is implemented. - -All references to SBR (Spectral Band Replication) are only applicable to HE-AAC -and AAC-ELD configurations of the FDK library. All references to PS (Parametric -Stereo) are only applicable to HE-AAC v2 decoder configuration of the library. - -\section DecoderBasics Decoder Basics - -This document can only give a rough overview about the ISO/MPEG-2, ISO/MPEG-4 -AAC audio and MPEG-D USAC coding standards. To understand all details referenced -in this document, you are encouraged to read the following documents. - -- ISO/IEC 13818-7 (MPEG-2 AAC) Standard, defines the syntax of MPEG-2 AAC audio -bitstreams. -- ISO/IEC 14496-3 (MPEG-4 AAC, subpart 1 and 4) Standard, defines the syntax of -MPEG-4 AAC audio bitstreams. -- ISO/IEC 23003-3 (MPEG-D USAC), defines MPEG-D USAC unified speech and audio -codec. -- Lutzky, Schuller, Gayer, Krämer, Wabnik, "A guideline to audio codec -delay", 116th AES Convention, May 8, 2004 - -In short, MPEG Advanced Audio Coding is based on a time-to-frequency mapping of -the signal. The signal is partitioned into overlapping time portions and -transformed into frequency domain. The spectral components are then quantized -and coded using a highly efficient coding scheme.\n Encoded MPEG-2 and MPEG-4 -AAC audio bitstreams are composed of frames. Contrary to MPEG-1/2 Layer-3 (mp3), -the length of individual frames is not restricted to a fixed number of bytes, -but can take any length between 1 and 768 bytes. - -In addition to the above mentioned frequency domain coding mode, MPEG-D USAC -also employs a time domain Algebraic Code-Excited Linear Prediction (ACELP) -speech coder core. This operating mode is selected by the encoder in order to -achieve the optimum audio quality for different content type. Several -enhancements allow achieving higher quality at lower bit rates compared to -MPEG-4 HE-AAC. - - -\page LIBUSE Library Usage - - -\section InterfaceDescritpion API Description - -All API header files are located in the folder /include of the release package. -The contents of each file is described in detail in this document. All header -files are provided for usage in specific C/C++ programs. The main AAC decoder -library API functions are located in aacdecoder_lib.h header file. - -In binary releases the decoder core resides in statically linkable libraries, -for example libAACdec.a. - - -\section Calling_Sequence Calling Sequence - -The following sequence is necessary for proper decoding of ISO/MPEG-2/4 AAC, -HE-AAC v2, or MPEG-D USAC bitstreams. In the following description, input stream -read and output write function details are left out, since they may be -implemented in a variety of configurations depending on the user's specific -requirements. The example implementation uses file-based input/output, and in -such case one may call mpegFileRead_Open() to open an input file and to allocate -memory for the required structures, and the corresponding mpegFileRead_Close() -to close opened files and to de-allocate associated structures. -mpegFileRead_Open() will attempt to detect the bitstream format and in case of -MPEG-4 file format or Raw Packets file format (a proprietary Fraunhofer IIS file -format suitable only for testing) it will read the Audio Specific Config data -(ASC). An unsuccessful attempt to recognize the bitstream format requires the -user to provide this information manually. For any other bitstream formats that -are usually applicable in streaming applications, the decoder itself will try to -synchronize and parse the given bitstream fragment using the FDK transport -library. Hence, for streaming applications (without file access) this step is -not necessary. - - --# Call aacDecoder_Open() to open and retrieve a handle to a new AAC decoder -instance. \code aacDecoderInfo = aacDecoder_Open(transportType, nrOfLayers); -\endcode --# If out-of-band config data (Audio Specific Config (ASC) or Stream Mux Config -(SMC)) is available, call aacDecoder_ConfigRaw() to pass this data to the -decoder before beginning the decoding process. If this data is not available in -advance, the decoder will configure itself while decoding, during the -aacDecoder_DecodeFrame() function call. --# Begin decoding loop. -\code -do { -\endcode --# Read data from bitstream file or stream buffer in to the driver program -working memory (a client-supplied input buffer "inBuffer" in framework). This -buffer will be used to load AAC bitstream data to the decoder. Only when all -data in this buffer has been processed will the decoder signal an empty buffer. -For file-based input, you may invoke mpegFileRead_Read() to acquire new -bitstream data. --# Call aacDecoder_Fill() to fill the decoder's internal bitstream input buffer -with the client-supplied bitstream input buffer. Note, if the data loaded in to -the internal buffer is not sufficient to decode a frame, -aacDecoder_DecodeFrame() will return ::AAC_DEC_NOT_ENOUGH_BITS until a -sufficient amount of data is loaded in to the internal buffer. For streaming -formats (ADTS, LOAS), it is acceptable to load more than one frame to the -decoder. However, for RAW file format (Fraunhofer IIS proprietary format), only -one frame may be loaded to the decoder per aacDecoder_DecodeFrame() call. For -least amount of communication delay, fill and decode should be performed on a -frame by frame basis. \code ErrorStatus = aacDecoder_Fill(aacDecoderInfo, -inBuffer, bytesRead, bytesValid); \endcode --# Call aacDecoder_DecodeFrame(). This function decodes one frame and writes -decoded PCM audio data to a client-supplied buffer. It is the client's -responsibility to allocate a buffer which is large enough to hold the decoded -output data. \code ErrorStatus = aacDecoder_DecodeFrame(aacDecoderInfo, -TimeData, OUT_BUF_SIZE, flags); \endcode If the bitstream configuration (number -of channels, sample rate, frame size) is not known a priori, you may call -aacDecoder_GetStreamInfo() to retrieve a structure that contains this -information. You may use this data to initialize an audio output device. In the -example program, if the number of channels or the sample rate has changed since -program start or the previously decoded frame, the audio output device is then -re-initialized. If WAVE file output is chosen, a new WAVE file for each new -stream configuration is be created. \code p_si = -aacDecoder_GetStreamInfo(aacDecoderInfo); \endcode --# Repeat steps 5 to 7 until no data is available to decode any more, or in case -of error. \code } while (bytesRead[0] > 0 || doFlush || doBsFlush || -forceContinue); \endcode --# Call aacDecoder_Close() to de-allocate all AAC decoder and transport layer -structures. \code aacDecoder_Close(aacDecoderInfo); \endcode - -\image latex decode.png "Decode calling sequence" width=11cm - -\image latex change_source.png "Change data source sequence" width 5cm - -\image latex conceal.png "Error concealment sequence" width=14cm - -\subsection Error_Concealment_Sequence Error Concealment Sequence - -There are different strategies to handle bit stream errors. Depending on the -system properties the product designer might choose to take different actions in -case a bit error occurs. In many cases the decoder might be able to do -reasonable error concealment without the need of any additional actions from the -system. But in some cases its not even possible to know how many decoded PCM -output samples are required to fill the gap due to the data error, then the -software surrounding the decoder must deal with the situation. The most simple -way would be to just stop audio playback and resume once enough bit stream data -and/or buffered output samples are available. More sophisticated designs might -also be able to deal with sender/receiver clock drifts or data drop outs by -using a closed loop control of FIFO fulness levels. The chosen strategy depends -on the final product requirements. - -The error concealment sequence diagram illustrates the general execution paths -for error handling. - -The macro IS_OUTPUT_VALID(err) can be used to identify if the audio output -buffer contains valid audio either from error free bit stream data or successful -error concealment. In case the result is false, the decoder output buffer does -not contain meaningful audio samples and should not be passed to any output as -it is. Most likely in case that a continuous audio output PCM stream is -required, the output buffer must be filled with audio data from the calling -framework. This might be e.g. an appropriate number of samples all zero. - -If error code ::AAC_DEC_TRANSPORT_SYNC_ERROR is returned by the decoder, under -some particular conditions it is possible to estimate lost frames due to the bit -stream error. In that case the bit stream is required to have a constant -bitrate, and compatible transport type. Audio samples for the lost frames can be -obtained by calling aacDecoder_DecodeFrame() with flag ::AACDEC_CONCEAL set -n-times where n is the count of lost frames. Please note that the decoder has to -have encountered valid configuration data at least once to be able to generate -concealed data, because at the minimum the sampling rate, frame size and amount -of audio channels needs to be known. - -If it is not possible to get an estimation of lost frames then a constant -fullness of the audio output buffer can be achieved by implementing different -FIFO control techniques e.g. just stop taking of samples from the buffer to -avoid underflow or stop filling new data to the buffer to avoid overflow. But -this techniques are out of scope of this document. - -For a detailed description of a specific error code please refer also to -::AAC_DECODER_ERROR. - -\section BufferSystem Buffer System - -There are three main buffers in an AAC decoder application. One external input -buffer to hold bitstream data from file I/O or elsewhere, one decoder-internal -input buffer, and one to hold the decoded output PCM sample data. In resource -limited applications, the output buffer may be reused as an external input -buffer prior to the subsequence aacDecoder_Fill() function call. - -The external input buffer is set in the example program and its size is defined -by ::IN_BUF_SIZE. You may freely choose different buffer sizes. To feed the data -to the decoder-internal input buffer, use the function aacDecoder_Fill(). This -function returns important information regarding the number of bytes in the -external input buffer that have not yet been copied into the internal input -buffer (variable bytesValid). Once the external buffer has been fully copied, it -can be completely re-filled again. In case you wish to refill the buffer while -there are unprocessed bytes (bytesValid is unequal 0), you should preserve the -unconsumed data. However, we recommend to refill the buffer only when bytesValid -returns 0. - -The bytesValid parameter is an input and output parameter to the FDK decoder. As -an input, it signals how many valid bytes are available in the external buffer. -After consumption of the external buffer using aacDecoder_Fill() function, the -bytesValid parameter indicates if any of the bytes in the external buffer were -not consumed. - -\image latex dec_buffer.png "Life cycle of the external input buffer" width=9cm - -\page OutputFormat Decoder audio output - -\section OutputFormatObtaining Obtaining channel mapping information - -The decoded audio output format is indicated by a set of variables of the -CStreamInfo structure. While the struct members sampleRate, frameSize and -numChannels might be self explanatory, pChannelType and pChannelIndices require -some further explanation. - -These two arrays indicate the configuration of channel data within the output -buffer. Both arrays have CStreamInfo::numChannels number of cells. Each cell of -pChannelType indicates the channel type, which is described in the enum -::AUDIO_CHANNEL_TYPE (defined in FDK_audio.h). The cells of pChannelIndices -indicate the sub index among the channels starting with 0 among channels of the -same audio channel type. - -The indexing scheme is structured as defined in MPEG-2/4 Standards. Indices -start from the front direction (a center channel if available, will always be -index 0) and increment, starting with the left side, pairwise (e.g. L, R) and -from front to back (Front L, Front R, Surround L, Surround R). For detailed -explanation, please refer to ISO/IEC 13818-7:2005(E), chapter 8.5.3.2. - -In case a Program Config is included in the audio configuration, the channel -mapping described within it will be adopted. - -In case of MPEG-D Surround the channel mapping will follow the same criteria -described in ISO/IEC 13818-7:2005(E), but adding corresponding top channels (if -available) to the channel types in order to avoid ambiguity. The examples below -explain these aspects in detail. - -\section OutputFormatChange Changing the audio output format - -For MPEG-4 audio the channel order can be changed at runtime through the -parameter -::AAC_PCM_OUTPUT_CHANNEL_MAPPING. See the description of those -parameters and the decoder library function aacDecoder_SetParam() for more -detail. - -\section OutputFormatExample Channel mapping examples - -The following examples illustrate the location of individual audio samples in -the audio buffer that is passed to aacDecoder_DecodeFrame() and the expected -data in the CStreamInfo structure which can be obtained by calling -aacDecoder_GetStreamInfo(). - -\subsection ExamplesStereo Stereo - -In case of ::AAC_PCM_OUTPUT_CHANNEL_MAPPING set to 1, -a AAC-LC bit stream which has channelConfiguration = 2 in its audio specific -config would lead to the following values in CStreamInfo: - -CStreamInfo::numChannels = 2 - -CStreamInfo::pChannelType = { ::ACT_FRONT, ::ACT_FRONT } - -CStreamInfo::pChannelIndices = { 0, 1 } - -The output buffer will be formatted as follows: - -\verbatim - ... - ... -\endverbatim - -Where N equals to CStreamInfo::frameSize . - -\subsection ExamplesSurround Surround 5.1 - -In case of ::AAC_PCM_OUTPUT_CHANNEL_MAPPING set to 1, -a AAC-LC bit stream which has channelConfiguration = 6 in its audio specific -config, would lead to the following values in CStreamInfo: - -CStreamInfo::numChannels = 6 - -CStreamInfo::pChannelType = { ::ACT_FRONT, ::ACT_FRONT, ::ACT_FRONT, ::ACT_LFE, -::ACT_BACK, ::ACT_BACK } - -CStreamInfo::pChannelIndices = { 1, 2, 0, 0, 0, 1 } - -Since ::AAC_PCM_OUTPUT_CHANNEL_MAPPING is 1, WAV file channel ordering will be -used. For a 5.1 channel scheme, thus the channels would be: front left, front -right, center, LFE, surround left, surround right. Thus the third channel is the -center channel, receiving the index 0. The other front channels are front left, -front right being placed as first and second channels with indices 1 and 2 -correspondingly. There is only one LFE, placed as the fourth channel and index -0. Finally both surround channels get the type definition ACT_BACK, and the -indices 0 and 1. - -The output buffer will be formatted as follows: - -\verbatim - -
- - - -
- - -... - - -
- -\endverbatim - -Where N equals to CStreamInfo::frameSize . - -\subsection ExamplesArib ARIB coding mode 2/1 - -In case of ::AAC_PCM_OUTPUT_CHANNEL_MAPPING set to 1, -in case of a ARIB bit stream using coding mode 2/1 as described in ARIB STD-B32 -Part 2 Version 2.1-E1, page 61, would lead to the following values in -CStreamInfo: - -CStreamInfo::numChannels = 3 - -CStreamInfo::pChannelType = { ::ACT_FRONT, ::ACT_FRONT, ::ACT_BACK } - -CStreamInfo::pChannelIndices = { 0, 1, 0 } - -The audio channels will be placed as follows in the audio output buffer: - -\verbatim - - - - -... - - - -Where N equals to CStreamInfo::frameSize . - -\endverbatim - -*/ - -#include "machine_type.h" -#include "FDK_audio.h" - -#include "genericStds.h" - -#define AACDECODER_LIB_VL0 3 -#define AACDECODER_LIB_VL1 0 -#define AACDECODER_LIB_VL2 0 - -/** - * \brief AAC decoder error codes. - */ -typedef enum { - AAC_DEC_OK = - 0x0000, /*!< No error occurred. Output buffer is valid and error free. */ - AAC_DEC_OUT_OF_MEMORY = - 0x0002, /*!< Heap returned NULL pointer. Output buffer is invalid. */ - AAC_DEC_UNKNOWN = - 0x0005, /*!< Error condition is of unknown reason, or from a another - module. Output buffer is invalid. */ - - /* Synchronization errors. Output buffer is invalid. */ - aac_dec_sync_error_start = 0x1000, - AAC_DEC_TRANSPORT_SYNC_ERROR = 0x1001, /*!< The transport decoder had - synchronization problems. Do not - exit decoding. Just feed new - bitstream data. */ - AAC_DEC_NOT_ENOUGH_BITS = 0x1002, /*!< The input buffer ran out of bits. */ - aac_dec_sync_error_end = 0x1FFF, - - /* Initialization errors. Output buffer is invalid. */ - aac_dec_init_error_start = 0x2000, - AAC_DEC_INVALID_HANDLE = - 0x2001, /*!< The handle passed to the function call was invalid (NULL). */ - AAC_DEC_UNSUPPORTED_AOT = - 0x2002, /*!< The AOT found in the configuration is not supported. */ - AAC_DEC_UNSUPPORTED_FORMAT = - 0x2003, /*!< The bitstream format is not supported. */ - AAC_DEC_UNSUPPORTED_ER_FORMAT = - 0x2004, /*!< The error resilience tool format is not supported. */ - AAC_DEC_UNSUPPORTED_EPCONFIG = - 0x2005, /*!< The error protection format is not supported. */ - AAC_DEC_UNSUPPORTED_MULTILAYER = - 0x2006, /*!< More than one layer for AAC scalable is not supported. */ - AAC_DEC_UNSUPPORTED_CHANNELCONFIG = - 0x2007, /*!< The channel configuration (either number or arrangement) is - not supported. */ - AAC_DEC_UNSUPPORTED_SAMPLINGRATE = 0x2008, /*!< The sample rate specified in - the configuration is not - supported. */ - AAC_DEC_INVALID_SBR_CONFIG = - 0x2009, /*!< The SBR configuration is not supported. */ - AAC_DEC_SET_PARAM_FAIL = 0x200A, /*!< The parameter could not be set. Either - the value was out of range or the - parameter does not exist. */ - AAC_DEC_NEED_TO_RESTART = 0x200B, /*!< The decoder needs to be restarted, - since the required configuration change - cannot be performed. */ - AAC_DEC_OUTPUT_BUFFER_TOO_SMALL = - 0x200C, /*!< The provided output buffer is too small. */ - aac_dec_init_error_end = 0x2FFF, - - /* Decode errors. Output buffer is valid but concealed. */ - aac_dec_decode_error_start = 0x4000, - AAC_DEC_TRANSPORT_ERROR = - 0x4001, /*!< The transport decoder encountered an unexpected error. */ - AAC_DEC_PARSE_ERROR = 0x4002, /*!< Error while parsing the bitstream. Most - probably it is corrupted, or the system - crashed. */ - AAC_DEC_UNSUPPORTED_EXTENSION_PAYLOAD = - 0x4003, /*!< Error while parsing the extension payload of the bitstream. - The extension payload type found is not supported. */ - AAC_DEC_DECODE_FRAME_ERROR = 0x4004, /*!< The parsed bitstream value is out of - range. Most probably the bitstream is - corrupt, or the system crashed. */ - AAC_DEC_CRC_ERROR = 0x4005, /*!< The embedded CRC did not match. */ - AAC_DEC_INVALID_CODE_BOOK = 0x4006, /*!< An invalid codebook was signaled. - Most probably the bitstream is corrupt, - or the system crashed. */ - AAC_DEC_UNSUPPORTED_PREDICTION = - 0x4007, /*!< Predictor found, but not supported in the AAC Low Complexity - profile. Most probably the bitstream is corrupt, or has a wrong - format. */ - AAC_DEC_UNSUPPORTED_CCE = 0x4008, /*!< A CCE element was found which is not - supported. Most probably the bitstream is - corrupt, or has a wrong format. */ - AAC_DEC_UNSUPPORTED_LFE = 0x4009, /*!< A LFE element was found which is not - supported. Most probably the bitstream is - corrupt, or has a wrong format. */ - AAC_DEC_UNSUPPORTED_GAIN_CONTROL_DATA = - 0x400A, /*!< Gain control data found but not supported. Most probably the - bitstream is corrupt, or has a wrong format. */ - AAC_DEC_UNSUPPORTED_SBA = - 0x400B, /*!< SBA found, but currently not supported in the BSAC profile. - */ - AAC_DEC_TNS_READ_ERROR = 0x400C, /*!< Error while reading TNS data. Most - probably the bitstream is corrupt or the - system crashed. */ - AAC_DEC_RVLC_ERROR = - 0x400D, /*!< Error while decoding error resilient data. */ - aac_dec_decode_error_end = 0x4FFF, - /* Ancillary data errors. Output buffer is valid. */ - aac_dec_anc_data_error_start = 0x8000, - AAC_DEC_ANC_DATA_ERROR = - 0x8001, /*!< Non severe error concerning the ancillary data handling. */ - AAC_DEC_TOO_SMALL_ANC_BUFFER = 0x8002, /*!< The registered ancillary data - buffer is too small to receive the - parsed data. */ - AAC_DEC_TOO_MANY_ANC_ELEMENTS = 0x8003, /*!< More than the allowed number of - ancillary data elements should be - written to buffer. */ - aac_dec_anc_data_error_end = 0x8FFF - -} AAC_DECODER_ERROR; - -/** Macro to identify initialization errors. Output buffer is invalid. */ -#define IS_INIT_ERROR(err) \ - ((((err) >= aac_dec_init_error_start) && ((err) <= aac_dec_init_error_end)) \ - ? 1 \ - : 0) -/** Macro to identify decode errors. Output buffer is valid but concealed. */ -#define IS_DECODE_ERROR(err) \ - ((((err) >= aac_dec_decode_error_start) && \ - ((err) <= aac_dec_decode_error_end)) \ - ? 1 \ - : 0) -/** - * Macro to identify if the audio output buffer contains valid samples after - * calling aacDecoder_DecodeFrame(). Output buffer is valid but can be - * concealed. - */ -#define IS_OUTPUT_VALID(err) (((err) == AAC_DEC_OK) || IS_DECODE_ERROR(err)) - -/*! \enum AAC_MD_PROFILE - * \brief The available metadata profiles which are mostly related to downmixing. The values define the arguments - * for the use with parameter ::AAC_METADATA_PROFILE. - */ -typedef enum { - AAC_MD_PROFILE_MPEG_STANDARD = - 0, /*!< The standard profile creates a mixdown signal based on the - advanced downmix metadata (from a DSE). The equations and default - values are defined in ISO/IEC 14496:3 Ammendment 4. Any other - (legacy) downmix metadata will be ignored. No other parameter will - be modified. */ - AAC_MD_PROFILE_MPEG_LEGACY = - 1, /*!< This profile behaves identical to the standard profile if advanced - downmix metadata (from a DSE) is available. If not, the - matrix_mixdown information embedded in the program configuration - element (PCE) will be applied. If neither is the case, the module - creates a mixdown using the default coefficients as defined in - ISO/IEC 14496:3 AMD 4. The profile can be used to support legacy - digital TV (e.g. DVB) streams. */ - AAC_MD_PROFILE_MPEG_LEGACY_PRIO = - 2, /*!< Similar to the ::AAC_MD_PROFILE_MPEG_LEGACY profile but if both - the advanced (ISO/IEC 14496:3 AMD 4) and the legacy (PCE) MPEG - downmix metadata are available the latter will be applied. - */ - AAC_MD_PROFILE_ARIB_JAPAN = - 3 /*!< Downmix creation as described in ABNT NBR 15602-2. But if advanced - downmix metadata (ISO/IEC 14496:3 AMD 4) is available it will be - preferred because of the higher resolutions. In addition the - metadata expiry time will be set to the value defined in the ARIB - standard (see ::AAC_METADATA_EXPIRY_TIME). - */ -} AAC_MD_PROFILE; - -/*! \enum AAC_DRC_DEFAULT_PRESENTATION_MODE_OPTIONS - * \brief Options for handling of DRC parameters, if presentation mode is not indicated in bitstream - */ -typedef enum { - AAC_DRC_PARAMETER_HANDLING_DISABLED = -1, /*!< DRC parameter handling - disabled, all parameters are - applied as requested. */ - AAC_DRC_PARAMETER_HANDLING_ENABLED = - 0, /*!< Apply changes to requested DRC parameters to prevent clipping. */ - AAC_DRC_PRESENTATION_MODE_1_DEFAULT = - 1, /*!< Use DRC presentation mode 1 as default (e.g. for Nordig) */ - AAC_DRC_PRESENTATION_MODE_2_DEFAULT = - 2 /*!< Use DRC presentation mode 2 as default (e.g. for DTG DBook) */ -} AAC_DRC_DEFAULT_PRESENTATION_MODE_OPTIONS; - -/** - * \brief AAC decoder setting parameters - */ -typedef enum { - AAC_PCM_DUAL_CHANNEL_OUTPUT_MODE = - 0x0002, /*!< Defines how the decoder processes two channel signals: \n - 0: Leave both signals as they are (default). \n - 1: Create a dual mono output signal from channel 1. \n - 2: Create a dual mono output signal from channel 2. \n - 3: Create a dual mono output signal by mixing both channels - (L' = R' = 0.5*Ch1 + 0.5*Ch2). */ - AAC_PCM_OUTPUT_CHANNEL_MAPPING = - 0x0003, /*!< Output buffer channel ordering. 0: MPEG PCE style order, 1: - WAV file channel order (default). */ - AAC_PCM_LIMITER_ENABLE = - 0x0004, /*!< Enable signal level limiting. \n - -1: Auto-config. Enable limiter for all - non-lowdelay configurations by default. \n - 0: Disable limiter in general. \n - 1: Enable limiter always. - It is recommended to call the decoder - with a AACDEC_CLRHIST flag to reset all - states when the limiter switch is changed - explicitly. */ - AAC_PCM_LIMITER_ATTACK_TIME = 0x0005, /*!< Signal level limiting attack time - in ms. Default configuration is 15 - ms. Adjustable range from 1 ms to 15 - ms. */ - AAC_PCM_LIMITER_RELEAS_TIME = 0x0006, /*!< Signal level limiting release time - in ms. Default configuration is 50 - ms. Adjustable time must be larger - than 0 ms. */ - AAC_PCM_MIN_OUTPUT_CHANNELS = - 0x0011, /*!< Minimum number of PCM output channels. If higher than the - number of encoded audio channels, a simple channel extension is - applied (see note 4 for exceptions). \n -1, 0: Disable channel - extension feature. The decoder output contains the same number - of channels as the encoded bitstream. \n 1: This value is - currently needed only together with the mix-down feature. See - ::AAC_PCM_MAX_OUTPUT_CHANNELS and note 2 below. \n - 2: Encoded mono signals will be duplicated to achieve a - 2/0/0.0 channel output configuration. \n 6: The decoder - tries to reorder encoded signals with less than six channels to - achieve a 3/0/2.1 channel output signal. Missing channels will - be filled with a zero signal. If reordering is not possible the - empty channels will simply be appended. Only available if - instance is configured to support multichannel output. \n 8: - The decoder tries to reorder encoded signals with less than - eight channels to achieve a 3/0/4.1 channel output signal. - Missing channels will be filled with a zero signal. If - reordering is not possible the empty channels will simply be - appended. Only available if instance is configured to - support multichannel output.\n NOTE: \n - 1. The channel signaling (CStreamInfo::pChannelType and - CStreamInfo::pChannelIndices) will not be modified. Added empty - channels will be signaled with channel type - AUDIO_CHANNEL_TYPE::ACT_NONE. \n - 2. If the parameter value is greater than that of - ::AAC_PCM_MAX_OUTPUT_CHANNELS both will be set to the same - value. \n - 3. This parameter does not affect MPEG Surround processing. - \n - 4. This parameter will be ignored if the number of encoded - audio channels is greater than 8. */ - AAC_PCM_MAX_OUTPUT_CHANNELS = - 0x0012, /*!< Maximum number of PCM output channels. If lower than the - number of encoded audio channels, downmixing is applied - accordingly (see note 5 for exceptions). If dedicated metadata - is available in the stream it will be used to achieve better - mixing results. \n -1, 0: Disable downmixing feature. The - decoder output contains the same number of channels as the - encoded bitstream. \n 1: All encoded audio configurations - with more than one channel will be mixed down to one mono - output signal. \n 2: The decoder performs a stereo mix-down - if the number encoded audio channels is greater than two. \n 6: - If the number of encoded audio channels is greater than six the - decoder performs a mix-down to meet the target output - configuration of 3/0/2.1 channels. Only available if instance - is configured to support multichannel output. \n 8: This - value is currently needed only together with the channel - extension feature. See ::AAC_PCM_MIN_OUTPUT_CHANNELS and note 2 - below. Only available if instance is configured to support - multichannel output. \n NOTE: \n - 1. Down-mixing of any seven or eight channel configuration - not defined in ISO/IEC 14496-3 PDAM 4 is not supported by this - software version. \n - 2. If the parameter value is greater than zero but smaller - than ::AAC_PCM_MIN_OUTPUT_CHANNELS both will be set to same - value. \n - 3. The operating mode of the MPEG Surround module will be - set accordingly. \n - 4. Setting this parameter with any value will disable the - binaural processing of the MPEG Surround module - 5. This parameter will be ignored if the number of encoded - audio channels is greater than 8. */ - AAC_METADATA_PROFILE = - 0x0020, /*!< See ::AAC_MD_PROFILE for all available values. */ - AAC_METADATA_EXPIRY_TIME = 0x0021, /*!< Defines the time in ms after which all - the bitstream associated meta-data (DRC, - downmix coefficients, ...) will be reset - to default if no update has been - received. Negative values disable the - feature. */ - - AAC_CONCEAL_METHOD = 0x0100, /*!< Error concealment: Processing method. \n - 0: Spectral muting. \n - 1: Noise substitution (see ::CONCEAL_NOISE). - \n 2: Energy interpolation (adds additional - signal delay of one frame, see - ::CONCEAL_INTER. only some AOTs are - supported). \n */ - AAC_DRC_BOOST_FACTOR = - 0x0200, /*!< Dynamic Range Control: Scaling factor for boosting gain - values. Defines how the boosting DRC factors (conveyed in the - bitstream) will be applied to the decoded signal. The valid - values range from 0 (don't apply boost factors) to 127 (fully - apply boost factors). Default value is 0. */ - AAC_DRC_ATTENUATION_FACTOR = - 0x0201, /*!< Dynamic Range Control: Scaling factor for attenuating gain - values. Same as - ::AAC_DRC_BOOST_FACTOR but for attenuating DRC factors. */ - AAC_DRC_REFERENCE_LEVEL = - 0x0202, /*!< Dynamic Range Control (DRC): Target reference level. Defines - the level below full-scale (quantized in steps of 0.25dB) to - which the output audio signal will be normalized to by the DRC - module. The parameter controls loudness normalization for both - MPEG-4 DRC and MPEG-D DRC. The valid values range from 40 (-10 - dBFS) to 127 (-31.75 dBFS). Any value smaller than 0 switches - off loudness normalization and MPEG-4 DRC. By default, loudness - normalization and MPEG-4 DRC is switched off. */ - AAC_DRC_HEAVY_COMPRESSION = - 0x0203, /*!< Dynamic Range Control: En-/Disable DVB specific heavy - compression (aka RF mode). If set to 1, the decoder will apply - the compression values from the DVB specific ancillary data - field. At the same time the MPEG-4 Dynamic Range Control tool - will be disabled. By default, heavy compression is disabled. */ - AAC_DRC_DEFAULT_PRESENTATION_MODE = - 0x0204, /*!< Dynamic Range Control: Default presentation mode (DRC - parameter handling). \n Defines the handling of the DRC - parameters boost factor, attenuation factor and heavy - compression, if no presentation mode is indicated in the - bitstream.\n For options, see - ::AAC_DRC_DEFAULT_PRESENTATION_MODE_OPTIONS.\n Default: - ::AAC_DRC_PARAMETER_HANDLING_DISABLED */ - AAC_DRC_ENC_TARGET_LEVEL = - 0x0205, /*!< Dynamic Range Control: Encoder target level for light (i.e. - not heavy) compression.\n If known, this declares the target - reference level that was assumed at the encoder for calculation - of limiting gains. The valid values range from 0 (full-scale) - to 127 (31.75 dB below full-scale). This parameter is used only - with ::AAC_DRC_PARAMETER_HANDLING_ENABLED and ignored - otherwise.\n Default: 127 (worst-case assumption).\n */ - AAC_QMF_LOWPOWER = 0x0300, /*!< Quadrature Mirror Filter (QMF) Bank processing - mode. \n -1: Use internal default. Implies MPEG - Surround partially complex accordingly. \n 0: - Use complex QMF data mode. \n 1: Use real (low - power) QMF data mode. \n */ - AAC_TPDEC_CLEAR_BUFFER = - 0x0603, /*!< Clear internal bit stream buffer of transport layers. The - decoder will start decoding at new data passed after this event - and any previous data is discarded. */ - AAC_UNIDRC_SET_EFFECT = 0x0903 /*!< MPEG-D DRC: Request a DRC effect type for - selection of a DRC set.\n Supported indices - are:\n -1: DRC off. Completely disables - MPEG-D DRC.\n 0: None (default). Disables - MPEG-D DRC, but automatically enables DRC if - necessary to prevent clipping.\n 1: Late - night\n 2: Noisy environment\n 3: Limited - playback range\n 4: Low playback level\n 5: - Dialog enhancement\n 6: General compression. - Used for generally enabling MPEG-D DRC - without particular request.\n */ - -} AACDEC_PARAM; - -/** - * \brief This structure gives information about the currently decoded audio - * data. All fields are read-only. - */ -typedef struct { - /* These five members are the only really relevant ones for the user. */ - INT sampleRate; /*!< The sample rate in Hz of the decoded PCM audio signal. */ - INT frameSize; /*!< The frame size of the decoded PCM audio signal. \n - Typically this is: \n - 1024 or 960 for AAC-LC \n - 2048 or 1920 for HE-AAC (v2) \n - 512 or 480 for AAC-LD and AAC-ELD \n - 768, 1024, 2048 or 4096 for USAC */ - INT numChannels; /*!< The number of output audio channels before the rendering - module, i.e. the original channel configuration. */ - AUDIO_CHANNEL_TYPE - *pChannelType; /*!< Audio channel type of each output audio channel. */ - UCHAR *pChannelIndices; /*!< Audio channel index for each output audio - channel. See ISO/IEC 13818-7:2005(E), 8.5.3.2 - Explicit channel mapping using a - program_config_element() */ - /* Decoder internal members. */ - INT aacSampleRate; /*!< Sampling rate in Hz without SBR (from configuration - info) divided by a (ELD) downscale factor if present. */ - INT profile; /*!< MPEG-2 profile (from file header) (-1: not applicable (e. g. - MPEG-4)). */ - AUDIO_OBJECT_TYPE - aot; /*!< Audio Object Type (from ASC): is set to the appropriate value - for MPEG-2 bitstreams (e. g. 2 for AAC-LC). */ - INT channelConfig; /*!< Channel configuration (0: PCE defined, 1: mono, 2: - stereo, ... */ - INT bitRate; /*!< Instantaneous bit rate. */ - INT aacSamplesPerFrame; /*!< Samples per frame for the AAC core (from ASC) - divided by a (ELD) downscale factor if present. \n - Typically this is (with a downscale factor of 1): - \n 1024 or 960 for AAC-LC \n 512 or 480 for - AAC-LD and AAC-ELD */ - INT aacNumChannels; /*!< The number of audio channels after AAC core - processing (before PS or MPS processing). CAUTION: This - are not the final number of output channels! */ - AUDIO_OBJECT_TYPE extAot; /*!< Extension Audio Object Type (from ASC) */ - INT extSamplingRate; /*!< Extension sampling rate in Hz (from ASC) divided by - a (ELD) downscale factor if present. */ - - UINT outputDelay; /*!< The number of samples the output is additionally - delayed by.the decoder. */ - UINT flags; /*!< Copy of internal flags. Only to be written by the decoder, - and only to be read externally. */ - - SCHAR epConfig; /*!< epConfig level (from ASC): only level 0 supported, -1 - means no ER (e. g. AOT=2, MPEG-2 AAC, etc.) */ - /* Statistics */ - INT numLostAccessUnits; /*!< This integer will reflect the estimated amount of - lost access units in case aacDecoder_DecodeFrame() - returns AAC_DEC_TRANSPORT_SYNC_ERROR. It will be - < 0 if the estimation failed. */ - - INT64 numTotalBytes; /*!< This is the number of total bytes that have passed - through the decoder. */ - INT64 - numBadBytes; /*!< This is the number of total bytes that were considered - with errors from numTotalBytes. */ - INT64 - numTotalAccessUnits; /*!< This is the number of total access units that - have passed through the decoder. */ - INT64 numBadAccessUnits; /*!< This is the number of total access units that - were considered with errors from numTotalBytes. */ - - /* Metadata */ - SCHAR drcProgRefLev; /*!< DRC program reference level. Defines the reference - level below full-scale. It is quantized in steps of - 0.25dB. The valid values range from 0 (0 dBFS) to 127 - (-31.75 dBFS). It is used to reflect the average - loudness of the audio in LKFS according to ITU-R BS - 1770. If no level has been found in the bitstream the - value is -1. */ - SCHAR - drcPresMode; /*!< DRC presentation mode. According to ETSI TS 101 154, - this field indicates whether light (MPEG-4 Dynamic Range - Control tool) or heavy compression (DVB heavy - compression) dynamic range control shall take priority - on the outputs. For details, see ETSI TS 101 154, table - C.33. Possible values are: \n -1: No corresponding - metadata found in the bitstream \n 0: DRC presentation - mode not indicated \n 1: DRC presentation mode 1 \n 2: - DRC presentation mode 2 \n 3: Reserved */ - -} CStreamInfo; - -typedef struct AAC_DECODER_INSTANCE - *HANDLE_AACDECODER; /*!< Pointer to a AAC decoder instance. */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Initialize ancillary data buffer. - * - * \param self AAC decoder handle. - * \param buffer Pointer to (external) ancillary data buffer. - * \param size Size of the buffer pointed to by buffer. - * \return Error code. - */ -LINKSPEC_H AAC_DECODER_ERROR aacDecoder_AncDataInit(HANDLE_AACDECODER self, - UCHAR *buffer, int size); - -/** - * \brief Get one ancillary data element. - * - * \param self AAC decoder handle. - * \param index Index of the ancillary data element to get. - * \param ptr Pointer to a buffer receiving a pointer to the requested - * ancillary data element. - * \param size Pointer to a buffer receiving the length of the requested - * ancillary data element. - * \return Error code. - */ -LINKSPEC_H AAC_DECODER_ERROR aacDecoder_AncDataGet(HANDLE_AACDECODER self, - int index, UCHAR **ptr, - int *size); - -/** - * \brief Set one single decoder parameter. - * - * \param self AAC decoder handle. - * \param param Parameter to be set. - * \param value Parameter value. - * \return Error code. - */ -LINKSPEC_H AAC_DECODER_ERROR aacDecoder_SetParam(const HANDLE_AACDECODER self, - const AACDEC_PARAM param, - const INT value); - -/** - * \brief Get free bytes inside decoder internal buffer. - * \param self Handle of AAC decoder instance. - * \param pFreeBytes Pointer to variable receiving amount of free bytes inside - * decoder internal buffer. - * \return Error code. - */ -LINKSPEC_H AAC_DECODER_ERROR -aacDecoder_GetFreeBytes(const HANDLE_AACDECODER self, UINT *pFreeBytes); - -/** - * \brief Open an AAC decoder instance. - * \param transportFmt The transport type to be used. - * \param nrOfLayers Number of transport layers. - * \return AAC decoder handle. - */ -LINKSPEC_H HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, - UINT nrOfLayers); - -/** - * \brief Explicitly configure the decoder by passing a raw AudioSpecificConfig - * (ASC) or a StreamMuxConfig (SMC), contained in a binary buffer. This is - * required for MPEG-4 and Raw Packets file format bitstreams as well as for - * LATM bitstreams with no in-band SMC. If the transport format is LATM with or - * without LOAS, configuration is assumed to be an SMC, for all other file - * formats an ASC. - * - * \param self AAC decoder handle. - * \param conf Pointer to an unsigned char buffer containing the binary - * configuration buffer (either ASC or SMC). - * \param length Length of the configuration buffer in bytes. - * \return Error code. - */ -LINKSPEC_H AAC_DECODER_ERROR aacDecoder_ConfigRaw(HANDLE_AACDECODER self, - UCHAR *conf[], - const UINT length[]); - -/** - * \brief Submit raw ISO base media file format boxes to decoder for parsing - * (only some box types are recognized). - * - * \param self AAC decoder handle. - * \param buffer Pointer to an unsigned char buffer containing the binary box - * data (including size and type, can be a sequence of multiple boxes). - * \param length Length of the data in bytes. - * \return Error code. - */ -LINKSPEC_H AAC_DECODER_ERROR aacDecoder_RawISOBMFFData(HANDLE_AACDECODER self, - UCHAR *buffer, - UINT length); - -/** - * \brief Fill AAC decoder's internal input buffer with bitstream data from the - * external input buffer. The function only copies such data as long as the - * decoder-internal input buffer is not full. So it grabs whatever it can from - * pBuffer and returns information (bytesValid) so that at a subsequent call of - * %aacDecoder_Fill(), the right position in pBuffer can be determined to grab - * the next data. - * - * \param self AAC decoder handle. - * \param pBuffer Pointer to external input buffer. - * \param bufferSize Size of external input buffer. This argument is required - * because decoder-internally we need the information to calculate the offset to - * pBuffer, where the next available data is, which is then - * fed into the decoder-internal buffer (as much as - * possible). Our example framework implementation fills the - * buffer at pBuffer again, once it contains no available valid bytes anymore - * (meaning bytesValid equal 0). - * \param bytesValid Number of bitstream bytes in the external bitstream buffer - * that have not yet been copied into the decoder's internal bitstream buffer by - * calling this function. The value is updated according to - * the amount of newly copied bytes. - * \return Error code. - */ -LINKSPEC_H AAC_DECODER_ERROR aacDecoder_Fill(HANDLE_AACDECODER self, - UCHAR *pBuffer[], - const UINT bufferSize[], - UINT *bytesValid); - -#define AACDEC_CONCEAL \ - 1 /*!< Flag for aacDecoder_DecodeFrame(): Trigger the built-in error \ - concealment module to generate a substitute signal for one lost frame. \ - New input data will not be considered. */ -#define AACDEC_FLUSH \ - 2 /*!< Flag for aacDecoder_DecodeFrame(): Flush all filterbanks to get all \ - delayed audio without having new input data. Thus new input data will \ - not be considered.*/ -#define AACDEC_INTR \ - 4 /*!< Flag for aacDecoder_DecodeFrame(): Signal an input bit stream data \ - discontinuity. Resync any internals as necessary. */ -#define AACDEC_CLRHIST \ - 8 /*!< Flag for aacDecoder_DecodeFrame(): Clear all signal delay lines and \ - history buffers. CAUTION: This can cause discontinuities in the output \ - signal. */ - -/** - * \brief Decode one audio frame - * - * \param self AAC decoder handle. - * \param pTimeData Pointer to external output buffer where the decoded PCM - * samples will be stored into. - * \param timeDataSize Size of external output buffer. - * \param flags Bit field with flags for the decoder: \n - * (flags & AACDEC_CONCEAL) == 1: Do concealment. \n - * (flags & AACDEC_FLUSH) == 2: Discard input data. Flush - * filter banks (output delayed audio). \n (flags & AACDEC_INTR) == 4: Input - * data is discontinuous. Resynchronize any internals as - * necessary. \n (flags & AACDEC_CLRHIST) == 8: Clear all signal delay lines and - * history buffers. - * \return Error code. - */ -LINKSPEC_H AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, - INT_PCM *pTimeData, - const INT timeDataSize, - const UINT flags); - -/** - * \brief De-allocate all resources of an AAC decoder instance. - * - * \param self AAC decoder handle. - * \return void. - */ -LINKSPEC_H void aacDecoder_Close(HANDLE_AACDECODER self); - -/** - * \brief Get CStreamInfo handle from decoder. - * - * \param self AAC decoder handle. - * \return Reference to requested CStreamInfo. - */ -LINKSPEC_H CStreamInfo *aacDecoder_GetStreamInfo(HANDLE_AACDECODER self); - -/** - * \brief Get decoder library info. - * - * \param info Pointer to an allocated LIB_INFO structure. - * \return 0 on success. - */ -LINKSPEC_H INT aacDecoder_GetLibInfo(LIB_INFO *info); - -#ifdef __cplusplus -} -#endif - -#endif /* AACDECODER_LIB_H */ diff --git a/code/dep_codecs/include/fdk-aac/aacenc_lib.h b/code/dep_codecs/include/fdk-aac/aacenc_lib.h deleted file mode 100755 index fa41ee68..00000000 --- a/code/dep_codecs/include/fdk-aac/aacenc_lib.h +++ /dev/null @@ -1,1731 +0,0 @@ -/* ----------------------------------------------------------------------------- -Software License for The Fraunhofer FDK AAC Codec Library for Android - -© Copyright 1995 - 2018 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 ------------------------------------------------------------------------------ */ - -/**************************** AAC encoder library ****************************** - - Author(s): M. Lohwasser - - Description: - -*******************************************************************************/ - -/** - * \file aacenc_lib.h - * \brief FDK AAC Encoder library interface header file. - * -\mainpage Introduction - -\section Scope - -This document describes the high-level interface and usage of the ISO/MPEG-2/4 -AAC Encoder library developed by the Fraunhofer Institute for Integrated -Circuits (IIS). - -The library implements encoding on the basis of the MPEG-2 and MPEG-4 AAC -Low-Complexity standard, and depending on the library's configuration, MPEG-4 -High-Efficiency AAC v2 and/or AAC-ELD standard. - -All references to SBR (Spectral Band Replication) are only applicable to HE-AAC -or AAC-ELD versions of the library. All references to PS (Parametric Stereo) are -only applicable to HE-AAC v2 versions of the library. - -\section encBasics Encoder Basics - -This document can only give a rough overview about the ISO/MPEG-2 and ISO/MPEG-4 -AAC audio coding standard. To understand all the terms in this document, you are -encouraged to read the following documents. - -- ISO/IEC 13818-7 (MPEG-2 AAC), which defines the syntax of MPEG-2 AAC audio -bitstreams. -- ISO/IEC 14496-3 (MPEG-4 AAC, subparts 1 and 4), which defines the syntax of -MPEG-4 AAC audio bitstreams. -- Lutzky, Schuller, Gayer, Krämer, Wabnik, "A guideline to audio codec -delay", 116th AES Convention, May 8, 2004 - -MPEG Advanced Audio Coding is based on a time-to-frequency mapping of the -signal. The signal is partitioned into overlapping portions and transformed into -frequency domain. The spectral components are then quantized and coded. \n An -MPEG-2 or MPEG-4 AAC audio bitstream is composed of frames. Contrary to MPEG-1/2 -Layer-3 (mp3), the length of individual frames is not restricted to a fixed -number of bytes, but can take on any length between 1 and 768 bytes. - - -\page LIBUSE Library Usage - -\section InterfaceDescription API Files - -All API header files are located in the folder /include of the release package. -All header files are provided for usage in C/C++ programs. The AAC encoder -library API functions are located in aacenc_lib.h. - -In binary releases the encoder core resides in statically linkable libraries -called for example libAACenc.a/libFDK.a (LINUX) or FDK_fastaaclib.lib (MS Visual -C++) for the plain AAC-LC core encoder and libSBRenc.a (LINUX) or -FDK_sbrEncLib.lib (MS Visual C++) for the SBR (Spectral Band Replication) and PS -(Parametric Stereo) modules. - -\section CallingSequence Calling Sequence - -For encoding of ISO/MPEG-2/4 AAC bitstreams the following sequence is mandatory. -Input read and output write functions as well as the corresponding open and -close functions are left out, since they may be implemented differently -according to the user's specific requirements. The example implementation uses -file-based input/output. - --# Call aacEncOpen() to allocate encoder instance with required \ref encOpen -"configuration". \code HANDLE_AACENCODER hAacEncoder = NULL; if ( (ErrorStatus = -aacEncOpen(&hAacEncoder,0,0)) != AACENC_OK ) { \endcode --# Call aacEncoder_SetParam() for each parameter to be set. AOT, samplingrate, -channelMode, bitrate and transport type are \ref encParams "mandatory". \code -ErrorStatus = aacEncoder_SetParam(hAacEncoder, parameter, value); -\endcode --# Call aacEncEncode() with NULL parameters to \ref encReconf "initialize" -encoder instance with present parameter set. \code ErrorStatus = -aacEncEncode(hAacEncoder, NULL, NULL, NULL, NULL); \endcode --# Call aacEncInfo() to retrieve a configuration data block to be transmitted -out of band. This is required when using RFC3640 or RFC3016 like transport. -\code -AACENC_InfoStruct encInfo; -aacEncInfo(hAacEncoder, &encInfo); -\endcode --# Encode input audio data in loop. -\code -do -{ -\endcode -Feed \ref feedInBuf "input buffer" with new audio data and provide input/output -\ref bufDes "arguments" to aacEncEncode(). \code ErrorStatus = -aacEncEncode(hAacEncoder, &inBufDesc, &outBufDesc, &inargs, &outargs); \endcode -Write \ref writeOutData "output data" to file or audio device. -\code -} while (ErrorStatus==AACENC_OK); -\endcode --# Call aacEncClose() and destroy encoder instance. -\code -aacEncClose(&hAacEncoder); -\endcode - - -\section encOpen Encoder Instance Allocation - -The assignment of the aacEncOpen() function is very flexible and can be used in -the following way. -- If the amount of memory consumption is not an issue, the encoder instance can -be allocated for the maximum number of possible audio channels (for example 6 or -8) with the full functional range supported by the library. This is the default -open procedure for the AAC encoder if memory consumption does not need to be -minimized. \code aacEncOpen(&hAacEncoder,0,0) \endcode -- If the required MPEG-4 AOTs do not call for the full functional range of the -library, encoder modules can be allocated selectively. \verbatim ------------------------------------------------------- - AAC | SBR | PS | MD | FLAGS | value ------+-----+-----+----+-----------------------+------- - X | - | - | - | (0x01) | 0x01 - X | X | - | - | (0x01|0x02) | 0x03 - X | X | X | - | (0x01|0x02|0x04) | 0x07 - X | - | - | X | (0x01 |0x10) | 0x11 - X | X | - | X | (0x01|0x02 |0x10) | 0x13 - X | X | X | X | (0x01|0x02|0x04|0x10) | 0x17 ------------------------------------------------------- - - AAC: Allocate AAC Core Encoder module. - - SBR: Allocate Spectral Band Replication module. - - PS: Allocate Parametric Stereo module. - - MD: Allocate Meta Data module within AAC encoder. -\endverbatim -\code aacEncOpen(&hAacEncoder,value,0) \endcode -- Specifying the maximum number of channels to be supported in the encoder -instance can be done as follows. - - For example allocate an encoder instance which supports 2 channels for all -supported AOTs. The library itself may be capable of encoding up to 6 or 8 -channels but in this example only 2 channel encoding is required and thus only -buffers for 2 channels are allocated to save data memory. \code -aacEncOpen(&hAacEncoder,0,2) \endcode - - Additionally the maximum number of supported channels in the SBR module can -be denoted separately.\n In this example the encoder instance provides a maximum -of 6 channels out of which up to 2 channels support SBR. This encoder instance -can produce for example 5.1 channel AAC-LC streams or stereo HE-AAC (v2) -streams. HE-AAC 5.1 multi channel is not possible since only 2 out of 6 channels -support SBR, which saves data memory. \code aacEncOpen(&hAacEncoder,0,6|(2<<8)) -\endcode \n - -\section bufDes Input/Output Arguments - -\subsection allocIOBufs Provide Buffer Descriptors -In the present encoder API, the input and output buffers are described with \ref -AACENC_BufDesc "buffer descriptors". This mechanism allows a flexible handling -of input and output buffers without impact to the actual encoding call. Optional -buffers are necessary e.g. for ancillary data, meta data input or additional -output buffers describing superframing data in DAB+ or DRM+.\n At least one -input buffer for audio input data and one output buffer for bitstream data must -be allocated. The input buffer size can be a user defined multiple of the number -of input channels. PCM input data will be copied from the user defined PCM -buffer to an internal input buffer and so input data can be less than one AAC -audio frame. The output buffer size should be 6144 bits per channel excluding -the LFE channel. If the output data does not fit into the provided buffer, an -AACENC_ERROR will be returned by aacEncEncode(). \code static INT_PCM -inputBuffer[8*2048]; static UCHAR ancillaryBuffer[50]; static -AACENC_MetaData metaDataSetup; static UCHAR outputBuffer[8192]; -\endcode - -All input and output buffer must be clustered in input and output buffer arrays. -\code -static void* inBuffer[] = { inputBuffer, ancillaryBuffer, &metaDataSetup -}; static INT inBufferIds[] = { IN_AUDIO_DATA, IN_ANCILLRY_DATA, -IN_METADATA_SETUP }; static INT inBufferSize[] = { sizeof(inputBuffer), -sizeof(ancillaryBuffer), sizeof(metaDataSetup) }; static INT inBufferElSize[] -= { sizeof(INT_PCM), sizeof(UCHAR), sizeof(AACENC_MetaData) }; - -static void* outBuffer[] = { outputBuffer }; -static INT outBufferIds[] = { OUT_BITSTREAM_DATA }; -static INT outBufferSize[] = { sizeof(outputBuffer) }; -static INT outBufferElSize[] = { sizeof(UCHAR) }; -\endcode - -Allocate buffer descriptors -\code -AACENC_BufDesc inBufDesc; -AACENC_BufDesc outBufDesc; -\endcode - -Initialize input buffer descriptor -\code -inBufDesc.numBufs = sizeof(inBuffer)/sizeof(void*); -inBufDesc.bufs = (void**)&inBuffer; -inBufDesc.bufferIdentifiers = inBufferIds; -inBufDesc.bufSizes = inBufferSize; -inBufDesc.bufElSizes = inBufferElSize; -\endcode - -Initialize output buffer descriptor -\code -outBufDesc.numBufs = sizeof(outBuffer)/sizeof(void*); -outBufDesc.bufs = (void**)&outBuffer; -outBufDesc.bufferIdentifiers = outBufferIds; -outBufDesc.bufSizes = outBufferSize; -outBufDesc.bufElSizes = outBufferElSize; -\endcode - -\subsection argLists Provide Input/Output Argument Lists -The input and output arguments of an aacEncEncode() call are described in -argument structures. \code AACENC_InArgs inargs; AACENC_OutArgs outargs; -\endcode - -\section feedInBuf Feed Input Buffer -The input buffer should be handled as a modulo buffer. New audio data in the -form of pulse-code- modulated samples (PCM) must be read from external and be -fed to the input buffer depending on its fill level. The required sample bitrate -(represented by the data type INT_PCM which is 16, 24 or 32 bits wide) is fixed -and depends on library configuration (usually 16 bit). \code inargs.numInSamples -+= WAV_InputRead ( wavIn, &inputBuffer[inargs.numInSamples], - FDKmin(encInfo.inputChannels*encInfo.frameLength, - sizeof(inputBuffer) / - sizeof(INT_PCM)-inargs.numInSamples), - SAMPLE_BITS - ); -\endcode - -After the encoder's internal buffer is fed with incoming audio samples, and -aacEncEncode() processed the new input data, update/move remaining samples in -input buffer, simulating a modulo buffer: \code if (outargs.numInSamples>0) { - FDKmemmove( inputBuffer, - &inputBuffer[outargs.numInSamples], - sizeof(INT_PCM)*(inargs.numInSamples-outargs.numInSamples) ); - inargs.numInSamples -= outargs.numInSamples; -} -\endcode - -\section writeOutData Output Bitstream Data -If any AAC bitstream data is available, write it to output file or device. This -can be done once the following condition is true: \code if -(outargs.numOutBytes>0) { - -} -\endcode - -If you use file I/O then for example call mpegFileWrite_Write() from the library -libMpegFileWrite \code mpegFileWrite_Write(hMpegFile, outputBuffer, -outargs.numOutBytes, aacEncoder_GetParam(hAacEncoder, AACENC_GRANULE_LENGTH)); -\endcode - -\section cfgMetaData Meta Data Configuration - -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 -::AACENC_METADATA_MODE parameter and aacEncoder_SetParam() function. \code -aacEncoder_SetParam(hAacEncoder, AACENC_METADATA_MODE, 0-3); \endcode - -This configuration indicates how to embed meta data into bitstrem. Either no -insertion, MPEG or ETSI style. The meta data itself must be specified within the -meta data setup structure AACENC_MetaData. - -Changing one of the AACENC_MetaData setup parameters can be achieved from -outside the library within ::IN_METADATA_SETUP input buffer. There is no need to -supply meta data setup structure every frame. If there is no new meta setup data -available, the encoder uses the previous setup or the default configuration in -initial state. - -In general the audio compressor and limiter within the encoder library can be -configured with the ::AACENC_METADATA_DRC_PROFILE parameter -AACENC_MetaData::drc_profile and and AACENC_MetaData::comp_profile. -\n - -\section encReconf Encoder Reconfiguration - -The encoder library allows reconfiguration of the encoder instance with new -settings continuously between encoding frames. Each parameter to be changed must -be set with a single aacEncoder_SetParam() call. The internal status of each -parameter can be retrieved with an aacEncoder_GetParam() call.\n There is no -stand-alone reconfiguration function available. When parameters were modified -from outside the library, an internal control mechanism triggers the necessary -reconfiguration process which will be applied at the beginning of the following -aacEncEncode() call. This state can be observed from external via the -AACENC_INIT_STATUS and aacEncoder_GetParam() function. The reconfiguration -process can also be applied immediately when all parameters of an aacEncEncode() -call are NULL with a valid encoder handle.\n\n The internal reconfiguration -process can be controlled from extern with the following access. \code -aacEncoder_SetParam(hAacEncoder, AACENC_CONTROL_STATE, AACENC_CTRLFLAGS); -\endcode - - -\section encParams Encoder Parametrization - -All parameteres listed in ::AACENC_PARAM can be modified within an encoder -instance. - -\subsection encMandatory Mandatory Encoder Parameters -The following parameters must be specified when the encoder instance is -initialized. \code aacEncoder_SetParam(hAacEncoder, AACENC_AOT, value); -aacEncoder_SetParam(hAacEncoder, AACENC_BITRATE, value); -aacEncoder_SetParam(hAacEncoder, AACENC_SAMPLERATE, value); -aacEncoder_SetParam(hAacEncoder, AACENC_CHANNELMODE, value); -\endcode -Beyond that is an internal auto mode which preinitizializes the ::AACENC_BITRATE -parameter if the parameter was not set from extern. The bitrate depends on the -number of effective channels and sampling rate and is determined as follows. -\code -AAC-LC (AOT_AAC_LC): 1.5 bits per sample -HE-AAC (AOT_SBR): 0.625 bits per sample (dualrate sbr) -HE-AAC (AOT_SBR): 1.125 bits per sample (downsampled sbr) -HE-AAC v2 (AOT_PS): 0.5 bits per sample -\endcode - -\subsection channelMode Channel Mode Configuration -The input audio data is described with the ::AACENC_CHANNELMODE parameter in the -aacEncoder_SetParam() call. It is not possible to use the encoder instance with -a 'number of input channels' argument. Instead, the channelMode must be set as -follows. \code aacEncoder_SetParam(hAacEncoder, AACENC_CHANNELMODE, value); -\endcode The parameter is specified in ::CHANNEL_MODE and can be mapped from the -number of input channels in the following way. \code CHANNEL_MODE chMode = -MODE_INVALID; - -switch (nChannels) { - case 1: chMode = MODE_1; break; - case 2: chMode = MODE_2; break; - case 3: chMode = MODE_1_2; break; - case 4: chMode = MODE_1_2_1; break; - case 5: chMode = MODE_1_2_2; break; - case 6: chMode = MODE_1_2_2_1; break; - case 7: chMode = MODE_6_1; break; - case 8: chMode = MODE_7_1_BACK; break; - default: - chMode = MODE_INVALID; -} -return chMode; -\endcode - -\subsection bitreservoir Bitreservoir Configuration -In AAC, the default bitreservoir configuration depends on the chosen bitrate per -frame and the number of effective channels. The size can be determined as below. -\f[ -bitreservoir = nEffChannels*6144 - (bitrate*framelength/samplerate) -\f] -Due to audio quality concerns it is not recommended to change the bitreservoir -size to a lower value than the default setting! However, for minimizing the -delay for streaming applications or for achieving a constant size of the -bitstream packages in each frame, it may be necessaray to change the -bitreservoir size. This can be done with the ::AACENC_PEAK_BITRATE parameter. -\code -aacEncoder_SetParam(hAacEncoder, AACENC_PEAK_BITRATE, value); -\endcode -By setting ::AACENC_BITRATEMODE to fixed framing, the bitreservoir is disabled. -A disabled bitreservoir results in a constant size for each bitstream package. -Please note that especially at lower bitrates a disabled bitreservoir can -downgrade the audio quality considerably! The default bitreservoir configuration -can be achieved as follows. \code aacEncoder_SetParam(hAacEncoder, -AACENC_BITRESERVOIR, -1); \endcode - -To achieve acceptable audio quality with a reduced bitreservoir size setting at -least 1000 bits per audio channel is recommended. For a multichannel audio file -with 5.1 channels the bitreservoir reduced to 5000 bits results in acceptable -audio quality. - - -\subsection vbrmode Variable Bitrate Mode -The encoder provides various Variable Bitrate Modes that differ in audio quality -and average overall bitrate. The given values are averages over time, different -encoder settings and strongly depend on the type of audio signal. The VBR -configurations can be adjusted via ::AACENC_BITRATEMODE encoder parameter. -\verbatim --------------------------------------------- - VBR_MODE | Approx. Bitrate in kbps/channel - | AAC-LC | AAC-LD/AC_ELD -----------+---------------+----------------- - VBR_1 | 32 - 48 | 32 - 56 - VBR_2 | 40 - 56 | 40 - 64 - VBR_3 | 48 - 64 | 48 - 72 - VBR_4 | 64 - 80 | 64 - 88 - VBR_5 | 96 - 120 | 112 - 144 --------------------------------------------- -\endverbatim -The bitrate ranges apply for individual audio channels. In case of multichannel -configurations the average bitrate might be estimated by multiplying with the -number of effective channels. This corresponds to all audio input channels -exclusively the low frequency channel. At configurations which are making use of -downmix modules the AAC core channels respectively downmix channels shall be -considered. For ::AACENC_AOT which are using SBR, the average bitrate can be -estimated by using the ratio of 0.5 for dualrate SBR and 0.75 for downsampled -SBR configurations. - - -\subsection encQual Audio Quality Considerations -The default encoder configuration is suggested to be used. Encoder tools such as -TNS and PNS are activated by default and are internally controlled (see \ref -BEHAVIOUR_TOOLS). - -There is an additional quality parameter called ::AACENC_AFTERBURNER. In the -default configuration this quality switch is deactivated because it would cause -a workload increase which might be significant. If workload is not an issue in -the application we recommended to activate this feature. \code -aacEncoder_SetParam(hAacEncoder, AACENC_AFTERBURNER, 0/1); \endcode - -\subsection encELD ELD Auto Configuration Mode -For ELD configuration a so called auto configurator is available which -configures SBR and the SBR ratio by itself. The configurator is used when the -encoder parameter ::AACENC_SBR_MODE and ::AACENC_SBR_RATIO are not set -explicitly. - -Based on sampling rate and chosen bitrate a reasonable SBR configuration will be -used. \verbatim ------------------------------------------------------------------- - Sampling Rate | Total Bitrate | No. of | SBR | SBR Ratio - [kHz] | [bit/s] | Chan | | - | | | | ----------------+-----------------+--------+-----+----------------- - ]min, 16[ | min - max | 1 | off | --- ----------------+-----------------+--------------+----------------- - [16] | min - 27999 | 1 | on | downsampled SBR - | 28000 - max | 1 | off | --- ----------------+-----------------+--------------+----------------- - ]16 - 24] | min - 39999 | 1 | on | downsampled SBR - | 40000 - max | 1 | off | --- ----------------+-----------------+--------------+----------------- - ]24 - 32] | min - 27999 | 1 | on | dualrate SBR - | 28000 - 55999 | 1 | on | downsampled SBR - | 56000 - max | 1 | off | --- ----------------+-----------------+--------------+----------------- - ]32 - 44.1] | min - 63999 | 1 | on | dualrate SBR - | 64000 - max | 1 | off | --- ----------------+-----------------+--------------+----------------- - ]44.1 - 48] | min - 63999 | 1 | on | dualrate SBR - | 64000 - max | 1 | off | --- - | | | | ----------------+-----------------+--------+-----+----------------- - ]min, 16[ | min - max | 2 | off | --- ----------------+-----------------+--------------+----------------- - [16] | min - 31999 | 2 | on | downsampled SBR - | 32000 - 63999 | 2 | on | downsampled SBR - | 64000 - max | 2 | off | --- ----------------+-----------------+--------------+----------------- - ]16 - 24] | min - 47999 | 2 | on | downsampled SBR - | 48000 - 79999 | 2 | on | downsampled SBR - | 80000 - max | 2 | off | --- ----------------+-----------------+--------------+----------------- - ]24 - 32] | min - 31999 | 2 | on | dualrate SBR - | 32000 - 67999 | 2 | on | dualrate SBR - | 68000 - 95999 | 2 | on | downsampled SBR - | 96000 - max | 2 | off | --- ----------------+-----------------+--------------+----------------- - ]32 - 44.1] | min - 43999 | 2 | on | dualrate SBR - | 44000 - 127999 | 2 | on | dualrate SBR - | 128000 - max | 2 | off | --- ----------------+-----------------+--------------+----------------- - ]44.1 - 48] | min - 43999 | 2 | on | dualrate SBR - | 44000 - 127999 | 2 | on | dualrate SBR - | 128000 - max | 2 | off | --- - | | | ------------------------------------------------------------------- -\endverbatim - -\subsection encDsELD Reduced Delay (Downscaled) Mode -The downscaled mode of AAC-ELD reduces the algorithmic delay of AAC-ELD by -virtually increasing the sampling rate. When using the downscaled mode, the -bitrate should be increased for keeping the same audio quality level. For common -signals, the bitrate should be increased by 25% for a downscale factor of 2. - -Currently, downscaling factors 2 and 4 are supported. -To enable the downscaled mode in the encoder, the framelength parameter -AACENC_GRANULE_LENGTH must be set accordingly to 256 or 240 for a downscale -factor of 2 or 128 or 120 for a downscale factor of 4. The default values of 512 -or 480 mean that no downscaling is applied. \code -aacEncoder_SetParam(hAacEncoder, AACENC_GRANULE_LENGTH, 256); -aacEncoder_SetParam(hAacEncoder, AACENC_GRANULE_LENGTH, 128); -\endcode - -Downscaled bitstreams are fully backwards compatible. However, the legacy -decoder needs to support high sample rate, e.g. 96kHz. The signaled sampling -rate is multiplied by the downscale factor. Although not required, downscaling -should be applied when decoding downscaled bitstreams. It reduces CPU workload -and the output will have the same sampling rate as the input. In an ideal -configuration both encoder and decoder should run with the same downscale -factor. - -The following table shows approximate filter bank delays in ms for common -sampling rates(sr) at framesize(fs), and downscale factor(dsf), based on this -formula: \f[ 1000 * fs / (dsf * sr) \f] - -\verbatim --------------------------------------- - | 512/2 | 512/4 | 480/2 | 480/4 -------+-------+-------+-------+------- -22050 | 17.41 | 8.71 | 16.33 | 8.16 -32000 | 12.00 | 6.00 | 11.25 | 5.62 -44100 | 8.71 | 4.35 | 8.16 | 4.08 -48000 | 8.00 | 4.00 | 7.50 | 3.75 --------------------------------------- -\endverbatim - -\section audiochCfg Audio Channel Configuration -The MPEG standard refers often to the so-called Channel Configuration. This -Channel Configuration is used for a fixed Channel Mapping. The configurations -1-7 and 11,12,14 are predefined in MPEG standard and used for implicit -signalling within the encoded bitstream. For user defined Configurations the -Channel Configuration is set to 0 and the Channel Mapping must be explecitly -described with an appropriate Program Config Element. The present Encoder -implementation does not allow the user to configure this Channel Configuration -from extern. The Encoder implementation supports fixed Channel Modes which are -mapped to Channel Configuration as follow. \verbatim ----------------------------------------------------------------------------------------- - ChannelMode | ChCfg | Height | front_El | side_El | back_El | -lfe_El ------------------------+-------+--------+---------------+----------+----------+--------- -MODE_1 | 1 | NORM | SCE | | | -MODE_2 | 2 | NORM | CPE | | | -MODE_1_2 | 3 | NORM | SCE, CPE | | | -MODE_1_2_1 | 4 | NORM | SCE, CPE | | SCE | -MODE_1_2_2 | 5 | NORM | SCE, CPE | | CPE | -MODE_1_2_2_1 | 6 | NORM | SCE, CPE | | CPE | -LFE MODE_1_2_2_2_1 | 7 | NORM | SCE, CPE, CPE | | CPE -| LFE MODE_6_1 | 11 | NORM | SCE, CPE | | CPE, -SCE | LFE MODE_7_1_BACK | 12 | NORM | SCE, CPE | | -CPE, CPE | LFE ------------------------+-------+--------+---------------+----------+----------+--------- -MODE_7_1_TOP_FRONT | 14 | NORM | SCE, CPE | | CPE | -LFE | | TOP | CPE | | | ------------------------+-------+--------+---------------+----------+----------+--------- -MODE_7_1_REAR_SURROUND | 0 | NORM | SCE, CPE | | CPE, CPE | -LFE MODE_7_1_FRONT_CENTER | 0 | NORM | SCE, CPE, CPE | | CPE -| LFE ----------------------------------------------------------------------------------------- -- NORM: Normal Height Layer. - TOP: Top Height Layer. - BTM: Bottom Height -Layer. -- SCE: Single Channel Element. - CPE: Channel Pair. - LFE: Low Frequency -Element. \endverbatim - -The Table describes all fixed Channel Elements for each Channel Mode which are -assigned to a speaker arrangement. The arrangement includes front, side, back -and lfe Audio Channel Elements in the normal height layer, possibly followed by -front, side, and back elements in the top and bottom layer (Channel -Configuration 14). \n This mapping of Audio Channel Elements is defined in MPEG -standard for Channel Config 1-7 and 11,12,14.\n In case of Channel Config 0 or -writing matrix mixdown coefficients, the encoder enables the writing of Program -Config Element itself as described in \ref encPCE. The configuration used in -Program Config Element refers to the denoted Table.\n Beside the Channel Element -assignment the Channel Modes are resposible for audio input data channel -mapping. The Channel Mapping of the audio data depends on the selected -::AACENC_CHANNELORDER which can be MPEG or WAV like order.\n Following table -describes the complete channel mapping for both Channel Order configurations. -\verbatim ---------------------------------------------------------------------------------------- -ChannelMode | MPEG-Channelorder | WAV-Channelorder ------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+--- -MODE_1 | 0 | | | | | | | | 0 | | | | | | -| MODE_2 | 0 | 1 | | | | | | | 0 | 1 | | | | -| | MODE_1_2 | 0 | 1 | 2 | | | | | | 2 | 0 | 1 | | -| | | MODE_1_2_1 | 0 | 1 | 2 | 3 | | | | | 2 | 0 | 1 | 3 -| | | | MODE_1_2_2 | 0 | 1 | 2 | 3 | 4 | | | | 2 | 0 | 1 -| 3 | 4 | | | MODE_1_2_2_1 | 0 | 1 | 2 | 3 | 4 | 5 | | | 2 | 0 -| 1 | 4 | 5 | 3 | | MODE_1_2_2_2_1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 2 -| 6 | 7 | 0 | 1 | 4 | 5 | 3 MODE_6_1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | -| 2 | 0 | 1 | 4 | 5 | 6 | 3 | MODE_7_1_BACK | 0 | 1 | 2 | 3 | 4 | 5 | 6 -| 7 | 2 | 0 | 1 | 6 | 7 | 4 | 5 | 3 MODE_7_1_TOP_FRONT | 0 | 1 | 2 | 3 | 4 | -5 | 6 | 7 | 2 | 0 | 1 | 4 | 5 | 3 | 6 | 7 ------------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+--- -MODE_7_1_REAR_SURROUND | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 2 | 0 | 1 | 6 | 7 | 4 | -5 | 3 MODE_7_1_FRONT_CENTER | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 2 | 6 | 7 | 0 | 1 -| 4 | 5 | 3 ---------------------------------------------------------------------------------------- -\endverbatim - -The denoted mapping is important for correct audio channel assignment when using -MPEG or WAV ordering. The incoming audio channels are distributed MPEG like -starting at the front channels and ending at the back channels. The distribution -is used as described in Table concering Channel Config and fix channel elements. -Please see the following example for clarification. - -\verbatim -Example: MODE_1_2_2_1 - WAV-Channelorder 5.1 ------------------------------------------- - Input Channel | Coder Channel ---------------------+--------------------- - 2 (front center) | 0 (SCE channel) - 0 (left center) | 1 (1st of 1st CPE) - 1 (right center) | 2 (2nd of 1st CPE) - 4 (left surround) | 3 (1st of 2nd CPE) - 5 (right surround) | 4 (2nd of 2nd CPE) - 3 (LFE) | 5 (LFE) ------------------------------------------- -\endverbatim - - -\section suppBitrates Supported Bitrates - -The FDK AAC Encoder provides a wide range of supported bitrates. -The minimum and maximum allowed bitrate depends on the Audio Object Type. For -AAC-LC the minimum bitrate is the bitrate that is required to write the most -basic and minimal valid bitstream. It consists of the bitstream format header -information and other static/mandatory information within the AAC payload. The -maximum AAC framesize allowed by the MPEG-4 standard determines the maximum -allowed bitrate for AAC-LC. For HE-AAC and HE-AAC v2 a library internal look-up -table is used. - -A good working point in terms of audio quality, sampling rate and bitrate, is at -1 to 1.5 bits/audio sample for AAC-LC, 0.625 bits/audio sample for dualrate -HE-AAC, 1.125 bits/audio sample for downsampled HE-AAC and 0.5 bits/audio sample -for HE-AAC v2. For example for one channel with a sampling frequency of 48 kHz, -the range from 48 kbit/s to 72 kbit/s achieves reasonable audio quality for -AAC-LC. - -For HE-AAC and HE-AAC v2 the lowest possible audio input sampling frequency is -16 kHz because then the AAC-LC core encoder operates in dual rate mode at its -lowest possible sampling frequency, which is 8 kHz. HE-AAC v2 requires stereo -input audio data. - -Please note that in HE-AAC or HE-AAC v2 mode the encoder supports much higher -bitrates than are appropriate for HE-AAC or HE-AAC v2. For example, at a bitrate -of more than 64 kbit/s for a stereo audio signal at 44.1 kHz it usually makes -sense to use AAC-LC, which will produce better audio quality at that bitrate -than HE-AAC or HE-AAC v2. - -\section reommendedConfig Recommended Sampling Rate and Bitrate Combinations - -The following table provides an overview of recommended encoder configuration -parameters which we determined by virtue of numerous listening tests. - -\subsection reommendedConfigLC AAC-LC, HE-AAC, HE-AACv2 in Dualrate SBR mode. -\verbatim ------------------------------------------------------------------------------------ -Audio Object Type | Bit Rate Range | Supported | Preferred | No. -of | [bit/s] | Sampling Rates | Sampl. | Chan. | -| [kHz] | Rate | | | -| [kHz] | --------------------+------------------+-----------------------+------------+------- -AAC LC + SBR + PS | 8000 - 11999 | 22.05, 24.00 | 24.00 | 2 -AAC LC + SBR + PS | 12000 - 17999 | 32.00 | 32.00 | 2 -AAC LC + SBR + PS | 18000 - 39999 | 32.00, 44.10, 48.00 | 44.10 | 2 -AAC LC + SBR + PS | 40000 - 64000 | 32.00, 44.10, 48.00 | 48.00 | 2 --------------------+------------------+-----------------------+------------+------- -AAC LC + SBR | 8000 - 11999 | 22.05, 24.00 | 24.00 | 1 -AAC LC + SBR | 12000 - 17999 | 32.00 | 32.00 | 1 -AAC LC + SBR | 18000 - 39999 | 32.00, 44.10, 48.00 | 44.10 | 1 -AAC LC + SBR | 40000 - 64000 | 32.00, 44.10, 48.00 | 48.00 | 1 --------------------+------------------+-----------------------+------------+------- -AAC LC + SBR | 16000 - 27999 | 32.00, 44.10, 48.00 | 32.00 | 2 -AAC LC + SBR | 28000 - 63999 | 32.00, 44.10, 48.00 | 44.10 | 2 -AAC LC + SBR | 64000 - 128000 | 32.00, 44.10, 48.00 | 48.00 | 2 --------------------+------------------+-----------------------+------------+------- -AAC LC + SBR | 64000 - 69999 | 32.00, 44.10, 48.00 | 32.00 | -5, 5.1 AAC LC + SBR | 70000 - 239999 | 32.00, 44.10, 48.00 | 44.10 -| 5, 5.1 AAC LC + SBR | 240000 - 319999 | 32.00, 44.10, 48.00 | -48.00 | 5, 5.1 --------------------+------------------+-----------------------+------------+------- -AAC LC | 8000 - 15999 | 11.025, 12.00, 16.00 | 12.00 | 1 -AAC LC | 16000 - 23999 | 16.00 | 16.00 | 1 -AAC LC | 24000 - 31999 | 16.00, 22.05, 24.00 | 24.00 | 1 -AAC LC | 32000 - 55999 | 32.00 | 32.00 | 1 -AAC LC | 56000 - 160000 | 32.00, 44.10, 48.00 | 44.10 | 1 -AAC LC | 160001 - 288000 | 48.00 | 48.00 | 1 --------------------+------------------+-----------------------+------------+------- -AAC LC | 16000 - 23999 | 11.025, 12.00, 16.00 | 12.00 | 2 -AAC LC | 24000 - 31999 | 16.00 | 16.00 | 2 -AAC LC | 32000 - 39999 | 16.00, 22.05, 24.00 | 22.05 | 2 -AAC LC | 40000 - 95999 | 32.00 | 32.00 | 2 -AAC LC | 96000 - 111999 | 32.00, 44.10, 48.00 | 32.00 | 2 -AAC LC | 112000 - 320001 | 32.00, 44.10, 48.00 | 44.10 | 2 -AAC LC | 320002 - 576000 | 48.00 | 48.00 | 2 --------------------+------------------+-----------------------+------------+------- -AAC LC | 160000 - 239999 | 32.00 | 32.00 | -5, 5.1 AAC LC | 240000 - 279999 | 32.00, 44.10, 48.00 | 32.00 -| 5, 5.1 AAC LC | 280000 - 800000 | 32.00, 44.10, 48.00 | -44.10 | 5, 5.1 ------------------------------------------------------------------------------------ -\endverbatim \n - -\subsection reommendedConfigLD AAC-LD, AAC-ELD, AAC-ELD with SBR in Dualrate SBR -mode. Unlike to HE-AAC configuration the SBR is not covered by ELD audio object -type and needs to be enabled explicitly. Use ::AACENC_SBR_MODE to configure SBR -and its samplingrate ratio with ::AACENC_SBR_RATIO parameter. \verbatim ------------------------------------------------------------------------------------ -Audio Object Type | Bit Rate Range | Supported | Preferred | No. -of | [bit/s] | Sampling Rates | Sampl. | Chan. | -| [kHz] | Rate | | | -| [kHz] | --------------------+------------------+-----------------------+------------+------- -ELD + SBR | 18000 - 24999 | 32.00 - 44.10 | 32.00 | 1 -ELD + SBR | 25000 - 31999 | 32.00 - 48.00 | 32.00 | 1 -ELD + SBR | 32000 - 64000 | 32.00 - 48.00 | 48.00 | 1 --------------------+------------------+-----------------------+------------+------- -ELD + SBR | 32000 - 51999 | 32.00 - 48.00 | 44.10 | 2 -ELD + SBR | 52000 - 128000 | 32.00 - 48.00 | 48.00 | 2 --------------------+------------------+-----------------------+------------+------- -ELD + SBR | 78000 - 160000 | 32.00 - 48.00 | 48.00 | 3 --------------------+------------------+-----------------------+------------+------- -ELD + SBR | 104000 - 212000 | 32.00 - 48.00 | 48.00 | 4 --------------------+------------------+-----------------------+------------+------- -ELD + SBR | 130000 - 246000 | 32.00 - 48.00 | 48.00 | -5, 5.1 --------------------+------------------+-----------------------+------------+------- -LD, ELD | 16000 - 19999 | 16.00 - 24.00 | 16.00 | 1 -LD, ELD | 20000 - 39999 | 16.00 - 32.00 | 24.00 | 1 -LD, ELD | 40000 - 49999 | 22.05 - 32.00 | 32.00 | 1 -LD, ELD | 50000 - 61999 | 24.00 - 44.10 | 32.00 | 1 -LD, ELD | 62000 - 84999 | 32.00 - 48.00 | 44.10 | 1 -LD, ELD | 85000 - 192000 | 44.10 - 48.00 | 48.00 | 1 --------------------+------------------+-----------------------+------------+------- -LD, ELD | 64000 - 75999 | 24.00 - 32.00 | 32.00 | 2 -LD, ELD | 76000 - 97999 | 24.00 - 44.10 | 32.00 | 2 -LD, ELD | 98000 - 135999 | 32.00 - 48.00 | 44.10 | 2 -LD, ELD | 136000 - 384000 | 44.10 - 48.00 | 48.00 | 2 --------------------+------------------+-----------------------+------------+------- -LD, ELD | 96000 - 113999 | 24.00 - 32.00 | 32.00 | 3 -LD, ELD | 114000 - 146999 | 24.00 - 44.10 | 32.00 | 3 -LD, ELD | 147000 - 203999 | 32.00 - 48.00 | 44.10 | 3 -LD, ELD | 204000 - 576000 | 44.10 - 48.00 | 48.00 | 3 --------------------+------------------+-----------------------+------------+------- -LD, ELD | 128000 - 151999 | 24.00 - 32.00 | 32.00 | 4 -LD, ELD | 152000 - 195999 | 24.00 - 44.10 | 32.00 | 4 -LD, ELD | 196000 - 271999 | 32.00 - 48.00 | 44.10 | 4 -LD, ELD | 272000 - 768000 | 44.10 - 48.00 | 48.00 | 4 --------------------+------------------+-----------------------+------------+------- -LD, ELD | 160000 - 189999 | 24.00 - 32.00 | 32.00 | -5, 5.1 LD, ELD | 190000 - 244999 | 24.00 - 44.10 | 32.00 -| 5, 5.1 LD, ELD | 245000 - 339999 | 32.00 - 48.00 | -44.10 | 5, 5.1 LD, ELD | 340000 - 960000 | 44.10 - 48.00 | -48.00 | 5, 5.1 ------------------------------------------------------------------------------------ -\endverbatim \n - -\subsection reommendedConfigELD AAC-ELD with SBR in Downsampled SBR mode. -\verbatim ------------------------------------------------------------------------------------ -Audio Object Type | Bit Rate Range | Supported | Preferred | No. -of | [bit/s] | Sampling Rates | Sampl. | Chan. | -| [kHz] | Rate | | | -| [kHz] | --------------------+------------------+-----------------------+------------+------- -ELD + SBR | 18000 - 24999 | 16.00 - 22.05 | 22.05 | 1 -(downsampled SBR) | 25000 - 31999 | 16.00 - 24.00 | 24.00 | 1 - | 32000 - 47999 | 22.05 - 32.00 | 32.00 | 1 - | 48000 - 64000 | 22.05 - 48.00 | 32.00 | 1 --------------------+------------------+-----------------------+------------+------- -ELD + SBR | 32000 - 51999 | 16.00 - 24.00 | 24.00 | 2 -(downsampled SBR) | 52000 - 59999 | 22.05 - 24.00 | 24.00 | 2 - | 60000 - 95999 | 22.05 - 32.00 | 32.00 | 2 - | 96000 - 128000 | 22.05 - 48.00 | 32.00 | 2 --------------------+------------------+-----------------------+------------+------- -ELD + SBR | 78000 - 99999 | 22.05 - 24.00 | 24.00 | 3 -(downsampled SBR) | 100000 - 143999 | 22.05 - 32.00 | 32.00 | 3 - | 144000 - 159999 | 22.05 - 48.00 | 32.00 | 3 - | 160000 - 192000 | 32.00 - 48.00 | 32.00 | 3 --------------------+------------------+-----------------------+------------+------- -ELD + SBR | 104000 - 149999 | 22.05 - 24.00 | 24.00 | 4 -(downsampled SBR) | 150000 - 191999 | 22.05 - 32.00 | 32.00 | 4 - | 192000 - 211999 | 22.05 - 48.00 | 32.00 | 4 - | 212000 - 256000 | 32.00 - 48.00 | 32.00 | 4 --------------------+------------------+-----------------------+------------+------- -ELD + SBR | 130000 - 171999 | 22.05 - 24.00 | 24.00 | -5, 5.1 (downsampled SBR) | 172000 - 239999 | 22.05 - 32.00 | 32.00 -| 5, 5.1 | 240000 - 320000 | 32.00 - 48.00 | 32.00 | 5, 5.1 ------------------------------------------------------------------------------------ -\endverbatim \n - -\subsection reommendedConfigELDv2 AAC-ELD v2, AAC-ELD v2 with SBR. -The ELD v2 212 configuration must be configured explicitly with -::AACENC_CHANNELMODE parameter according MODE_212 value. SBR can be configured -separately through ::AACENC_SBR_MODE and ::AACENC_SBR_RATIO parameter. Following -configurations shall apply to both framelengths 480 and 512. For ELD v2 -configuration without SBR and framelength 480 the supported sampling rate is -restricted to the range from 16 kHz up to 24 kHz. \verbatim ------------------------------------------------------------------------------------ -Audio Object Type | Bit Rate Range | Supported | Preferred | No. -of | [bit/s] | Sampling Rates | Sampl. | Chan. | -| [kHz] | Rate | | | -| [kHz] | --------------------+------------------+-----------------------+------------+------- -ELD-212 | 16000 - 19999 | 16.00 - 24.00 | 16.00 | 2 -(without SBR) | 20000 - 39999 | 16.00 - 32.00 | 24.00 | 2 - | 40000 - 49999 | 22.05 - 32.00 | 32.00 | 2 - | 50000 - 61999 | 24.00 - 44.10 | 32.00 | 2 - | 62000 - 84999 | 32.00 - 48.00 | 44.10 | 2 - | 85000 - 192000 | 44.10 - 48.00 | 48.00 | 2 --------------------+------------------+-----------------------+------------+------- -ELD-212 + SBR | 18000 - 20999 | 32.00 | 32.00 | 2 -(dualrate SBR) | 21000 - 25999 | 32.00 - 44.10 | 32.00 | 2 - | 26000 - 31999 | 32.00 - 48.00 | 44.10 | 2 - | 32000 - 64000 | 32.00 - 48.00 | 48.00 | 2 --------------------+------------------+-----------------------+------------+------- -ELD-212 + SBR | 18000 - 19999 | 16.00 - 22.05 | 22.05 | 2 -(downsampled SBR) | 20000 - 24999 | 16.00 - 24.00 | 22.05 | 2 - | 25000 - 31999 | 16.00 - 24.00 | 24.00 | 2 - | 32000 - 64000 | 24.00 - 24.00 | 24.00 | 2 --------------------+------------------+-----------------------+------------+------- -\endverbatim \n - -\page ENCODERBEHAVIOUR Encoder Behaviour - -\section BEHAVIOUR_BANDWIDTH Bandwidth - -The FDK AAC encoder usually does not use the full frequency range of the input -signal, but restricts the bandwidth according to certain library-internal -settings. They can be changed in the table "bandWidthTable" in the file -bandwidth.cpp (if available). - -The encoder API provides the ::AACENC_BANDWIDTH parameter to adjust the -bandwidth explicitly. \code aacEncoder_SetParam(hAacEncoder, AACENC_BANDWIDTH, -value); \endcode - -However it is not recommended to change these settings, because they are based -on numerous listening tests and careful tweaks to ensure the best overall -encoding quality. Also, the maximum bandwidth that can be set manually by the -user is 20kHz or fs/2, whichever value is smaller. - -Theoretically a signal of for example 48 kHz can contain frequencies up to 24 -kHz, but to use this full range in an audio encoder usually does not make sense. -Usually the encoder has a very limited amount of bits to spend (typically 128 -kbit/s for stereo 48 kHz content) and to allow full range bandwidth would waste -a lot of these bits for frequencies the human ear is hardly able to perceive -anyway, if at all. Hence it is wise to use the available bits for the really -important frequency range and just skip the rest. At lower bitrates (e. g. <= 80 -kbit/s for stereo 48 kHz content) the encoder will choose an even smaller -bandwidth, because an encoded signal with smaller bandwidth and hence less -artifacts sounds better than a signal with higher bandwidth but then more coding -artefacts across all frequencies. These artefacts would occur if small bitrates -and high bandwidths are chosen because the available bits are just not enough to -encode all frequencies well. - -Unfortunately some people evaluate encoding quality based on possible bandwidth -as well, but it is a double-edged sword considering the trade-off described -above. - -Another aspect is workload consumption. The higher the allowed bandwidth, the -more frequency lines have to be processed, which in turn increases the workload. - -\section FRAMESIZES_AND_BIT_RESERVOIR Frame Sizes & Bit Reservoir - -For AAC there is a difference between constant bit rate and constant frame -length due to the so-called bit reservoir technique, which allows the encoder to -use less bits in an AAC frame for those audio signal sections which are easy to -encode, and then spend them at a later point in time for more complex audio -sections. The extent to which this "bit exchange" is done is limited to allow -for reliable and relatively low delay real time streaming. Therefore, for -AAC-ELD, the bitreservoir is limited. It varies between 500 and 4000 bits/frame, -depending on the bitrate/channel. -- For a bitrate of 12kbps/channel and below, the AAC-ELD bitreservoir is 500 -bits/frame. -- For a bitrate of 70kbps/channel and above, the AAC-ELD bitreservoir is 4000 -bits/frame. -- Between 12kbps/channel and 70kbps/channel, the AAC-ELD bitrervoir is increased -linearly. -- For AAC-LC, the bitrate is only limited by the maximum AAC frame length. It -is, regardless of the available bit reservoir, defined as 6144 bits per channel. - -Over a longer period in time the bitrate will be constant in the AAC constant -bitrate mode, e.g. for ISDN transmission. This means that in AAC each bitstream -frame will in general have a different length in bytes but over time it -will reach the target bitrate. - - -One could also make an MPEG compliant -AAC encoder which always produces constant length packages for each AAC frame, -but the audio quality would be considerably worse since the bit reservoir -technique would have to be switched off completely. A higher bit rate would have -to be used to get the same audio quality as with an enabled bit reservoir. - -For mp3 by the way, the same bit reservoir technique exists, but there each bit -stream frame has a constant length for a given bit rate (ignoring the -padding byte). In mp3 there is a so-called "back pointer" which tells -the decoder which bits belong to the current mp3 frame - and in general some or -many bits have been transmitted in an earlier mp3 frame. Basically this leads to -the same "bit exchange between mp3 frames" as in AAC but with virtually constant -length frames. - -This variable frame length at "constant bit rate" is not something special -in this Fraunhofer IIS AAC encoder. AAC has been designed in that way. - -\subsection BEHAVIOUR_ESTIM_AVG_FRAMESIZES Estimating Average Frame Sizes - -A HE-AAC v1 or v2 audio frame contains 2048 PCM samples per channel (there is -also one mode with 1920 samples per channel but this is only for special -purposes such as DAB+ digital radio). - -The number of HE-AAC frames \f$N\_FRAMES\f$ per second at 44.1 kHz is: - -\f[ -N\_FRAMES = 44100 / 2048 = 21.5332 -\f] - -At a bit rate of 8 kbps the average number of bits per frame -\f$N\_BITS\_PER\_FRAME\f$ is: - -\f[ -N\_BITS\_PER\_FRAME = 8000 / 21.5332 = 371.52 -\f] - -which is about 46.44 bytes per encoded frame. - -At a bit rate of 32 kbps, which is quite high for single channel HE-AAC v1, it -is: - -\f[ -N\_BITS\_PER\_FRAME = 32000 / 21.5332 = 1486 -\f] - -which is about 185.76 bytes per encoded frame. - -These bits/frame figures are average figures where each AAC frame generally has -a different size in bytes. To calculate the same for AAC-LC just use 1024 -instead of 2048 PCM samples per frame and channel. For AAC-LD/ELD it is either -480 or 512 PCM samples per frame and channel. - - -\section BEHAVIOUR_TOOLS Encoder Tools - -The AAC encoder supports TNS, PNS, MS, Intensity and activates these tools -depending on the audio signal and the encoder configuration (i.e. bitrate or -AOT). It is not required to configure these tools manually. - -PNS improves encoding quality only for certain bitrates. Therefore it makes -sense to activate PNS only for these bitrates and save the processing power -required for PNS (about 10 % of the encoder) when using other bitrates. This is -done automatically inside the encoder library. PNS is disabled inside the -encoder library if an MPEG-2 AOT is choosen since PNS is an MPEG-4 AAC feature. - -If SBR is activated, the encoder automatically deactivates PNS internally. If -TNS is disabled but PNS is allowed, the encoder deactivates PNS calculation -internally. - -*/ - -#ifndef AACENC_LIB_H -#define AACENC_LIB_H - -#include "machine_type.h" -#include "FDK_audio.h" - -#define AACENCODER_LIB_VL0 4 -#define AACENCODER_LIB_VL1 0 -#define AACENCODER_LIB_VL2 0 - -/** - * AAC encoder error codes. - */ -typedef enum { - AACENC_OK = 0x0000, /*!< No error happened. All fine. */ - - AACENC_INVALID_HANDLE = - 0x0020, /*!< Handle passed to function call was invalid. */ - AACENC_MEMORY_ERROR = 0x0021, /*!< Memory allocation failed. */ - AACENC_UNSUPPORTED_PARAMETER = 0x0022, /*!< Parameter not available. */ - AACENC_INVALID_CONFIG = 0x0023, /*!< Configuration not provided. */ - - AACENC_INIT_ERROR = 0x0040, /*!< General initialization error. */ - AACENC_INIT_AAC_ERROR = 0x0041, /*!< AAC library initialization error. */ - AACENC_INIT_SBR_ERROR = 0x0042, /*!< SBR library initialization error. */ - AACENC_INIT_TP_ERROR = 0x0043, /*!< Transport library initialization error. */ - AACENC_INIT_META_ERROR = - 0x0044, /*!< Meta data library initialization error. */ - AACENC_INIT_MPS_ERROR = 0x0045, /*!< MPS library initialization error. */ - - AACENC_ENCODE_ERROR = 0x0060, /*!< The encoding process was interrupted by an - unexpected error. */ - - AACENC_ENCODE_EOF = 0x0080 /*!< End of file reached. */ - -} AACENC_ERROR; - -/** - * AAC encoder buffer descriptors identifier. - * This identifier are used within buffer descriptors - * AACENC_BufDesc::bufferIdentifiers. - */ -typedef enum { - /* Input buffer identifier. */ - IN_AUDIO_DATA = 0, /*!< Audio input buffer, interleaved INT_PCM samples. */ - IN_ANCILLRY_DATA = 1, /*!< Ancillary data to be embedded into bitstream. */ - IN_METADATA_SETUP = 2, /*!< Setup structure for embedding meta data. */ - - /* Output buffer identifier. */ - OUT_BITSTREAM_DATA = 3, /*!< Buffer holds bitstream output data. */ - OUT_AU_SIZES = - 4 /*!< Buffer contains sizes of each access unit. This information - is necessary for superframing. */ - -} AACENC_BufferIdentifier; - -/** - * AAC encoder handle. - */ -typedef struct AACENCODER *HANDLE_AACENCODER; - -/** - * Provides some info about the encoder configuration. - */ -typedef struct { - UINT maxOutBufBytes; /*!< Maximum number of encoder bitstream bytes within one - frame. Size depends on maximum number of supported - channels in encoder instance. For superframing (as - used for example in DAB+), size has to be a multiple - accordingly. */ - - UINT maxAncBytes; /*!< Maximum number of ancillary data bytes which can be - inserted into bitstream within one frame. */ - - UINT inBufFillLevel; /*!< Internal input buffer fill level in samples per - channel. This parameter will automatically be cleared - if samplingrate or channel(Mode/Order) changes. */ - - UINT inputChannels; /*!< Number of input channels expected in encoding - process. */ - - UINT frameLength; /*!< Amount of input audio samples consumed each frame per - channel, depending on audio object type configuration. */ - - UINT nDelay; /*!< Codec delay in PCM samples/channel. Depends on framelength - and AOT. Does not include framing delay for filling up encoder - PCM input buffer. */ - - UINT nDelayCore; /*!< Codec delay in PCM samples/channel, w/o delay caused by - the decoder SBR module. This delay is needed to correctly - write edit lists for gapless playback. The decoder may not - know how much delay is introdcued by SBR, since it may not - know if SBR is active at all (implicit signaling), - therefore the deocder must take into account any delay - caused by the SBR module. */ - - UCHAR confBuf[64]; /*!< Configuration buffer in binary format as an - AudioSpecificConfig or StreamMuxConfig according to the - selected transport type. */ - - UINT confSize; /*!< Number of valid bytes in confBuf. */ - -} AACENC_InfoStruct; - -/** - * Describes the input and output buffers for an aacEncEncode() call. - */ -typedef struct { - INT numBufs; /*!< Number of buffers. */ - void **bufs; /*!< Pointer to vector containing buffer addresses. */ - INT *bufferIdentifiers; /*!< Identifier of each buffer element. See - ::AACENC_BufferIdentifier. */ - INT *bufSizes; /*!< Size of each buffer in 8-bit bytes. */ - INT *bufElSizes; /*!< Size of each buffer element in bytes. */ - -} AACENC_BufDesc; - -/** - * Defines the input arguments for an aacEncEncode() call. - */ -typedef struct { - INT numInSamples; /*!< Number of valid input audio samples (multiple of input - channels). */ - INT numAncBytes; /*!< Number of ancillary data bytes to be encoded. */ - -} AACENC_InArgs; - -/** - * Defines the output arguments for an aacEncEncode() call. - */ -typedef struct { - INT numOutBytes; /*!< Number of valid bitstream bytes generated during - aacEncEncode(). */ - INT numInSamples; /*!< Number of input audio samples consumed by the encoder. - */ - INT numAncBytes; /*!< Number of ancillary data bytes consumed by the encoder. - */ - INT bitResState; /*!< State of the bit reservoir in bits. */ - -} AACENC_OutArgs; - -/** - * Meta Data Compression Profiles. - */ -typedef enum { - AACENC_METADATA_DRC_NONE = 0, /*!< None. */ - AACENC_METADATA_DRC_FILMSTANDARD = 1, /*!< Film standard. */ - AACENC_METADATA_DRC_FILMLIGHT = 2, /*!< Film light. */ - AACENC_METADATA_DRC_MUSICSTANDARD = 3, /*!< Music standard. */ - AACENC_METADATA_DRC_MUSICLIGHT = 4, /*!< Music light. */ - AACENC_METADATA_DRC_SPEECH = 5, /*!< Speech. */ - AACENC_METADATA_DRC_NOT_PRESENT = - 256 /*!< Disable writing gain factor (used for comp_profile only). */ - -} AACENC_METADATA_DRC_PROFILE; - -/** - * Meta Data setup structure. - */ -typedef struct { - AACENC_METADATA_DRC_PROFILE - drc_profile; /*!< MPEG DRC compression profile. See - ::AACENC_METADATA_DRC_PROFILE. */ - AACENC_METADATA_DRC_PROFILE - comp_profile; /*!< ETSI heavy compression profile. See - ::AACENC_METADATA_DRC_PROFILE. */ - - INT drc_TargetRefLevel; /*!< Used to define expected level to: - Scaled with 16 bit. x*2^16. */ - INT comp_TargetRefLevel; /*!< Adjust limiter to avoid overload. - Scaled with 16 bit. x*2^16. */ - - INT prog_ref_level_present; /*!< Flag, if prog_ref_level is present */ - INT prog_ref_level; /*!< Programme Reference Level = Dialogue Level: - -31.75dB .. 0 dB ; stepsize: 0.25dB - Scaled with 16 bit. x*2^16.*/ - - UCHAR PCE_mixdown_idx_present; /*!< Flag, if dmx-idx should be written in - programme config element */ - UCHAR ETSI_DmxLvl_present; /*!< Flag, if dmx-lvl should be written in - ETSI-ancData */ - - SCHAR centerMixLevel; /*!< Center downmix level (0...7, according to table) */ - SCHAR surroundMixLevel; /*!< Surround downmix level (0...7, according to - table) */ - - UCHAR - dolbySurroundMode; /*!< Indication for Dolby Surround Encoding Mode. - - 0: Dolby Surround mode not indicated - - 1: 2-ch audio part is not Dolby surround encoded - - 2: 2-ch audio part is Dolby surround encoded */ - - UCHAR drcPresentationMode; /*!< Indicatin for DRC Presentation Mode. - - 0: Presentation mode not inticated - - 1: Presentation mode 1 - - 2: Presentation mode 2 */ - - struct { - /* extended ancillary data */ - UCHAR extAncDataEnable; /*< Indicates if MPEG4_ext_ancillary_data() exists. - - 0: No MPEG4_ext_ancillary_data(). - - 1: Insert MPEG4_ext_ancillary_data(). */ - - UCHAR - extDownmixLevelEnable; /*< Indicates if ext_downmixing_levels() exists. - - 0: No ext_downmixing_levels(). - - 1: Insert ext_downmixing_levels(). */ - UCHAR extDownmixLevel_A; /*< Downmix level index A (0...7, according to - table) */ - UCHAR extDownmixLevel_B; /*< Downmix level index B (0...7, according to - table) */ - - UCHAR dmxGainEnable; /*< Indicates if ext_downmixing_global_gains() exists. - - 0: No ext_downmixing_global_gains(). - - 1: Insert ext_downmixing_global_gains(). */ - INT dmxGain5; /*< Gain factor for downmix to 5 channels. - -15.75dB .. -15.75dB; stepsize: 0.25dB - Scaled with 16 bit. x*2^16.*/ - INT dmxGain2; /*< Gain factor for downmix to 2 channels. - -15.75dB .. -15.75dB; stepsize: 0.25dB - Scaled with 16 bit. x*2^16.*/ - - UCHAR lfeDmxEnable; /*< Indicates if ext_downmixing_lfe_level() exists. - - 0: No ext_downmixing_lfe_level(). - - 1: Insert ext_downmixing_lfe_level(). */ - UCHAR lfeDmxLevel; /*< Downmix level index for LFE (0..15, according to - table) */ - - } ExtMetaData; - -} AACENC_MetaData; - -/** - * AAC encoder control flags. - * - * In interaction with the ::AACENC_CONTROL_STATE parameter it is possible to - * get information about the internal initialization process. It is also - * possible to overwrite the internal state from extern when necessary. - */ -typedef enum { - AACENC_INIT_NONE = 0x0000, /*!< Do not trigger initialization. */ - AACENC_INIT_CONFIG = - 0x0001, /*!< Initialize all encoder modules configuration. */ - AACENC_INIT_STATES = 0x0002, /*!< Reset all encoder modules history buffer. */ - AACENC_INIT_TRANSPORT = - 0x1000, /*!< Initialize transport lib with new parameters. */ - AACENC_RESET_INBUFFER = - 0x2000, /*!< Reset fill level of internal input buffer. */ - AACENC_INIT_ALL = 0xFFFF /*!< Initialize all. */ -} AACENC_CTRLFLAGS; - -/** - * \brief AAC encoder setting parameters. - * - * Use aacEncoder_SetParam() function to configure, or use aacEncoder_GetParam() - * function to read the internal status of the following parameters. - */ -typedef enum { - AACENC_AOT = - 0x0100, /*!< Audio object type. See ::AUDIO_OBJECT_TYPE in FDK_audio.h. - - 2: MPEG-4 AAC Low Complexity. - - 5: MPEG-4 AAC Low Complexity with Spectral Band Replication - (HE-AAC). - - 29: MPEG-4 AAC Low Complexity with Spectral Band - Replication and Parametric Stereo (HE-AAC v2). This - configuration can be used only with stereo input audio data. - - 23: MPEG-4 AAC Low-Delay. - - 39: MPEG-4 AAC Enhanced Low-Delay. Since there is no - ::AUDIO_OBJECT_TYPE for ELD in combination with SBR defined, - enable SBR explicitely by ::AACENC_SBR_MODE parameter. The ELD - v2 212 configuration can be configured by ::AACENC_CHANNELMODE - parameter. - - 129: MPEG-2 AAC Low Complexity. - - 132: MPEG-2 AAC Low Complexity with Spectral Band - Replication (HE-AAC). - - Please note that the virtual MPEG-2 AOT's basically disables - non-existing Perceptual Noise Substitution tool in AAC encoder - and controls the MPEG_ID flag in adts header. The virtual - MPEG-2 AOT doesn't prohibit specific transport formats. */ - - AACENC_BITRATE = 0x0101, /*!< Total encoder bitrate. This parameter is - mandatory and interacts with ::AACENC_BITRATEMODE. - - CBR: Bitrate in bits/second. - - VBR: Variable bitrate. Bitrate argument will - be ignored. See \ref suppBitrates for details. */ - - AACENC_BITRATEMODE = 0x0102, /*!< Bitrate mode. Configuration can be different - kind of bitrate configurations: - - 0: Constant bitrate, use bitrate according - to ::AACENC_BITRATE. (default) Within none - LD/ELD ::AUDIO_OBJECT_TYPE, the CBR mode makes - use of full allowed bitreservoir. In contrast, - at Low-Delay ::AUDIO_OBJECT_TYPE the - bitreservoir is kept very small. - - 1: Variable bitrate mode, \ref vbrmode - "very low bitrate". - - 2: Variable bitrate mode, \ref vbrmode - "low bitrate". - - 3: Variable bitrate mode, \ref vbrmode - "medium bitrate". - - 4: Variable bitrate mode, \ref vbrmode - "high bitrate". - - 5: Variable bitrate mode, \ref vbrmode - "very high bitrate". */ - - AACENC_SAMPLERATE = 0x0103, /*!< Audio input data sampling rate. Encoder - supports following sampling rates: 8000, 11025, - 12000, 16000, 22050, 24000, 32000, 44100, - 48000, 64000, 88200, 96000 */ - - AACENC_SBR_MODE = 0x0104, /*!< Configure SBR independently of the chosen Audio - Object Type ::AUDIO_OBJECT_TYPE. This parameter - is for ELD audio object type only. - - -1: Use ELD SBR auto configurator (default). - - 0: Disable Spectral Band Replication. - - 1: Enable Spectral Band Replication. */ - - AACENC_GRANULE_LENGTH = - 0x0105, /*!< Core encoder (AAC) audio frame length in samples: - - 1024: Default configuration. - - 512: Default length in LD/ELD configuration. - - 480: Length in LD/ELD configuration. - - 256: Length for ELD reduced delay mode (x2). - - 240: Length for ELD reduced delay mode (x2). - - 128: Length for ELD reduced delay mode (x4). - - 120: Length for ELD reduced delay mode (x4). */ - - AACENC_CHANNELMODE = 0x0106, /*!< Set explicit channel mode. Channel mode must - match with number of input channels. - - 1-7, 11,12,14 and 33,34: MPEG channel - modes supported, see ::CHANNEL_MODE in - FDK_audio.h. */ - - AACENC_CHANNELORDER = - 0x0107, /*!< Input audio data channel ordering scheme: - - 0: MPEG channel ordering (e. g. 5.1: C, L, R, SL, SR, LFE). - (default) - - 1: WAVE file format channel ordering (e. g. 5.1: L, R, C, - LFE, SL, SR). */ - - AACENC_SBR_RATIO = - 0x0108, /*!< Controls activation of downsampled SBR. With downsampled - SBR, the delay will be shorter. On the other hand, for - achieving the same quality level, downsampled SBR needs more - bits than dual-rate SBR. With downsampled SBR, the AAC encoder - will work at the same sampling rate as the SBR encoder (single - rate). Downsampled SBR is supported for AAC-ELD and HE-AACv1. - - 1: Downsampled SBR (default for ELD). - - 2: Dual-rate SBR (default for HE-AAC). */ - - AACENC_AFTERBURNER = - 0x0200, /*!< This parameter controls the use of the afterburner feature. - The afterburner is a type of analysis by synthesis algorithm - which increases the audio quality but also the required - processing power. It is recommended to always activate this if - additional memory consumption and processing power consumption - is not a problem. If increased MHz and memory consumption are - an issue then the MHz and memory cost of this optional module - need to be evaluated against the improvement in audio quality - on a case by case basis. - - 0: Disable afterburner (default). - - 1: Enable afterburner. */ - - AACENC_BANDWIDTH = 0x0203, /*!< Core encoder audio bandwidth: - - 0: Determine audio bandwidth internally - (default, see chapter \ref BEHAVIOUR_BANDWIDTH). - - 1 to fs/2: Audio bandwidth in Hertz. Limited - to 20kHz max. Not usable if SBR is active. This - setting is for experts only, better do not touch - this value to avoid degraded audio quality. */ - - AACENC_PEAK_BITRATE = - 0x0207, /*!< Peak bitrate configuration parameter to adjust maximum bits - per audio frame. Bitrate is in bits/second. The peak bitrate - will internally be limited to the chosen bitrate - ::AACENC_BITRATE as lower limit and the - number_of_effective_channels*6144 bit as upper limit. - - Setting the peak bitrate equal to ::AACENC_BITRATE does not - necessarily mean that the audio frames will be of constant - size. Since the peak bitate is in bits/second, the frame sizes - can vary by one byte in one or the other direction over various - frames. However, it is not recommended to reduce the peak - pitrate to ::AACENC_BITRATE - it would disable the - bitreservoir, which would affect the audio quality by a large - amount. */ - - AACENC_TRANSMUX = 0x0300, /*!< Transport type to be used. See ::TRANSPORT_TYPE - in FDK_audio.h. Following types can be configured - in encoder library: - - 0: raw access units - - 1: ADIF bitstream format - - 2: ADTS bitstream format - - 6: Audio Mux Elements (LATM) with - muxConfigPresent = 1 - - 7: Audio Mux Elements (LATM) with - muxConfigPresent = 0, out of band StreamMuxConfig - - 10: Audio Sync Stream (LOAS) */ - - AACENC_HEADER_PERIOD = - 0x0301, /*!< Frame count period for sending in-band configuration buffers - within LATM/LOAS transport layer. Additionally this parameter - configures the PCE repetition period in raw_data_block(). See - \ref encPCE. - - 0xFF: auto-mode default 10 for TT_MP4_ADTS, TT_MP4_LOAS and - TT_MP4_LATM_MCP1, otherwise 0. - - n: Frame count period. */ - - AACENC_SIGNALING_MODE = - 0x0302, /*!< Signaling mode of the extension AOT: - - 0: Implicit backward compatible signaling (default for - non-MPEG-4 based AOT's and for the transport formats ADIF and - ADTS) - - A stream that uses implicit signaling can be decoded - by every AAC decoder, even AAC-LC-only decoders - - An AAC-LC-only decoder will only decode the - low-frequency part of the stream, resulting in a band-limited - output - - This method works with all transport formats - - This method does not work with downsampled SBR - - 1: Explicit backward compatible signaling - - A stream that uses explicit backward compatible - signaling can be decoded by every AAC decoder, even AAC-LC-only - decoders - - An AAC-LC-only decoder will only decode the - low-frequency part of the stream, resulting in a band-limited - output - - A decoder not capable of decoding PS will only decode - the AAC-LC+SBR part. If the stream contained PS, the result - will be a a decoded mono downmix - - This method does not work with ADIF or ADTS. For - LOAS/LATM, it only works with AudioMuxVersion==1 - - This method does work with downsampled SBR - - 2: Explicit hierarchical signaling (default for MPEG-4 - based AOT's and for all transport formats excluding ADIF and - ADTS) - - A stream that uses explicit hierarchical signaling can - be decoded only by HE-AAC decoders - - An AAC-LC-only decoder will not decode a stream that - uses explicit hierarchical signaling - - A decoder not capable of decoding PS will not decode - the stream at all if it contained PS - - This method does not work with ADIF or ADTS. It works - with LOAS/LATM and the MPEG-4 File format - - This method does work with downsampled SBR - - For making sure that the listener always experiences the - best audio quality, explicit hierarchical signaling should be - used. This makes sure that only a full HE-AAC-capable decoder - will decode those streams. The audio is played at full - bandwidth. For best backwards compatibility, it is recommended - to encode with implicit SBR signaling. A decoder capable of - AAC-LC only will then only decode the AAC part, which means the - decoded audio will sound band-limited. - - For MPEG-2 transport types (ADTS,ADIF), only implicit - signaling is possible. - - For LOAS and LATM, explicit backwards compatible signaling - only works together with AudioMuxVersion==1. The reason is - that, for explicit backwards compatible signaling, additional - information will be appended to the ASC. A decoder that is only - capable of decoding AAC-LC will skip this part. Nevertheless, - for jumping to the end of the ASC, it needs to know the ASC - length. Transmitting the length of the ASC is a feature of - AudioMuxVersion==1, it is not possible to transmit the length - of the ASC with AudioMuxVersion==0, therefore an AAC-LC-only - decoder will not be able to parse a LOAS/LATM stream that was - being encoded with AudioMuxVersion==0. - - For downsampled SBR, explicit signaling is mandatory. The - reason for this is that the extension sampling frequency (which - is in case of SBR the sampling frequqncy of the SBR part) can - only be signaled in explicit mode. - - For AAC-ELD, the SBR information is transmitted in the - ELDSpecific Config, which is part of the AudioSpecificConfig. - Therefore, the settings here will have no effect on AAC-ELD.*/ - - AACENC_TPSUBFRAMES = - 0x0303, /*!< Number of sub frames in a transport frame for LOAS/LATM or - ADTS (default 1). - - ADTS: Maximum number of sub frames restricted to 4. - - LOAS/LATM: Maximum number of sub frames restricted to 2.*/ - - AACENC_AUDIOMUXVER = - 0x0304, /*!< AudioMuxVersion to be used for LATM. (AudioMuxVersionA, - currently not implemented): - - 0: Default, no transmission of tara Buffer fullness, no ASC - length and including actual latm Buffer fullnes. - - 1: Transmission of tara Buffer fullness, ASC length and - actual latm Buffer fullness. - - 2: Transmission of tara Buffer fullness, ASC length and - maximum level of latm Buffer fullness. */ - - AACENC_PROTECTION = 0x0306, /*!< Configure protection in transport layer: - - 0: No protection. (default) - - 1: CRC active for ADTS transport format. */ - - AACENC_ANCILLARY_BITRATE = - 0x0500, /*!< Constant ancillary data bitrate in bits/second. - - 0: Either no ancillary data or insert exact number of - bytes, denoted via input parameter, numAncBytes in - AACENC_InArgs. - - else: Insert ancillary data with specified bitrate. */ - - AACENC_METADATA_MODE = 0x0600, /*!< Configure Meta Data. See ::AACENC_MetaData - for further details: - - 0: Do not embed any metadata. - - 1: Embed dynamic_range_info metadata. - - 2: Embed dynamic_range_info and - ancillary_data metadata. - - 3: Embed ancillary_data metadata. */ - - AACENC_CONTROL_STATE = - 0xFF00, /*!< There is an automatic process which internally reconfigures - the encoder instance when a configuration parameter changed or - an error occured. This paramerter allows overwriting or getting - the control status of this process. See ::AACENC_CTRLFLAGS. */ - - AACENC_NONE = 0xFFFF /*!< ------ */ - -} AACENC_PARAM; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Open an instance of the encoder. - * - * Allocate memory for an encoder instance with a functional range denoted by - * the function parameters. Preinitialize encoder instance with default - * configuration. - * - * \param phAacEncoder A pointer to an encoder handle. Initialized on return. - * \param encModules Specify encoder modules to be supported in this encoder - * instance: - * - 0x0: Allocate memory for all available encoder - * modules. - * - else: Select memory allocation regarding encoder - * modules. Following flags are possible and can be combined. - * - 0x01: AAC module. - * - 0x02: SBR module. - * - 0x04: PS module. - * - 0x08: MPS module. - * - 0x10: Metadata module. - * - example: (0x01|0x02|0x04|0x08|0x10) allocates - * all modules and is equivalent to default configuration denotet by 0x0. - * \param maxChannels Number of channels to be allocated. This parameter can - * be used in different ways: - * - 0: Allocate maximum number of AAC and SBR channels as - * supported by the library. - * - nChannels: Use same maximum number of channels for - * allocating memory in AAC and SBR module. - * - nChannels | (nSbrCh<<8): Number of SBR channels can be - * different to AAC channels to save data memory. - * - * \return - * - AACENC_OK, on succes. - * - AACENC_INVALID_HANDLE, AACENC_MEMORY_ERROR, AACENC_INVALID_CONFIG, - * on failure. - */ -AACENC_ERROR aacEncOpen(HANDLE_AACENCODER *phAacEncoder, const UINT encModules, - const UINT maxChannels); - -/** - * \brief Close the encoder instance. - * - * Deallocate encoder instance and free whole memory. - * - * \param phAacEncoder Pointer to the encoder handle to be deallocated. - * - * \return - * - AACENC_OK, on success. - * - AACENC_INVALID_HANDLE, on failure. - */ -AACENC_ERROR aacEncClose(HANDLE_AACENCODER *phAacEncoder); - -/** - * \brief Encode audio data. - * - * This function is mainly for encoding audio data. In addition the function can - * be used for an encoder (re)configuration process. - * - PCM input data will be retrieved from external input buffer until the fill - * level allows encoding a single frame. This functionality allows an external - * buffer with reduced size in comparison to the AAC or HE-AAC audio frame - * length. - * - If the value of the input samples argument is zero, just internal - * reinitialization will be applied if it is requested. - * - At the end of a file the flushing process can be triggerd via setting the - * value of the input samples argument to -1. The encoder delay lines are fully - * flushed when the encoder returns no valid bitstream data - * AACENC_OutArgs::numOutBytes. Furthermore the end of file is signaled by the - * return value AACENC_ENCODE_EOF. - * - If an error occured in the previous frame or any of the encoder parameters - * changed, an internal reinitialization process will be applied before encoding - * the incoming audio samples. - * - The function can also be used for an independent reconfiguration process - * without encoding. The first parameter has to be a valid encoder handle and - * all other parameters can be set to NULL. - * - If the size of the external bitbuffer in outBufDesc is not sufficient for - * writing the whole bitstream, an internal error will be the return value and a - * reconfiguration will be triggered. - * - * \param hAacEncoder A valid AAC encoder handle. - * \param inBufDesc Input buffer descriptor, see AACENC_BufDesc: - * - At least one input buffer with audio data is - * expected. - * - Optionally a second input buffer with - * ancillary data can be fed. - * \param outBufDesc Output buffer descriptor, see AACENC_BufDesc: - * - Provide one output buffer for the encoded - * bitstream. - * \param inargs Input arguments, see AACENC_InArgs. - * \param outargs Output arguments, AACENC_OutArgs. - * - * \return - * - AACENC_OK, on success. - * - AACENC_INVALID_HANDLE, AACENC_ENCODE_ERROR, on failure in encoding - * process. - * - AACENC_INVALID_CONFIG, AACENC_INIT_ERROR, AACENC_INIT_AAC_ERROR, - * AACENC_INIT_SBR_ERROR, AACENC_INIT_TP_ERROR, AACENC_INIT_META_ERROR, - * AACENC_INIT_MPS_ERROR, on failure in encoder initialization. - * - AACENC_UNSUPPORTED_PARAMETER, on incorrect input or output buffer - * descriptor initialization. - * - AACENC_ENCODE_EOF, when flushing fully concluded. - */ -AACENC_ERROR aacEncEncode(const HANDLE_AACENCODER hAacEncoder, - const AACENC_BufDesc *inBufDesc, - const AACENC_BufDesc *outBufDesc, - const AACENC_InArgs *inargs, AACENC_OutArgs *outargs); - -/** - * \brief Acquire info about present encoder instance. - * - * This function retrieves information of the encoder configuration. In addition - * to informative internal states, a configuration data block of the current - * encoder settings will be returned. The format is either Audio Specific Config - * in case of Raw Packets transport format or StreamMuxConfig in case of - * LOAS/LATM transport format. The configuration data block is binary coded as - * specified in ISO/IEC 14496-3 (MPEG-4 audio), to be used directly for MPEG-4 - * File Format or RFC3016 or RFC3640 applications. - * - * \param hAacEncoder A valid AAC encoder handle. - * \param pInfo Pointer to AACENC_InfoStruct. Filled on return. - * - * \return - * - AACENC_OK, on succes. - * - AACENC_INIT_ERROR, on failure. - */ -AACENC_ERROR aacEncInfo(const HANDLE_AACENCODER hAacEncoder, - AACENC_InfoStruct *pInfo); - -/** - * \brief Set one single AAC encoder parameter. - * - * This function allows configuration of all encoder parameters specified in - * ::AACENC_PARAM. Each parameter must be set with a separate function call. An - * internal validation of the configuration value range will be done and an - * internal reconfiguration will be signaled. The actual configuration adoption - * is part of the subsequent aacEncEncode() call. - * - * \param hAacEncoder A valid AAC encoder handle. - * \param param Parameter to be set. See ::AACENC_PARAM. - * \param value Parameter value. See parameter description in - * ::AACENC_PARAM. - * - * \return - * - AACENC_OK, on success. - * - AACENC_INVALID_HANDLE, AACENC_UNSUPPORTED_PARAMETER, - * AACENC_INVALID_CONFIG, on failure. - */ -AACENC_ERROR aacEncoder_SetParam(const HANDLE_AACENCODER hAacEncoder, - const AACENC_PARAM param, const UINT value); - -/** - * \brief Get one single AAC encoder parameter. - * - * This function is the complement to aacEncoder_SetParam(). After encoder - * reinitialization with user defined settings, the internal status can be - * obtained of each parameter, specified with ::AACENC_PARAM. - * - * \param hAacEncoder A valid AAC encoder handle. - * \param param Parameter to be returned. See ::AACENC_PARAM. - * - * \return Internal configuration value of specifed parameter ::AACENC_PARAM. - */ -UINT aacEncoder_GetParam(const HANDLE_AACENCODER hAacEncoder, - const AACENC_PARAM param); - -/** - * \brief Get information about encoder library build. - * - * Fill a given LIB_INFO structure with library version information. - * - * \param info Pointer to an allocated LIB_INFO struct. - * - * \return - * - AACENC_OK, on success. - * - AACENC_INVALID_HANDLE, AACENC_INIT_ERROR, on failure. - */ -AACENC_ERROR aacEncGetLibInfo(LIB_INFO *info); - -#ifdef __cplusplus -} -#endif - -#endif /* AACENC_LIB_H */ diff --git a/code/dep_codecs/include/fdk-aac/genericStds.h b/code/dep_codecs/include/fdk-aac/genericStds.h deleted file mode 100755 index 8828ba77..00000000 --- a/code/dep_codecs/include/fdk-aac/genericStds.h +++ /dev/null @@ -1,584 +0,0 @@ -/* ----------------------------------------------------------------------------- -Software License for The Fraunhofer FDK AAC Codec Library for Android - -© Copyright 1995 - 2018 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 ------------------------------------------------------------------------------ */ - -/************************* System integration library ************************** - - Author(s): - - Description: - -*******************************************************************************/ - -/** \file genericStds.h - \brief Generic Run-Time Support function wrappers and heap allocation - monitoring. - */ - -#if !defined(GENERICSTDS_H) -#define GENERICSTDS_H - -#include "machine_type.h" - -#ifndef M_PI -#define M_PI 3.14159265358979323846 /*!< Pi. Only used in example projects. */ -#endif - -/** - * Identifiers for various memory locations. They are used along with memory - * allocation functions like FDKcalloc_L() to specify the requested memory's - * location. - */ -typedef enum { - /* Internal */ - SECT_DATA_L1 = 0x2000, - SECT_DATA_L2, - SECT_DATA_L1_A, - SECT_DATA_L1_B, - SECT_CONSTDATA_L1, - - /* External */ - SECT_DATA_EXTERN = 0x4000, - SECT_CONSTDATA_EXTERN - -} MEMORY_SECTION; - -/*! \addtogroup SYSLIB_MEMORY_MACROS FDK memory macros - * - * The \c H_ prefix indicates that the macro is to be used in a header file, the - * \c C_ prefix indicates that the macro is to be used in a source file. - * - * Declaring memory areas requires to specify a unique name and a data type. - * - * For defining a memory area you require additionally one or two sizes, - * depending if the memory should be organized into one or two dimensions. - * - * The macros containing the keyword \c AALLOC instead of \c ALLOC additionally - * take care of returning aligned memory addresses (beyond the natural alignment - * of its type). The preprocesor macro - * ::ALIGNMENT_DEFAULT indicates the aligment to be used (this is hardware - * specific). - * - * The \c _L suffix indicates that the memory will be located in a specific - * section. This is useful to allocate critical memory section into fast - * internal SRAM for example. - * - * @{ - */ - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define H_ALLOC_MEM(name, type) \ - type *Get##name(int n = 0); \ - void Free##name(type **p); \ - UINT GetRequiredMem##name(void); - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define H_ALLOC_MEM_OVERLAY(name, type) \ - type *Get##name(int n = 0); \ - void Free##name(type **p); \ - UINT GetRequiredMem##name(void); - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_ALLOC_MEM(name, type, num) \ - type *Get##name(int n) { \ - FDK_ASSERT((n) == 0); \ - return ((type *)FDKcalloc(num, sizeof(type))); \ - } \ - void Free##name(type **p) { \ - if (p != NULL) { \ - FDKfree(*p); \ - *p = NULL; \ - } \ - } \ - UINT GetRequiredMem##name(void) { \ - return ALGN_SIZE_EXTRES((num) * sizeof(type)); \ - } - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_ALLOC_MEM2(name, type, n1, n2) \ - type *Get##name(int n) { \ - FDK_ASSERT((n) < (n2)); \ - return ((type *)FDKcalloc(n1, sizeof(type))); \ - } \ - void Free##name(type **p) { \ - if (p != NULL) { \ - FDKfree(*p); \ - *p = NULL; \ - } \ - } \ - UINT GetRequiredMem##name(void) { \ - return ALGN_SIZE_EXTRES((n1) * sizeof(type)) * (n2); \ - } - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_AALLOC_MEM(name, type, num) \ - type *Get##name(int n) { \ - type *ap; \ - FDK_ASSERT((n) == 0); \ - ap = ((type *)FDKaalloc((num) * sizeof(type), ALIGNMENT_DEFAULT)); \ - return ap; \ - } \ - void Free##name(type **p) { \ - if (p != NULL) { \ - FDKafree(*p); \ - *p = NULL; \ - } \ - } \ - UINT GetRequiredMem##name(void) { \ - return ALGN_SIZE_EXTRES((num) * sizeof(type) + ALIGNMENT_DEFAULT + \ - sizeof(void *)); \ - } - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_AALLOC_MEM2(name, type, n1, n2) \ - type *Get##name(int n) { \ - type *ap; \ - FDK_ASSERT((n) < (n2)); \ - ap = ((type *)FDKaalloc((n1) * sizeof(type), ALIGNMENT_DEFAULT)); \ - return ap; \ - } \ - void Free##name(type **p) { \ - if (p != NULL) { \ - FDKafree(*p); \ - *p = NULL; \ - } \ - } \ - UINT GetRequiredMem##name(void) { \ - return ALGN_SIZE_EXTRES((n1) * sizeof(type) + ALIGNMENT_DEFAULT + \ - sizeof(void *)) * \ - (n2); \ - } - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_ALLOC_MEM_L(name, type, num, s) \ - type *Get##name(int n) { \ - FDK_ASSERT((n) == 0); \ - return ((type *)FDKcalloc_L(num, sizeof(type), s)); \ - } \ - void Free##name(type **p) { \ - if (p != NULL) { \ - FDKfree_L(*p); \ - *p = NULL; \ - } \ - } \ - UINT GetRequiredMem##name(void) { \ - return ALGN_SIZE_EXTRES((num) * sizeof(type)); \ - } - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_ALLOC_MEM2_L(name, type, n1, n2, s) \ - type *Get##name(int n) { \ - FDK_ASSERT((n) < (n2)); \ - return (type *)FDKcalloc_L(n1, sizeof(type), s); \ - } \ - void Free##name(type **p) { \ - if (p != NULL) { \ - FDKfree_L(*p); \ - *p = NULL; \ - } \ - } \ - UINT GetRequiredMem##name(void) { \ - return ALGN_SIZE_EXTRES((n1) * sizeof(type)) * (n2); \ - } - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_AALLOC_MEM_L(name, type, num, s) \ - type *Get##name(int n) { \ - type *ap; \ - FDK_ASSERT((n) == 0); \ - ap = ((type *)FDKaalloc_L((num) * sizeof(type), ALIGNMENT_DEFAULT, s)); \ - return ap; \ - } \ - void Free##name(type **p) { \ - if (p != NULL) { \ - FDKafree_L(*p); \ - *p = NULL; \ - } \ - } \ - UINT GetRequiredMem##name(void) { \ - return ALGN_SIZE_EXTRES((num) * sizeof(type) + ALIGNMENT_DEFAULT + \ - sizeof(void *)); \ - } - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_AALLOC_MEM2_L(name, type, n1, n2, s) \ - type *Get##name(int n) { \ - type *ap; \ - FDK_ASSERT((n) < (n2)); \ - ap = ((type *)FDKaalloc_L((n1) * sizeof(type), ALIGNMENT_DEFAULT, s)); \ - return ap; \ - } \ - void Free##name(type **p) { \ - if (p != NULL) { \ - FDKafree_L(*p); \ - *p = NULL; \ - } \ - } \ - UINT GetRequiredMem##name(void) { \ - return ALGN_SIZE_EXTRES((n1) * sizeof(type) + ALIGNMENT_DEFAULT + \ - sizeof(void *)) * \ - (n2); \ - } - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_ALLOC_MEM_OVERLAY(name, type, num, sect, tag) \ - C_AALLOC_MEM_L(name, type, num, sect) - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_AALLOC_SCRATCH_START(name, type, n) \ - type _##name[(n) + (ALIGNMENT_DEFAULT + sizeof(type) - 1)]; \ - type *name = (type *)ALIGN_PTR(_##name); \ - C_ALLOC_ALIGNED_REGISTER(name, (n) * sizeof(type)); - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_ALLOC_SCRATCH_START(name, type, n) type name[n]; - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_AALLOC_SCRATCH_END(name, type, n) C_ALLOC_ALIGNED_UNREGISTER(name); -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_ALLOC_SCRATCH_END(name, type, n) - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_AALLOC_STACK_START(name, type, n) \ - type _##name[(n) + (ALIGNMENT_DEFAULT + sizeof(type) - 1)]; \ - type *name = (type *)ALIGN_PTR(_##name); \ - C_ALLOC_ALIGNED_REGISTER(name, (n) * sizeof(type)); - -/** See \ref SYSLIB_MEMORY_MACROS for description. */ -#define C_AALLOC_STACK_END(name, type, n) C_ALLOC_ALIGNED_UNREGISTER(name); - -/*! @} */ - -#define C_ALLOC_ALIGNED_REGISTER(x, size) -#define C_ALLOC_ALIGNED_UNREGISTER(x) -#define C_ALLOC_ALIGNED_CHECK(x) -#define C_ALLOC_ALIGNED_CHECK2(x, y) -#define FDK_showBacktrace(a, b) - -/*! \addtogroup SYSLIB_EXITCODES Unified exit codes - * Exit codes to be used as return values of FDK software test and - * demonstration applications. Not as return values of product modules and/or - * libraries. - * @{ - */ -#define FDK_EXITCODE_OK 0 /*!< Successful termination. No errors. */ -#define FDK_EXITCODE_USAGE \ - 64 /*!< The command/application was used incorrectly, e.g. with the wrong \ - number of arguments, a bad flag, a bad syntax in a parameter, or \ - whatever. */ -#define FDK_EXITCODE_DATAERROR \ - 65 /*!< The input data was incorrect in some way. This should only be used \ - for user data and not system files. */ -#define FDK_EXITCODE_NOINPUT \ - 66 /*!< An input file (not a system file) did not exist or was not readable. \ - */ -#define FDK_EXITCODE_UNAVAILABLE \ - 69 /*!< A service is unavailable. This can occur if a support program or \ - file does not exist. This can also be used as a catchall message when \ - something you wanted to do doesn't work, but you don't know why. */ -#define FDK_EXITCODE_SOFTWARE \ - 70 /*!< An internal software error has been detected. This should be limited \ - to non- operating system related errors as possible. */ -#define FDK_EXITCODE_CANTCREATE \ - 73 /*!< A (user specified) output file cannot be created. */ -#define FDK_EXITCODE_IOERROR \ - 74 /*!< An error occurred while doing I/O on some file. */ -/*! @} */ - -/*-------------------------------------------- - * Runtime support declarations - *---------------------------------------------*/ -#ifdef __cplusplus -extern "C" { -#endif - -void FDKprintf(const char *szFmt, ...); - -void FDKprintfErr(const char *szFmt, ...); - -/** Wrapper for 's getchar(). */ -int FDKgetchar(void); - -INT FDKfprintf(void *stream, const char *format, ...); -INT FDKsprintf(char *str, const char *format, ...); - -char *FDKstrchr(char *s, INT c); -const char *FDKstrstr(const char *haystack, const char *needle); -char *FDKstrcpy(char *dest, const char *src); -char *FDKstrncpy(char *dest, const char *src, const UINT n); - -#define FDK_MAX_OVERLAYS 8 /**< Maximum number of memory overlays. */ - -void *FDKcalloc(const UINT n, const UINT size); -void *FDKmalloc(const UINT size); -void FDKfree(void *ptr); - -/** - * Allocate and clear an aligned memory area. Use FDKafree() instead of - * FDKfree() for these memory areas. - * - * \param size Size of requested memory in bytes. - * \param alignment Alignment of requested memory in bytes. - * \return Pointer to allocated memory. - */ -void *FDKaalloc(const UINT size, const UINT alignment); - -/** - * Free an aligned memory area. - * - * \param ptr Pointer to be freed. - */ -void FDKafree(void *ptr); - -/** - * Allocate memory in a specific memory section. - * Requests can be made for internal or external memory. If internal memory is - * requested, FDKcalloc_L() first tries to use L1 memory, which sizes are - * defined by ::DATA_L1_A_SIZE and ::DATA_L1_B_SIZE. If no L1 memory is - * available, then FDKcalloc_L() tries to use L2 memory. If that fails as well, - * the requested memory is allocated at an extern location using the fallback - * FDKcalloc(). - * - * \param n See MSDN documentation on calloc(). - * \param size See MSDN documentation on calloc(). - * \param s Memory section. - * \return See MSDN documentation on calloc(). - */ -void *FDKcalloc_L(const UINT n, const UINT size, MEMORY_SECTION s); - -/** - * Allocate aligned memory in a specific memory section. - * See FDKcalloc_L() description for details - same applies here. - */ -void *FDKaalloc_L(const UINT size, const UINT alignment, MEMORY_SECTION s); - -/** - * Free memory that was allocated in a specific memory section. - */ -void FDKfree_L(void *ptr); - -/** - * Free aligned memory that was allocated in a specific memory section. - */ -void FDKafree_L(void *ptr); - -/** - * Copy memory. Source and destination memory must not overlap. - * Either use implementation from a Standard Library, or, if no Standard Library - * is available, a generic implementation. - * The define ::USE_BUILTIN_MEM_FUNCTIONS in genericStds.cpp controls what to - * use. The function arguments correspond to the standard memcpy(). Please see - * MSDN documentation for details on how to use it. - */ -void FDKmemcpy(void *dst, const void *src, const UINT size); - -/** - * Copy memory. Source and destination memory are allowed to overlap. - * Either use implementation from a Standard Library, or, if no Standard Library - * is available, a generic implementation. - * The define ::USE_BUILTIN_MEM_FUNCTIONS in genericStds.cpp controls what to - * use. The function arguments correspond to the standard memmove(). Please see - * MSDN documentation for details on how to use it. - */ -void FDKmemmove(void *dst, const void *src, const UINT size); - -/** - * Clear memory. - * Either use implementation from a Standard Library, or, if no Standard Library - * is available, a generic implementation. - * The define ::USE_BUILTIN_MEM_FUNCTIONS in genericStds.cpp controls what to - * use. The function arguments correspond to the standard memclear(). Please see - * MSDN documentation for details on how to use it. - */ -void FDKmemclear(void *memPtr, const UINT size); - -/** - * Fill memory with values. - * The function arguments correspond to the standard memset(). Please see MSDN - * documentation for details on how to use it. - */ -void FDKmemset(void *memPtr, const INT value, const UINT size); - -/* Compare function wrappers */ -INT FDKmemcmp(const void *s1, const void *s2, const UINT size); -INT FDKstrcmp(const char *s1, const char *s2); -INT FDKstrncmp(const char *s1, const char *s2, const UINT size); - -UINT FDKstrlen(const char *s); - -#define FDKmax(a, b) ((a) > (b) ? (a) : (b)) -#define FDKmin(a, b) ((a) < (b) ? (a) : (b)) - -#define FDK_INT_MAX ((INT)0x7FFFFFFF) -#define FDK_INT_MIN ((INT)0x80000000) - -/* FILE I/O */ - -/*! - * Check platform for endianess. - * - * \return 1 if platform is little endian, non-1 if platform is big endian. - */ -int IS_LITTLE_ENDIAN(void); - -/*! - * Convert input value to little endian format. - * - * \param val Value to be converted. It may be in both big or little endian. - * \return Value in little endian format. - */ -UINT TO_LITTLE_ENDIAN(UINT val); - -/*! - * \fn FDKFILE *FDKfopen(const char *filename, const char *mode); - * Standard fopen() wrapper. - * \fn INT FDKfclose(FDKFILE *FP); - * Standard fclose() wrapper. - * \fn INT FDKfseek(FDKFILE *FP, LONG OFFSET, int WHENCE); - * Standard fseek() wrapper. - * \fn INT FDKftell(FDKFILE *FP); - * Standard ftell() wrapper. - * \fn INT FDKfflush(FDKFILE *fp); - * Standard fflush() wrapper. - * \fn UINT FDKfwrite(const void *ptrf, INT size, UINT nmemb, FDKFILE *fp); - * Standard fwrite() wrapper. - * \fn UINT FDKfread(void *dst, INT size, UINT nmemb, FDKFILE *fp); - * Standard fread() wrapper. - */ -typedef void FDKFILE; -extern const INT FDKSEEK_SET, FDKSEEK_CUR, FDKSEEK_END; - -FDKFILE *FDKfopen(const char *filename, const char *mode); -INT FDKfclose(FDKFILE *FP); -INT FDKfseek(FDKFILE *FP, LONG OFFSET, int WHENCE); -INT FDKftell(FDKFILE *FP); -INT FDKfflush(FDKFILE *fp); -UINT FDKfwrite(const void *ptrf, INT size, UINT nmemb, FDKFILE *fp); -UINT FDKfread(void *dst, INT size, UINT nmemb, FDKFILE *fp); -char *FDKfgets(void *dst, INT size, FDKFILE *fp); -void FDKrewind(FDKFILE *fp); -INT FDKfeof(FDKFILE *fp); - -/** - * \brief Write each member in little endian order. Convert automatically - * to host endianess. - * \param ptrf Pointer to memory where to read data from. - * \param size Size of each item to be written. - * \param nmemb Number of items to be written. - * \param fp File pointer of type FDKFILE. - * \return Number of items read on success and fread() error on failure. - */ -UINT FDKfwrite_EL(const void *ptrf, INT size, UINT nmemb, FDKFILE *fp); - -/** - * \brief Read variable of size "size" as little endian. Convert - * automatically to host endianess. 4-byte alignment is enforced for 24 bit - * data, at 32 bit full scale. - * \param dst Pointer to memory where to store data into. - * \param size Size of each item to be read. - * \param nmemb Number of items to be read. - * \param fp File pointer of type FDKFILE. - * \return Number of items read on success and fread() error on failure. - */ -UINT FDKfread_EL(void *dst, INT size, UINT nmemb, FDKFILE *fp); - -/** - * \brief Print FDK software disclaimer. - */ -void FDKprintDisclaimer(void); - -#ifdef __cplusplus -} -#endif - -#endif /* GENERICSTDS_H */ diff --git a/code/dep_codecs/include/fdk-aac/machine_type.h b/code/dep_codecs/include/fdk-aac/machine_type.h deleted file mode 100755 index bd97669c..00000000 --- a/code/dep_codecs/include/fdk-aac/machine_type.h +++ /dev/null @@ -1,411 +0,0 @@ -/* ----------------------------------------------------------------------------- -Software License for The Fraunhofer FDK AAC Codec Library for Android - -© Copyright 1995 - 2018 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 ------------------------------------------------------------------------------ */ - -/************************* System integration library ************************** - - Author(s): - - Description: - -*******************************************************************************/ - -/** \file machine_type.h - * \brief Type defines for various processors and compiler tools. - */ - -#if !defined(MACHINE_TYPE_H) -#define MACHINE_TYPE_H - -#include /* Needed to define size_t */ - -#if defined(__ANDROID__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 4) && \ - (__GNUC_GNU_INLINE__ == 1) -typedef unsigned long long uint64_t; -#include -#endif - -/* Library calling convention spec. __cdecl and friends might be added here as - * required. */ -#define LINKSPEC_H -#define LINKSPEC_CPP - -/* for doxygen the following docu parts must be separated */ -/** \var SCHAR - * Data type representing at least 1 byte signed integer on all supported - * platforms. - */ -/** \var UCHAR - * Data type representing at least 1 byte unsigned integer on all - * supported platforms. - */ -/** \var INT - * Data type representing at least 4 byte signed integer on all supported - * platforms. - */ -/** \var UINT - * Data type representing at least 4 byte unsigned integer on all - * supported platforms. - */ -/** \var LONG - * Data type representing 4 byte signed integer on all supported - * platforms. - */ -/** \var ULONG - * Data type representing 4 byte unsigned integer on all supported - * platforms. - */ -/** \var SHORT - * Data type representing 2 byte signed integer on all supported - * platforms. - */ -/** \var USHORT - * Data type representing 2 byte unsigned integer on all supported - * platforms. - */ -/** \var INT64 - * Data type representing 8 byte signed integer on all supported - * platforms. - */ -/** \var UINT64 - * Data type representing 8 byte unsigned integer on all supported - * platforms. - */ -/** \def SHORT_BITS - * Number of bits the data type short represents. sizeof() is not suited - * to get this info, because a byte is not always defined as 8 bits. - */ -/** \def CHAR_BITS - * Number of bits the data type char represents. sizeof() is not suited - * to get this info, because a byte is not always defined as 8 bits. - */ -/** \var INT_PCM - * Data type representing the width of input and output PCM samples. - */ - -typedef signed int INT; -typedef unsigned int UINT; -#ifdef __LP64__ -/* force FDK long-datatypes to 4 byte */ -/* Use defines to avoid type alias problems on 64 bit machines. */ -#define LONG INT -#define ULONG UINT -#else /* __LP64__ */ -typedef signed long LONG; -typedef unsigned long ULONG; -#endif /* __LP64__ */ -typedef signed short SHORT; -typedef unsigned short USHORT; -typedef signed char SCHAR; -typedef unsigned char UCHAR; - -#define SHORT_BITS 16 -#define CHAR_BITS 8 - -/* Define 64 bit base integer type. */ -#ifdef _MSC_VER -typedef __int64 INT64; -typedef unsigned __int64 UINT64; -#else -typedef long long INT64; -typedef unsigned long long UINT64; -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#if ((defined(__i686__) || defined(__i586__) || defined(__i386__) || \ - defined(__x86_64__)) || \ - (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)))) && \ - !defined(FDK_ASSERT_ENABLE) -#define FDK_ASSERT_ENABLE -#endif - -#if defined(FDK_ASSERT_ENABLE) -#include -#define FDK_ASSERT(x) assert(x) -#else -#define FDK_ASSERT(ignore) -#endif - -typedef SHORT INT_PCM; -#define MAXVAL_PCM MAXVAL_SGL -#define MINVAL_PCM MINVAL_SGL -#define WAV_BITS 16 -#define SAMPLE_BITS 16 -#define SAMPLE_MAX ((INT_PCM)(((ULONG)1 << (SAMPLE_BITS - 1)) - 1)) -#define SAMPLE_MIN (~SAMPLE_MAX) - -/*! -* \def RAM_ALIGN -* Used to align memory as prefix before memory declaration. For example: - \code - RAM_ALIGN - int myArray[16]; - \endcode - - Note, that not all platforms support this mechanism. For example with TI -compilers a preprocessor pragma is used, but to do something like - - \code - #define RAM_ALIGN #pragma DATA_ALIGN(x) - \endcode - - would require the preprocessor to process this line twice to fully resolve -it. Hence, a fully platform-independant way to use alignment is not supported. - -* \def ALIGNMENT_DEFAULT -* Default alignment in bytes. -*/ - -#define ALIGNMENT_DEFAULT 8 - -/* RAM_ALIGN keyword causes memory alignment of global variables. */ -#if defined(_MSC_VER) -#define RAM_ALIGN __declspec(align(ALIGNMENT_DEFAULT)) -#elif defined(__GNUC__) -#define RAM_ALIGN __attribute__((aligned(ALIGNMENT_DEFAULT))) -#else -#define RAM_ALIGN -#endif - -/*! - * \def RESTRICT - * The restrict keyword is supported by some platforms and RESTRICT maps - * to either the corresponding keyword on each platform or to void if the - * compiler does not provide such feature. It tells the compiler that a - * pointer points to memory that does not overlap with other memories pointed to - * by other pointers. If this keyword is used and the assumption of no - * overlap is not true the resulting code might crash. - * - * \def WORD_ALIGNED(x) - * Tells the compiler that pointer x is 16 bit aligned. It does not cause - * the address itself to be aligned, but serves as a hint to the optimizer. The - * alignment of the pointer must be guarranteed, if not the code might - * crash. - * - * \def DWORD_ALIGNED(x) - * Tells the compiler that pointer x is 32 bit aligned. It does not cause - * the address itself to be aligned, but serves as a hint to the optimizer. The - * alignment of the pointer must be guarranteed, if not the code might - * crash. - * - */ -#define RESTRICT -#define WORD_ALIGNED(x) C_ALLOC_ALIGNED_CHECK2((const void *)(x), 2); -#define DWORD_ALIGNED(x) C_ALLOC_ALIGNED_CHECK2((const void *)(x), 4); - -/*----------------------------------------------------------------------------------- - * ALIGN_SIZE - *-----------------------------------------------------------------------------------*/ -/*! - * \brief This macro aligns a given value depending on ::ALIGNMENT_DEFAULT. - * - * For example if #ALIGNMENT_DEFAULT equals 8, then: - * - ALIGN_SIZE(3) returns 8 - * - ALIGN_SIZE(8) returns 8 - * - ALIGN_SIZE(9) returns 16 - */ -#define ALIGN_SIZE(a) \ - ((a) + (((INT)ALIGNMENT_DEFAULT - ((size_t)(a) & (ALIGNMENT_DEFAULT - 1))) & \ - (ALIGNMENT_DEFAULT - 1))) - -/*! - * \brief This macro aligns a given address depending on ::ALIGNMENT_DEFAULT. - */ -#define ALIGN_PTR(a) \ - ((void *)((unsigned char *)(a) + \ - ((((INT)ALIGNMENT_DEFAULT - \ - ((size_t)(a) & (ALIGNMENT_DEFAULT - 1))) & \ - (ALIGNMENT_DEFAULT - 1))))) - -/* Alignment macro for libSYS heap implementation */ -#define ALIGNMENT_EXTRES (ALIGNMENT_DEFAULT) -#define ALGN_SIZE_EXTRES(a) \ - ((a) + (((INT)ALIGNMENT_EXTRES - ((INT)(a) & (ALIGNMENT_EXTRES - 1))) & \ - (ALIGNMENT_EXTRES - 1))) - -/*! - * \def FDK_FORCEINLINE - * Sometimes compiler do not do what they are told to do, and in case of - * inlining some additional command might be necessary depending on the - * platform. - * - * \def FDK_INLINE - * Defines how the compiler is told to inline stuff. - */ -#ifndef FDK_FORCEINLINE -#if defined(__GNUC__) && !defined(__SDE_MIPS__) -#define FDK_FORCEINLINE inline __attribute((always_inline)) -#else -#define FDK_FORCEINLINE inline -#endif -#endif - -#define FDK_INLINE static inline - -/*! - * \def LNK_SECTION_DATA_L1 - * The LNK_SECTION_* defines allow memory to be drawn from specific memory - * sections. Used as prefix before variable declaration. - * - * \def LNK_SECTION_DATA_L2 - * See ::LNK_SECTION_DATA_L1 - * \def LNK_SECTION_L1_DATA_A - * See ::LNK_SECTION_DATA_L1 - * \def LNK_SECTION_L1_DATA_B - * See ::LNK_SECTION_DATA_L1 - * \def LNK_SECTION_CONSTDATA_L1 - * See ::LNK_SECTION_DATA_L1 - * \def LNK_SECTION_CONSTDATA - * See ::LNK_SECTION_DATA_L1 - * \def LNK_SECTION_CODE_L1 - * See ::LNK_SECTION_DATA_L1 - * \def LNK_SECTION_CODE_L2 - * See ::LNK_SECTION_DATA_L1 - * \def LNK_SECTION_INITCODE - * See ::LNK_SECTION_DATA_L1 - */ -/************************************************** - * Code Section macros - **************************************************/ -#define LNK_SECTION_CODE_L1 -#define LNK_SECTION_CODE_L2 -#define LNK_SECTION_INITCODE - -/* Memory section macros. */ - -/* default fall back */ -#define LNK_SECTION_DATA_L1 -#define LNK_SECTION_DATA_L2 -#define LNK_SECTION_CONSTDATA -#define LNK_SECTION_CONSTDATA_L1 - -#define LNK_SECTION_L1_DATA_A -#define LNK_SECTION_L1_DATA_B - -/************************************************** - * Macros regarding static code analysis - **************************************************/ -#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]] -#endif -#endif - -#ifndef FDK_FALLTHROUGH -#if defined(__GNUC__) && (__GNUC__ >= 7) -#define FDK_FALLTHROUGH __attribute__((fallthrough)) -#else -#define FDK_FALLTHROUGH -#endif -#endif - -#ifdef _MSC_VER -/* - * Sometimes certain features are excluded from compilation and therefore the - * warning 4065 may occur: "switch statement contains 'default' but no 'case' - * labels" We consider this warning irrelevant and disable it. - */ -#pragma warning(disable : 4065) -#endif - -#endif /* MACHINE_TYPE_H */ diff --git a/code/dep_codecs/include/fdk-aac/syslib_channelMapDescr.h b/code/dep_codecs/include/fdk-aac/syslib_channelMapDescr.h deleted file mode 100755 index 375a24d6..00000000 --- a/code/dep_codecs/include/fdk-aac/syslib_channelMapDescr.h +++ /dev/null @@ -1,202 +0,0 @@ -/* ----------------------------------------------------------------------------- -Software License for The Fraunhofer FDK AAC Codec Library for Android - -© Copyright 1995 - 2018 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 ------------------------------------------------------------------------------ */ - -/************************* System integration library ************************** - - Author(s): Thomas Dietzen - - Description: - -*******************************************************************************/ - -/** \file syslib_channelMapDescr.h - * \brief Function and structure declarations for the channel map descriptor implementation. - */ - -#ifndef SYSLIB_CHANNELMAPDESCR_H -#define SYSLIB_CHANNELMAPDESCR_H - -#include "machine_type.h" - -/** - * \brief Contains information needed for a single channel map. - */ -typedef struct { - const UCHAR* - pChannelMap; /*!< Actual channel mapping for one single configuration. */ - UCHAR numChannels; /*!< The number of channels for the channel map which is - the maximum used channel index+1. */ -} CHANNEL_MAP_INFO; - -/** - * \brief This is the main data struct. It contains the mapping for all - * channel configurations such as administration information. - * - * CAUTION: Do not access this structure directly from a algorithm specific - * library. Always use one of the API access functions below! - */ -typedef struct { - const CHANNEL_MAP_INFO* pMapInfoTab; /*!< Table of channel maps. */ - UINT mapInfoTabLen; /*!< Length of the channel map table array. */ - UINT fPassThrough; /*!< Flag that defines whether the specified mapping shall - be applied (value: 0) or the input just gets passed - through (MPEG mapping). */ -} FDK_channelMapDescr; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Initialize a given channel map descriptor. - * - * \param pMapDescr Pointer to a channel map descriptor to be initialized. - * \param pMapInfoTab Table of channel maps to initizalize the descriptor - with. - * If a NULL pointer is given a default table for - WAV-like mapping will be used. - * \param mapInfoTabLen Length of the channel map table array (pMapInfoTab). - If a zero length is given a default table for WAV-like mapping will be used. - * \param fPassThrough If the flag is set the reordering (given by - pMapInfoTab) will be bypassed. - */ -void FDK_chMapDescr_init(FDK_channelMapDescr* const pMapDescr, - const CHANNEL_MAP_INFO* const pMapInfoTab, - const UINT mapInfoTabLen, const UINT fPassThrough); - -/** - * \brief Change the channel reordering state of a given channel map - * descriptor. - * - * \param pMapDescr Pointer to a (initialized) channel map descriptor. - * \param fPassThrough If the flag is set the reordering (given by - * pMapInfoTab) will be bypassed. - * \return Value unequal to zero if set operation was not - * successful. And zero on success. - */ -int FDK_chMapDescr_setPassThrough(FDK_channelMapDescr* const pMapDescr, - UINT fPassThrough); - -/** - * \brief Get the mapping value for a specific channel and map index. - * - * \param pMapDescr Pointer to channel map descriptor. - * \param chIdx Channel index. - * \param mapIdx Mapping index (corresponding to the channel configuration - * index). - * \return Mapping value. - */ -UCHAR FDK_chMapDescr_getMapValue(const FDK_channelMapDescr* const pMapDescr, - const UCHAR chIdx, const UINT mapIdx); - -/** - * \brief Evaluate whether channel map descriptor is reasonable or not. - * - * \param pMapDescr Pointer to channel map descriptor. - * \return Value unequal to zero if descriptor is valid, otherwise - * zero. - */ -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 - -#endif /* !defined(SYSLIB_CHANNELMAPDESCR_H) */ diff --git a/code/dep_codecs/include/opus/opus.h b/code/dep_codecs/include/opus/opus.h deleted file mode 100755 index 0c69c627..00000000 --- a/code/dep_codecs/include/opus/opus.h +++ /dev/null @@ -1,981 +0,0 @@ -/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited - Written by Jean-Marc Valin and Koen Vos */ -/* - 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 OWNER - 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. -*/ - -/** - * @file opus.h - * @brief Opus reference implementation API - */ - -#ifndef OPUS_H -#define OPUS_H - -#include "opus_types.h" -#include "opus_defines.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @mainpage Opus - * - * The Opus codec is designed for interactive speech and audio transmission over the Internet. - * It is designed by the IETF Codec Working Group and incorporates technology from - * Skype's SILK codec and Xiph.Org's CELT codec. - * - * The Opus codec is designed to handle a wide range of interactive audio applications, - * including Voice over IP, videoconferencing, in-game chat, and even remote live music - * performances. It can scale from low bit-rate narrowband speech to very high quality - * stereo music. Its main features are: - - * @li Sampling rates from 8 to 48 kHz - * @li Bit-rates from 6 kb/s to 510 kb/s - * @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR) - * @li Audio bandwidth from narrowband to full-band - * @li Support for speech and music - * @li Support for mono and stereo - * @li Support for multichannel (up to 255 channels) - * @li Frame sizes from 2.5 ms to 60 ms - * @li Good loss robustness and packet loss concealment (PLC) - * @li Floating point and fixed-point implementation - * - * Documentation sections: - * @li @ref opus_encoder - * @li @ref opus_decoder - * @li @ref opus_repacketizer - * @li @ref opus_multistream - * @li @ref opus_libinfo - * @li @ref opus_custom - */ - -/** @defgroup opus_encoder Opus Encoder - * @{ - * - * @brief This page describes the process and functions used to encode Opus. - * - * Since Opus is a stateful codec, the encoding process starts with creating an encoder - * state. This can be done with: - * - * @code - * int error; - * OpusEncoder *enc; - * enc = opus_encoder_create(Fs, channels, application, &error); - * @endcode - * - * From this point, @c enc can be used for encoding an audio stream. An encoder state - * @b must @b not be used for more than one stream at the same time. Similarly, the encoder - * state @b must @b not be re-initialized for each frame. - * - * While opus_encoder_create() allocates memory for the state, it's also possible - * to initialize pre-allocated memory: - * - * @code - * int size; - * int error; - * OpusEncoder *enc; - * size = opus_encoder_get_size(channels); - * enc = malloc(size); - * error = opus_encoder_init(enc, Fs, channels, application); - * @endcode - * - * where opus_encoder_get_size() returns the required size for the encoder state. Note that - * future versions of this code may change the size, so no assuptions should be made about it. - * - * The encoder state is always continuous in memory and only a shallow copy is sufficient - * to copy it (e.g. memcpy()) - * - * It is possible to change some of the encoder's settings using the opus_encoder_ctl() - * interface. All these settings already default to the recommended value, so they should - * only be changed when necessary. The most common settings one may want to change are: - * - * @code - * opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate)); - * opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); - * opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type)); - * @endcode - * - * where - * - * @arg bitrate is in bits per second (b/s) - * @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest - * @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC - * - * See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream. - * - * To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data: - * @code - * len = opus_encode(enc, audio_frame, frame_size, packet, max_packet); - * @endcode - * - * where - *
    - *
  • audio_frame is the audio data in opus_int16 (or float for opus_encode_float())
  • - *
  • frame_size is the duration of the frame in samples (per channel)
  • - *
  • packet is the byte array to which the compressed data is written
  • - *
  • max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended). - * Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.
  • - *
- * - * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet. - * The return value can be negative, which indicates that an error has occurred. If the return value - * is 2 bytes or less, then the packet does not need to be transmitted (DTX). - * - * Once the encoder state if no longer needed, it can be destroyed with - * - * @code - * opus_encoder_destroy(enc); - * @endcode - * - * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(), - * then no action is required aside from potentially freeing the memory that was manually - * allocated for it (calling free(enc) for the example above) - * - */ - -/** Opus encoder state. - * This contains the complete state of an Opus encoder. - * It is position independent and can be freely copied. - * @see opus_encoder_create,opus_encoder_init - */ -typedef struct OpusEncoder OpusEncoder; - -/** Gets the size of an OpusEncoder structure. - * @param[in] channels int: Number of channels. - * This must be 1 or 2. - * @returns The size in bytes. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels); - -/** - */ - -/** Allocates and initializes an encoder state. - * There are three coding modes: - * - * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice - * signals. It enhances the input signal by high-pass filtering and - * emphasizing formants and harmonics. Optionally it includes in-band - * forward error correction to protect against packet loss. Use this - * mode for typical VoIP applications. Because of the enhancement, - * even at high bitrates the output may sound different from the input. - * - * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most - * non-voice signals like music. Use this mode for music and mixed - * (music/voice) content, broadcast, and applications requiring less - * than 15 ms of coding delay. - * - * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that - * disables the speech-optimized mode in exchange for slightly reduced delay. - * This mode can only be set on an newly initialized or freshly reset encoder - * because it changes the codec delay. - * - * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution). - * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param [in] channels int: Number of channels (1 or 2) in input signal - * @param [in] application int: Coding mode (one of @ref OPUS_APPLICATION_VOIP, @ref OPUS_APPLICATION_AUDIO, or @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY) - * @param [out] error int*: @ref opus_errorcodes - * @note Regardless of the sampling rate and number channels selected, the Opus encoder - * can switch to a lower audio bandwidth or number of channels if the bitrate - * selected is too low. This also means that it is safe to always use 48 kHz stereo input - * and let the encoder optimize the encoding. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create( - opus_int32 Fs, - int channels, - int application, - int *error -); - -/** Initializes a previously allocated encoder state - * The memory pointed to by st must be at least the size returned by opus_encoder_get_size(). - * This is intended for applications which use their own allocator instead of malloc. - * @see opus_encoder_create(),opus_encoder_get_size() - * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. - * @param [in] st OpusEncoder*: Encoder state - * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param [in] channels int: Number of channels (1 or 2) in input signal - * @param [in] application int: Coding mode (one of OPUS_APPLICATION_VOIP, OPUS_APPLICATION_AUDIO, or OPUS_APPLICATION_RESTRICTED_LOWDELAY) - * @retval #OPUS_OK Success or @ref opus_errorcodes - */ -OPUS_EXPORT int opus_encoder_init( - OpusEncoder *st, - opus_int32 Fs, - int channels, - int application -) OPUS_ARG_NONNULL(1); - -/** Encodes an Opus frame. - * @param [in] st OpusEncoder*: Encoder state - * @param [in] pcm opus_int16*: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16) - * @param [in] frame_size int: Number of samples per channel in the - * input signal. - * This must be an Opus frame size for - * the encoder's sampling rate. - * For example, at 48 kHz the permitted - * values are 120, 240, 480, 960, 1920, - * and 2880. - * Passing in a duration of less than - * 10 ms (480 samples at 48 kHz) will - * prevent the encoder from using the LPC - * or hybrid modes. - * @param [out] data unsigned char*: Output payload. - * This must contain storage for at - * least \a max_data_bytes. - * @param [in] max_data_bytes opus_int32: Size of the allocated - * memory for the output - * payload. This may be - * used to impose an upper limit on - * the instant bitrate, but should - * not be used as the only bitrate - * control. Use #OPUS_SET_BITRATE to - * control the bitrate. - * @returns The length of the encoded packet (in bytes) on success or a - * negative error code (see @ref opus_errorcodes) on failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode( - OpusEncoder *st, - const opus_int16 *pcm, - int frame_size, - unsigned char *data, - opus_int32 max_data_bytes -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); - -/** Encodes an Opus frame from floating point input. - * @param [in] st OpusEncoder*: Encoder state - * @param [in] pcm float*: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0. - * Samples with a range beyond +/-1.0 are supported but will - * be clipped by decoders using the integer API and should - * only be used if it is known that the far end supports - * extended dynamic range. - * length is frame_size*channels*sizeof(float) - * @param [in] frame_size int: Number of samples per channel in the - * input signal. - * This must be an Opus frame size for - * the encoder's sampling rate. - * For example, at 48 kHz the permitted - * values are 120, 240, 480, 960, 1920, - * and 2880. - * Passing in a duration of less than - * 10 ms (480 samples at 48 kHz) will - * prevent the encoder from using the LPC - * or hybrid modes. - * @param [out] data unsigned char*: Output payload. - * This must contain storage for at - * least \a max_data_bytes. - * @param [in] max_data_bytes opus_int32: Size of the allocated - * memory for the output - * payload. This may be - * used to impose an upper limit on - * the instant bitrate, but should - * not be used as the only bitrate - * control. Use #OPUS_SET_BITRATE to - * control the bitrate. - * @returns The length of the encoded packet (in bytes) on success or a - * negative error code (see @ref opus_errorcodes) on failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float( - OpusEncoder *st, - const float *pcm, - int frame_size, - unsigned char *data, - opus_int32 max_data_bytes -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); - -/** Frees an OpusEncoder allocated by opus_encoder_create(). - * @param[in] st OpusEncoder*: State to be freed. - */ -OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st); - -/** Perform a CTL function on an Opus encoder. - * - * Generally the request and subsequent arguments are generated - * by a convenience macro. - * @param st OpusEncoder*: Encoder state. - * @param request This and all remaining parameters should be replaced by one - * of the convenience macros in @ref opus_genericctls or - * @ref opus_encoderctls. - * @see opus_genericctls - * @see opus_encoderctls - */ -OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); -/**@}*/ - -/** @defgroup opus_decoder Opus Decoder - * @{ - * - * @brief This page describes the process and functions used to decode Opus. - * - * The decoding process also starts with creating a decoder - * state. This can be done with: - * @code - * int error; - * OpusDecoder *dec; - * dec = opus_decoder_create(Fs, channels, &error); - * @endcode - * where - * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000 - * @li channels is the number of channels (1 or 2) - * @li error will hold the error code in case of failure (or #OPUS_OK on success) - * @li the return value is a newly created decoder state to be used for decoding - * - * While opus_decoder_create() allocates memory for the state, it's also possible - * to initialize pre-allocated memory: - * @code - * int size; - * int error; - * OpusDecoder *dec; - * size = opus_decoder_get_size(channels); - * dec = malloc(size); - * error = opus_decoder_init(dec, Fs, channels); - * @endcode - * where opus_decoder_get_size() returns the required size for the decoder state. Note that - * future versions of this code may change the size, so no assuptions should be made about it. - * - * The decoder state is always continuous in memory and only a shallow copy is sufficient - * to copy it (e.g. memcpy()) - * - * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data: - * @code - * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0); - * @endcode - * where - * - * @li packet is the byte array containing the compressed data - * @li len is the exact number of bytes contained in the packet - * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float()) - * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array - * - * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet. - * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio - * buffer is too small to hold the decoded audio. - * - * Opus is a stateful codec with overlapping blocks and as a result Opus - * packets are not coded independently of each other. Packets must be - * passed into the decoder serially and in the correct order for a correct - * decode. Lost packets can be replaced with loss concealment by calling - * the decoder with a null pointer and zero length for the missing packet. - * - * A single codec state may only be accessed from a single thread at - * a time and any required locking must be performed by the caller. Separate - * streams must be decoded with separate decoder states and can be decoded - * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK - * defined. - * - */ - -/** Opus decoder state. - * This contains the complete state of an Opus decoder. - * It is position independent and can be freely copied. - * @see opus_decoder_create,opus_decoder_init - */ -typedef struct OpusDecoder OpusDecoder; - -/** Gets the size of an OpusDecoder structure. - * @param [in] channels int: Number of channels. - * This must be 1 or 2. - * @returns The size in bytes. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels); - -/** Allocates and initializes a decoder state. - * @param [in] Fs opus_int32: Sample rate to decode at (Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param [in] channels int: Number of channels (1 or 2) to decode - * @param [out] error int*: #OPUS_OK Success or @ref opus_errorcodes - * - * Internally Opus stores data at 48000 Hz, so that should be the default - * value for Fs. However, the decoder can efficiently decode to buffers - * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use - * data at the full sample rate, or knows the compressed data doesn't - * use the full frequency range, it can request decoding at a reduced - * rate. Likewise, the decoder is capable of filling in either mono or - * interleaved stereo pcm buffers, at the caller's request. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create( - opus_int32 Fs, - int channels, - int *error -); - -/** Initializes a previously allocated decoder state. - * The state must be at least the size returned by opus_decoder_get_size(). - * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size - * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. - * @param [in] st OpusDecoder*: Decoder state. - * @param [in] Fs opus_int32: Sampling rate to decode to (Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param [in] channels int: Number of channels (1 or 2) to decode - * @retval #OPUS_OK Success or @ref opus_errorcodes - */ -OPUS_EXPORT int opus_decoder_init( - OpusDecoder *st, - opus_int32 Fs, - int channels -) OPUS_ARG_NONNULL(1); - -/** Decode an Opus packet. - * @param [in] st OpusDecoder*: Decoder state - * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss - * @param [in] len opus_int32: Number of bytes in payload* - * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length - * is frame_size*channels*sizeof(opus_int16) - * @param [in] frame_size Number of samples per channel of available space in \a pcm. - * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will - * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), - * then frame_size needs to be exactly the duration of audio that is missing, otherwise the - * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and - * FEC cases, frame_size must be a multiple of 2.5 ms. - * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be - * decoded. If no such data is available, the frame is decoded as if it were lost. - * @returns Number of decoded samples or @ref opus_errorcodes - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode( - OpusDecoder *st, - const unsigned char *data, - opus_int32 len, - opus_int16 *pcm, - int frame_size, - int decode_fec -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); - -/** Decode an Opus packet with floating point output. - * @param [in] st OpusDecoder*: Decoder state - * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss - * @param [in] len opus_int32: Number of bytes in payload - * @param [out] pcm float*: Output signal (interleaved if 2 channels). length - * is frame_size*channels*sizeof(float) - * @param [in] frame_size Number of samples per channel of available space in \a pcm. - * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will - * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), - * then frame_size needs to be exactly the duration of audio that is missing, otherwise the - * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and - * FEC cases, frame_size must be a multiple of 2.5 ms. - * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be - * decoded. If no such data is available the frame is decoded as if it were lost. - * @returns Number of decoded samples or @ref opus_errorcodes - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float( - OpusDecoder *st, - const unsigned char *data, - opus_int32 len, - float *pcm, - int frame_size, - int decode_fec -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); - -/** Perform a CTL function on an Opus decoder. - * - * Generally the request and subsequent arguments are generated - * by a convenience macro. - * @param st OpusDecoder*: Decoder state. - * @param request This and all remaining parameters should be replaced by one - * of the convenience macros in @ref opus_genericctls or - * @ref opus_decoderctls. - * @see opus_genericctls - * @see opus_decoderctls - */ -OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); - -/** Frees an OpusDecoder allocated by opus_decoder_create(). - * @param[in] st OpusDecoder*: State to be freed. - */ -OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st); - -/** Parse an opus packet into one or more frames. - * Opus_decode will perform this operation internally so most applications do - * not need to use this function. - * This function does not copy the frames, the returned pointers are pointers into - * the input packet. - * @param [in] data char*: Opus packet to be parsed - * @param [in] len opus_int32: size of data - * @param [out] out_toc char*: TOC pointer - * @param [out] frames char*[48] encapsulated frames - * @param [out] size opus_int16[48] sizes of the encapsulated frames - * @param [out] payload_offset int*: returns the position of the payload within the packet (in bytes) - * @returns number of frames - */ -OPUS_EXPORT int opus_packet_parse( - const unsigned char *data, - opus_int32 len, - unsigned char *out_toc, - const unsigned char *frames[48], - opus_int16 size[48], - int *payload_offset -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5); - -/** Gets the bandwidth of an Opus packet. - * @param [in] data char*: Opus packet - * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass) - * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass) - * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass) - * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass) - * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass) - * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1); - -/** Gets the number of samples per frame from an Opus packet. - * @param [in] data char*: Opus packet. - * This must contain at least one byte of - * data. - * @param [in] Fs opus_int32: Sampling rate in Hz. - * This must be a multiple of 400, or - * inaccurate results will be returned. - * @returns Number of samples per frame. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1); - -/** Gets the number of channels from an Opus packet. - * @param [in] data char*: Opus packet - * @returns Number of channels - * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1); - -/** Gets the number of frames in an Opus packet. - * @param [in] packet char*: Opus packet - * @param [in] len opus_int32: Length of packet - * @returns Number of frames - * @retval OPUS_BAD_ARG Insufficient data was passed to the function - * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1); - -/** Gets the number of samples of an Opus packet. - * @param [in] packet char*: Opus packet - * @param [in] len opus_int32: Length of packet - * @param [in] Fs opus_int32: Sampling rate in Hz. - * This must be a multiple of 400, or - * inaccurate results will be returned. - * @returns Number of samples - * @retval OPUS_BAD_ARG Insufficient data was passed to the function - * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1); - -/** Gets the number of samples of an Opus packet. - * @param [in] dec OpusDecoder*: Decoder state - * @param [in] packet char*: Opus packet - * @param [in] len opus_int32: Length of packet - * @returns Number of samples - * @retval OPUS_BAD_ARG Insufficient data was passed to the function - * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); - -/** Applies soft-clipping to bring a float signal within the [-1,1] range. If - * the signal is already in that range, nothing is done. If there are values - * outside of [-1,1], then the signal is clipped as smoothly as possible to - * both fit in the range and avoid creating excessive distortion in the - * process. - * @param [in,out] pcm float*: Input PCM and modified PCM - * @param [in] frame_size int Number of samples per channel to process - * @param [in] channels int: Number of channels - * @param [in,out] softclip_mem float*: State memory for the soft clipping process (one float per channel, initialized to zero) - */ -OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem); - - -/**@}*/ - -/** @defgroup opus_repacketizer Repacketizer - * @{ - * - * The repacketizer can be used to merge multiple Opus packets into a single - * packet or alternatively to split Opus packets that have previously been - * merged. Splitting valid Opus packets is always guaranteed to succeed, - * whereas merging valid packets only succeeds if all frames have the same - * mode, bandwidth, and frame size, and when the total duration of the merged - * packet is no more than 120 ms. The 120 ms limit comes from the - * specification and limits decoder memory requirements at a point where - * framing overhead becomes negligible. - * - * The repacketizer currently only operates on elementary Opus - * streams. It will not manipualte multistream packets successfully, except in - * the degenerate case where they consist of data from a single stream. - * - * The repacketizing process starts with creating a repacketizer state, either - * by calling opus_repacketizer_create() or by allocating the memory yourself, - * e.g., - * @code - * OpusRepacketizer *rp; - * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size()); - * if (rp != NULL) - * opus_repacketizer_init(rp); - * @endcode - * - * Then the application should submit packets with opus_repacketizer_cat(), - * extract new packets with opus_repacketizer_out() or - * opus_repacketizer_out_range(), and then reset the state for the next set of - * input packets via opus_repacketizer_init(). - * - * For example, to split a sequence of packets into individual frames: - * @code - * unsigned char *data; - * int len; - * while (get_next_packet(&data, &len)) - * { - * unsigned char out[1276]; - * opus_int32 out_len; - * int nb_frames; - * int err; - * int i; - * err = opus_repacketizer_cat(rp, data, len); - * if (err != OPUS_OK) - * { - * release_packet(data); - * return err; - * } - * nb_frames = opus_repacketizer_get_nb_frames(rp); - * for (i = 0; i < nb_frames; i++) - * { - * out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out)); - * if (out_len < 0) - * { - * release_packet(data); - * return (int)out_len; - * } - * output_next_packet(out, out_len); - * } - * opus_repacketizer_init(rp); - * release_packet(data); - * } - * @endcode - * - * Alternatively, to combine a sequence of frames into packets that each - * contain up to TARGET_DURATION_MS milliseconds of data: - * @code - * // The maximum number of packets with duration TARGET_DURATION_MS occurs - * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5) - * // packets. - * unsigned char *data[(TARGET_DURATION_MS*2/5)+1]; - * opus_int32 len[(TARGET_DURATION_MS*2/5)+1]; - * int nb_packets; - * unsigned char out[1277*(TARGET_DURATION_MS*2/2)]; - * opus_int32 out_len; - * int prev_toc; - * nb_packets = 0; - * while (get_next_packet(data+nb_packets, len+nb_packets)) - * { - * int nb_frames; - * int err; - * nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]); - * if (nb_frames < 1) - * { - * release_packets(data, nb_packets+1); - * return nb_frames; - * } - * nb_frames += opus_repacketizer_get_nb_frames(rp); - * // If adding the next packet would exceed our target, or it has an - * // incompatible TOC sequence, output the packets we already have before - * // submitting it. - * // N.B., The nb_packets > 0 check ensures we've submitted at least one - * // packet since the last call to opus_repacketizer_init(). Otherwise a - * // single packet longer than TARGET_DURATION_MS would cause us to try to - * // output an (invalid) empty packet. It also ensures that prev_toc has - * // been set to a valid value. Additionally, len[nb_packets] > 0 is - * // guaranteed by the call to opus_packet_get_nb_frames() above, so the - * // reference to data[nb_packets][0] should be valid. - * if (nb_packets > 0 && ( - * ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) || - * opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames > - * TARGET_DURATION_MS*48)) - * { - * out_len = opus_repacketizer_out(rp, out, sizeof(out)); - * if (out_len < 0) - * { - * release_packets(data, nb_packets+1); - * return (int)out_len; - * } - * output_next_packet(out, out_len); - * opus_repacketizer_init(rp); - * release_packets(data, nb_packets); - * data[0] = data[nb_packets]; - * len[0] = len[nb_packets]; - * nb_packets = 0; - * } - * err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]); - * if (err != OPUS_OK) - * { - * release_packets(data, nb_packets+1); - * return err; - * } - * prev_toc = data[nb_packets][0]; - * nb_packets++; - * } - * // Output the final, partial packet. - * if (nb_packets > 0) - * { - * out_len = opus_repacketizer_out(rp, out, sizeof(out)); - * release_packets(data, nb_packets); - * if (out_len < 0) - * return (int)out_len; - * output_next_packet(out, out_len); - * } - * @endcode - * - * An alternate way of merging packets is to simply call opus_repacketizer_cat() - * unconditionally until it fails. At that point, the merged packet can be - * obtained with opus_repacketizer_out() and the input packet for which - * opus_repacketizer_cat() needs to be re-added to a newly reinitialized - * repacketizer state. - */ - -typedef struct OpusRepacketizer OpusRepacketizer; - -/** Gets the size of an OpusRepacketizer structure. - * @returns The size in bytes. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void); - -/** (Re)initializes a previously allocated repacketizer state. - * The state must be at least the size returned by opus_repacketizer_get_size(). - * This can be used for applications which use their own allocator instead of - * malloc(). - * It must also be called to reset the queue of packets waiting to be - * repacketized, which is necessary if the maximum packet duration of 120 ms - * is reached or if you wish to submit packets with a different Opus - * configuration (coding mode, audio bandwidth, frame size, or channel count). - * Failure to do so will prevent a new packet from being added with - * opus_repacketizer_cat(). - * @see opus_repacketizer_create - * @see opus_repacketizer_get_size - * @see opus_repacketizer_cat - * @param rp OpusRepacketizer*: The repacketizer state to - * (re)initialize. - * @returns A pointer to the same repacketizer state that was passed in. - */ -OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); - -/** Allocates memory and initializes the new repacketizer with - * opus_repacketizer_init(). - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void); - -/** Frees an OpusRepacketizer allocated by - * opus_repacketizer_create(). - * @param[in] rp OpusRepacketizer*: State to be freed. - */ -OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp); - -/** Add a packet to the current repacketizer state. - * This packet must match the configuration of any packets already submitted - * for repacketization since the last call to opus_repacketizer_init(). - * This means that it must have the same coding mode, audio bandwidth, frame - * size, and channel count. - * This can be checked in advance by examining the top 6 bits of the first - * byte of the packet, and ensuring they match the top 6 bits of the first - * byte of any previously submitted packet. - * The total duration of audio in the repacketizer state also must not exceed - * 120 ms, the maximum duration of a single packet, after adding this packet. - * - * The contents of the current repacketizer state can be extracted into new - * packets using opus_repacketizer_out() or opus_repacketizer_out_range(). - * - * In order to add a packet with a different configuration or to add more - * audio beyond 120 ms, you must clear the repacketizer state by calling - * opus_repacketizer_init(). - * If a packet is too large to add to the current repacketizer state, no part - * of it is added, even if it contains multiple frames, some of which might - * fit. - * If you wish to be able to add parts of such packets, you should first use - * another repacketizer to split the packet into pieces and add them - * individually. - * @see opus_repacketizer_out_range - * @see opus_repacketizer_out - * @see opus_repacketizer_init - * @param rp OpusRepacketizer*: The repacketizer state to which to - * add the packet. - * @param[in] data const unsigned char*: The packet data. - * The application must ensure - * this pointer remains valid - * until the next call to - * opus_repacketizer_init() or - * opus_repacketizer_destroy(). - * @param len opus_int32: The number of bytes in the packet data. - * @returns An error code indicating whether or not the operation succeeded. - * @retval #OPUS_OK The packet's contents have been added to the repacketizer - * state. - * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence, - * the packet's TOC sequence was not compatible - * with previously submitted packets (because - * the coding mode, audio bandwidth, frame size, - * or channel count did not match), or adding - * this packet would increase the total amount of - * audio stored in the repacketizer state to more - * than 120 ms. - */ -OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); - - -/** Construct a new packet from data previously submitted to the repacketizer - * state via opus_repacketizer_cat(). - * @param rp OpusRepacketizer*: The repacketizer state from which to - * construct the new packet. - * @param begin int: The index of the first frame in the current - * repacketizer state to include in the output. - * @param end int: One past the index of the last frame in the - * current repacketizer state to include in the - * output. - * @param[out] data const unsigned char*: The buffer in which to - * store the output packet. - * @param maxlen opus_int32: The maximum number of bytes to store in - * the output buffer. In order to guarantee - * success, this should be at least - * 1276 for a single frame, - * or for multiple frames, - * 1277*(end-begin). - * However, 1*(end-begin) plus - * the size of all packet data submitted to - * the repacketizer since the last call to - * opus_repacketizer_init() or - * opus_repacketizer_create() is also - * sufficient, and possibly much smaller. - * @returns The total size of the output packet on success, or an error code - * on failure. - * @retval #OPUS_BAD_ARG [begin,end) was an invalid range of - * frames (begin < 0, begin >= end, or end > - * opus_repacketizer_get_nb_frames()). - * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the - * complete output packet. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); - -/** Return the total number of frames contained in packet data submitted to - * the repacketizer state so far via opus_repacketizer_cat() since the last - * call to opus_repacketizer_init() or opus_repacketizer_create(). - * This defines the valid range of packets that can be extracted with - * opus_repacketizer_out_range() or opus_repacketizer_out(). - * @param rp OpusRepacketizer*: The repacketizer state containing the - * frames. - * @returns The total number of frames contained in the packet data submitted - * to the repacketizer state. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); - -/** Construct a new packet from data previously submitted to the repacketizer - * state via opus_repacketizer_cat(). - * This is a convenience routine that returns all the data submitted so far - * in a single packet. - * It is equivalent to calling - * @code - * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp), - * data, maxlen) - * @endcode - * @param rp OpusRepacketizer*: The repacketizer state from which to - * construct the new packet. - * @param[out] data const unsigned char*: The buffer in which to - * store the output packet. - * @param maxlen opus_int32: The maximum number of bytes to store in - * the output buffer. In order to guarantee - * success, this should be at least - * 1277*opus_repacketizer_get_nb_frames(rp). - * However, - * 1*opus_repacketizer_get_nb_frames(rp) - * plus the size of all packet data - * submitted to the repacketizer since the - * last call to opus_repacketizer_init() or - * opus_repacketizer_create() is also - * sufficient, and possibly much smaller. - * @returns The total size of the output packet on success, or an error code - * on failure. - * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the - * complete output packet. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1); - -/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence). - * @param[in,out] data const unsigned char*: The buffer containing the - * packet to pad. - * @param len opus_int32: The size of the packet. - * This must be at least 1. - * @param new_len opus_int32: The desired size of the packet after padding. - * This must be at least as large as len. - * @returns an error code - * @retval #OPUS_OK \a on success. - * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len. - * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. - */ -OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len); - -/** Remove all padding from a given Opus packet and rewrite the TOC sequence to - * minimize space usage. - * @param[in,out] data const unsigned char*: The buffer containing the - * packet to strip. - * @param len opus_int32: The size of the packet. - * This must be at least 1. - * @returns The new size of the output packet on success, or an error code - * on failure. - * @retval #OPUS_BAD_ARG \a len was less than 1. - * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len); - -/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence). - * @param[in,out] data const unsigned char*: The buffer containing the - * packet to pad. - * @param len opus_int32: The size of the packet. - * This must be at least 1. - * @param new_len opus_int32: The desired size of the packet after padding. - * This must be at least 1. - * @param nb_streams opus_int32: The number of streams (not channels) in the packet. - * This must be at least as large as len. - * @returns an error code - * @retval #OPUS_OK \a on success. - * @retval #OPUS_BAD_ARG \a len was less than 1. - * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. - */ -OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams); - -/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to - * minimize space usage. - * @param[in,out] data const unsigned char*: The buffer containing the - * packet to strip. - * @param len opus_int32: The size of the packet. - * This must be at least 1. - * @param nb_streams opus_int32: The number of streams (not channels) in the packet. - * This must be at least 1. - * @returns The new size of the output packet on success, or an error code - * on failure. - * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len. - * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif /* OPUS_H */ diff --git a/code/dep_codecs/include/opus/opus_defines.h b/code/dep_codecs/include/opus/opus_defines.h deleted file mode 100755 index 94b9e0d9..00000000 --- a/code/dep_codecs/include/opus/opus_defines.h +++ /dev/null @@ -1,801 +0,0 @@ -/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited - Written by Jean-Marc Valin and Koen Vos */ -/* - 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 OWNER - 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. -*/ - -/** - * @file opus_defines.h - * @brief Opus reference implementation constants - */ - -#ifndef OPUS_DEFINES_H -#define OPUS_DEFINES_H - -#include "opus_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @defgroup opus_errorcodes Error codes - * @{ - */ -/** No error @hideinitializer*/ -#define OPUS_OK 0 -/** One or more invalid/out of range arguments @hideinitializer*/ -#define OPUS_BAD_ARG -1 -/** Not enough bytes allocated in the buffer @hideinitializer*/ -#define OPUS_BUFFER_TOO_SMALL -2 -/** An internal error was detected @hideinitializer*/ -#define OPUS_INTERNAL_ERROR -3 -/** The compressed data passed is corrupted @hideinitializer*/ -#define OPUS_INVALID_PACKET -4 -/** Invalid/unsupported request number @hideinitializer*/ -#define OPUS_UNIMPLEMENTED -5 -/** An encoder or decoder structure is invalid or already freed @hideinitializer*/ -#define OPUS_INVALID_STATE -6 -/** Memory allocation has failed @hideinitializer*/ -#define OPUS_ALLOC_FAIL -7 -/**@}*/ - -/** @cond OPUS_INTERNAL_DOC */ -/**Export control for opus functions */ - -#ifndef OPUS_EXPORT -# if defined(_WIN32) -# if defined(OPUS_BUILD) && defined(DLL_EXPORT) -# define OPUS_EXPORT __declspec(dllexport) -# else -# define OPUS_EXPORT -# endif -# elif defined(__GNUC__) && defined(OPUS_BUILD) -# define OPUS_EXPORT __attribute__ ((visibility ("default"))) -# else -# define OPUS_EXPORT -# endif -#endif - -# if !defined(OPUS_GNUC_PREREQ) -# if defined(__GNUC__)&&defined(__GNUC_MINOR__) -# define OPUS_GNUC_PREREQ(_maj,_min) \ - ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) -# else -# define OPUS_GNUC_PREREQ(_maj,_min) 0 -# endif -# endif - -#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if OPUS_GNUC_PREREQ(3,0) -# define OPUS_RESTRICT __restrict__ -# elif (defined(_MSC_VER) && _MSC_VER >= 1400) -# define OPUS_RESTRICT __restrict -# else -# define OPUS_RESTRICT -# endif -#else -# define OPUS_RESTRICT restrict -#endif - -#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if OPUS_GNUC_PREREQ(2,7) -# define OPUS_INLINE __inline__ -# elif (defined(_MSC_VER)) -# define OPUS_INLINE __inline -# else -# define OPUS_INLINE -# endif -#else -# define OPUS_INLINE inline -#endif - -/**Warning attributes for opus functions - * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out - * some paranoid null checks. */ -#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) -# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) -#else -# define OPUS_WARN_UNUSED_RESULT -#endif -#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) -# define OPUS_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) -#else -# define OPUS_ARG_NONNULL(_x) -#endif - -/** These are the actual Encoder CTL ID numbers. - * They should not be used directly by applications. - * In general, SETs should be even and GETs should be odd.*/ -#define OPUS_SET_APPLICATION_REQUEST 4000 -#define OPUS_GET_APPLICATION_REQUEST 4001 -#define OPUS_SET_BITRATE_REQUEST 4002 -#define OPUS_GET_BITRATE_REQUEST 4003 -#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004 -#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005 -#define OPUS_SET_VBR_REQUEST 4006 -#define OPUS_GET_VBR_REQUEST 4007 -#define OPUS_SET_BANDWIDTH_REQUEST 4008 -#define OPUS_GET_BANDWIDTH_REQUEST 4009 -#define OPUS_SET_COMPLEXITY_REQUEST 4010 -#define OPUS_GET_COMPLEXITY_REQUEST 4011 -#define OPUS_SET_INBAND_FEC_REQUEST 4012 -#define OPUS_GET_INBAND_FEC_REQUEST 4013 -#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014 -#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015 -#define OPUS_SET_DTX_REQUEST 4016 -#define OPUS_GET_DTX_REQUEST 4017 -#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020 -#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021 -#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022 -#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023 -#define OPUS_SET_SIGNAL_REQUEST 4024 -#define OPUS_GET_SIGNAL_REQUEST 4025 -#define OPUS_GET_LOOKAHEAD_REQUEST 4027 -/* #define OPUS_RESET_STATE 4028 */ -#define OPUS_GET_SAMPLE_RATE_REQUEST 4029 -#define OPUS_GET_FINAL_RANGE_REQUEST 4031 -#define OPUS_GET_PITCH_REQUEST 4033 -#define OPUS_SET_GAIN_REQUEST 4034 -#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */ -#define OPUS_SET_LSB_DEPTH_REQUEST 4036 -#define OPUS_GET_LSB_DEPTH_REQUEST 4037 -#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039 -#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040 -#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041 -#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042 -#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043 -/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */ -#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046 -#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047 -#define OPUS_GET_IN_DTX_REQUEST 4049 - -/** Defines for the presence of extended APIs. */ -#define OPUS_HAVE_OPUS_PROJECTION_H - -/* Macros to trigger compilation errors when the wrong types are provided to a CTL */ -#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x)) -#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr))) -#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr))) -#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr))) -/** @endcond */ - -/** @defgroup opus_ctlvalues Pre-defined values for CTL interface - * @see opus_genericctls, opus_encoderctls - * @{ - */ -/* Values for the various encoder CTLs */ -#define OPUS_AUTO -1000 /**opus_int32: Allowed values: 0-10, inclusive. - * - * @hideinitializer */ -#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x) -/** Gets the encoder's complexity configuration. - * @see OPUS_SET_COMPLEXITY - * @param[out] x opus_int32 *: Returns a value in the range 0-10, - * inclusive. - * @hideinitializer */ -#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x) - -/** Configures the bitrate in the encoder. - * Rates from 500 to 512000 bits per second are meaningful, as well as the - * special values #OPUS_AUTO and #OPUS_BITRATE_MAX. - * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much - * rate as it can, which is useful for controlling the rate by adjusting the - * output buffer size. - * @see OPUS_GET_BITRATE - * @param[in] x opus_int32: Bitrate in bits per second. The default - * is determined based on the number of - * channels and the input sampling rate. - * @hideinitializer */ -#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x) -/** Gets the encoder's bitrate configuration. - * @see OPUS_SET_BITRATE - * @param[out] x opus_int32 *: Returns the bitrate in bits per second. - * The default is determined based on the - * number of channels and the input - * sampling rate. - * @hideinitializer */ -#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x) - -/** Enables or disables variable bitrate (VBR) in the encoder. - * The configured bitrate may not be met exactly because frames must - * be an integer number of bytes in length. - * @see OPUS_GET_VBR - * @see OPUS_SET_VBR_CONSTRAINT - * @param[in] x opus_int32: Allowed values: - *
- *
0
Hard CBR. For LPC/hybrid modes at very low bit-rate, this can - * cause noticeable quality degradation.
- *
1
VBR (default). The exact type of VBR is controlled by - * #OPUS_SET_VBR_CONSTRAINT.
- *
- * @hideinitializer */ -#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x) -/** Determine if variable bitrate (VBR) is enabled in the encoder. - * @see OPUS_SET_VBR - * @see OPUS_GET_VBR_CONSTRAINT - * @param[out] x opus_int32 *: Returns one of the following values: - *
- *
0
Hard CBR.
- *
1
VBR (default). The exact type of VBR may be retrieved via - * #OPUS_GET_VBR_CONSTRAINT.
- *
- * @hideinitializer */ -#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x) - -/** Enables or disables constrained VBR in the encoder. - * This setting is ignored when the encoder is in CBR mode. - * @warning Only the MDCT mode of Opus currently heeds the constraint. - * Speech mode ignores it completely, hybrid mode may fail to obey it - * if the LPC layer uses more bitrate than the constraint would have - * permitted. - * @see OPUS_GET_VBR_CONSTRAINT - * @see OPUS_SET_VBR - * @param[in] x opus_int32: Allowed values: - *
- *
0
Unconstrained VBR.
- *
1
Constrained VBR (default). This creates a maximum of one - * frame of buffering delay assuming a transport with a - * serialization speed of the nominal bitrate.
- *
- * @hideinitializer */ -#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x) -/** Determine if constrained VBR is enabled in the encoder. - * @see OPUS_SET_VBR_CONSTRAINT - * @see OPUS_GET_VBR - * @param[out] x opus_int32 *: Returns one of the following values: - *
- *
0
Unconstrained VBR.
- *
1
Constrained VBR (default).
- *
- * @hideinitializer */ -#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x) - -/** Configures mono/stereo forcing in the encoder. - * This can force the encoder to produce packets encoded as either mono or - * stereo, regardless of the format of the input audio. This is useful when - * the caller knows that the input signal is currently a mono source embedded - * in a stereo stream. - * @see OPUS_GET_FORCE_CHANNELS - * @param[in] x opus_int32: Allowed values: - *
- *
#OPUS_AUTO
Not forced (default)
- *
1
Forced mono
- *
2
Forced stereo
- *
- * @hideinitializer */ -#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x) -/** Gets the encoder's forced channel configuration. - * @see OPUS_SET_FORCE_CHANNELS - * @param[out] x opus_int32 *: - *
- *
#OPUS_AUTO
Not forced (default)
- *
1
Forced mono
- *
2
Forced stereo
- *
- * @hideinitializer */ -#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x) - -/** Configures the maximum bandpass that the encoder will select automatically. - * Applications should normally use this instead of #OPUS_SET_BANDWIDTH - * (leaving that set to the default, #OPUS_AUTO). This allows the - * application to set an upper bound based on the type of input it is - * providing, but still gives the encoder the freedom to reduce the bandpass - * when the bitrate becomes too low, for better overall quality. - * @see OPUS_GET_MAX_BANDWIDTH - * @param[in] x opus_int32: Allowed values: - *
- *
OPUS_BANDWIDTH_NARROWBAND
4 kHz passband
- *
OPUS_BANDWIDTH_MEDIUMBAND
6 kHz passband
- *
OPUS_BANDWIDTH_WIDEBAND
8 kHz passband
- *
OPUS_BANDWIDTH_SUPERWIDEBAND
12 kHz passband
- *
OPUS_BANDWIDTH_FULLBAND
20 kHz passband (default)
- *
- * @hideinitializer */ -#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x) - -/** Gets the encoder's configured maximum allowed bandpass. - * @see OPUS_SET_MAX_BANDWIDTH - * @param[out] x opus_int32 *: Allowed values: - *
- *
#OPUS_BANDWIDTH_NARROWBAND
4 kHz passband
- *
#OPUS_BANDWIDTH_MEDIUMBAND
6 kHz passband
- *
#OPUS_BANDWIDTH_WIDEBAND
8 kHz passband
- *
#OPUS_BANDWIDTH_SUPERWIDEBAND
12 kHz passband
- *
#OPUS_BANDWIDTH_FULLBAND
20 kHz passband (default)
- *
- * @hideinitializer */ -#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) - -/** Sets the encoder's bandpass to a specific value. - * This prevents the encoder from automatically selecting the bandpass based - * on the available bitrate. If an application knows the bandpass of the input - * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH - * instead, which still gives the encoder the freedom to reduce the bandpass - * when the bitrate becomes too low, for better overall quality. - * @see OPUS_GET_BANDWIDTH - * @param[in] x opus_int32: Allowed values: - *
- *
#OPUS_AUTO
(default)
- *
#OPUS_BANDWIDTH_NARROWBAND
4 kHz passband
- *
#OPUS_BANDWIDTH_MEDIUMBAND
6 kHz passband
- *
#OPUS_BANDWIDTH_WIDEBAND
8 kHz passband
- *
#OPUS_BANDWIDTH_SUPERWIDEBAND
12 kHz passband
- *
#OPUS_BANDWIDTH_FULLBAND
20 kHz passband
- *
- * @hideinitializer */ -#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x) - -/** Configures the type of signal being encoded. - * This is a hint which helps the encoder's mode selection. - * @see OPUS_GET_SIGNAL - * @param[in] x opus_int32: Allowed values: - *
- *
#OPUS_AUTO
(default)
- *
#OPUS_SIGNAL_VOICE
Bias thresholds towards choosing LPC or Hybrid modes.
- *
#OPUS_SIGNAL_MUSIC
Bias thresholds towards choosing MDCT modes.
- *
- * @hideinitializer */ -#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x) -/** Gets the encoder's configured signal type. - * @see OPUS_SET_SIGNAL - * @param[out] x opus_int32 *: Returns one of the following values: - *
- *
#OPUS_AUTO
(default)
- *
#OPUS_SIGNAL_VOICE
Bias thresholds towards choosing LPC or Hybrid modes.
- *
#OPUS_SIGNAL_MUSIC
Bias thresholds towards choosing MDCT modes.
- *
- * @hideinitializer */ -#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x) - - -/** Configures the encoder's intended application. - * The initial value is a mandatory argument to the encoder_create function. - * @see OPUS_GET_APPLICATION - * @param[in] x opus_int32: Returns one of the following values: - *
- *
#OPUS_APPLICATION_VOIP
- *
Process signal for improved speech intelligibility.
- *
#OPUS_APPLICATION_AUDIO
- *
Favor faithfulness to the original input.
- *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
- *
Configure the minimum possible coding delay by disabling certain modes - * of operation.
- *
- * @hideinitializer */ -#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x) -/** Gets the encoder's configured application. - * @see OPUS_SET_APPLICATION - * @param[out] x opus_int32 *: Returns one of the following values: - *
- *
#OPUS_APPLICATION_VOIP
- *
Process signal for improved speech intelligibility.
- *
#OPUS_APPLICATION_AUDIO
- *
Favor faithfulness to the original input.
- *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
- *
Configure the minimum possible coding delay by disabling certain modes - * of operation.
- *
- * @hideinitializer */ -#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x) - -/** Gets the total samples of delay added by the entire codec. - * This can be queried by the encoder and then the provided number of samples can be - * skipped on from the start of the decoder's output to provide time aligned input - * and output. From the perspective of a decoding application the real data begins this many - * samples late. - * - * The decoder contribution to this delay is identical for all decoders, but the - * encoder portion of the delay may vary from implementation to implementation, - * version to version, or even depend on the encoder's initial configuration. - * Applications needing delay compensation should call this CTL rather than - * hard-coding a value. - * @param[out] x opus_int32 *: Number of lookahead samples - * @hideinitializer */ -#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x) - -/** Configures the encoder's use of inband forward error correction (FEC). - * @note This is only applicable to the LPC layer - * @see OPUS_GET_INBAND_FEC - * @param[in] x opus_int32: Allowed values: - *
- *
0
Disable inband FEC (default).
- *
1
Inband FEC enabled. If the packet loss rate is sufficiently high, Opus will automatically switch to SILK even at high rates to enable use of that FEC.
- *
2
Inband FEC enabled, but does not necessarily switch to SILK if we have music.
- *
- * @hideinitializer */ -#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x) -/** Gets encoder's configured use of inband forward error correction. - * @see OPUS_SET_INBAND_FEC - * @param[out] x opus_int32 *: Returns one of the following values: - *
- *
0
Inband FEC disabled (default).
- *
1
Inband FEC enabled. If the packet loss rate is sufficiently high, Opus will automatically switch to SILK even at high rates to enable use of that FEC.
- *
2
Inband FEC enabled, but does not necessarily switch to SILK if we have music.
- *
- * @hideinitializer */ -#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x) - -/** Configures the encoder's expected packet loss percentage. - * Higher values trigger progressively more loss resistant behavior in the encoder - * at the expense of quality at a given bitrate in the absence of packet loss, but - * greater quality under loss. - * @see OPUS_GET_PACKET_LOSS_PERC - * @param[in] x opus_int32: Loss percentage in the range 0-100, inclusive (default: 0). - * @hideinitializer */ -#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x) -/** Gets the encoder's configured packet loss percentage. - * @see OPUS_SET_PACKET_LOSS_PERC - * @param[out] x opus_int32 *: Returns the configured loss percentage - * in the range 0-100, inclusive (default: 0). - * @hideinitializer */ -#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x) - -/** Configures the encoder's use of discontinuous transmission (DTX). - * @note This is only applicable to the LPC layer - * @see OPUS_GET_DTX - * @param[in] x opus_int32: Allowed values: - *
- *
0
Disable DTX (default).
- *
1
Enabled DTX.
- *
- * @hideinitializer */ -#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x) -/** Gets encoder's configured use of discontinuous transmission. - * @see OPUS_SET_DTX - * @param[out] x opus_int32 *: Returns one of the following values: - *
- *
0
DTX disabled (default).
- *
1
DTX enabled.
- *
- * @hideinitializer */ -#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x) -/** Configures the depth of signal being encoded. - * - * This is a hint which helps the encoder identify silence and near-silence. - * It represents the number of significant bits of linear intensity below - * which the signal contains ignorable quantization or other noise. - * - * For example, OPUS_SET_LSB_DEPTH(14) would be an appropriate setting - * for G.711 u-law input. OPUS_SET_LSB_DEPTH(16) would be appropriate - * for 16-bit linear pcm input with opus_encode_float(). - * - * When using opus_encode() instead of opus_encode_float(), or when libopus - * is compiled for fixed-point, the encoder uses the minimum of the value - * set here and the value 16. - * - * @see OPUS_GET_LSB_DEPTH - * @param[in] x opus_int32: Input precision in bits, between 8 and 24 - * (default: 24). - * @hideinitializer */ -#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x) -/** Gets the encoder's configured signal depth. - * @see OPUS_SET_LSB_DEPTH - * @param[out] x opus_int32 *: Input precision in bits, between 8 and - * 24 (default: 24). - * @hideinitializer */ -#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x) - -/** Configures the encoder's use of variable duration frames. - * When variable duration is enabled, the encoder is free to use a shorter frame - * size than the one requested in the opus_encode*() call. - * It is then the user's responsibility - * to verify how much audio was encoded by checking the ToC byte of the encoded - * packet. The part of the audio that was not encoded needs to be resent to the - * encoder for the next call. Do not use this option unless you really - * know what you are doing. - * @see OPUS_GET_EXPERT_FRAME_DURATION - * @param[in] x opus_int32: Allowed values: - *
- *
OPUS_FRAMESIZE_ARG
Select frame size from the argument (default).
- *
OPUS_FRAMESIZE_2_5_MS
Use 2.5 ms frames.
- *
OPUS_FRAMESIZE_5_MS
Use 5 ms frames.
- *
OPUS_FRAMESIZE_10_MS
Use 10 ms frames.
- *
OPUS_FRAMESIZE_20_MS
Use 20 ms frames.
- *
OPUS_FRAMESIZE_40_MS
Use 40 ms frames.
- *
OPUS_FRAMESIZE_60_MS
Use 60 ms frames.
- *
OPUS_FRAMESIZE_80_MS
Use 80 ms frames.
- *
OPUS_FRAMESIZE_100_MS
Use 100 ms frames.
- *
OPUS_FRAMESIZE_120_MS
Use 120 ms frames.
- *
- * @hideinitializer */ -#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x) -/** Gets the encoder's configured use of variable duration frames. - * @see OPUS_SET_EXPERT_FRAME_DURATION - * @param[out] x opus_int32 *: Returns one of the following values: - *
- *
OPUS_FRAMESIZE_ARG
Select frame size from the argument (default).
- *
OPUS_FRAMESIZE_2_5_MS
Use 2.5 ms frames.
- *
OPUS_FRAMESIZE_5_MS
Use 5 ms frames.
- *
OPUS_FRAMESIZE_10_MS
Use 10 ms frames.
- *
OPUS_FRAMESIZE_20_MS
Use 20 ms frames.
- *
OPUS_FRAMESIZE_40_MS
Use 40 ms frames.
- *
OPUS_FRAMESIZE_60_MS
Use 60 ms frames.
- *
OPUS_FRAMESIZE_80_MS
Use 80 ms frames.
- *
OPUS_FRAMESIZE_100_MS
Use 100 ms frames.
- *
OPUS_FRAMESIZE_120_MS
Use 120 ms frames.
- *
- * @hideinitializer */ -#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x) - -/** If set to 1, disables almost all use of prediction, making frames almost - * completely independent. This reduces quality. - * @see OPUS_GET_PREDICTION_DISABLED - * @param[in] x opus_int32: Allowed values: - *
- *
0
Enable prediction (default).
- *
1
Disable prediction.
- *
- * @hideinitializer */ -#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x) -/** Gets the encoder's configured prediction status. - * @see OPUS_SET_PREDICTION_DISABLED - * @param[out] x opus_int32 *: Returns one of the following values: - *
- *
0
Prediction enabled (default).
- *
1
Prediction disabled.
- *
- * @hideinitializer */ -#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x) - -/**@}*/ - -/** @defgroup opus_genericctls Generic CTLs - * - * These macros are used with the \c opus_decoder_ctl and - * \c opus_encoder_ctl calls to generate a particular - * request. - * - * When called on an \c OpusDecoder they apply to that - * particular decoder instance. When called on an - * \c OpusEncoder they apply to the corresponding setting - * on that encoder instance, if present. - * - * Some usage examples: - * - * @code - * int ret; - * opus_int32 pitch; - * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch)); - * if (ret == OPUS_OK) return ret; - * - * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE); - * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE); - * - * opus_int32 enc_bw, dec_bw; - * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw)); - * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw)); - * if (enc_bw != dec_bw) { - * printf("packet bandwidth mismatch!\n"); - * } - * @endcode - * - * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls - * @{ - */ - -/** Resets the codec state to be equivalent to a freshly initialized state. - * This should be called when switching streams in order to prevent - * the back to back decoding from giving different results from - * one at a time decoding. - * @hideinitializer */ -#define OPUS_RESET_STATE 4028 - -/** Gets the final state of the codec's entropy coder. - * This is used for testing purposes, - * The encoder and decoder state should be identical after coding a payload - * (assuming no data corruption or software bugs) - * - * @param[out] x opus_uint32 *: Entropy coder state - * - * @hideinitializer */ -#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x) - -/** Gets the encoder's configured bandpass or the decoder's last bandpass. - * @see OPUS_SET_BANDWIDTH - * @param[out] x opus_int32 *: Returns one of the following values: - *
- *
#OPUS_AUTO
(default)
- *
#OPUS_BANDWIDTH_NARROWBAND
4 kHz passband
- *
#OPUS_BANDWIDTH_MEDIUMBAND
6 kHz passband
- *
#OPUS_BANDWIDTH_WIDEBAND
8 kHz passband
- *
#OPUS_BANDWIDTH_SUPERWIDEBAND
12 kHz passband
- *
#OPUS_BANDWIDTH_FULLBAND
20 kHz passband
- *
- * @hideinitializer */ -#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) - -/** Gets the sampling rate the encoder or decoder was initialized with. - * This simply returns the Fs value passed to opus_encoder_init() - * or opus_decoder_init(). - * @param[out] x opus_int32 *: Sampling rate of encoder or decoder. - * @hideinitializer - */ -#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x) - -/** If set to 1, disables the use of phase inversion for intensity stereo, - * improving the quality of mono downmixes, but slightly reducing normal - * stereo quality. Disabling phase inversion in the decoder does not comply - * with RFC 6716, although it does not cause any interoperability issue and - * is expected to become part of the Opus standard once RFC 6716 is updated - * by draft-ietf-codec-opus-update. - * @see OPUS_GET_PHASE_INVERSION_DISABLED - * @param[in] x opus_int32: Allowed values: - *
- *
0
Enable phase inversion (default).
- *
1
Disable phase inversion.
- *
- * @hideinitializer */ -#define OPUS_SET_PHASE_INVERSION_DISABLED(x) OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int(x) -/** Gets the encoder's configured phase inversion status. - * @see OPUS_SET_PHASE_INVERSION_DISABLED - * @param[out] x opus_int32 *: Returns one of the following values: - *
- *
0
Stereo phase inversion enabled (default).
- *
1
Stereo phase inversion disabled.
- *
- * @hideinitializer */ -#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x) -/** Gets the DTX state of the encoder. - * Returns whether the last encoded frame was either a comfort noise update - * during DTX or not encoded because of DTX. - * @param[out] x opus_int32 *: Returns one of the following values: - *
- *
0
The encoder is not in DTX.
- *
1
The encoder is in DTX.
- *
- * @hideinitializer */ -#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x) - -/**@}*/ - -/** @defgroup opus_decoderctls Decoder related CTLs - * @see opus_genericctls, opus_encoderctls, opus_decoder - * @{ - */ - -/** Configures decoder gain adjustment. - * Scales the decoded output by a factor specified in Q8 dB units. - * This has a maximum range of -32768 to 32767 inclusive, and returns - * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment. - * This setting survives decoder reset. - * - * gain = pow(10, x/(20.0*256)) - * - * @param[in] x opus_int32: Amount to scale PCM signal by in Q8 dB units. - * @hideinitializer */ -#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x) -/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN - * - * @param[out] x opus_int32 *: Amount to scale PCM signal by in Q8 dB units. - * @hideinitializer */ -#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x) - -/** Gets the duration (in samples) of the last packet successfully decoded or concealed. - * @param[out] x opus_int32 *: Number of samples (at current sampling rate). - * @hideinitializer */ -#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x) - -/** Gets the pitch of the last decoded frame, if available. - * This can be used for any post-processing algorithm requiring the use of pitch, - * e.g. time stretching/shortening. If the last frame was not voiced, or if the - * pitch was not coded in the frame, then zero is returned. - * - * This CTL is only implemented for decoder instances. - * - * @param[out] x opus_int32 *: pitch period at 48 kHz (or 0 if not available) - * - * @hideinitializer */ -#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x) - -/**@}*/ - -/** @defgroup opus_libinfo Opus library information functions - * @{ - */ - -/** Converts an opus error code into a human readable string. - * - * @param[in] error int: Error number - * @returns Error string - */ -OPUS_EXPORT const char *opus_strerror(int error); - -/** Gets the libopus version string. - * - * Applications may look for the substring "-fixed" in the version string to - * determine whether they have a fixed-point or floating-point build at - * runtime. - * - * @returns Version string - */ -OPUS_EXPORT const char *opus_get_version_string(void); -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif /* OPUS_DEFINES_H */ diff --git a/code/dep_codecs/include/opus/opus_multistream.h b/code/dep_codecs/include/opus/opus_multistream.h deleted file mode 100644 index babcee69..00000000 --- a/code/dep_codecs/include/opus/opus_multistream.h +++ /dev/null @@ -1,660 +0,0 @@ -/* Copyright (c) 2011 Xiph.Org Foundation - Written by Jean-Marc Valin */ -/* - 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 OWNER - 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. -*/ - -/** - * @file opus_multistream.h - * @brief Opus reference implementation multistream API - */ - -#ifndef OPUS_MULTISTREAM_H -#define OPUS_MULTISTREAM_H - -#include "opus.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @cond OPUS_INTERNAL_DOC */ - -/** Macros to trigger compilation errors when the wrong types are provided to a - * CTL. */ -/**@{*/ -#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr))) -#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr))) -/**@}*/ - -/** These are the actual encoder and decoder CTL ID numbers. - * They should not be used directly by applications. - * In general, SETs should be even and GETs should be odd.*/ -/**@{*/ -#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120 -#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122 -/**@}*/ - -/** @endcond */ - -/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs - * - * These are convenience macros that are specific to the - * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl() - * interface. - * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and - * @ref opus_decoderctls may be applied to a multistream encoder or decoder as - * well. - * In addition, you may retrieve the encoder or decoder state for an specific - * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or - * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually. - */ -/**@{*/ - -/** Gets the encoder state for an individual stream of a multistream encoder. - * @param[in] x opus_int32: The index of the stream whose encoder you - * wish to retrieve. - * This must be non-negative and less than - * the streams parameter used - * to initialize the encoder. - * @param[out] y OpusEncoder**: Returns a pointer to the given - * encoder state. - * @retval OPUS_BAD_ARG The index of the requested stream was out of range. - * @hideinitializer - */ -#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y) - -/** Gets the decoder state for an individual stream of a multistream decoder. - * @param[in] x opus_int32: The index of the stream whose decoder you - * wish to retrieve. - * This must be non-negative and less than - * the streams parameter used - * to initialize the decoder. - * @param[out] y OpusDecoder**: Returns a pointer to the given - * decoder state. - * @retval OPUS_BAD_ARG The index of the requested stream was out of range. - * @hideinitializer - */ -#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y) - -/**@}*/ - -/** @defgroup opus_multistream Opus Multistream API - * @{ - * - * The multistream API allows individual Opus streams to be combined into a - * single packet, enabling support for up to 255 channels. Unlike an - * elementary Opus stream, the encoder and decoder must negotiate the channel - * configuration before the decoder can successfully interpret the data in the - * packets produced by the encoder. Some basic information, such as packet - * duration, can be computed without any special negotiation. - * - * The format for multistream Opus packets is defined in - * RFC 7845 - * and is based on the self-delimited Opus framing described in Appendix B of - * RFC 6716. - * Normal Opus packets are just a degenerate case of multistream Opus packets, - * and can be encoded or decoded with the multistream API by setting - * streams to 1 when initializing the encoder or - * decoder. - * - * Multistream Opus streams can contain up to 255 elementary Opus streams. - * These may be either "uncoupled" or "coupled", indicating that the decoder - * is configured to decode them to either 1 or 2 channels, respectively. - * The streams are ordered so that all coupled streams appear at the - * beginning. - * - * A mapping table defines which decoded channel i - * should be used for each input/output (I/O) channel j. This table is - * typically provided as an unsigned char array. - * Let i = mapping[j] be the index for I/O channel j. - * If i < 2*coupled_streams, then I/O channel j is - * encoded as the left channel of stream (i/2) if i - * is even, or as the right channel of stream (i/2) if - * i is odd. Otherwise, I/O channel j is encoded as - * mono in stream (i - coupled_streams), unless it has the special - * value 255, in which case it is omitted from the encoding entirely (the - * decoder will reproduce it as silence). Each value i must either - * be the special value 255 or be less than streams + coupled_streams. - * - * The output channels specified by the encoder - * should use the - * Vorbis - * channel ordering. A decoder may wish to apply an additional permutation - * to the mapping the encoder used to achieve a different output channel - * order (e.g. for outputing in WAV order). - * - * Each multistream packet contains an Opus packet for each stream, and all of - * the Opus packets in a single multistream packet must have the same - * duration. Therefore the duration of a multistream packet can be extracted - * from the TOC sequence of the first stream, which is located at the - * beginning of the packet, just like an elementary Opus stream: - * - * @code - * int nb_samples; - * int nb_frames; - * nb_frames = opus_packet_get_nb_frames(data, len); - * if (nb_frames < 1) - * return nb_frames; - * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames; - * @endcode - * - * The general encoding and decoding process proceeds exactly the same as in - * the normal @ref opus_encoder and @ref opus_decoder APIs. - * See their documentation for an overview of how to use the corresponding - * multistream functions. - */ - -/** Opus multistream encoder state. - * This contains the complete state of a multistream Opus encoder. - * It is position independent and can be freely copied. - * @see opus_multistream_encoder_create - * @see opus_multistream_encoder_init - */ -typedef struct OpusMSEncoder OpusMSEncoder; - -/** Opus multistream decoder state. - * This contains the complete state of a multistream Opus decoder. - * It is position independent and can be freely copied. - * @see opus_multistream_decoder_create - * @see opus_multistream_decoder_init - */ -typedef struct OpusMSDecoder OpusMSDecoder; - -/**\name Multistream encoder functions */ -/**@{*/ - -/** Gets the size of an OpusMSEncoder structure. - * @param streams int: The total number of streams to encode from the - * input. - * This must be no more than 255. - * @param coupled_streams int: Number of coupled (2 channel) streams - * to encode. - * This must be no larger than the total - * number of streams. - * Additionally, The total number of - * encoded channels (streams + - * coupled_streams) must be no - * more than 255. - * @returns The size in bytes on success, or a negative error code - * (see @ref opus_errorcodes) on error. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size( - int streams, - int coupled_streams -); - -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_surround_encoder_get_size( - int channels, - int mapping_family -); - - -/** Allocates and initializes a multistream encoder state. - * Call opus_multistream_encoder_destroy() to release - * this object when finished. - * @param Fs opus_int32: Sampling rate of the input signal (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels int: Number of channels in the input signal. - * This must be at most 255. - * It may be greater than the number of - * coded channels (streams + - * coupled_streams). - * @param streams int: The total number of streams to encode from the - * input. - * This must be no more than the number of channels. - * @param coupled_streams int: Number of coupled (2 channel) streams - * to encode. - * This must be no larger than the total - * number of streams. - * Additionally, The total number of - * encoded channels (streams + - * coupled_streams) must be no - * more than the number of input channels. - * @param[in] mapping const unsigned char[channels]: Mapping from - * encoded channels to input channels, as described in - * @ref opus_multistream. As an extra constraint, the - * multistream encoder does not allow encoding coupled - * streams for which one channel is unused since this - * is never a good idea. - * @param application int: The target encoder application. - * This must be one of the following: - *
- *
#OPUS_APPLICATION_VOIP
- *
Process signal for improved speech intelligibility.
- *
#OPUS_APPLICATION_AUDIO
- *
Favor faithfulness to the original input.
- *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
- *
Configure the minimum possible coding delay by disabling certain modes - * of operation.
- *
- * @param[out] error int *: Returns #OPUS_OK on success, or an error - * code (see @ref opus_errorcodes) on - * failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create( - opus_int32 Fs, - int channels, - int streams, - int coupled_streams, - const unsigned char *mapping, - int application, - int *error -) OPUS_ARG_NONNULL(5); - -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_encoder_create( - opus_int32 Fs, - int channels, - int mapping_family, - int *streams, - int *coupled_streams, - unsigned char *mapping, - int application, - int *error -) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6); - -/** Initialize a previously allocated multistream encoder state. - * The memory pointed to by \a st must be at least the size returned by - * opus_multistream_encoder_get_size(). - * This is intended for applications which use their own allocator instead of - * malloc. - * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. - * @see opus_multistream_encoder_create - * @see opus_multistream_encoder_get_size - * @param st OpusMSEncoder*: Multistream encoder state to initialize. - * @param Fs opus_int32: Sampling rate of the input signal (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels int: Number of channels in the input signal. - * This must be at most 255. - * It may be greater than the number of - * coded channels (streams + - * coupled_streams). - * @param streams int: The total number of streams to encode from the - * input. - * This must be no more than the number of channels. - * @param coupled_streams int: Number of coupled (2 channel) streams - * to encode. - * This must be no larger than the total - * number of streams. - * Additionally, The total number of - * encoded channels (streams + - * coupled_streams) must be no - * more than the number of input channels. - * @param[in] mapping const unsigned char[channels]: Mapping from - * encoded channels to input channels, as described in - * @ref opus_multistream. As an extra constraint, the - * multistream encoder does not allow encoding coupled - * streams for which one channel is unused since this - * is never a good idea. - * @param application int: The target encoder application. - * This must be one of the following: - *
- *
#OPUS_APPLICATION_VOIP
- *
Process signal for improved speech intelligibility.
- *
#OPUS_APPLICATION_AUDIO
- *
Favor faithfulness to the original input.
- *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
- *
Configure the minimum possible coding delay by disabling certain modes - * of operation.
- *
- * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) - * on failure. - */ -OPUS_EXPORT int opus_multistream_encoder_init( - OpusMSEncoder *st, - opus_int32 Fs, - int channels, - int streams, - int coupled_streams, - const unsigned char *mapping, - int application -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); - -OPUS_EXPORT int opus_multistream_surround_encoder_init( - OpusMSEncoder *st, - opus_int32 Fs, - int channels, - int mapping_family, - int *streams, - int *coupled_streams, - unsigned char *mapping, - int application -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6) OPUS_ARG_NONNULL(7); - -/** Encodes a multistream Opus frame. - * @param st OpusMSEncoder*: Multistream encoder state. - * @param[in] pcm const opus_int16*: The input signal as interleaved - * samples. - * This must contain - * frame_size*channels - * samples. - * @param frame_size int: Number of samples per channel in the input - * signal. - * This must be an Opus frame size for the - * encoder's sampling rate. - * For example, at 48 kHz the permitted values - * are 120, 240, 480, 960, 1920, and 2880. - * Passing in a duration of less than 10 ms - * (480 samples at 48 kHz) will prevent the - * encoder from using the LPC or hybrid modes. - * @param[out] data unsigned char*: Output payload. - * This must contain storage for at - * least \a max_data_bytes. - * @param [in] max_data_bytes opus_int32: Size of the allocated - * memory for the output - * payload. This may be - * used to impose an upper limit on - * the instant bitrate, but should - * not be used as the only bitrate - * control. Use #OPUS_SET_BITRATE to - * control the bitrate. - * @returns The length of the encoded packet (in bytes) on success or a - * negative error code (see @ref opus_errorcodes) on failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode( - OpusMSEncoder *st, - const opus_int16 *pcm, - int frame_size, - unsigned char *data, - opus_int32 max_data_bytes -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); - -/** Encodes a multistream Opus frame from floating point input. - * @param st OpusMSEncoder*: Multistream encoder state. - * @param[in] pcm const float*: The input signal as interleaved - * samples with a normal range of - * +/-1.0. - * Samples with a range beyond +/-1.0 - * are supported but will be clipped by - * decoders using the integer API and - * should only be used if it is known - * that the far end supports extended - * dynamic range. - * This must contain - * frame_size*channels - * samples. - * @param frame_size int: Number of samples per channel in the input - * signal. - * This must be an Opus frame size for the - * encoder's sampling rate. - * For example, at 48 kHz the permitted values - * are 120, 240, 480, 960, 1920, and 2880. - * Passing in a duration of less than 10 ms - * (480 samples at 48 kHz) will prevent the - * encoder from using the LPC or hybrid modes. - * @param[out] data unsigned char*: Output payload. - * This must contain storage for at - * least \a max_data_bytes. - * @param [in] max_data_bytes opus_int32: Size of the allocated - * memory for the output - * payload. This may be - * used to impose an upper limit on - * the instant bitrate, but should - * not be used as the only bitrate - * control. Use #OPUS_SET_BITRATE to - * control the bitrate. - * @returns The length of the encoded packet (in bytes) on success or a - * negative error code (see @ref opus_errorcodes) on failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float( - OpusMSEncoder *st, - const float *pcm, - int frame_size, - unsigned char *data, - opus_int32 max_data_bytes -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); - -/** Frees an OpusMSEncoder allocated by - * opus_multistream_encoder_create(). - * @param st OpusMSEncoder*: Multistream encoder state to be freed. - */ -OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st); - -/** Perform a CTL function on a multistream Opus encoder. - * - * Generally the request and subsequent arguments are generated by a - * convenience macro. - * @param st OpusMSEncoder*: Multistream encoder state. - * @param request This and all remaining parameters should be replaced by one - * of the convenience macros in @ref opus_genericctls, - * @ref opus_encoderctls, or @ref opus_multistream_ctls. - * @see opus_genericctls - * @see opus_encoderctls - * @see opus_multistream_ctls - */ -OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); - -/**@}*/ - -/**\name Multistream decoder functions */ -/**@{*/ - -/** Gets the size of an OpusMSDecoder structure. - * @param streams int: The total number of streams coded in the - * input. - * This must be no more than 255. - * @param coupled_streams int: Number streams to decode as coupled - * (2 channel) streams. - * This must be no larger than the total - * number of streams. - * Additionally, The total number of - * coded channels (streams + - * coupled_streams) must be no - * more than 255. - * @returns The size in bytes on success, or a negative error code - * (see @ref opus_errorcodes) on error. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size( - int streams, - int coupled_streams -); - -/** Allocates and initializes a multistream decoder state. - * Call opus_multistream_decoder_destroy() to release - * this object when finished. - * @param Fs opus_int32: Sampling rate to decode at (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels int: Number of channels to output. - * This must be at most 255. - * It may be different from the number of coded - * channels (streams + - * coupled_streams). - * @param streams int: The total number of streams coded in the - * input. - * This must be no more than 255. - * @param coupled_streams int: Number of streams to decode as coupled - * (2 channel) streams. - * This must be no larger than the total - * number of streams. - * Additionally, The total number of - * coded channels (streams + - * coupled_streams) must be no - * more than 255. - * @param[in] mapping const unsigned char[channels]: Mapping from - * coded channels to output channels, as described in - * @ref opus_multistream. - * @param[out] error int *: Returns #OPUS_OK on success, or an error - * code (see @ref opus_errorcodes) on - * failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create( - opus_int32 Fs, - int channels, - int streams, - int coupled_streams, - const unsigned char *mapping, - int *error -) OPUS_ARG_NONNULL(5); - -/** Intialize a previously allocated decoder state object. - * The memory pointed to by \a st must be at least the size returned by - * opus_multistream_encoder_get_size(). - * This is intended for applications which use their own allocator instead of - * malloc. - * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. - * @see opus_multistream_decoder_create - * @see opus_multistream_deocder_get_size - * @param st OpusMSEncoder*: Multistream encoder state to initialize. - * @param Fs opus_int32: Sampling rate to decode at (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels int: Number of channels to output. - * This must be at most 255. - * It may be different from the number of coded - * channels (streams + - * coupled_streams). - * @param streams int: The total number of streams coded in the - * input. - * This must be no more than 255. - * @param coupled_streams int: Number of streams to decode as coupled - * (2 channel) streams. - * This must be no larger than the total - * number of streams. - * Additionally, The total number of - * coded channels (streams + - * coupled_streams) must be no - * more than 255. - * @param[in] mapping const unsigned char[channels]: Mapping from - * coded channels to output channels, as described in - * @ref opus_multistream. - * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) - * on failure. - */ -OPUS_EXPORT int opus_multistream_decoder_init( - OpusMSDecoder *st, - opus_int32 Fs, - int channels, - int streams, - int coupled_streams, - const unsigned char *mapping -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); - -/** Decode a multistream Opus packet. - * @param st OpusMSDecoder*: Multistream decoder state. - * @param[in] data const unsigned char*: Input payload. - * Use a NULL - * pointer to indicate packet - * loss. - * @param len opus_int32: Number of bytes in payload. - * @param[out] pcm opus_int16*: Output signal, with interleaved - * samples. - * This must contain room for - * frame_size*channels - * samples. - * @param frame_size int: The number of samples per channel of - * available space in \a pcm. - * If this is less than the maximum packet duration - * (120 ms; 5760 for 48kHz), this function will not be capable - * of decoding some packets. In the case of PLC (data==NULL) - * or FEC (decode_fec=1), then frame_size needs to be exactly - * the duration of audio that is missing, otherwise the - * decoder will not be in the optimal state to decode the - * next incoming packet. For the PLC and FEC cases, frame_size - * must be a multiple of 2.5 ms. - * @param decode_fec int: Flag (0 or 1) to request that any in-band - * forward error correction data be decoded. - * If no such data is available, the frame is - * decoded as if it were lost. - * @returns Number of samples decoded on success or a negative error code - * (see @ref opus_errorcodes) on failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode( - OpusMSDecoder *st, - const unsigned char *data, - opus_int32 len, - opus_int16 *pcm, - int frame_size, - int decode_fec -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); - -/** Decode a multistream Opus packet with floating point output. - * @param st OpusMSDecoder*: Multistream decoder state. - * @param[in] data const unsigned char*: Input payload. - * Use a NULL - * pointer to indicate packet - * loss. - * @param len opus_int32: Number of bytes in payload. - * @param[out] pcm opus_int16*: Output signal, with interleaved - * samples. - * This must contain room for - * frame_size*channels - * samples. - * @param frame_size int: The number of samples per channel of - * available space in \a pcm. - * If this is less than the maximum packet duration - * (120 ms; 5760 for 48kHz), this function will not be capable - * of decoding some packets. In the case of PLC (data==NULL) - * or FEC (decode_fec=1), then frame_size needs to be exactly - * the duration of audio that is missing, otherwise the - * decoder will not be in the optimal state to decode the - * next incoming packet. For the PLC and FEC cases, frame_size - * must be a multiple of 2.5 ms. - * @param decode_fec int: Flag (0 or 1) to request that any in-band - * forward error correction data be decoded. - * If no such data is available, the frame is - * decoded as if it were lost. - * @returns Number of samples decoded on success or a negative error code - * (see @ref opus_errorcodes) on failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float( - OpusMSDecoder *st, - const unsigned char *data, - opus_int32 len, - float *pcm, - int frame_size, - int decode_fec -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); - -/** Perform a CTL function on a multistream Opus decoder. - * - * Generally the request and subsequent arguments are generated by a - * convenience macro. - * @param st OpusMSDecoder*: Multistream decoder state. - * @param request This and all remaining parameters should be replaced by one - * of the convenience macros in @ref opus_genericctls, - * @ref opus_decoderctls, or @ref opus_multistream_ctls. - * @see opus_genericctls - * @see opus_decoderctls - * @see opus_multistream_ctls - */ -OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); - -/** Frees an OpusMSDecoder allocated by - * opus_multistream_decoder_create(). - * @param st OpusMSDecoder: Multistream decoder state to be freed. - */ -OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st); - -/**@}*/ - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif /* OPUS_MULTISTREAM_H */ diff --git a/code/dep_codecs/include/opus/opus_projection.h b/code/dep_codecs/include/opus/opus_projection.h deleted file mode 100644 index 9dabf4e8..00000000 --- a/code/dep_codecs/include/opus/opus_projection.h +++ /dev/null @@ -1,568 +0,0 @@ -/* Copyright (c) 2017 Google Inc. - Written by Andrew Allen */ -/* - 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 OWNER - 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. -*/ - -/** - * @file opus_projection.h - * @brief Opus projection reference API - */ - -#ifndef OPUS_PROJECTION_H -#define OPUS_PROJECTION_H - -#include "opus_multistream.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @cond OPUS_INTERNAL_DOC */ - -/** These are the actual encoder and decoder CTL ID numbers. - * They should not be used directly by applications.c - * In general, SETs should be even and GETs should be odd.*/ -/**@{*/ -#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST 6001 -#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST 6003 -#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST 6005 -/**@}*/ - - -/** @endcond */ - -/** @defgroup opus_projection_ctls Projection specific encoder and decoder CTLs - * - * These are convenience macros that are specific to the - * opus_projection_encoder_ctl() and opus_projection_decoder_ctl() - * interface. - * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, - * @ref opus_decoderctls, and @ref opus_multistream_ctls may be applied to a - * projection encoder or decoder as well. - */ -/**@{*/ - -/** Gets the gain (in dB. S7.8-format) of the demixing matrix from the encoder. - * @param[out] x opus_int32 *: Returns the gain (in dB. S7.8-format) - * of the demixing matrix. - * @hideinitializer - */ -#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST, __opus_check_int_ptr(x) - - -/** Gets the size in bytes of the demixing matrix from the encoder. - * @param[out] x opus_int32 *: Returns the size in bytes of the - * demixing matrix. - * @hideinitializer - */ -#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, __opus_check_int_ptr(x) - - -/** Copies the demixing matrix to the supplied pointer location. - * @param[out] x unsigned char *: Returns the demixing matrix to the - * supplied pointer location. - * @param y opus_int32: The size in bytes of the reserved memory at the - * pointer location. - * @hideinitializer - */ -#define OPUS_PROJECTION_GET_DEMIXING_MATRIX(x,y) OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, x, __opus_check_int(y) - - -/**@}*/ - -/** Opus projection encoder state. - * This contains the complete state of a projection Opus encoder. - * It is position independent and can be freely copied. - * @see opus_projection_ambisonics_encoder_create - */ -typedef struct OpusProjectionEncoder OpusProjectionEncoder; - - -/** Opus projection decoder state. - * This contains the complete state of a projection Opus decoder. - * It is position independent and can be freely copied. - * @see opus_projection_decoder_create - * @see opus_projection_decoder_init - */ -typedef struct OpusProjectionDecoder OpusProjectionDecoder; - - -/**\name Projection encoder functions */ -/**@{*/ - -/** Gets the size of an OpusProjectionEncoder structure. - * @param channels int: The total number of input channels to encode. - * This must be no more than 255. - * @param mapping_family int: The mapping family to use for selecting - * the appropriate projection. - * @returns The size in bytes on success, or a negative error code - * (see @ref opus_errorcodes) on error. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_ambisonics_encoder_get_size( - int channels, - int mapping_family -); - - -/** Allocates and initializes a projection encoder state. - * Call opus_projection_encoder_destroy() to release - * this object when finished. - * @param Fs opus_int32: Sampling rate of the input signal (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels int: Number of channels in the input signal. - * This must be at most 255. - * It may be greater than the number of - * coded channels (streams + - * coupled_streams). - * @param mapping_family int: The mapping family to use for selecting - * the appropriate projection. - * @param[out] streams int *: The total number of streams that will - * be encoded from the input. - * @param[out] coupled_streams int *: Number of coupled (2 channel) - * streams that will be encoded from the input. - * @param application int: The target encoder application. - * This must be one of the following: - *
- *
#OPUS_APPLICATION_VOIP
- *
Process signal for improved speech intelligibility.
- *
#OPUS_APPLICATION_AUDIO
- *
Favor faithfulness to the original input.
- *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
- *
Configure the minimum possible coding delay by disabling certain modes - * of operation.
- *
- * @param[out] error int *: Returns #OPUS_OK on success, or an error - * code (see @ref opus_errorcodes) on - * failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionEncoder *opus_projection_ambisonics_encoder_create( - opus_int32 Fs, - int channels, - int mapping_family, - int *streams, - int *coupled_streams, - int application, - int *error -) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5); - - -/** Initialize a previously allocated projection encoder state. - * The memory pointed to by \a st must be at least the size returned by - * opus_projection_ambisonics_encoder_get_size(). - * This is intended for applications which use their own allocator instead of - * malloc. - * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. - * @see opus_projection_ambisonics_encoder_create - * @see opus_projection_ambisonics_encoder_get_size - * @param st OpusProjectionEncoder*: Projection encoder state to initialize. - * @param Fs opus_int32: Sampling rate of the input signal (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels int: Number of channels in the input signal. - * This must be at most 255. - * It may be greater than the number of - * coded channels (streams + - * coupled_streams). - * @param streams int: The total number of streams to encode from the - * input. - * This must be no more than the number of channels. - * @param coupled_streams int: Number of coupled (2 channel) streams - * to encode. - * This must be no larger than the total - * number of streams. - * Additionally, The total number of - * encoded channels (streams + - * coupled_streams) must be no - * more than the number of input channels. - * @param application int: The target encoder application. - * This must be one of the following: - *
- *
#OPUS_APPLICATION_VOIP
- *
Process signal for improved speech intelligibility.
- *
#OPUS_APPLICATION_AUDIO
- *
Favor faithfulness to the original input.
- *
#OPUS_APPLICATION_RESTRICTED_LOWDELAY
- *
Configure the minimum possible coding delay by disabling certain modes - * of operation.
- *
- * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) - * on failure. - */ -OPUS_EXPORT int opus_projection_ambisonics_encoder_init( - OpusProjectionEncoder *st, - opus_int32 Fs, - int channels, - int mapping_family, - int *streams, - int *coupled_streams, - int application -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6); - - -/** Encodes a projection Opus frame. - * @param st OpusProjectionEncoder*: Projection encoder state. - * @param[in] pcm const opus_int16*: The input signal as interleaved - * samples. - * This must contain - * frame_size*channels - * samples. - * @param frame_size int: Number of samples per channel in the input - * signal. - * This must be an Opus frame size for the - * encoder's sampling rate. - * For example, at 48 kHz the permitted values - * are 120, 240, 480, 960, 1920, and 2880. - * Passing in a duration of less than 10 ms - * (480 samples at 48 kHz) will prevent the - * encoder from using the LPC or hybrid modes. - * @param[out] data unsigned char*: Output payload. - * This must contain storage for at - * least \a max_data_bytes. - * @param [in] max_data_bytes opus_int32: Size of the allocated - * memory for the output - * payload. This may be - * used to impose an upper limit on - * the instant bitrate, but should - * not be used as the only bitrate - * control. Use #OPUS_SET_BITRATE to - * control the bitrate. - * @returns The length of the encoded packet (in bytes) on success or a - * negative error code (see @ref opus_errorcodes) on failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode( - OpusProjectionEncoder *st, - const opus_int16 *pcm, - int frame_size, - unsigned char *data, - opus_int32 max_data_bytes -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); - - -/** Encodes a projection Opus frame from floating point input. - * @param st OpusProjectionEncoder*: Projection encoder state. - * @param[in] pcm const float*: The input signal as interleaved - * samples with a normal range of - * +/-1.0. - * Samples with a range beyond +/-1.0 - * are supported but will be clipped by - * decoders using the integer API and - * should only be used if it is known - * that the far end supports extended - * dynamic range. - * This must contain - * frame_size*channels - * samples. - * @param frame_size int: Number of samples per channel in the input - * signal. - * This must be an Opus frame size for the - * encoder's sampling rate. - * For example, at 48 kHz the permitted values - * are 120, 240, 480, 960, 1920, and 2880. - * Passing in a duration of less than 10 ms - * (480 samples at 48 kHz) will prevent the - * encoder from using the LPC or hybrid modes. - * @param[out] data unsigned char*: Output payload. - * This must contain storage for at - * least \a max_data_bytes. - * @param [in] max_data_bytes opus_int32: Size of the allocated - * memory for the output - * payload. This may be - * used to impose an upper limit on - * the instant bitrate, but should - * not be used as the only bitrate - * control. Use #OPUS_SET_BITRATE to - * control the bitrate. - * @returns The length of the encoded packet (in bytes) on success or a - * negative error code (see @ref opus_errorcodes) on failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode_float( - OpusProjectionEncoder *st, - const float *pcm, - int frame_size, - unsigned char *data, - opus_int32 max_data_bytes -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); - - -/** Frees an OpusProjectionEncoder allocated by - * opus_projection_ambisonics_encoder_create(). - * @param st OpusProjectionEncoder*: Projection encoder state to be freed. - */ -OPUS_EXPORT void opus_projection_encoder_destroy(OpusProjectionEncoder *st); - - -/** Perform a CTL function on a projection Opus encoder. - * - * Generally the request and subsequent arguments are generated by a - * convenience macro. - * @param st OpusProjectionEncoder*: Projection encoder state. - * @param request This and all remaining parameters should be replaced by one - * of the convenience macros in @ref opus_genericctls, - * @ref opus_encoderctls, @ref opus_multistream_ctls, or - * @ref opus_projection_ctls - * @see opus_genericctls - * @see opus_encoderctls - * @see opus_multistream_ctls - * @see opus_projection_ctls - */ -OPUS_EXPORT int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); - - -/**@}*/ - -/**\name Projection decoder functions */ -/**@{*/ - -/** Gets the size of an OpusProjectionDecoder structure. - * @param channels int: The total number of output channels. - * This must be no more than 255. - * @param streams int: The total number of streams coded in the - * input. - * This must be no more than 255. - * @param coupled_streams int: Number streams to decode as coupled - * (2 channel) streams. - * This must be no larger than the total - * number of streams. - * Additionally, The total number of - * coded channels (streams + - * coupled_streams) must be no - * more than 255. - * @returns The size in bytes on success, or a negative error code - * (see @ref opus_errorcodes) on error. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_decoder_get_size( - int channels, - int streams, - int coupled_streams -); - - -/** Allocates and initializes a projection decoder state. - * Call opus_projection_decoder_destroy() to release - * this object when finished. - * @param Fs opus_int32: Sampling rate to decode at (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels int: Number of channels to output. - * This must be at most 255. - * It may be different from the number of coded - * channels (streams + - * coupled_streams). - * @param streams int: The total number of streams coded in the - * input. - * This must be no more than 255. - * @param coupled_streams int: Number of streams to decode as coupled - * (2 channel) streams. - * This must be no larger than the total - * number of streams. - * Additionally, The total number of - * coded channels (streams + - * coupled_streams) must be no - * more than 255. - * @param[in] demixing_matrix const unsigned char[demixing_matrix_size]: Demixing matrix - * that mapping from coded channels to output channels, - * as described in @ref opus_projection and - * @ref opus_projection_ctls. - * @param demixing_matrix_size opus_int32: The size in bytes of the - * demixing matrix, as - * described in @ref - * opus_projection_ctls. - * @param[out] error int *: Returns #OPUS_OK on success, or an error - * code (see @ref opus_errorcodes) on - * failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionDecoder *opus_projection_decoder_create( - opus_int32 Fs, - int channels, - int streams, - int coupled_streams, - unsigned char *demixing_matrix, - opus_int32 demixing_matrix_size, - int *error -) OPUS_ARG_NONNULL(5); - - -/** Intialize a previously allocated projection decoder state object. - * The memory pointed to by \a st must be at least the size returned by - * opus_projection_decoder_get_size(). - * This is intended for applications which use their own allocator instead of - * malloc. - * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. - * @see opus_projection_decoder_create - * @see opus_projection_deocder_get_size - * @param st OpusProjectionDecoder*: Projection encoder state to initialize. - * @param Fs opus_int32: Sampling rate to decode at (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels int: Number of channels to output. - * This must be at most 255. - * It may be different from the number of coded - * channels (streams + - * coupled_streams). - * @param streams int: The total number of streams coded in the - * input. - * This must be no more than 255. - * @param coupled_streams int: Number of streams to decode as coupled - * (2 channel) streams. - * This must be no larger than the total - * number of streams. - * Additionally, The total number of - * coded channels (streams + - * coupled_streams) must be no - * more than 255. - * @param[in] demixing_matrix const unsigned char[demixing_matrix_size]: Demixing matrix - * that mapping from coded channels to output channels, - * as described in @ref opus_projection and - * @ref opus_projection_ctls. - * @param demixing_matrix_size opus_int32: The size in bytes of the - * demixing matrix, as - * described in @ref - * opus_projection_ctls. - * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) - * on failure. - */ -OPUS_EXPORT int opus_projection_decoder_init( - OpusProjectionDecoder *st, - opus_int32 Fs, - int channels, - int streams, - int coupled_streams, - unsigned char *demixing_matrix, - opus_int32 demixing_matrix_size -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); - - -/** Decode a projection Opus packet. - * @param st OpusProjectionDecoder*: Projection decoder state. - * @param[in] data const unsigned char*: Input payload. - * Use a NULL - * pointer to indicate packet - * loss. - * @param len opus_int32: Number of bytes in payload. - * @param[out] pcm opus_int16*: Output signal, with interleaved - * samples. - * This must contain room for - * frame_size*channels - * samples. - * @param frame_size int: The number of samples per channel of - * available space in \a pcm. - * If this is less than the maximum packet duration - * (120 ms; 5760 for 48kHz), this function will not be capable - * of decoding some packets. In the case of PLC (data==NULL) - * or FEC (decode_fec=1), then frame_size needs to be exactly - * the duration of audio that is missing, otherwise the - * decoder will not be in the optimal state to decode the - * next incoming packet. For the PLC and FEC cases, frame_size - * must be a multiple of 2.5 ms. - * @param decode_fec int: Flag (0 or 1) to request that any in-band - * forward error correction data be decoded. - * If no such data is available, the frame is - * decoded as if it were lost. - * @returns Number of samples decoded on success or a negative error code - * (see @ref opus_errorcodes) on failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode( - OpusProjectionDecoder *st, - const unsigned char *data, - opus_int32 len, - opus_int16 *pcm, - int frame_size, - int decode_fec -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); - - -/** Decode a projection Opus packet with floating point output. - * @param st OpusProjectionDecoder*: Projection decoder state. - * @param[in] data const unsigned char*: Input payload. - * Use a NULL - * pointer to indicate packet - * loss. - * @param len opus_int32: Number of bytes in payload. - * @param[out] pcm opus_int16*: Output signal, with interleaved - * samples. - * This must contain room for - * frame_size*channels - * samples. - * @param frame_size int: The number of samples per channel of - * available space in \a pcm. - * If this is less than the maximum packet duration - * (120 ms; 5760 for 48kHz), this function will not be capable - * of decoding some packets. In the case of PLC (data==NULL) - * or FEC (decode_fec=1), then frame_size needs to be exactly - * the duration of audio that is missing, otherwise the - * decoder will not be in the optimal state to decode the - * next incoming packet. For the PLC and FEC cases, frame_size - * must be a multiple of 2.5 ms. - * @param decode_fec int: Flag (0 or 1) to request that any in-band - * forward error correction data be decoded. - * If no such data is available, the frame is - * decoded as if it were lost. - * @returns Number of samples decoded on success or a negative error code - * (see @ref opus_errorcodes) on failure. - */ -OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode_float( - OpusProjectionDecoder *st, - const unsigned char *data, - opus_int32 len, - float *pcm, - int frame_size, - int decode_fec -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); - - -/** Perform a CTL function on a projection Opus decoder. - * - * Generally the request and subsequent arguments are generated by a - * convenience macro. - * @param st OpusProjectionDecoder*: Projection decoder state. - * @param request This and all remaining parameters should be replaced by one - * of the convenience macros in @ref opus_genericctls, - * @ref opus_decoderctls, @ref opus_multistream_ctls, or - * @ref opus_projection_ctls. - * @see opus_genericctls - * @see opus_decoderctls - * @see opus_multistream_ctls - * @see opus_projection_ctls - */ -OPUS_EXPORT int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); - - -/** Frees an OpusProjectionDecoder allocated by - * opus_projection_decoder_create(). - * @param st OpusProjectionDecoder: Projection decoder state to be freed. - */ -OPUS_EXPORT void opus_projection_decoder_destroy(OpusProjectionDecoder *st); - - -/**@}*/ - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif /* OPUS_PROJECTION_H */ diff --git a/code/dep_codecs/include/opus/opus_types.h b/code/dep_codecs/include/opus/opus_types.h deleted file mode 100644 index 7cf67558..00000000 --- a/code/dep_codecs/include/opus/opus_types.h +++ /dev/null @@ -1,166 +0,0 @@ -/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */ -/* Modified by Jean-Marc Valin */ -/* - 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 OWNER - 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. -*/ -/* opus_types.h based on ogg_types.h from libogg */ - -/** - @file opus_types.h - @brief Opus reference implementation types -*/ -#ifndef OPUS_TYPES_H -#define OPUS_TYPES_H - -#define opus_int int /* used for counters etc; at least 16 bits */ -#define opus_int64 long long -#define opus_int8 signed char - -#define opus_uint unsigned int /* used for counters etc; at least 16 bits */ -#define opus_uint64 unsigned long long -#define opus_uint8 unsigned char - -/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */ -#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H)) -#include -# undef opus_int64 -# undef opus_int8 -# undef opus_uint64 -# undef opus_uint8 - typedef int8_t opus_int8; - typedef uint8_t opus_uint8; - typedef int16_t opus_int16; - typedef uint16_t opus_uint16; - typedef int32_t opus_int32; - typedef uint32_t opus_uint32; - typedef int64_t opus_int64; - typedef uint64_t opus_uint64; -#elif defined(_WIN32) - -# if defined(__CYGWIN__) -# include <_G_config.h> - typedef _G_int32_t opus_int32; - typedef _G_uint32_t opus_uint32; - typedef _G_int16 opus_int16; - typedef _G_uint16 opus_uint16; -# elif defined(__MINGW32__) - typedef short opus_int16; - typedef unsigned short opus_uint16; - typedef int opus_int32; - typedef unsigned int opus_uint32; -# elif defined(__MWERKS__) - typedef int opus_int32; - typedef unsigned int opus_uint32; - typedef short opus_int16; - typedef unsigned short opus_uint16; -# else - /* MSVC/Borland */ - typedef __int32 opus_int32; - typedef unsigned __int32 opus_uint32; - typedef __int16 opus_int16; - typedef unsigned __int16 opus_uint16; -# endif - -#elif defined(__MACOS__) - -# include - typedef SInt16 opus_int16; - typedef UInt16 opus_uint16; - typedef SInt32 opus_int32; - typedef UInt32 opus_uint32; - -#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ - -# include - typedef int16_t opus_int16; - typedef u_int16_t opus_uint16; - typedef int32_t opus_int32; - typedef u_int32_t opus_uint32; - -#elif defined(__BEOS__) - - /* Be */ -# include - typedef int16 opus_int16; - typedef u_int16 opus_uint16; - typedef int32_t opus_int32; - typedef u_int32_t opus_uint32; - -#elif defined (__EMX__) - - /* OS/2 GCC */ - typedef short opus_int16; - typedef unsigned short opus_uint16; - typedef int opus_int32; - typedef unsigned int opus_uint32; - -#elif defined (DJGPP) - - /* DJGPP */ - typedef short opus_int16; - typedef unsigned short opus_uint16; - typedef int opus_int32; - typedef unsigned int opus_uint32; - -#elif defined(R5900) - - /* PS2 EE */ - typedef int opus_int32; - typedef unsigned opus_uint32; - typedef short opus_int16; - typedef unsigned short opus_uint16; - -#elif defined(__SYMBIAN32__) - - /* Symbian GCC */ - typedef signed short opus_int16; - typedef unsigned short opus_uint16; - typedef signed int opus_int32; - typedef unsigned int opus_uint32; - -#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) - - typedef short opus_int16; - typedef unsigned short opus_uint16; - typedef long opus_int32; - typedef unsigned long opus_uint32; - -#elif defined(CONFIG_TI_C6X) - - typedef short opus_int16; - typedef unsigned short opus_uint16; - typedef int opus_int32; - typedef unsigned int opus_uint32; - -#else - - /* Give up, take a reasonable guess */ - typedef short opus_int16; - typedef unsigned short opus_uint16; - typedef int opus_int32; - typedef unsigned int opus_uint32; - -#endif - -#endif /* OPUS_TYPES_H */ diff --git a/code/dep_codecs/lib/FLAC.lib b/code/dep_codecs/lib/FLAC.lib deleted file mode 100755 index a77c6c98..00000000 Binary files a/code/dep_codecs/lib/FLAC.lib and /dev/null differ diff --git a/code/dep_codecs/lib/fdk-aac.lib b/code/dep_codecs/lib/fdk-aac.lib deleted file mode 100755 index b60873f1..00000000 Binary files a/code/dep_codecs/lib/fdk-aac.lib and /dev/null differ diff --git a/code/dep_codecs/lib/libFLAC.a b/code/dep_codecs/lib/libFLAC.a deleted file mode 100755 index 649fc15e..00000000 Binary files a/code/dep_codecs/lib/libFLAC.a and /dev/null differ diff --git a/code/dep_codecs/lib/libfdk-aac.a b/code/dep_codecs/lib/libfdk-aac.a deleted file mode 100755 index 91129a63..00000000 Binary files a/code/dep_codecs/lib/libfdk-aac.a and /dev/null differ diff --git a/code/dep_codecs/lib/libopus.a b/code/dep_codecs/lib/libopus.a deleted file mode 100755 index 720d63eb..00000000 Binary files a/code/dep_codecs/lib/libopus.a and /dev/null differ diff --git a/code/dep_codecs/lib/opus.lib b/code/dep_codecs/lib/opus.lib deleted file mode 100755 index a9cd3046..00000000 Binary files a/code/dep_codecs/lib/opus.lib and /dev/null differ diff --git a/code/dep_external/include/bear/iamf_bear_api.h b/code/dep_external/include/bear/iamf_bear_api.h deleted file mode 100755 index 868c0d84..00000000 --- a/code/dep_external/include/bear/iamf_bear_api.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file iamf_bear_api.h - * @brief API header for IAMF decoder to BEAR renderer Interface. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#ifndef IANF_BEAR_API_H_ -#define IANF_BEAR_API_H_ - -#include -#include - -#if defined(_WIN32) -// EXPORT_API can be used to define the dllimport storage-class attribute. -#ifdef DLL_EXPORTS -#define EXPORT_API __declspec(dllexport) -#else -#define EXPORT_API __declspec(dllimport) -#endif -#else -#define EXPORT_API -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -EXPORT_API void* CreateBearAPI(char* tf_data_path); -EXPORT_API void DestroyBearAPI(void* pv_thiz); -EXPORT_API int ConfigureBearDirectSpeakerChannel(void* pv_thiz, int layout, - int sp_flags, - size_t nsample_per_frame, - int sample_rate); -EXPORT_API int SetBearDirectSpeakerChannel(void* pv_thiz, int source_id, - float** in); -// EXPORT_API int ConfigureBearObjectChannel(...); -// EXPORT_API void SetBearObjectChannel(...); -// EXPORT_API int ConfigureBearHOAChannel(...); -// EXPORT_API void SetBearHOAChannel(...); -EXPORT_API void DestroyBearChannel(void* pv_thiz, int source_id); -EXPORT_API int GetBearRenderedAudio(void* pv_thiz, int source_id, float** out); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/code/dep_external/include/resonance/iamf_resonance_api.h b/code/dep_external/include/resonance/iamf_resonance_api.h deleted file mode 100755 index fc00303c..00000000 --- a/code/dep_external/include/resonance/iamf_resonance_api.h +++ /dev/null @@ -1,431 +0,0 @@ - -/* -Copyright 2018 Google Inc. All Rights Reserved. - -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 RESONANCE_AUDIO_API_RESONANCE_AUDIO_API2_H_ -#define RESONANCE_AUDIO_API_RESONANCE_AUDIO_API2_H_ - -#if defined(_WIN32) -// EXPORT_API can be used to define the dllimport storage-class attribute. -#ifdef DLL_EXPORTS -#define EXPORT_API __declspec(dllexport) -#else -#define EXPORT_API __declspec(dllimport) -#endif -#else -#define EXPORT_API -#endif -//#include "api/resonance_audio_api.h" -#include // size_t declaration. -#include // int16_t declaration. - -typedef int SourceId; - -typedef int16_t int16; - -// Rendering modes define CPU load / rendering quality balances. -// Note that this struct is C-compatible by design to be used across external -// C/C++ and C# implementations. -typedef enum _RenderingMode2 { - // Stereo panning, i.e., this disables HRTF-based rendering. - kStereoPanning = 0, - // HRTF-based rendering using First Order Ambisonics, over a virtual array of - // 8 loudspeakers arranged in a cube configuration around the listener's head. - kBinauralLowQuality, - // HRTF-based rendering using Second Order Ambisonics, over a virtual array of - // 12 loudspeakers arranged in a dodecahedral configuration (using faces of - // the dodecahedron). - kBinauralMediumQuality, - // HRTF-based rendering using Third Order Ambisonics, over a virtual array of - // 26 loudspeakers arranged in a Lebedev grid: https://goo.gl/DX1wh3. - kBinauralHighQuality, - // Room effects only rendering. This disables HRTF-based rendering and direct - // (dry) output of a sound object. Note that this rendering mode should *not* - // be used for general-purpose sound object spatialization, as it will only - // render the corresponding room effects of given sound objects without the - // direct spatialization. - kRoomEffectsOnly, -} RenderingMode2; - -// Distance rolloff models used for distance attenuation. -// Note that this enum is C-compatible by design to be used across external -// C/C++ and C# implementations. -typedef enum _DistanceRolloffModel2 { - // Logarithmic distance rolloff model. - kLogarithmic = 0, - // Linear distance rolloff model. - kLinear, - // Distance attenuation value will be explicitly set by the user. - kNone, -} DistanceRolloffModel2; - -// Early reflection properties of an acoustic environment. -// Note that this struct is C-compatible by design to be used across external -// C/C++ and C# implementations. -typedef struct _ReflectionProperties2 { - // Default constructor initializing all data members to 0. - // ReflectionProperties() - // : room_position{0.0f, 0.0f, 0.0f}, - // room_rotation{0.0f, 0.0f, 0.0f, 1.0f}, - // room_dimensions{0.0f, 0.0f, 0.0f}, - // cutoff_frequency(0.0f), - // coefficients{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, - // gain(0.0f) {} - - // Center position of the shoebox room in world space. - float room_position[3]; - - // Rotation (quaternion) of the shoebox room in world space. - float room_rotation[4]; - - // Size of the shoebox shoebox room in world space. - float room_dimensions[3]; - - // Frequency threshold for low pass filtering (-3dB cuttoff). - float cutoff_frequency; - - // Reflection coefficients that are stored in world space as follows: - // [0] (-)ive x-axis wall (left) - // [1] (+)ive x-axis wall (right) - // [2] (-)ive y-axis wall (bottom) - // [3] (+)ive y-axis wall (top) - // [4] (-)ive z-axis wall (front) - // [5] (+)ive z-axis wall (back) - float coefficients[6]; - - // Uniform reflections gain which is applied to all reflections. - float gain; -} ReflectionProperties2; - -// Late reverberation properties of an acoustic environment. -// Note that this struct is C-compatible by design to be used across external -// C/C++ and C# implementations. -typedef struct _ReverbProperties2 { - // Default constructor initializing all data members to 0. - // ReverbProperties() - // : rt60_values{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, - // gain(0.0f) {} - - // RT60's of the reverberation tail at different octave band centre - // frequencies in seconds. - float rt60_values[9]; - - // Reverb gain. - float gain; -} ReverbProperties2; - -// Factory method to create a |ResonanceAudioApi| instance. Caller must -// take ownership of returned instance and destroy it via operator delete. -// -// @param num_channels Number of channels of audio output. -// @param frames_per_buffer Number of frames per buffer. -// @param sample_rate_hz System sample rate. - -#ifdef __cplusplus -extern "C" { -#endif - -EXPORT_API void* CreateResonanceAudioApi2(size_t num_channels, - size_t frames_per_buffer, - int sample_rate_hz); - -// The ResonanceAudioApi library renders high-quality spatial audio. It provides -// methods to binaurally render virtual sound sources with simulated room -// acoustics. In addition, it supports decoding and binaural rendering of -// ambisonic soundfields. Its implementation is single-threaded, thread-safe -// and non-blocking to be able to process raw PCM audio buffers directly on the -// audio thread while receiving parameter updates from the main/render thread. - -// Invalid source id that can be used to initialize handler variables during -// // class construction. -// static const SourceId kInvalidSourceId = -1; - -EXPORT_API void DestroyResonanceAudioApi2(void* pv_thiz); - -// Renders and outputs an interleaved output buffer in float format. -// -// @param num_frames Size of output buffer in frames. -// @param num_channels Number of channels in output buffer. -// @param buffer_ptr Raw float pointer to audio buffer. -// @return True if a valid output was successfully rendered, false otherwise. -EXPORT_API int FillInterleavedOutputBufferFloat(void* pv_thiz, - size_t num_channels, - size_t num_frames, - float* buffer_ptr); - -// Renders and outputs an interleaved output buffer in int16 format. -// -// @param num_channels Number of channels in output buffer. -// @param num_frames Size of output buffer in frames. -// @param buffer_ptr Raw int16 pointer to audio buffer. -// @return True if a valid output was successfully rendered, false otherwise. -EXPORT_API int FillInterleavedOutputBufferInt16(void* pv_thiz, - size_t num_channels, - size_t num_frames, - int16* buffer_ptr); - -// Renders and outputs a planar output buffer in float format. -// -// @param num_frames Size of output buffer in frames. -// @param num_channels Number of channels in output buffer. -// @param buffer_ptr Pointer to array of raw float pointers to each channel of -// the audio buffer. -// @return True if a valid output was successfully rendered, false otherwise. -EXPORT_API int FillPlanarOutputBufferFloat(void* pv_thiz, size_t num_channels, - size_t num_frames, - float* const* buffer_ptr); - -// Renders and outputs a planar output buffer in int16 format. -// -// @param num_channels Number of channels in output buffer. -// @param num_frames Size of output buffer in frames. -// @param buffer_ptr Pointer to array of raw int16 pointers to each channel of -// the audio buffer. -// @return True if a valid output was successfully rendered, false otherwise. -EXPORT_API int FillPlanarOutputBufferInt16(void* pv_thiz, size_t num_channels, - size_t num_frames, - int16* const* buffer_ptr); - -// Sets listener's head position. -// -// @param x X coordinate of head position in world space. -// @param y Y coordinate of head position in world space. -// @param z Z coordinate of head position in world space. -EXPORT_API void SetHeadPositionXYZ(void* pv_thiz, float x, float y, float z); - -// Sets listener's head rotation. -// -// @param x X component of quaternion. -// @param y Y component of quaternion. -// @param z Z component of quaternion. -// @param w W component of quaternion. -EXPORT_API void SetHeadRotationXYZW(void* pv_thiz, float x, float y, float z, - float w); - -// Sets the master volume of the main audio output. -// -// @param volume Master volume (linear) in amplitude in range [0, 1] for -// attenuation, range [1, inf) for gain boost. -EXPORT_API void SetMasterVolume(void* pv_thiz, float volume); - -// Enables the stereo speaker mode. When activated, it disables HRTF-based -// filtering and switches to computationally cheaper stereo-panning. This -// helps to avoid HRTF-based coloring effects when stereo speakers are used -// and reduces computational complexity when headphone-based HRTF filtering is -// not needed. By default the stereo speaker mode is disabled. Note that -// stereo speaker mode overrides the |enable_hrtf| flag in -// |CreateSoundObjectSource|. -// -// @param enabled Flag to enable stereo speaker mode. -EXPORT_API void SetStereoSpeakerMode(void* pv_thiz, int enabled); - -// Creates an ambisonic source instance. -// -// @param num_channels Number of input channels. -// @return Id of new ambisonic source. -EXPORT_API SourceId CreateAmbisonicSource(void* pv_thiz, size_t num_channels); - -// Creates a stereo non-spatialized source instance, which directly plays back -// mono or stereo audio. -// -// @param num_channels Number of input channels. -// @return Id of new non-spatialized source. -EXPORT_API SourceId CreateStereoSource(void* pv_thiz, size_t num_channels); - -// Creates a sound object source instance. -// -// @param rendering_mode Rendering mode which governs quality and performance. -// @return Id of new sound object source. -EXPORT_API SourceId CreateSoundObjectSource(void* pv_thiz, - RenderingMode2 rendering_mode); - -// Destroys source instance. -// -// @param source_id Id of source to be destroyed. -EXPORT_API void DestroySource(void* pv_thiz, SourceId id); - -// Sets the next audio buffer in interleaved float format to a sound source. -// -// @param source_id Id of sound source. -// @param audio_buffer_ptr Pointer to interleaved float audio buffer. -// @param num_channels Number of channels in interleaved audio buffer. -// @param num_frames Number of frames per channel in interleaved audio buffer. -EXPORT_API void SetInterleavedBufferFloat(void* pv_thiz, SourceId source_id, - const float* audio_buffer_ptr, - size_t num_channels, - size_t num_frames); - -// Sets the next audio buffer in interleaved int16 format to a sound source. -// -// @param source_id Id of sound source. -// @param audio_buffer_ptr Pointer to interleaved int16 audio buffer. -// @param num_channels Number of channels in interleaved audio buffer. -// @param num_frames Number of frames per channel in interleaved audio buffer. -EXPORT_API void SetInterleavedBufferInt16(void* pv_thiz, SourceId source_id, - const int16* audio_buffer_ptr, - size_t num_channels, - size_t num_frames); - -// Sets the next audio buffer in planar float format to a sound source. -// -// @param source_id Id of sound source. -// @param audio_buffer_ptr Pointer to array of pointers referring to planar -// audio buffers for each channel. -// @param num_channels Number of planar input audio buffers. -// @param num_frames Number of frames per channel. -EXPORT_API void SetPlanarBufferFloat(void* pv_thiz, SourceId source_id, - const float* const* audio_buffer_ptr, - size_t num_channels, size_t num_frames); - -// Sets the next audio buffer in planar int16 format to a sound source. -// -// @param source_id Id of sound source. -// @param audio_buffer_ptr Pointer to array of pointers referring to planar -// audio buffers for each channel. -// @param num_channels Number of planar input audio buffers. -// @param num_frames Number of frames per channel. -EXPORT_API void SetPlanarBufferInt16(void* pv_thiz, SourceId source_id, - const int16* const* audio_buffer_ptr, - size_t num_channels, size_t num_frames); - -// Sets the given source's distance attenuation value explicitly. The distance -// rolloff model of the source must be set to |DistanceRolloffModel::kNone| -// for the set value to take effect. -// -// @param source_id Id of source. -// @param distance_attenuation Distance attenuation value. -EXPORT_API void SetSourceDistanceAttenuation(void* pv_thiz, SourceId source_id, - float distance_attenuation); - -// Sets the given source's distance attenuation method with minimum and -// maximum distances. Maximum distance must be greater than the minimum -// distance for the method to be set. -// -// @param source_id Id of source. -// @param rolloff Linear or logarithmic distance rolloff models. -// @param min_distance Minimum distance to apply distance attenuation method. -// @param max_distance Maximum distance to apply distance attenuation method. -EXPORT_API void SetSourceDistanceModel(void* pv_thiz, SourceId source_id, - DistanceRolloffModel2 rolloff, - float min_distance, float max_distance); - -// Sets the given source's position. Note that, the given position for an -// ambisonic source is only used to determine the corresponding room effects -// to be applied. -// -// @param source_id Id of source. -// @param x X coordinate of source position in world space. -// @param y Y coordinate of source position in world space. -// @param z Z coordinate of source position in world space. -EXPORT_API void SetSourcePosition(void* pv_thiz, SourceId source_id, float x, - float y, float z); - -// Sets the room effects contribution for the given source. -// -// @param source_id Id of source. -// @param room_effects_gain Linear room effects volume in amplitude in range -// [0, 1] for attenuation, range [1, inf) for gain boost. -EXPORT_API void SetSourceRoomEffectsGain(void* pv_thiz, SourceId source_id, - float room_effects_gain); - -// Sets the given source's rotation. -// -// @param source_id Id of source. -// @param x X component of quaternion. -// @param y Y component of quaternion. -// @param z Z component of quaternion. -// @param w W component of quaternion. -EXPORT_API void SetSourceRotation(void* pv_thiz, SourceId source_id, float x, - float y, float z, float w); - -// Sets the given source's volume. -// -// @param source_id Id of source. -// @param volume Linear source volume in amplitude in range [0, 1] for -// attenuation, range [1, inf) for gain boost. -EXPORT_API void SetSourceVolume(void* pv_thiz, SourceId source_id, - float volume); - -// Sets the given sound object source's directivity. -// -// @param sound_object_source_id Id of sound object source. -// @param alpha Weighting balance between figure of eight pattern and circular -// pattern for source emission in range [0, 1]. A value of 0.5 results in -// a cardioid pattern. -// @param order Order applied to computed directivity. Higher values will -// result in narrower and sharper directivity patterns. Range [1, inf). -EXPORT_API void SetSoundObjectDirectivity(void* pv_thiz, - SourceId sound_object_source_id, - float alpha, float order); - -// Sets the listener's directivity with respect to the given sound object. -// This method could be used to simulate an angular rolloff in terms of the -// listener's orientation, given the polar pickup pattern with |alpha| and -// |order|. -// -// @param sound_object_source_id Id of sound object source. -// @param alpha Weighting balance between figure of eight pattern and circular -// pattern for listener's pickup in range [0, 1]. A value of 0.5 results -// in a cardioid pattern. -// @param order Order applied to computed pickup pattern. Higher values will -// result in narrower and sharper pickup patterns. Range [1, inf). -EXPORT_API void SetSoundObjectListenerDirectivity( - void* pv_thiz, SourceId sound_object_source_id, float alpha, float order); - -// Sets the gain (linear) of the near field effect. -// -// @param sound_object_source_id Id of sound object source. -// @param gain Gain of the near field effect. Range [0, 9] (corresponding to -// approx. (-Inf, +20dB]). -EXPORT_API void SetSoundObjectNearFieldEffectGain( - void* pv_thiz, SourceId sound_object_source_id, float gain); - -// Sets the given sound object source's occlusion intensity. -// -// @param sound_object_source_id Id of sound object source. -// @param intensity Number of occlusions occurred for the object. The value -// can be set to fractional for partial occlusions. Range [0, inf). -EXPORT_API void SetSoundObjectOcclusionIntensity( - void* pv_thiz, SourceId sound_object_source_id, float intensity); - -// Sets the given sound object source's spread. -// -// @param sound_object_source_id Id of sound object source. -// @param spread_deg Spread in degrees. -EXPORT_API void SetSoundObjectSpread(void* pv_thiz, - SourceId sound_object_source_id, - float spread_deg); - -// Turns on/off the reflections and reverberation. -EXPORT_API void EnableRoomEffects(void* pv_thiz, int enable); - -// Sets the early reflection properties of the environment. -// -// @param reflection_properties Reflection properties. -EXPORT_API void SetReflectionProperties( - void* pv_thiz, const ReflectionProperties2* reflection_properties); - -// Sets the late reverberation properties of the environment. -// -// @param reverb_properties Reverb properties. -EXPORT_API void SetReverbProperties(void* pv_thiz, - const ReverbProperties2* reverb_properties); - -#ifdef __cplusplus -} -#endif - -#endif // RESONANCE_AUDIO_API_RESONANCE_AUDIO_API2_H_ diff --git a/code/dep_external/lib/binaural/libboost_filesystem.so b/code/dep_external/lib/binaural/libboost_filesystem.so deleted file mode 100755 index 60cb176e..00000000 Binary files a/code/dep_external/lib/binaural/libboost_filesystem.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/libboost_filesystem.so.1.82.0 b/code/dep_external/lib/binaural/libboost_filesystem.so.1.82.0 deleted file mode 100755 index 60cb176e..00000000 Binary files a/code/dep_external/lib/binaural/libboost_filesystem.so.1.82.0 and /dev/null differ diff --git a/code/dep_external/lib/binaural/libboost_system.so b/code/dep_external/lib/binaural/libboost_system.so deleted file mode 100755 index 63baf9bd..00000000 Binary files a/code/dep_external/lib/binaural/libboost_system.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/libboost_system.so.1.82.0 b/code/dep_external/lib/binaural/libboost_system.so.1.82.0 deleted file mode 100755 index 63baf9bd..00000000 Binary files a/code/dep_external/lib/binaural/libboost_system.so.1.82.0 and /dev/null differ diff --git a/code/dep_external/lib/binaural/libboost_thread.so b/code/dep_external/lib/binaural/libboost_thread.so deleted file mode 100755 index bd016ace..00000000 Binary files a/code/dep_external/lib/binaural/libboost_thread.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/libboost_thread.so.1.82.0 b/code/dep_external/lib/binaural/libboost_thread.so.1.82.0 deleted file mode 100755 index bd016ace..00000000 Binary files a/code/dep_external/lib/binaural/libboost_thread.so.1.82.0 and /dev/null differ diff --git a/code/dep_external/lib/binaural/libefl.so b/code/dep_external/lib/binaural/libefl.so deleted file mode 100755 index 4ad6964c..00000000 Binary files a/code/dep_external/lib/binaural/libefl.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/libiamf2bear.so b/code/dep_external/lib/binaural/libiamf2bear.so deleted file mode 100755 index 47c2a791..00000000 Binary files a/code/dep_external/lib/binaural/libiamf2bear.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/libiamf2resonance.so b/code/dep_external/lib/binaural/libiamf2resonance.so deleted file mode 100755 index de077099..00000000 Binary files a/code/dep_external/lib/binaural/libiamf2resonance.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/libobjectmodel.so b/code/dep_external/lib/binaural/libobjectmodel.so deleted file mode 100755 index 0cb271bb..00000000 Binary files a/code/dep_external/lib/binaural/libobjectmodel.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/libpanning.so b/code/dep_external/lib/binaural/libpanning.so deleted file mode 100755 index c654ea73..00000000 Binary files a/code/dep_external/lib/binaural/libpanning.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/libpml.so b/code/dep_external/lib/binaural/libpml.so deleted file mode 100755 index 2dca9c55..00000000 Binary files a/code/dep_external/lib/binaural/libpml.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/librbbl.so b/code/dep_external/lib/binaural/librbbl.so deleted file mode 100755 index f24cf293..00000000 Binary files a/code/dep_external/lib/binaural/librbbl.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/librcl.so b/code/dep_external/lib/binaural/librcl.so deleted file mode 100755 index aac5cf40..00000000 Binary files a/code/dep_external/lib/binaural/librcl.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/librrl.so b/code/dep_external/lib/binaural/librrl.so deleted file mode 100755 index 2a4a7185..00000000 Binary files a/code/dep_external/lib/binaural/librrl.so and /dev/null differ diff --git a/code/dep_external/lib/binaural/libvisr.so b/code/dep_external/lib/binaural/libvisr.so deleted file mode 100755 index 142ce277..00000000 Binary files a/code/dep_external/lib/binaural/libvisr.so and /dev/null differ diff --git a/code/dep_external/src/binaural/README.md b/code/dep_external/src/binaural/README.md deleted file mode 100755 index 5741d275..00000000 --- a/code/dep_external/src/binaural/README.md +++ /dev/null @@ -1,29 +0,0 @@ -README.md -========= -# Dependent Externals Libraries - -## Contents -1. [Downloading the opensource](#Downloading-the-opensource) -2. [Building the libraries](#Building-the-libraries) - - [Prerequisites](#Prerequisites) - - [Basic build](#Basic-build) - - -## Downloading the opensource - 1. [bear](https://github.com/ebu/bear) - 2. [resonance-audio](https://github.com/resonance-audio/resonance-audio) - - -## Building the libraries - -### Prerequisites - 1. [CMake](https://cmake.org) version 3.6 or higher. - 2. [boost](https://boostorg.jfrog.io/artifactory/main/release/1.82.0/source/boost_1_82_0.zip), version 1.82 -~~~ - $ ./bootstrap.sh --with-toolset=gcc - $ ./b2 toolset=gcc - $ ./b2 install -~~~ - -### Basic build -"build.sh" is an example to build, you can run it directly at your side. \ No newline at end of file diff --git a/code/dep_external/src/binaural/build.sh b/code/dep_external/src/binaural/build.sh deleted file mode 100755 index ab440db7..00000000 --- a/code/dep_external/src/binaural/build.sh +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (c) 2024, Alliance for Open Media. All rights reserved -# -# This source code is subject to the terms of the BSD 3-Clause Clear License -# and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear -# License was not distributed with this source code in the LICENSE file, you -# can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the -# Alliance for Open Media Patent License 1.0 was not distributed with this -# source code in the PATENTS file, you can obtain it at -# www.aomedia.org/license/patent. -# - -set -e - -PROGDIR=`pwd` -VISR_DIR="$( cd "$(dirname "$0")" ; pwd -P )/visr" -BEAR_DIR="$( cd "$(dirname "$0")" ; pwd -P )/bear" -RESONANCE_DIR="$( cd "$(dirname "$0")" ; pwd -P )/resonance-audio" -EXTERNALS_DIR="$( cd "$(dirname "$0")" ; pwd -P )/../.." -IAMF2BEAR_DIR="$( cd "$(dirname "$0")" ; pwd -P )/iamf2bear" -IAMF2RESONANCE_DIR="$( cd "$(dirname "$0")" ; pwd -P )/iamf2resonance" - - -declare -a CONFIG_FLAGS_BEAR -declare -a CONFIG_FLAGS_BEAR2 -declare -a CONFIG_FLAGS_VISR - -CONFIG_FLAGS_BEAR="-DBUILD_PYTHON_BINDINGS=OFF" -CONFIG_FLAGS_BEAR2="$VISR_DIR/build/cmake" -CONFIG_FLAGS_VISR="-DBUILD_PYTHON_BINDINGS=OFF -DBUILD_DOCUMENTATION=OFF -DBUILD_AUDIOINTERFACES_PORTAUDIO=OFF -DBUILD_USE_SNDFILE_LIBRARY=OFF" - -#Delete old libraries -rm -rf $EXTERNALS_DIR/lib/binaural/* - -CLEAN=yes -DOWNLOAD=yes - -if [ $CLEAN = yes ] ; then - echo "Cleaning: $VISR_DIR" - rm -f -r $VISR_DIR - - echo "Cleaning: $BEAR_DIR" - rm -f -r $BEAR_DIR - - echo "Cleaning: $RESONANCE_DIR" - rm -f -r $RESONANCE_DIR - [ "$DOWNLOAD" = "yes" ] || exit 0 -fi - -cd $PROGDIR -git clone -b visr --single-branch https://github.com/ebu/bear.git visr -echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>VISR Compile<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" -cd $VISR_DIR -sed -i '1 i set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)' src/libefl/CMakeLists.txt -rm -f -r build -cmake -B build . $CONFIG_FLAGS_VISR -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=NEVER -cmake --build build -cmake --install build --prefix $IAMF2BEAR_DIR - -cd $PROGDIR -git clone https://github.com/ebu/bear -echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>BEAR Compile<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" -cd $BEAR_DIR -git submodule update --init --recursive -cd visr_bear -rm -f -r build -cmake -B build . $CONFIG_FLAGS_BEAR -DVISR_DIR=$CONFIG_FLAGS_BEAR2 -cmake --build build --clean-first -cmake --install build --prefix $IAMF2BEAR_DIR - - -echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>iamf2bear Compile<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" -cd $IAMF2BEAR_DIR -cmake . -DCMAKE_INSTALL_PREFIX=$EXTERNALS_DIR -make -make install - -cd $PROGDIR -git clone https://github.com/resonance-audio/resonance-audio -echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>Resonance Compile<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" -cd $RESONANCE_DIR -./third_party/clone_core_deps.sh -rm -rf third_party/eigen -cp -rf ../bear/visr_bear/submodules/libear/submodules/eigen third_party/ -./build.sh -t=RESONANCE_AUDIO_API -p=Debug -cp -rf install/resonance_audio $IAMF2RESONANCE_DIR - -echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>iamf2resonance Compile<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" -cd $IAMF2RESONANCE_DIR -cmake . -DCMAKE_INSTALL_PREFIX=$EXTERNALS_DIR -make -make install - - diff --git a/code/dep_external/src/binaural/iamf2bear/CMakeLists.txt b/code/dep_external/src/binaural/iamf2bear/CMakeLists.txt deleted file mode 100755 index 53f54212..00000000 --- a/code/dep_external/src/binaural/iamf2bear/CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -cmake_minimum_required(VERSION 3.6) - -project (iamf2bear) - -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11") -SET(CMAKE_POSITION_INDEPENDENT_CODE ON) - -option(BUILD_SHARED_LIBS "Build shared library" ON) - -set(EXTERNAL_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib") -set(EXTERNAL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") - -find_package(Boost REQUIRED) -include_directories(${Boost_INCLUDE_DIRS}) - -include_directories( - ${EXTERNAL_INCLUDE_DIR} -) - -link_directories ( - ${EXTERNAL_LIB_DIR} -) - -set(3rd_libraries - efl - objectmodel - panning - pml - rbbl - rcl - rrl - visr -) -set(available_libraries) -foreach(library IN LISTS 3rd_libraries) - file( GLOB cmake_varibale ${EXTERNAL_LIB_DIR}/*${library}*) - list(APPEND available_libraries ${cmake_varibale}) -endforeach() - -if(BUILD_SHARED_LIBS) - add_library(${PROJECT_NAME} SHARED iamf2bear.cpp) - target_link_libraries (${PROJECT_NAME} ${3rd_libraries} bear ear) -endif() - -set(IAMF2RESONANCE_PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/iamf_bear_api.h) -set_target_properties(iamf2bear PROPERTIES PUBLIC_HEADER "${IAMF2RESONANCE_PUBLIC_HEADER}") - -install(TARGETS ${PROJECT_NAME} - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/binaural - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/bear) - -install(FILES ${available_libraries} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/binaural) - diff --git a/code/dep_external/src/binaural/iamf2bear/iamf2bear.cpp b/code/dep_external/src/binaural/iamf2bear/iamf2bear.cpp deleted file mode 100755 index d242c121..00000000 --- a/code/dep_external/src/binaural/iamf2bear/iamf2bear.cpp +++ /dev/null @@ -1,621 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file bear.cpp - * @brief API implementation for IAMF decoder to BEAR renderer Interface. - * @version 0.1 - * @date Created 03/03/2023 - **/ -#define _CRT_SECURE_NO_WARNINGS -#define DLL_EXPORTS - -#if defined(_WIN32) -#include -#else -#include -#endif -#include -#if defined(__APPLE__) -#include -#endif -#include - -#include "bear/api.hpp" -#include "bear/variable_block_size.hpp" -#include "ear/ear.hpp" -#include "iamf_bear_api.h" -using namespace bear; -using namespace ear; - -#if defined(_WIN32) -// EXPORT_API can be used to define the dllimport storage-class attribute. -#ifdef DLL_EXPORTS -#define EXPORT_API __declspec(dllexport) -#else -#define EXPORT_API __declspec(dllimport) -#endif -#else -#define EXPORT_API -#endif - -// max input audio element number is 28 -#define MAX_INPUT_SOURCES 28 -// max total number of input channels is number channels of IAMF_916 source -#define MAX_INPUT_CHANNELS 16 -#define MAX_PATH 260 - -struct BearAPIImplement { - Config *m_pConfig[MAX_INPUT_SOURCES]; - Renderer *m_pRenderer[MAX_INPUT_SOURCES]; - DirectSpeakersInput *m_pDirectSpeakersInput[MAX_INPUT_SOURCES]; - float **in[MAX_INPUT_SOURCES]; - char tf_data[MAX_PATH]; -}; - -typedef enum { - BS2051_A = 0x020, // 2ch output - BS2051_B = 0x050, // 6ch output - BS2051_C = 0x250, // 8ch output - BS2051_D = 0x450, // 10ch output - BS2051_E = 0x451, // 11ch output - BS2051_F = 0x370, // 12ch output - BS2051_G = 0x490, // 14ch output - BS2051_H = 0x9A3, // 24ch output - BS2051_I = 0x070, // 8ch output - BS2051_J = 0x470, // 12ch output - IAMF_STEREO = 0x200, // 2ch input - IAMF_51 = 0x510, // 6ch input - IAMF_512 = 0x512, // 8ch input - IAMF_514 = 0x514, // 10ch input - IAMF_71 = 0x710, // 8ch input - IAMF_714 = 0x714, // 12ch input - IAMF_MONO = 0x100, // 1ch input, AOM only - IAMF_712 = 0x712, // 10ch input, AOM only - IAMF_312 = 0x312, // 6ch input, AOM only - IAMF_BINAURAL = 0x1020, // binaural input/output AOM only - IAMF_916 = 0x916 // 16ch input/output, AOM only -} IAMF_SOUND_SYSTEM; - -typedef enum { - SP_MP000 = 0x00000001, - SP_MP030 = 0x00000002, - SP_MM030 = 0x00000004, - SP_MP045 = 0x00000008, - SP_MM045 = 0x00000010, - SP_MP060 = 0x00000020, - SP_MM060 = 0x00000040, - SP_MP090 = 0x00000080, - SP_MM090 = 0x00000100, - SP_MP110 = 0x00000200, - SP_MM110 = 0x00000400, - SP_MP135 = 0x00000800, - SP_MM135 = 0x00001000, - SP_MP180 = 0x00002000, - SP_TP000 = 0x00004000, - SP_UP000 = 0x00008000, - SP_UP030 = 0x00010000, - SP_UM030 = 0x00020000, - SP_UP045 = 0x00040000, - SP_UM045 = 0x00080000, - SP_UP090 = 0x00100000, - SP_UM090 = 0x00200000, - SP_UP110 = 0x00400000, - SP_UM110 = 0x00800000, - SP_UP135 = 0x01000000, - SP_UM135 = 0x02000000, - SP_UP180 = 0x04000000, - SP_BP000 = 0x08000000, - SP_BP045 = 0x10000000, - SP_BM045 = 0x20000000, - SP_LFE1 = 0x40000000, - SP_LFE2 = 0x80000000 -} BS2051_SPLABEL; - -BS2051_SPLABEL iamf_stereo_spl[] = {SP_MP030, SP_MM030}; -BS2051_SPLABEL iamf_51_spl[] = {SP_MP030, SP_MM030, SP_MP000, - SP_LFE1, SP_MP110, SP_MM110}; -BS2051_SPLABEL iamf_512_spl[] = {SP_MP030, SP_MM030, SP_MP000, SP_LFE1, - SP_MP110, SP_MM110, SP_UP030, SP_UM030}; -BS2051_SPLABEL iamf_514_spl[] = {SP_MP030, SP_MM030, SP_MP000, SP_LFE1, - SP_MP110, SP_MM110, SP_UP030, SP_UM030, - SP_UP110, SP_UM110}; -BS2051_SPLABEL iamf_71_spl[] = {SP_MP030, SP_MM030, SP_MP000, SP_LFE1, - SP_MP090, SP_MM090, SP_MP135, SP_MM135}; -BS2051_SPLABEL iamf_714_spl[] = {SP_MP030, SP_MM030, SP_MP000, SP_LFE1, - SP_MP090, SP_MM090, SP_MP135, SP_MM135, - SP_UP045, SP_UM045, SP_UP135, SP_UM135}; -BS2051_SPLABEL iamf_mono_spl[] = {SP_MP000}; -BS2051_SPLABEL iamf_712_spl[] = {SP_MP030, SP_MM030, SP_MP000, SP_LFE1, - SP_MP090, SP_MM090, SP_MP135, SP_MM135, - SP_UP045, SP_UM045}; -BS2051_SPLABEL iamf_312_spl[] = {SP_MP030, SP_MM030, SP_MP000, - SP_LFE1, SP_UP030, SP_UM030}; -BS2051_SPLABEL iamf_916_spl[] = {SP_MP060, SP_MM060, SP_MP000, SP_LFE1, - SP_MP135, SP_MM135, SP_MP030, SP_MM030, - SP_MP090, SP_MM090, SP_UP045, SP_UM045, - SP_UP135, SP_UM135, SP_UP090, SP_UM090}; - -struct iamf_splabel_per_layout_t { - IAMF_SOUND_SYSTEM system; - int channels; - BS2051_SPLABEL *sp_labels; -} iamf_splabel_per_layout[] = { - {IAMF_STEREO, 2, iamf_stereo_spl}, {IAMF_51, 6, iamf_51_spl}, - {IAMF_512, 8, iamf_512_spl}, {IAMF_514, 10, iamf_514_spl}, - {IAMF_71, 8, iamf_71_spl}, {IAMF_714, 12, iamf_714_spl}, - {IAMF_MONO, 1, iamf_mono_spl}, {IAMF_712, 10, iamf_712_spl}, - {IAMF_312, 6, iamf_312_spl}, {IAMF_BINAURAL, 2, iamf_stereo_spl}, - {IAMF_916, 16, iamf_916_spl}}; - -Layout layout010 = Layout{ - "0+1+0", - std::vector{ - Channel{"M+000", - PolarPosition{0.0, 0.0}, - PolarPosition{0.0, 0.0}, - std::make_pair(0.0, 0.0), - std::make_pair(0.0, 0.0), - false}, - }}; - -Layout layout230 = Layout{ - "2+3+0", - std::vector{ - Channel{"M+030", - PolarPosition{30.0, 0.0}, - PolarPosition{30.0, 0.0}, - std::make_pair(30.0, 30.0), - std::make_pair(0.0, 0.0), - false}, - Channel{"M-030", - PolarPosition{-30.0, 0.0}, - PolarPosition{-30.0, 0.0}, - std::make_pair(-30.0, -30.0), - std::make_pair(0.0, 0.0), - false}, - Channel{"M+000", - PolarPosition{0.0, 0.0}, - PolarPosition{0.0, 0.0}, - std::make_pair(0.0, 0.0), - std::make_pair(0.0, 0.0), - false}, - Channel{"LFE1", - PolarPosition{45.0, -30.0}, - PolarPosition{45.0, -30.0}, - std::make_pair(-180.0, 180.0), - std::make_pair(-90.0, 90.0), - true}, - Channel{"U+030", - PolarPosition{30.0, 30.0}, - PolarPosition{30.0, 30.0}, - std::make_pair(30.0, 45.0), - std::make_pair(30.0, 55.0), - false}, - Channel{"U-030", - PolarPosition{-30.0, 30.0}, - PolarPosition{-30.0, 30.0}, - std::make_pair(-45.0, -30.0), - std::make_pair(30.0, 55.0), - false}, - }}; - -Layout layout270 = Layout{ - "2+7+0", - std::vector{ - Channel{"M+030", - PolarPosition{30.0, 0.0}, - PolarPosition{30.0, 0.0}, - std::make_pair(30.0, 45.0), - std::make_pair(0.0, 0.0), - false}, - Channel{"M-030", - PolarPosition{-30.0, 0.0}, - PolarPosition{-30.0, 0.0}, - std::make_pair(-45.0, -30.0), - std::make_pair(0.0, 0.0), - false}, - Channel{"M+000", - PolarPosition{0.0, 0.0}, - PolarPosition{0.0, 0.0}, - std::make_pair(0.0, 0.0), - std::make_pair(0.0, 0.0), - false}, - Channel{"LFE1", - PolarPosition{45.0, -30.0}, - PolarPosition{45.0, -30.0}, - std::make_pair(-180.0, 180.0), - std::make_pair(-90.0, 90.0), - true}, - Channel{"M+090", - PolarPosition{90.0, 0.0}, - PolarPosition{90.0, 0.0}, - std::make_pair(85.0, 110.0), - std::make_pair(0.0, 0.0), - false}, - Channel{"M-090", - PolarPosition{-90.0, 0.0}, - PolarPosition{-90.0, 0.0}, - std::make_pair(-110.0, -85.0), - std::make_pair(0.0, 0.0), - false}, - Channel{"M+135", - PolarPosition{135.0, 0.0}, - PolarPosition{135.0, 0.0}, - std::make_pair(120.0, 150.0), - std::make_pair(0.0, 0.0), - false}, - Channel{"M-135", - PolarPosition{-135.0, 0.0}, - PolarPosition{-135.0, 0.0}, - std::make_pair(-150.0, -120.0), - std::make_pair(0.0, 0.0), - false}, - Channel{"U+045", - PolarPosition{45.0, 30.0}, - PolarPosition{45.0, 30.0}, - std::make_pair(30.0, 45.0), - std::make_pair(30.0, 55.0), - false}, - Channel{"U-045", - PolarPosition{-45.0, 30.0}, - PolarPosition{-45.0, 30.0}, - std::make_pair(-45.0, -30.0), - std::make_pair(30.0, 55.0), - false}, - }}; - -Layout layout690 = Layout{ - "6+9+0", - std::vector{ - Channel{"M+060", - PolarPosition{60.0, 0.0}, - PolarPosition{60.0, 0.0}, - std::make_pair(45.0, 60.0), - std::make_pair(0.0, 5.0), - false}, - Channel{"M-060", - PolarPosition{-60.0, 0.0}, - PolarPosition{-60.0, 0.0}, - std::make_pair(-60.0, -45.0), - std::make_pair(0.0, 5.0), - false}, - Channel{"M+000", - PolarPosition{0.0, 0.0}, - PolarPosition{0.0, 0.0}, - std::make_pair(0.0, 0.0), - std::make_pair(0.0, 5.0), - false}, - Channel{"LFE1", - PolarPosition{45.0, -30.0}, - PolarPosition{45.0, -30.0}, - std::make_pair(30.0, 90.0), - std::make_pair(-30.0, -15.0), - true}, - Channel{"M+135", - PolarPosition{135.0, 0.0}, - PolarPosition{135.0, 0.0}, - std::make_pair(110.0, 135.0), - std::make_pair(0.0, 15.0), - false}, - Channel{"M-135", - PolarPosition{-135.0, 0.0}, - PolarPosition{-135.0, 0.0}, - std::make_pair(-135.0, -110.0), - std::make_pair(0.0, 15.0), - false}, - Channel{"M+030", - PolarPosition{30.0, 0.0}, - PolarPosition{30.0, 0.0}, - std::make_pair(22.5, 30.0), - std::make_pair(0.0, 5.0), - false}, - Channel{"M-030", - PolarPosition{-30.0, 0.0}, - PolarPosition{-30.0, 0.0}, - std::make_pair(-30.0, -22.5), - std::make_pair(0.0, 5.0), - false}, - Channel{"M+090", - PolarPosition{90.0, 0.0}, - PolarPosition{90.0, 0.0}, - std::make_pair(90.0, 90.0), - std::make_pair(0.0, 15.0), - false}, - Channel{"M-090", - PolarPosition{-90.0, 0.0}, - PolarPosition{-90.0, 0.0}, - std::make_pair(-90.0, -90.0), - std::make_pair(0.0, 15.0), - false}, - Channel{"U+045", - PolarPosition{45.0, 30.0}, - PolarPosition{45.0, 30.0}, - std::make_pair(45.0, 60.0), - std::make_pair(30.0, 45.0), - false}, - Channel{"U-045", - PolarPosition{-45.0, 30.0}, - PolarPosition{-45.0, 30.0}, - std::make_pair(-60.0, -45.0), - std::make_pair(30.0, 45.0), - false}, - Channel{"U+135", - PolarPosition{135.0, 30.0}, - PolarPosition{135.0, 30.0}, - std::make_pair(110.0, 135.0), - std::make_pair(30.0, 45.0), - false}, - Channel{"U-135", - PolarPosition{-135.0, 30.0}, - PolarPosition{-135.0, 30.0}, - std::make_pair(-135.0, -110.0), - std::make_pair(30.0, 45.0), - false}, - Channel{"U+090", - PolarPosition{90.0, 30.0}, - PolarPosition{90.0, 30.0}, - std::make_pair(90.0, 90.0), - std::make_pair(30.0, 45.0), - false}, - Channel{"U-090", - PolarPosition{-90.0, 30.0}, - PolarPosition{-90.0, 30.0}, - std::make_pair(-90.0, -90.0), - std::make_pair(30.0, 45.0), - false}}}; - -static int getmodulepath(char *path, int buffsize) { - int count = 0, i = 0; -#if defined(_WIN32) - count = GetModuleFileName(NULL, path, buffsize); -#elif defined(__APPLE__) - uint32_t size = MAX_PATH; - _NSGetExecutablePath(path, &size); - count = size; -#else - count = readlink("/proc/self/exe", path, buffsize); -#endif - for (i = count - 1; i >= 0; --i) { - if (path[i] == '\\' || path[i] == '/') { - path[i] = '\0'; - return (strlen(path)); - } - } - return (0); -} - -extern "C" EXPORT_API void *CreateBearAPI(char *tf_data_path) { - int i; - struct BearAPIImplement *thiz = - (struct BearAPIImplement *)malloc(sizeof(struct BearAPIImplement)); - char mod_path[MAX_PATH]; - - if (thiz) { - if (tf_data_path == NULL || strlen(tf_data_path) >= sizeof(thiz->tf_data)) { - if (getmodulepath(mod_path, sizeof(mod_path)) > 0) { - strcpy(thiz->tf_data, mod_path); -#if defined(_WIN32) - strcat(thiz->tf_data, "\\default.tf"); -#else - strcat(thiz->tf_data, "/default.tf"); -#endif - } else { - free(thiz); - return (NULL); - } - } else { - strcpy(thiz->tf_data, tf_data_path); - } -#ifdef __linux__ - if (access(thiz->tf_data, F_OK) == -1) { - fprintf(stderr, "%s is not found.\n", thiz->tf_data); - free(thiz); - return (NULL); - } -#elif _WIN32 - DWORD attrib = GetFileAttributes(thiz->tf_data); - if (attrib == INVALID_FILE_ATTRIBUTES) { - fprintf(stderr, "%s is not found.\n", thiz->tf_data); - free(thiz); - return (NULL); - } else if (attrib & FILE_ATTRIBUTE_DIRECTORY) { - fprintf(stderr, "%s is not found.\n", thiz->tf_data); - free(thiz); - return (NULL); - } -#endif - for (i = 0; i < MAX_INPUT_SOURCES; i++) { - thiz->m_pConfig[i] = NULL; - thiz->m_pRenderer[i] = NULL; - thiz->m_pDirectSpeakersInput[i] = NULL; - } - return ((void *)thiz); - } else { - return (NULL); - } -} - -extern "C" EXPORT_API void DestroyBearAPI(void *pv_thiz) { - int i; - BearAPIImplement *thiz = (BearAPIImplement *)pv_thiz; - - if (pv_thiz) { - for (i = 0; i < MAX_INPUT_SOURCES; i++) { - if (thiz->m_pConfig[i]) delete thiz->m_pConfig[i]; - if (thiz->m_pConfig[i]) delete thiz->m_pRenderer[i]; - if (thiz->m_pConfig[i]) delete thiz->m_pDirectSpeakersInput[i]; - } - return free(pv_thiz); - } -} - -extern "C" EXPORT_API int ConfigureBearDirectSpeakerChannel( - void *pv_thiz, int layout, int sp_flags, size_t nsample_per_frame, - int sample_rate) { - int source_id = -1; - int is, ch, m; - BearAPIImplement *thiz = (BearAPIImplement *)pv_thiz; - ear::Layout baselayout; - ear::Layout earlayout; - int channels; - std::vector channel_list; - int chmap[MAX_INPUT_CHANNELS] = { - 0, - }; - - if (pv_thiz) { - for (is = 0; is < MAX_INPUT_SOURCES; is++) { - if (!thiz->m_pConfig[is]) break; - } - if (is < MAX_INPUT_SOURCES) { - thiz->m_pConfig[is] = new Config(); - switch (layout) { - case IAMF_STEREO: - baselayout = ear::getLayout("0+2+0"); - channels = 2; - break; - case IAMF_51: - baselayout = ear::getLayout("0+5+0"); - channels = 6; - break; - case IAMF_512: - baselayout = ear::getLayout("2+5+0"); - channels = 8; - break; - case IAMF_514: - baselayout = ear::getLayout("4+5+0"); - channels = 10; - break; - case IAMF_71: - baselayout = ear::getLayout("0+7+0"); - channels = 8; - break; - case IAMF_714: - baselayout = ear::getLayout("4+7+0"); - channels = 12; - break; - case IAMF_MONO: - baselayout = layout010; // extended - channels = 1; - break; - case IAMF_712: - baselayout = layout270; // extended - channels = 10; - break; - case IAMF_312: - baselayout = layout230; // extended - channels = 6; - break; - case IAMF_916: - baselayout = layout690; // extended - channels = 16; - break; - } - if (sp_flags == 0) { // predefinded layout(input) - earlayout = baselayout; - } else { // custom speaker layout(input) - for (int i = 0; i < sizeof(iamf_splabel_per_layout) / - sizeof(struct iamf_splabel_per_layout_t); - i++) { - if (layout == iamf_splabel_per_layout[i].system) { - m = 0; - for (ch = 0; ch < iamf_splabel_per_layout[i].channels; ch++) { - if (sp_flags & iamf_splabel_per_layout[i].sp_labels[ch]) { - chmap[m] = ch; - m++; - } - } - break; - } - } - channels = m; - for (int i = 0; i < channels; i++) { - Channel chx = baselayout.channels()[chmap[i]]; - channel_list.push_back(chx); - } - earlayout = Layout("extended_layout", channel_list); - } - - thiz->m_pConfig[is]->set_num_direct_speakers_channels(channels); - thiz->m_pConfig[is]->set_period_size(nsample_per_frame); - thiz->m_pConfig[is]->set_sample_rate(sample_rate); - thiz->m_pConfig[is]->set_data_path(thiz->tf_data); - - thiz->m_pRenderer[is] = new Renderer(*thiz->m_pConfig[is]); - thiz->m_pDirectSpeakersInput[is] = new DirectSpeakersInput(); - - for (ch = 0; ch < earlayout.channels().size(); ch++) { - double Azi = earlayout.channels().at(ch).polarPosition().azimuth; - double El = earlayout.channels().at(ch).polarPosition().elevation; - double Dist = earlayout.channels().at(ch).polarPosition().distance; - thiz->m_pDirectSpeakersInput[is]->type_metadata.position = - ear::PolarSpeakerPosition(Azi, El, Dist); - thiz->m_pRenderer[is]->add_direct_speakers_block( - ch, *thiz->m_pDirectSpeakersInput[is]); - } - - source_id = is; - } - } - - return (source_id); -} - -extern "C" EXPORT_API int SetBearDirectSpeakerChannel(void *pv_thiz, - int source_id, - float **in) { - BearAPIImplement *thiz = (BearAPIImplement *)pv_thiz; - if (0 <= source_id && source_id < MAX_INPUT_SOURCES) { - if (pv_thiz && thiz->m_pConfig[source_id] != NULL) { - thiz->in[source_id] = in; - return (0); - } - } - return (-1); -} - -extern "C" EXPORT_API void DestroyBearChannel(void *pv_thiz, int source_id) { - BearAPIImplement *thiz = (BearAPIImplement *)pv_thiz; - - if (pv_thiz) { - if (0 <= source_id && source_id < MAX_INPUT_SOURCES) { - if (thiz->m_pConfig[source_id]) { - if (thiz->m_pConfig[source_id]) delete thiz->m_pConfig[source_id]; - if (thiz->m_pConfig[source_id]) delete thiz->m_pRenderer[source_id]; - if (thiz->m_pConfig[source_id]) - delete thiz->m_pDirectSpeakersInput[source_id]; - thiz->m_pConfig[source_id] = NULL; - thiz->m_pRenderer[source_id] = NULL; - thiz->m_pDirectSpeakersInput[source_id] = NULL; - thiz->in[source_id] = NULL; - } - } - } -} - -extern "C" EXPORT_API int GetBearRenderedAudio(void *pv_thiz, int source_id, - float **out) { - BearAPIImplement *thiz = (BearAPIImplement *)pv_thiz; - - if (pv_thiz) { - if (0 <= source_id && source_id < MAX_INPUT_SOURCES && - thiz->in[source_id] != NULL) { - if (thiz->m_pConfig[source_id]) { - thiz->m_pRenderer[source_id]->process(NULL, thiz->in[source_id], NULL, - out); - return (0); - } - } - } - return (-1); -} diff --git a/code/dep_external/src/binaural/iamf2bear/iamf_bear_api.h b/code/dep_external/src/binaural/iamf2bear/iamf_bear_api.h deleted file mode 100755 index 868c0d84..00000000 --- a/code/dep_external/src/binaural/iamf2bear/iamf_bear_api.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file iamf_bear_api.h - * @brief API header for IAMF decoder to BEAR renderer Interface. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#ifndef IANF_BEAR_API_H_ -#define IANF_BEAR_API_H_ - -#include -#include - -#if defined(_WIN32) -// EXPORT_API can be used to define the dllimport storage-class attribute. -#ifdef DLL_EXPORTS -#define EXPORT_API __declspec(dllexport) -#else -#define EXPORT_API __declspec(dllimport) -#endif -#else -#define EXPORT_API -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -EXPORT_API void* CreateBearAPI(char* tf_data_path); -EXPORT_API void DestroyBearAPI(void* pv_thiz); -EXPORT_API int ConfigureBearDirectSpeakerChannel(void* pv_thiz, int layout, - int sp_flags, - size_t nsample_per_frame, - int sample_rate); -EXPORT_API int SetBearDirectSpeakerChannel(void* pv_thiz, int source_id, - float** in); -// EXPORT_API int ConfigureBearObjectChannel(...); -// EXPORT_API void SetBearObjectChannel(...); -// EXPORT_API int ConfigureBearHOAChannel(...); -// EXPORT_API void SetBearHOAChannel(...); -EXPORT_API void DestroyBearChannel(void* pv_thiz, int source_id); -EXPORT_API int GetBearRenderedAudio(void* pv_thiz, int source_id, float** out); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/code/dep_external/src/binaural/iamf2resonance/CMakeLists.txt b/code/dep_external/src/binaural/iamf2resonance/CMakeLists.txt deleted file mode 100755 index 01f68137..00000000 --- a/code/dep_external/src/binaural/iamf2resonance/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -cmake_minimum_required(VERSION 3.6) - -project (iamf2resonance) - -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11") -SET(CMAKE_POSITION_INDEPENDENT_CODE ON) - -option(BUILD_SHARED_LIBS "Build shared library" ON) - -set(EXTERNAL_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resonance_audio/lib") -set(EXTERNAL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resonance_audio/include") - -include_directories( - ${EXTERNAL_INCLUDE_DIR} -) - -link_directories ( - ${EXTERNAL_LIB_DIR} -) - -if(BUILD_SHARED_LIBS) - add_library(${PROJECT_NAME} SHARED iamf2resonance.cc) - target_link_libraries (${PROJECT_NAME} ResonanceAudioStatic) -endif() - - - -set(IAMF2RESONANCE_PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/iamf_resonance_api.h) -set_target_properties(iamf2resonance PROPERTIES PUBLIC_HEADER "${IAMF2RESONANCE_PUBLIC_HEADER}") - -install(TARGETS ${PROJECT_NAME} - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/binaural - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/resonance) \ No newline at end of file diff --git a/code/dep_external/src/binaural/iamf2resonance/iamf2resonance.cc b/code/dep_external/src/binaural/iamf2resonance/iamf2resonance.cc deleted file mode 100755 index 2702f318..00000000 --- a/code/dep_external/src/binaural/iamf2resonance/iamf2resonance.cc +++ /dev/null @@ -1,399 +0,0 @@ -/* -Copyright 2018 Google Inc. All Rights Reserved. - -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 // size_t declaration. -#include // int16_t declaration. -#define DLL_EXPORTS - -#include "resonance_audio_api.h" -#include "iamf_resonance_api.h" - -namespace vraudio { - - - extern "C" EXPORT_API void* CreateResonanceAudioApi2( - size_t num_channels, size_t frames_per_buffer, int sample_rate_hz) { - return (void*)CreateResonanceAudioApi(num_channels, frames_per_buffer, - sample_rate_hz); - } - - - // Sound object / ambisonic source identifier. - typedef int SourceId; - - // Invalid source id that can be used to initialize handler variables during - // class construction. - //static const SourceId ` = -1; - - extern "C" EXPORT_API void DestroyResonanceAudioApi2(void* pv_thiz) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - delete thiz; - } - - // Renders and outputs an interleaved output buffer in float format. - // - // @param num_frames Size of output buffer in frames. - // @param num_channels Number of channels in output buffer. - // @param buffer_ptr Raw float pointer to audio buffer. - // @return True if a valid output was successfully rendered, false otherwise. - extern "C" EXPORT_API int FillInterleavedOutputBufferFloat(void* pv_thiz, size_t num_channels, - size_t num_frames, - float* buffer_ptr) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (int)(thiz->FillInterleavedOutputBuffer(num_channels, num_frames, buffer_ptr)); - } - - - // Renders and outputs an interleaved output buffer in int16 format. - // - // @param num_channels Number of channels in output buffer. - // @param num_frames Size of output buffer in frames. - // @param buffer_ptr Raw int16 pointer to audio buffer. - // @return True if a valid output was successfully rendered, false otherwise. - extern "C" EXPORT_API int FillInterleavedOutputBufferInt16(void* pv_thiz, size_t num_channels, - size_t num_frames, - int16 * buffer_ptr) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (int)(thiz->FillInterleavedOutputBuffer(num_channels, num_frames, buffer_ptr)); - } - - // Renders and outputs a planar output buffer in float format. - // - // @param num_frames Size of output buffer in frames. - // @param num_channels Number of channels in output buffer. - // @param buffer_ptr Pointer to array of raw float pointers to each channel of - // the audio buffer. - // @return True if a valid output was successfully rendered, false otherwise. - extern "C" EXPORT_API int FillPlanarOutputBufferFloat(void* pv_thiz, size_t num_channels, size_t num_frames, - float* const* buffer_ptr) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (int)(thiz->FillPlanarOutputBuffer(num_channels, num_frames, buffer_ptr)); - } - // Renders and outputs a planar output buffer in int16 format. - // - // @param num_channels Number of channels in output buffer. - // @param num_frames Size of output buffer in frames. - // @param buffer_ptr Pointer to array of raw int16 pointers to each channel of - // the audio buffer. - // @return True if a valid output was successfully rendered, false otherwise. - extern "C" EXPORT_API int FillPlanarOutputBufferInt16(void* pv_thiz, size_t num_channels, size_t num_frames, - int16* const* buffer_ptr) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (int)(thiz->FillPlanarOutputBuffer(num_channels, num_frames, buffer_ptr)); - } - // Sets listener's head position. - // - // @param x X coordinate of head position in world space. - // @param y Y coordinate of head position in world space. - // @param z Z coordinate of head position in world space. - extern "C" EXPORT_API void SetHeadPositionXYZ(void* pv_thiz, float x, float y, float z) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetHeadPosition(x, y, z)); - } - // Sets listener's head rotation. - // - // @param x X component of quaternion. - // @param y Y component of quaternion. - // @param z Z component of quaternion. - // @param w W component of quaternion. - extern "C" EXPORT_API void SetHeadRotationXYZW(void* pv_thiz, float x, float y, float z, float w) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetHeadRotation(x, y, z, w)); - } - // Sets the master volume of the main audio output. - // - // @param volume Master volume (linear) in amplitude in range [0, 1] for - // attenuation, range [1, inf) for gain boost. - extern "C" EXPORT_API void SetMasterVolume(void* pv_thiz, float volume) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetMasterVolume(volume)); - } - // Enables the stereo speaker mode. When activated, it disables HRTF-based - // filtering and switches to computationally cheaper stereo-panning. This - // helps to avoid HRTF-based coloring effects when stereo speakers are used - // and reduces computational complexity when headphone-based HRTF filtering is - // not needed. By default the stereo speaker mode is disabled. Note that - // stereo speaker mode overrides the |enable_hrtf| flag in - // |CreateSoundObjectSource|. - // - // @param enabled Flag to enable stereo speaker mode. - extern "C" EXPORT_API void SetStereoSpeakerMode(void* pv_thiz, int enabled) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetStereoSpeakerMode((bool)enabled)); - } - // Creates an ambisonic source instance. - // - // @param num_channels Number of input channels. - // @return Id of new ambisonic source. - extern "C" EXPORT_API SourceId CreateAmbisonicSource(void* pv_thiz, size_t num_channels) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->CreateAmbisonicSource(num_channels)); - } - // Creates a stereo non-spatialized source instance, which directly plays back - // mono or stereo audio. - // - // @param num_channels Number of input channels. - // @return Id of new non-spatialized source. - extern "C" EXPORT_API SourceId CreateStereoSource(void* pv_thiz, size_t num_channels) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->CreateStereoSource(num_channels)); - } - // Creates a sound object source instance. - // - // @param rendering_mode Rendering mode which governs quality and performance. - // @return Id of new sound object source. - extern "C" EXPORT_API SourceId CreateSoundObjectSource(void* pv_thiz, RenderingMode2 rendering_mode) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->CreateSoundObjectSource((RenderingMode)rendering_mode)); - } - // Destroys source instance. - // - // @param source_id Id of source to be destroyed. - extern "C" EXPORT_API void DestroySource(void* pv_thiz, SourceId id) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->DestroySource(id)); - } - // Sets the next audio buffer in interleaved float format to a sound source. - // - // @param source_id Id of sound source. - // @param audio_buffer_ptr Pointer to interleaved float audio buffer. - // @param num_channels Number of channels in interleaved audio buffer. - // @param num_frames Number of frames per channel in interleaved audio buffer. - extern "C" EXPORT_API void SetInterleavedBufferFloat(void* pv_thiz, SourceId source_id, - const float* audio_buffer_ptr, - size_t num_channels, size_t num_frames) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetInterleavedBuffer(source_id, audio_buffer_ptr, num_channels, num_frames)); - } - // Sets the next audio buffer in interleaved int16 format to a sound source. - // - // @param source_id Id of sound source. - // @param audio_buffer_ptr Pointer to interleaved int16 audio buffer. - // @param num_channels Number of channels in interleaved audio buffer. - // @param num_frames Number of frames per channel in interleaved audio buffer. - extern "C" EXPORT_API void SetInterleavedBufferInt16(void* pv_thiz, SourceId source_id, - const int16 * audio_buffer_ptr, - size_t num_channels, size_t num_frames) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetInterleavedBuffer(source_id, audio_buffer_ptr, num_channels, num_frames)); - } - // Sets the next audio buffer in planar float format to a sound source. - // - // @param source_id Id of sound source. - // @param audio_buffer_ptr Pointer to array of pointers referring to planar - // audio buffers for each channel. - // @param num_channels Number of planar input audio buffers. - // @param num_frames Number of frames per channel. - extern "C" EXPORT_API void SetPlanarBufferFloat(void* pv_thiz, SourceId source_id, - const float* const* audio_buffer_ptr, - size_t num_channels, size_t num_frames) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetPlanarBuffer(source_id, audio_buffer_ptr, num_channels, num_frames)); - } - // Sets the next audio buffer in planar int16 format to a sound source. - // - // @param source_id Id of sound source. - // @param audio_buffer_ptr Pointer to array of pointers referring to planar - // audio buffers for each channel. - // @param num_channels Number of planar input audio buffers. - // @param num_frames Number of frames per channel. - extern "C" EXPORT_API void SetPlanarBufferInt16(void* pv_thiz, SourceId source_id, - const int16* const* audio_buffer_ptr, - size_t num_channels, size_t num_frames) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetPlanarBuffer(source_id, audio_buffer_ptr, num_channels, num_frames)); - } - // Sets the given source's distance attenuation value explicitly. The distance - // rolloff model of the source must be set to |DistanceRolloffModel::kNone| - // for the set value to take effect. - // - // @param source_id Id of source. - // @param distance_attenuation Distance attenuation value. - extern "C" EXPORT_API void SetSourceDistanceAttenuation(void* pv_thiz, SourceId source_id, - float distance_attenuation) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetSourceDistanceAttenuation(source_id, distance_attenuation)); - } - // Sets the given source's distance attenuation method with minimum and - // maximum distances. Maximum distance must be greater than the minimum - // distance for the method to be set. - // - // @param source_id Id of source. - // @param rolloff Linear or logarithmic distance rolloff models. - // @param min_distance Minimum distance to apply distance attenuation method. - // @param max_distance Maximum distance to apply distance attenuation method. - extern "C" EXPORT_API void SetSourceDistanceModel(void* pv_thiz, SourceId source_id, - DistanceRolloffModel2 rolloff, - float min_distance, - float max_distance) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetSourceDistanceModel(source_id, (DistanceRolloffModel)rolloff, min_distance, max_distance)); - } - // Sets the given source's position. Note that, the given position for an - // ambisonic source is only used to determine the corresponding room effects - // to be applied. - // - // @param source_id Id of source. - // @param x X coordinate of source position in world space. - // @param y Y coordinate of source position in world space. - // @param z Z coordinate of source position in world space. - extern "C" EXPORT_API void SetSourcePosition(void* pv_thiz, SourceId source_id, float x, float y, - float z) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetSourcePosition(source_id, x, y, z)); - } - // Sets the room effects contribution for the given source. - // - // @param source_id Id of source. - // @param room_effects_gain Linear room effects volume in amplitude in range - // [0, 1] for attenuation, range [1, inf) for gain boost. - extern "C" EXPORT_API void SetSourceRoomEffectsGain(void* pv_thiz, SourceId source_id, - float room_effects_gain) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetSourceRoomEffectsGain(source_id, room_effects_gain)); - } - // Sets the given source's rotation. - // - // @param source_id Id of source. - // @param x X component of quaternion. - // @param y Y component of quaternion. - // @param z Z component of quaternion. - // @param w W component of quaternion. - extern "C" EXPORT_API void SetSourceRotation(void* pv_thiz, SourceId source_id, float x, float y, float z, - float w) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetSourceRotation(source_id, x, y, z, w)); - } - // Sets the given source's volume. - // - // @param source_id Id of source. - // @param volume Linear source volume in amplitude in range [0, 1] for - // attenuation, range [1, inf) for gain boost. - extern "C" EXPORT_API void SetSourceVolume(void* pv_thiz, SourceId source_id, float volume) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetSourceVolume(source_id, volume)); - } - // Sets the given sound object source's directivity. - // - // @param sound_object_source_id Id of sound object source. - // @param alpha Weighting balance between figure of eight pattern and circular - // pattern for source emission in range [0, 1]. A value of 0.5 results in - // a cardioid pattern. - // @param order Order applied to computed directivity. Higher values will - // result in narrower and sharper directivity patterns. Range [1, inf). - extern "C" EXPORT_API void SetSoundObjectDirectivity(void* pv_thiz, SourceId sound_object_source_id, - float alpha, float order) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetSoundObjectDirectivity(sound_object_source_id, alpha, order)); - } - // Sets the listener's directivity with respect to the given sound object. - // This method could be used to simulate an angular rolloff in terms of the - // listener's orientation, given the polar pickup pattern with |alpha| and - // |order|. - // - // @param sound_object_source_id Id of sound object source. - // @param alpha Weighting balance between figure of eight pattern and circular - // pattern for listener's pickup in range [0, 1]. A value of 0.5 results - // in a cardioid pattern. - // @param order Order applied to computed pickup pattern. Higher values will - // result in narrower and sharper pickup patterns. Range [1, inf). - extern "C" EXPORT_API void SetSoundObjectListenerDirectivity(void* pv_thiz, - SourceId sound_object_source_id, float alpha, float order) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetSoundObjectListenerDirectivity(sound_object_source_id, alpha, order)); - } - // Sets the gain (linear) of the near field effect. - // - // @param sound_object_source_id Id of sound object source. - // @param gain Gain of the near field effect. Range [0, 9] (corresponding to - // approx. (-Inf, +20dB]). - extern "C" EXPORT_API void SetSoundObjectNearFieldEffectGain(void* pv_thiz, - SourceId sound_object_source_id, float gain) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetSoundObjectNearFieldEffectGain(sound_object_source_id, gain)); - } - // Sets the given sound object source's occlusion intensity. - // - // @param sound_object_source_id Id of sound object source. - // @param intensity Number of occlusions occurred for the object. The value - // can be set to fractional for partial occlusions. Range [0, inf). - extern "C" EXPORT_API void SetSoundObjectOcclusionIntensity(void* pv_thiz, SourceId sound_object_source_id, - float intensity) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetSoundObjectOcclusionIntensity(sound_object_source_id, intensity)); - } - // Sets the given sound object source's spread. - // - // @param sound_object_source_id Id of sound object source. - // @param spread_deg Spread in degrees. - extern "C" EXPORT_API void SetSoundObjectSpread(void* pv_thiz, SourceId sound_object_source_id, - float spread_deg) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetSoundObjectSpread(sound_object_source_id, spread_deg)); - } - // Turns on/off the reflections and reverberation. - extern "C" EXPORT_API void EnableRoomEffects(void* pv_thiz, int enable) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->EnableRoomEffects((bool)enable)); - } - // Sets the early reflection properties of the environment. - // - // @param reflection_properties Reflection properties. - extern "C" EXPORT_API void SetReflectionProperties(void* pv_thiz, - const ReflectionProperties2 * reflection_properties) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetReflectionProperties((ReflectionProperties&)*reflection_properties)); - } - // Sets the late reverberation properties of the environment. - // - // @param reverb_properties Reverb properties. - extern "C" EXPORT_API void SetReverbProperties(void* pv_thiz, - const ReverbProperties2 * reverb_properties) - { - ResonanceAudioApi* thiz = (ResonanceAudioApi*)pv_thiz; - return (thiz->SetReverbProperties((ReverbProperties&)*reverb_properties)); - } -} // namespace vraudio diff --git a/code/dep_external/src/binaural/iamf2resonance/iamf_resonance_api.h b/code/dep_external/src/binaural/iamf2resonance/iamf_resonance_api.h deleted file mode 100755 index fc00303c..00000000 --- a/code/dep_external/src/binaural/iamf2resonance/iamf_resonance_api.h +++ /dev/null @@ -1,431 +0,0 @@ - -/* -Copyright 2018 Google Inc. All Rights Reserved. - -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 RESONANCE_AUDIO_API_RESONANCE_AUDIO_API2_H_ -#define RESONANCE_AUDIO_API_RESONANCE_AUDIO_API2_H_ - -#if defined(_WIN32) -// EXPORT_API can be used to define the dllimport storage-class attribute. -#ifdef DLL_EXPORTS -#define EXPORT_API __declspec(dllexport) -#else -#define EXPORT_API __declspec(dllimport) -#endif -#else -#define EXPORT_API -#endif -//#include "api/resonance_audio_api.h" -#include // size_t declaration. -#include // int16_t declaration. - -typedef int SourceId; - -typedef int16_t int16; - -// Rendering modes define CPU load / rendering quality balances. -// Note that this struct is C-compatible by design to be used across external -// C/C++ and C# implementations. -typedef enum _RenderingMode2 { - // Stereo panning, i.e., this disables HRTF-based rendering. - kStereoPanning = 0, - // HRTF-based rendering using First Order Ambisonics, over a virtual array of - // 8 loudspeakers arranged in a cube configuration around the listener's head. - kBinauralLowQuality, - // HRTF-based rendering using Second Order Ambisonics, over a virtual array of - // 12 loudspeakers arranged in a dodecahedral configuration (using faces of - // the dodecahedron). - kBinauralMediumQuality, - // HRTF-based rendering using Third Order Ambisonics, over a virtual array of - // 26 loudspeakers arranged in a Lebedev grid: https://goo.gl/DX1wh3. - kBinauralHighQuality, - // Room effects only rendering. This disables HRTF-based rendering and direct - // (dry) output of a sound object. Note that this rendering mode should *not* - // be used for general-purpose sound object spatialization, as it will only - // render the corresponding room effects of given sound objects without the - // direct spatialization. - kRoomEffectsOnly, -} RenderingMode2; - -// Distance rolloff models used for distance attenuation. -// Note that this enum is C-compatible by design to be used across external -// C/C++ and C# implementations. -typedef enum _DistanceRolloffModel2 { - // Logarithmic distance rolloff model. - kLogarithmic = 0, - // Linear distance rolloff model. - kLinear, - // Distance attenuation value will be explicitly set by the user. - kNone, -} DistanceRolloffModel2; - -// Early reflection properties of an acoustic environment. -// Note that this struct is C-compatible by design to be used across external -// C/C++ and C# implementations. -typedef struct _ReflectionProperties2 { - // Default constructor initializing all data members to 0. - // ReflectionProperties() - // : room_position{0.0f, 0.0f, 0.0f}, - // room_rotation{0.0f, 0.0f, 0.0f, 1.0f}, - // room_dimensions{0.0f, 0.0f, 0.0f}, - // cutoff_frequency(0.0f), - // coefficients{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, - // gain(0.0f) {} - - // Center position of the shoebox room in world space. - float room_position[3]; - - // Rotation (quaternion) of the shoebox room in world space. - float room_rotation[4]; - - // Size of the shoebox shoebox room in world space. - float room_dimensions[3]; - - // Frequency threshold for low pass filtering (-3dB cuttoff). - float cutoff_frequency; - - // Reflection coefficients that are stored in world space as follows: - // [0] (-)ive x-axis wall (left) - // [1] (+)ive x-axis wall (right) - // [2] (-)ive y-axis wall (bottom) - // [3] (+)ive y-axis wall (top) - // [4] (-)ive z-axis wall (front) - // [5] (+)ive z-axis wall (back) - float coefficients[6]; - - // Uniform reflections gain which is applied to all reflections. - float gain; -} ReflectionProperties2; - -// Late reverberation properties of an acoustic environment. -// Note that this struct is C-compatible by design to be used across external -// C/C++ and C# implementations. -typedef struct _ReverbProperties2 { - // Default constructor initializing all data members to 0. - // ReverbProperties() - // : rt60_values{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, - // gain(0.0f) {} - - // RT60's of the reverberation tail at different octave band centre - // frequencies in seconds. - float rt60_values[9]; - - // Reverb gain. - float gain; -} ReverbProperties2; - -// Factory method to create a |ResonanceAudioApi| instance. Caller must -// take ownership of returned instance and destroy it via operator delete. -// -// @param num_channels Number of channels of audio output. -// @param frames_per_buffer Number of frames per buffer. -// @param sample_rate_hz System sample rate. - -#ifdef __cplusplus -extern "C" { -#endif - -EXPORT_API void* CreateResonanceAudioApi2(size_t num_channels, - size_t frames_per_buffer, - int sample_rate_hz); - -// The ResonanceAudioApi library renders high-quality spatial audio. It provides -// methods to binaurally render virtual sound sources with simulated room -// acoustics. In addition, it supports decoding and binaural rendering of -// ambisonic soundfields. Its implementation is single-threaded, thread-safe -// and non-blocking to be able to process raw PCM audio buffers directly on the -// audio thread while receiving parameter updates from the main/render thread. - -// Invalid source id that can be used to initialize handler variables during -// // class construction. -// static const SourceId kInvalidSourceId = -1; - -EXPORT_API void DestroyResonanceAudioApi2(void* pv_thiz); - -// Renders and outputs an interleaved output buffer in float format. -// -// @param num_frames Size of output buffer in frames. -// @param num_channels Number of channels in output buffer. -// @param buffer_ptr Raw float pointer to audio buffer. -// @return True if a valid output was successfully rendered, false otherwise. -EXPORT_API int FillInterleavedOutputBufferFloat(void* pv_thiz, - size_t num_channels, - size_t num_frames, - float* buffer_ptr); - -// Renders and outputs an interleaved output buffer in int16 format. -// -// @param num_channels Number of channels in output buffer. -// @param num_frames Size of output buffer in frames. -// @param buffer_ptr Raw int16 pointer to audio buffer. -// @return True if a valid output was successfully rendered, false otherwise. -EXPORT_API int FillInterleavedOutputBufferInt16(void* pv_thiz, - size_t num_channels, - size_t num_frames, - int16* buffer_ptr); - -// Renders and outputs a planar output buffer in float format. -// -// @param num_frames Size of output buffer in frames. -// @param num_channels Number of channels in output buffer. -// @param buffer_ptr Pointer to array of raw float pointers to each channel of -// the audio buffer. -// @return True if a valid output was successfully rendered, false otherwise. -EXPORT_API int FillPlanarOutputBufferFloat(void* pv_thiz, size_t num_channels, - size_t num_frames, - float* const* buffer_ptr); - -// Renders and outputs a planar output buffer in int16 format. -// -// @param num_channels Number of channels in output buffer. -// @param num_frames Size of output buffer in frames. -// @param buffer_ptr Pointer to array of raw int16 pointers to each channel of -// the audio buffer. -// @return True if a valid output was successfully rendered, false otherwise. -EXPORT_API int FillPlanarOutputBufferInt16(void* pv_thiz, size_t num_channels, - size_t num_frames, - int16* const* buffer_ptr); - -// Sets listener's head position. -// -// @param x X coordinate of head position in world space. -// @param y Y coordinate of head position in world space. -// @param z Z coordinate of head position in world space. -EXPORT_API void SetHeadPositionXYZ(void* pv_thiz, float x, float y, float z); - -// Sets listener's head rotation. -// -// @param x X component of quaternion. -// @param y Y component of quaternion. -// @param z Z component of quaternion. -// @param w W component of quaternion. -EXPORT_API void SetHeadRotationXYZW(void* pv_thiz, float x, float y, float z, - float w); - -// Sets the master volume of the main audio output. -// -// @param volume Master volume (linear) in amplitude in range [0, 1] for -// attenuation, range [1, inf) for gain boost. -EXPORT_API void SetMasterVolume(void* pv_thiz, float volume); - -// Enables the stereo speaker mode. When activated, it disables HRTF-based -// filtering and switches to computationally cheaper stereo-panning. This -// helps to avoid HRTF-based coloring effects when stereo speakers are used -// and reduces computational complexity when headphone-based HRTF filtering is -// not needed. By default the stereo speaker mode is disabled. Note that -// stereo speaker mode overrides the |enable_hrtf| flag in -// |CreateSoundObjectSource|. -// -// @param enabled Flag to enable stereo speaker mode. -EXPORT_API void SetStereoSpeakerMode(void* pv_thiz, int enabled); - -// Creates an ambisonic source instance. -// -// @param num_channels Number of input channels. -// @return Id of new ambisonic source. -EXPORT_API SourceId CreateAmbisonicSource(void* pv_thiz, size_t num_channels); - -// Creates a stereo non-spatialized source instance, which directly plays back -// mono or stereo audio. -// -// @param num_channels Number of input channels. -// @return Id of new non-spatialized source. -EXPORT_API SourceId CreateStereoSource(void* pv_thiz, size_t num_channels); - -// Creates a sound object source instance. -// -// @param rendering_mode Rendering mode which governs quality and performance. -// @return Id of new sound object source. -EXPORT_API SourceId CreateSoundObjectSource(void* pv_thiz, - RenderingMode2 rendering_mode); - -// Destroys source instance. -// -// @param source_id Id of source to be destroyed. -EXPORT_API void DestroySource(void* pv_thiz, SourceId id); - -// Sets the next audio buffer in interleaved float format to a sound source. -// -// @param source_id Id of sound source. -// @param audio_buffer_ptr Pointer to interleaved float audio buffer. -// @param num_channels Number of channels in interleaved audio buffer. -// @param num_frames Number of frames per channel in interleaved audio buffer. -EXPORT_API void SetInterleavedBufferFloat(void* pv_thiz, SourceId source_id, - const float* audio_buffer_ptr, - size_t num_channels, - size_t num_frames); - -// Sets the next audio buffer in interleaved int16 format to a sound source. -// -// @param source_id Id of sound source. -// @param audio_buffer_ptr Pointer to interleaved int16 audio buffer. -// @param num_channels Number of channels in interleaved audio buffer. -// @param num_frames Number of frames per channel in interleaved audio buffer. -EXPORT_API void SetInterleavedBufferInt16(void* pv_thiz, SourceId source_id, - const int16* audio_buffer_ptr, - size_t num_channels, - size_t num_frames); - -// Sets the next audio buffer in planar float format to a sound source. -// -// @param source_id Id of sound source. -// @param audio_buffer_ptr Pointer to array of pointers referring to planar -// audio buffers for each channel. -// @param num_channels Number of planar input audio buffers. -// @param num_frames Number of frames per channel. -EXPORT_API void SetPlanarBufferFloat(void* pv_thiz, SourceId source_id, - const float* const* audio_buffer_ptr, - size_t num_channels, size_t num_frames); - -// Sets the next audio buffer in planar int16 format to a sound source. -// -// @param source_id Id of sound source. -// @param audio_buffer_ptr Pointer to array of pointers referring to planar -// audio buffers for each channel. -// @param num_channels Number of planar input audio buffers. -// @param num_frames Number of frames per channel. -EXPORT_API void SetPlanarBufferInt16(void* pv_thiz, SourceId source_id, - const int16* const* audio_buffer_ptr, - size_t num_channels, size_t num_frames); - -// Sets the given source's distance attenuation value explicitly. The distance -// rolloff model of the source must be set to |DistanceRolloffModel::kNone| -// for the set value to take effect. -// -// @param source_id Id of source. -// @param distance_attenuation Distance attenuation value. -EXPORT_API void SetSourceDistanceAttenuation(void* pv_thiz, SourceId source_id, - float distance_attenuation); - -// Sets the given source's distance attenuation method with minimum and -// maximum distances. Maximum distance must be greater than the minimum -// distance for the method to be set. -// -// @param source_id Id of source. -// @param rolloff Linear or logarithmic distance rolloff models. -// @param min_distance Minimum distance to apply distance attenuation method. -// @param max_distance Maximum distance to apply distance attenuation method. -EXPORT_API void SetSourceDistanceModel(void* pv_thiz, SourceId source_id, - DistanceRolloffModel2 rolloff, - float min_distance, float max_distance); - -// Sets the given source's position. Note that, the given position for an -// ambisonic source is only used to determine the corresponding room effects -// to be applied. -// -// @param source_id Id of source. -// @param x X coordinate of source position in world space. -// @param y Y coordinate of source position in world space. -// @param z Z coordinate of source position in world space. -EXPORT_API void SetSourcePosition(void* pv_thiz, SourceId source_id, float x, - float y, float z); - -// Sets the room effects contribution for the given source. -// -// @param source_id Id of source. -// @param room_effects_gain Linear room effects volume in amplitude in range -// [0, 1] for attenuation, range [1, inf) for gain boost. -EXPORT_API void SetSourceRoomEffectsGain(void* pv_thiz, SourceId source_id, - float room_effects_gain); - -// Sets the given source's rotation. -// -// @param source_id Id of source. -// @param x X component of quaternion. -// @param y Y component of quaternion. -// @param z Z component of quaternion. -// @param w W component of quaternion. -EXPORT_API void SetSourceRotation(void* pv_thiz, SourceId source_id, float x, - float y, float z, float w); - -// Sets the given source's volume. -// -// @param source_id Id of source. -// @param volume Linear source volume in amplitude in range [0, 1] for -// attenuation, range [1, inf) for gain boost. -EXPORT_API void SetSourceVolume(void* pv_thiz, SourceId source_id, - float volume); - -// Sets the given sound object source's directivity. -// -// @param sound_object_source_id Id of sound object source. -// @param alpha Weighting balance between figure of eight pattern and circular -// pattern for source emission in range [0, 1]. A value of 0.5 results in -// a cardioid pattern. -// @param order Order applied to computed directivity. Higher values will -// result in narrower and sharper directivity patterns. Range [1, inf). -EXPORT_API void SetSoundObjectDirectivity(void* pv_thiz, - SourceId sound_object_source_id, - float alpha, float order); - -// Sets the listener's directivity with respect to the given sound object. -// This method could be used to simulate an angular rolloff in terms of the -// listener's orientation, given the polar pickup pattern with |alpha| and -// |order|. -// -// @param sound_object_source_id Id of sound object source. -// @param alpha Weighting balance between figure of eight pattern and circular -// pattern for listener's pickup in range [0, 1]. A value of 0.5 results -// in a cardioid pattern. -// @param order Order applied to computed pickup pattern. Higher values will -// result in narrower and sharper pickup patterns. Range [1, inf). -EXPORT_API void SetSoundObjectListenerDirectivity( - void* pv_thiz, SourceId sound_object_source_id, float alpha, float order); - -// Sets the gain (linear) of the near field effect. -// -// @param sound_object_source_id Id of sound object source. -// @param gain Gain of the near field effect. Range [0, 9] (corresponding to -// approx. (-Inf, +20dB]). -EXPORT_API void SetSoundObjectNearFieldEffectGain( - void* pv_thiz, SourceId sound_object_source_id, float gain); - -// Sets the given sound object source's occlusion intensity. -// -// @param sound_object_source_id Id of sound object source. -// @param intensity Number of occlusions occurred for the object. The value -// can be set to fractional for partial occlusions. Range [0, inf). -EXPORT_API void SetSoundObjectOcclusionIntensity( - void* pv_thiz, SourceId sound_object_source_id, float intensity); - -// Sets the given sound object source's spread. -// -// @param sound_object_source_id Id of sound object source. -// @param spread_deg Spread in degrees. -EXPORT_API void SetSoundObjectSpread(void* pv_thiz, - SourceId sound_object_source_id, - float spread_deg); - -// Turns on/off the reflections and reverberation. -EXPORT_API void EnableRoomEffects(void* pv_thiz, int enable); - -// Sets the early reflection properties of the environment. -// -// @param reflection_properties Reflection properties. -EXPORT_API void SetReflectionProperties( - void* pv_thiz, const ReflectionProperties2* reflection_properties); - -// Sets the late reverberation properties of the environment. -// -// @param reverb_properties Reverb properties. -EXPORT_API void SetReverbProperties(void* pv_thiz, - const ReverbProperties2* reverb_properties); - -#ifdef __cplusplus -} -#endif - -#endif // RESONANCE_AUDIO_API_RESONANCE_AUDIO_API2_H_ diff --git a/code/dep_external/src/oar-private b/code/dep_external/src/oar-private new file mode 160000 index 00000000..3ebd5b03 --- /dev/null +++ b/code/dep_external/src/oar-private @@ -0,0 +1 @@ +Subproject commit 3ebd5b03c98cafa3385febfb8fe8d3c000481b51 diff --git a/code/include/IAMF_decoder.h b/code/include/IAMF_decoder.h index 06503509..4071ad69 100755 --- a/code/include/IAMF_decoder.h +++ b/code/include/IAMF_decoder.h @@ -13,12 +13,12 @@ /** * @file IAMF_decoder.h * @brief IAMF decoder APIs. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ -#ifndef IAMF_DECODER_H -#define IAMF_DECODER_H +#ifndef __IAMF_DECODER_H__ +#define __IAMF_DECODER_H__ #include @@ -28,10 +28,88 @@ extern "C" { #endif +/** + * @brief Audio element gain offset range information. + * + * This structure defines the valid range for gain adjustment of a specific + * audio element within a mix presentation. It allows users to adjust the + * gain of individual audio elements within specified limits. + */ +typedef struct IamfElementGainOffsetRange { + float min; /**< Minimum gain offset value in dB */ + float max; /**< Maximum gain offset value in dB */ +} iamf_element_gain_offset_range_t; + +typedef struct IamfElementPresentationInfo { + uint32_t eid; /**< Audio element identifier */ + IAMF_HeadphonesRenderingMode mode; /**< Headphones rendering mode */ + IAMF_BinauralFilterProfile profile; /**< Binaural filter profile */ + iamf_element_gain_offset_range_t *gain_offset_range; /**< Gain offset range */ +} iamf_element_presentation_info_t; + +/** + * @brief Mix presentation information structure. + * + * This structure contains comprehensive information about a specific mix + * presentation within an IAMF stream. Mix presentations define how different + * audio elements are combined, processed, and presented to the listener, + * supporting various output configurations including stereo, multichannel, and + * binaural rendering. + * + * Each mix presentation can contain multiple audio elements with different + * rendering modes, gain adjustments, and spatial audio processing parameters. + * This structure provides the metadata needed for applications to understand + * and select appropriate mix presentations based on playback capabilities and + * user preferences. + * + * The structure includes information about audio elements such as their + * identifiers, rendering modes (stereo, binaural), binaural filter profiles, + * and gain offset ranges for user customization. + */ +typedef struct IamfMixPresentationInfo { + uint32_t id; /**< Mix presentation identifier. Unique identifier for this mix + presentation within the IAMF stream. */ + uint32_t num_audio_elements; /**< Number of audio elements in this mix + presentation. Indicates the size of the + elements array. */ + /**< Array of audio element presentation information. Contains detailed + * information about each audio element including rendering mode, binaural + * profile, and gain settings. */ + iamf_element_presentation_info_t *elements; +} iamf_mix_presentation_info_t; + +#define IAMF_MAX_CODECS 2 + +/** + * @brief IAMF stream information structure. + * + * This structure contains comprehensive information about an IAMF stream, + * including codec configuration, audio parameters, and available mix + * presentations. It is returned by @ref IAMF_decoder_get_stream_info and + * provides details about the stream's capabilities and configuration. + */ typedef struct IAMF_StreamInfo { - uint32_t max_frame_size; + uint32_t max_frame_size; /**< Maximum frame size in samples */ + + struct { + IA_Profile primary_profile; /**< Primary IAMF profile */ + IA_Profile additional_profile; /**< Additional IAMF profile */ + + IAMF_CodecID codec_ids[IAMF_MAX_CODECS]; + IAMF_SampleBitDepth sampling_rate; /**< Output sampling rate */ + /**< Number of samples per channel per frame */ + uint32_t samples_per_channel_in_frame; + + /**< Number of available mix presentations */ + uint32_t mix_presentation_count; + /**< Array of mix presentation information */ + iamf_mix_presentation_info_t *mix_presentations; + } iamf_stream_info; + } IAMF_StreamInfo; +typedef struct IAMF_StreamInfo iamf_stream_info_t; + /**@}*/ /**\name Immersive audio decoder functions */ /**@{*/ @@ -50,6 +128,42 @@ IAMF_DecoderHandle IAMF_decoder_open(void); */ int IAMF_decoder_close(IAMF_DecoderHandle handle); +/** + * @brief Set the IAMF profile for the decoder. + * + * This function sets the IAMF profile that the decoder will use for processing + * audio data. The profile determines the features and capabilities that the + * decoder will support. The profile must be set before configuring the decoder + * with descriptor OBUs. + * + * @param [in] handle : IAMF decoder handle. + * @param [in] profile : The IAMF profile to set. Must be one of the values + * defined in @ref IA_Profile. + * @return @ref IAErrCode. IAMF_OK on success, IAMF_ERR_BAD_ARG on invalid + * parameters. + * + * @note The profile must be set before calling @ref IAMF_decoder_configure + * with descriptor OBUs. Setting the profile after configuration may not have + * the desired effect. + */ +int IAMF_decoder_set_profile(IAMF_DecoderHandle handle, IA_Profile profile); + +/** + * @brief Get the current IAMF profile of the decoder. + * + * This function retrieves the currently set IAMF profile of the decoder. The + * profile determines the features and capabilities that the decoder supports. + * + * @param [in] handle : IAMF decoder handle. + * @return The current IAMF profile, or ck_iamf_profile_none if the handle + * is invalid. + * + * @note The returned profile may be different from the one set by + * @ref IAMF_decoder_set_profile if the decoder has been configured + * with an IA Sequence Header OBU that specifies a different profile. + */ +IA_Profile IAMF_decoder_get_profile(IAMF_DecoderHandle handle); + /** * @brief Configurate an iamf decoder. The first configurating decoder must * need descriptor OBUs, then if only some properties have been @@ -92,6 +206,13 @@ int IAMF_decoder_decode(IAMF_DecoderHandle handle, const uint8_t *data, int IAMF_decoder_set_mix_presentation_id(IAMF_DecoderHandle handle, uint64_t id); +/** + * @brief Get selected mix presentation id. + * @param [in] handle : iamf decoder handle. + * @return valid id ( >= 0) or -1. + */ +int64_t IAMF_decoder_get_mix_presentation_id(IAMF_DecoderHandle handle); + /** * @brief Set sound system output layout. * @param [in] handle : iamf decoder handle. @@ -146,7 +267,9 @@ int IAMF_decoder_set_normalization_loudness(IAMF_DecoderHandle handle, /** * @brief Set pcm output bitdepth. * @param [in] handle : iamf decoder handle. - * @param [in] bit depth : target bit depth in bit. + * @param [in] bit_depth : target bit depth in bit. Must be one of the + * values defined in @ref iamf_sample_bit_depth_t + * (16, 24, or 32 bits). * @return @ref IAErrCode. */ int IAMF_decoder_set_bit_depth(IAMF_DecoderHandle handle, uint32_t bit_depth); @@ -180,72 +303,137 @@ float IAMF_decoder_peak_limiter_get_threshold(IAMF_DecoderHandle handle); /** * @brief Set pcm output sampling rate. * @param [in] handle : iamf decoder handle. - * @param [in] rate : sampling rate. + * @param [in] rate : sampling rate. Must be one of the values defined in + * @ref IAMF_SampleBitDepth (7350, 8000, 11025, 16000, + * 22050, 24000, 32000, 44100, 48000, 64000, 88200, + * 96000, 176400, or 192000 Hz). * @return @ref IAErrCode. */ int IAMF_decoder_set_sampling_rate(IAMF_DecoderHandle handle, uint32_t rate); /** - * @brief Get stream info. Must be used after decoder configuration. - * max frame size could be gotten. + * @brief Set gain offset for a specific audio element. * @param [in] handle : iamf decoder handle. - * @return @stream info. + * @param [in] id : audio element identifier. + * @param [in] gain : gain offset value in dB. + * @return @ref IAErrCode. */ -IAMF_StreamInfo *IAMF_decoder_get_stream_info(IAMF_DecoderHandle handle); +int IAMF_decoder_set_audio_element_gain_offset(IAMF_DecoderHandle handle, + uint32_t id, float gain); -// Following functions are provided for handling metadata and pts. -typedef struct IAMF_Param { - int parameter_length; - uint32_t parameter_definition_type; - union { - uint32_t dmixp_mode; - }; -} IAMF_Param; - -typedef enum IAMF_SoundMode { - IAMF_SOUND_MODE_NONE = -2, - IAMF_SOUND_MODE_NA = -1, - IAMF_SOUND_MODE_STEREO, - IAMF_SOUND_MODE_MULTICHANNEL, - IAMF_SOUND_MODE_BINAURAL -} IAMF_SoundMode; - -typedef struct IAMF_extradata { - IAMF_SoundSystem output_sound_system; - uint32_t number_of_samples; - uint32_t bitdepth; - uint32_t sampling_rate; - IAMF_SoundMode output_sound_mode; - - int num_loudness_layouts; - IAMF_Layout *loudness_layout; - IAMF_LoudnessInfo *loudness; - - uint32_t num_parameters; - IAMF_Param *param; -} IAMF_extradata; - -/** - * @brief Set the start timestamp and time base to decoder. +/** + * @brief Get gain offset for a specific audio element. * @param [in] handle : iamf decoder handle. - * @param [in] pts : the start timestamp. - * @param [in] time_base : the time base used for pts. + * @param [in] id : audio element identifier. + * @param [out] gain : pointer to store the gain offset value in dB. * @return @ref IAErrCode. */ -int IAMF_decoder_set_pts(IAMF_DecoderHandle handle, int64_t pts, - uint32_t time_base); +int IAMF_decoder_get_audio_element_gain_offset(IAMF_DecoderHandle handle, + uint32_t id, float *gain); /** - * @brief Get the metadata and pts corresponding to last PCM frame. - * @param [in] handle : iamf decoder handle. - * @param [in] pts : the timestamp of last PCM frame. - * @param [in] metadata : the metadata of last PCM frame. + * @brief Enable or disable head tracking for 3D audio rendering. + * + * This function enables or disables head tracking functionality. When enabled, + * the decoder will use head rotation data to create immersive 3D audio + * experiences. Head tracking must be enabled before setting head rotation + * values. + * + * @param [in] handle : IAMF decoder handle. + * @param [in] enable : 1 to enable head tracking, 0 to disable. * @return @ref IAErrCode. */ -int IAMF_decoder_get_last_metadata(IAMF_DecoderHandle handle, int64_t *pts, - IAMF_extradata *metadata); +int IAMF_decoder_enable_head_tracking(IAMF_DecoderHandle handle, + uint32_t enable); + +/** + * @brief Set the head rotation for 3D audio rendering in world space. + * + * This function sets the head rotation using quaternion representation to + * counter-rotate the intermediate Ambisonic bed, producing stable sound sources + * in binaural reproduction. The head rotation is essential for immersive 3D + * audio experiences where the listener's head orientation affects audio + * perception. + * + * The function uses a right-handed coordinate system with the following + * reference frame: + * - X axis: points to the right + * - Y axis: points up + * - Z axis: points backward (swap sign of z if using front-facing Z coordinate) + * + * The quaternion will be automatically normalized if not unit length. Invalid + * quaternions (too close to zero) will be rejected. + * + * @param [in] handle : IAMF decoder handle. + * @param [in] w : Quaternion scalar component (W). + * @param [in] x : Quaternion X component. + * @param [in] y : Quaternion Y component. + * @param [in] z : Quaternion Z component. + * @return @ref IAErrCode. IAMF_OK on success, IAMF_ERR_BAD_ARG on invalid + * parameters. + * + * @note This function should be called regularly during audio playback to + * update the head position based on sensor data from head tracking devices. The + * head rotation data is used during the rendering process to create realistic + * 3D audio spatialization in world space. + * + * @warning Head rotation functionality is only effective for binaural output + * layout. The decoder must be configured for binaural output using + * @ref IAMF_decoder_output_layout_set_binaural() before calling this + * function. For other output layouts (stereo, multichannel), head rotation + * settings will be stored but will not affect the audio output. + */ +int IAMF_decoder_set_head_rotation(IAMF_DecoderHandle handle, float w, float x, + float y, float z); + +/** + * @brief Get comprehensive IAMF stream information. + * + * This function retrieves detailed information about the configured IAMF + * stream, including codec parameters, audio format specifications, and + * available mix presentations. The stream information is essential for + * applications to understand the capabilities and configuration of the audio + * stream for proper playback setup. + * + * The function must be called after successful decoder configuration using + * @ref IAMF_decoder_configure. It returns a pointer to an @ref IAMF_StreamInfo + * structure containing: + * - Maximum frame size for buffer allocation + * - IAMF profile information (primary and additional) + * - Codec types and parameters (Opus, AAC, FLAC, etc.) + * - Sampling rate and frame size information + * - Available mix presentations with their audio elements + * - Audio element rendering modes and gain settings + * + * @param [in] handle : IAMF decoder handle. Must be a valid handle returned + * by + * @ref IAMF_decoder_open and successfully configured. + * + * @return Pointer to allocated @ref IAMF_StreamInfo structure containing + * stream information, or NULL if the decoder is not configured or an error + * occurs. + * + * @note The returned structure and all its nested arrays are dynamically + * allocated. After using the stream information, the caller MUST free the + * allocated memory by calling @ref IAMF_decoder_free_stream_info to prevent + * memory leaks. The stream information remains valid until the decoder is + * reconfigured or closed. + * + * @warning Do not attempt to free the returned structure manually using + * standard free() as it contains nested allocations that require proper + * cleanup. Always use @ref IAMF_decoder_free_stream_info for proper resource + * management. + */ +IAMF_StreamInfo *IAMF_decoder_get_stream_info(IAMF_DecoderHandle handle); + +/** + * @brief Free the memory allocated for stream info. + * @param [in] info : pointer to the stream info structure to be freed. + */ +void IAMF_decoder_free_stream_info(iamf_stream_info_t *info); + #ifdef __cplusplus } #endif -#endif /* IAMF_DECODER_H */ +#endif /* __IAMF_DECODER_H__ */ diff --git a/code/include/IAMF_defines.h b/code/include/IAMF_defines.h index 5a3bb2c8..eb8a62ee 100755 --- a/code/include/IAMF_defines.h +++ b/code/include/IAMF_defines.h @@ -13,30 +13,36 @@ /** * @file IAMF_defines.h * @brief AMF Common defines - * @version 0.1 + * @version 2.0.0 * @date Created 3/3/2023 **/ -#ifndef IAMF_DEFINES_H -#define IAMF_DEFINES_H +#ifndef __IAMF_DEFINES_H__ +#define __IAMF_DEFINES_H__ #include +typedef enum IA_Profile { + IA_PROFILE_NONE = -1, + IA_PROFILE_SIMPLE, + IA_PROFILE_BASE, + IA_PROFILE_BASE_ENHANCED, + IA_PROFILE_BASE_ADVANCED, + IA_PROFILE_ADVANCED_1, + IA_PROFILE_ADVANCED_2, +} IA_Profile; + /** * Audio Element Type * */ -typedef enum { +typedef enum IAMF_AudioElementType { AUDIO_ELEMENT_INVALID = -1, AUDIO_ELEMENT_CHANNEL_BASED, AUDIO_ELEMENT_SCENE_BASED, + AUDIO_ELEMENT_OBJECT_BASED, AUDIO_ELEMENT_COUNT -} AudioElementType; - -typedef enum AmbisonicsMode { - AMBISONICS_MONO, - AMBISONICS_PROJECTION -} AmbisonicsMode; +} IAMF_AudioElementType; typedef enum IAMF_LayoutType { IAMF_LAYOUT_TYPE_NOT_DEFINED = 0, @@ -46,125 +52,31 @@ typedef enum IAMF_LayoutType { typedef enum IAMF_SoundSystem { SOUND_SYSTEM_INVALID = -1, - SOUND_SYSTEM_A, // 0+2+0, 0 - SOUND_SYSTEM_B, // 0+5+0, 1 - SOUND_SYSTEM_C, // 2+5+0, 1 - SOUND_SYSTEM_D, // 4+5+0, 1 - SOUND_SYSTEM_E, // 4+5+1, 1 - SOUND_SYSTEM_F, // 3+7+0, 2 - SOUND_SYSTEM_G, // 4+9+0, 1 - SOUND_SYSTEM_H, // 9+10+3, 2 - SOUND_SYSTEM_I, // 0+7+0, 1 - SOUND_SYSTEM_J, // 4+7+0, 1 - SOUND_SYSTEM_EXT_712, // 2+7+0, 1 - SOUND_SYSTEM_EXT_312, // 2+3+0, 1 - SOUND_SYSTEM_MONO, // 0+1+0, 0 - SOUND_SYSTEM_EXT_916, // 6+9+0, 1 + SOUND_SYSTEM_NONE = SOUND_SYSTEM_INVALID, + SOUND_SYSTEM_A, // 0+2+0, 0 + SOUND_SYSTEM_B, // 0+5+0, 1 + SOUND_SYSTEM_C, // 2+5+0, 1 + SOUND_SYSTEM_D, // 4+5+0, 1 + SOUND_SYSTEM_E, // 4+5+1, 1 + SOUND_SYSTEM_F, // 3+7+0, 2 + SOUND_SYSTEM_G, // 4+9+0, 1 + SOUND_SYSTEM_H, // 9+10+3, 2 + SOUND_SYSTEM_I, // 0+7+0, 1 + SOUND_SYSTEM_J, // 4+7+0, 1 + SOUND_SYSTEM_EXT_712, // 2+7+0, 1 + SOUND_SYSTEM_EXT_312, // 2+3+0, 1 + SOUND_SYSTEM_MONO, // 0+1+0, 0 + SOUND_SYSTEM_EXT_916, // 6+9+0, 1 + SOUND_SYSTEM_EXT_7154, // 5+7+4, 1 SOUND_SYSTEM_END } IAMF_SoundSystem; -typedef enum IAMF_ParameterType { - IAMF_PARAMETER_TYPE_MIX_GAIN = 0, - IAMF_PARAMETER_TYPE_DEMIXING, - IAMF_PARAMETER_TYPE_RECON_GAIN, -} IAMF_ParameterType; - -typedef enum IAMF_AnimationType { - ANIMATION_TYPE_INVALID = -1, - ANIMATION_TYPE_STEP, - ANIMATION_TYPE_LINEAR, - ANIMATION_TYPE_BEZIER -} IAMF_AnimationType; - -/** - * Layout Syntax: - * - * class layout() { - * unsigned int (2) layout_type; - * - * if (layout_type == LOUDSPEAKERS_SS_CONVENTION) { - * unsigned int (4) sound_system; - * unsigned int (2) reserved; - * } else if (layout_type == BINAURAL or NOT_DEFINED) { - * unsigned int (6) reserved; - * } - * } - * - * */ -typedef struct IAMF_Layout { - union { - struct { - uint8_t reserved : 2; - uint8_t sound_system : 4; - uint8_t type : 2; - } sound_system; - - struct { - uint8_t reserved : 6; - uint8_t type : 2; - } binaural; - - struct { - uint8_t reserved : 6; - uint8_t type : 2; - }; - }; -} IAMF_Layout; - -/** - * - * Loudness Info Syntax: - * - * class loudness_info() { - * unsigned int (8) info_type; - * signed int (16) integrated_loudness; - * signed int (16) digital_peak; - * - * if (info_type & 1) { - * signed int (16) true_peak; - * } - * - * if (info_type & 2) { - * unsigned int (8) num_anchored_loudness; - * for (i = 0; i < num_anchored_loudness; i++) { - * unsigned int (8) anchor_element; - * signed int (16) anchored_loudness; - * } - * } - * - * if (info_type & 0b11111100 > 0) { - * leb128() info_type_size; - * unsigned int (8 x info_type_size) info_type_bytes; - * } - * - * } - * - * */ - -typedef struct _anchor_loudness_t { - uint8_t anchor_element; - int16_t anchored_loudness; -} anchor_loudness_t; - -typedef struct IAMF_LoudnessInfo { - uint8_t info_type; - int16_t integrated_loudness; - int16_t digital_peak; - - int16_t true_peak; - - uint8_t num_anchor_loudness; - anchor_loudness_t *anchor_loudness; - - uint64_t info_type_size; - uint8_t *info_type_bytes; -} IAMF_LoudnessInfo; - /** * Codec ID * */ -typedef enum { +typedef enum IAMF_CodecID { IAMF_CODEC_UNKNOWN = 0, + IAMF_CODEC_NONE = IAMF_CODEC_UNKNOWN, // no codec IAMF_CODEC_OPUS, IAMF_CODEC_AAC, IAMF_CODEC_FLAC, @@ -185,14 +97,16 @@ enum { IAMF_ERR_INVALID_STATE = -5, IAMF_ERR_UNIMPLEMENTED = -6, IAMF_ERR_ALLOC_FAIL = -7, + IAMF_ERR_PENDING = -8, }; /** * IA channel layout type. * */ -typedef enum { +typedef enum IAMF_LoudspeakerLayoutType { IA_CHANNEL_LAYOUT_INVALID = -1, + IA_CHANNEL_LAYOUT_NONE = IA_CHANNEL_LAYOUT_INVALID, IA_CHANNEL_LAYOUT_MONO = 0, // 1.0.0 IA_CHANNEL_LAYOUT_STEREO, // 2.0.0 IA_CHANNEL_LAYOUT_510, // 5.1.0 @@ -233,7 +147,64 @@ typedef enum { IA_CHANNEL_LAYOUT_EXPANDED_STEREO_TPSI, /// @brief The top 6 channels (TpFL/TpFR/TpSiL/TpSiR/TpBL/TpBR) of 9.1.6ch IA_CHANNEL_LAYOUT_EXPANDED_TOP_6CH, + /// @brief Loudspeaker configuration for Sound System H (9+10+3) of + /// [ITU-2051-3] + IA_CHANNEL_LAYOUT_EXPANDED_A293, + /// @brief The low-frequency effects subset (LFE1/LFE2) of 10.2.9.3ch + IA_CHANNEL_LAYOUT_EXPANDED_LFE_PAIR, + /// @brief The bottom 3 channels (BtFL/BtFC/BtFR) of 10.2.9.3ch + IA_CHANNEL_LAYOUT_EXPANDED_BOTTOM_3CH, + /// @brief Loudspeaker configuration with the top and the bottom speakers + /// added to Loudspeaker configuration for Sound System J (4+7+0) of + /// [ITU-2051-3] + IA_CHANNEL_LAYOUT_EXPANDED_7154, + /// @brief The bottom 4 channels (BtFL/BtFR/BtBL/BtBR) of 7.1.5.4ch + IA_CHANNEL_LAYOUT_EXPANDED_BOTTOM_4CH, + /// @brief The top subset (TpC) of 7.1.5.4ch + IA_CHANNEL_LAYOUT_EXPANDED_TOP_1CH, + /// @brief The top 5 channels (Ltf/Rtf/TpC/Ltb/Rtb) of 7.1.5.4ch + IA_CHANNEL_LAYOUT_EXPANDED_TOP_5CH, /// @brief The end of expanded loudspeaker layout IA_CHANNEL_LAYOUT_EXPANDED_END, } IAChannelLayoutType; -#endif /* IAMF_DEFINES_H */ + +typedef enum IAMF_SamplingRate { + SAMPLING_RATE_NONE = 0, + SAMPLING_RATE_7350 = 7350, + SAMPLING_RATE_8000 = 8000, + SAMPLING_RATE_11025 = 11025, + SAMPLING_RATE_16000 = 16000, + SAMPLING_RATE_22050 = 22050, + SAMPLING_RATE_24000 = 24000, + SAMPLING_RATE_32000 = 32000, + SAMPLING_RATE_44100 = 44100, + SAMPLING_RATE_48000 = 48000, + SAMPLING_RATE_64000 = 64000, + SAMPLING_RATE_88200 = 88200, + SAMPLING_RATE_96000 = 96000, + SAMPLING_RATE_176400 = 176400, + SAMPLING_RATE_192000 = 192000, +} IAMF_SamplingRate; + +typedef enum IAMF_SampleBitDepth { + SAMPLE_BIT_DEPTH_NONE = 0, + SAMPLE_BIT_DEPTH_16 = 16, + SAMPLE_BIT_DEPTH_24 = 24, + SAMPLE_BIT_DEPTH_32 = 32, +} IAMF_SampleBitDepth; + +typedef enum IAMF_HeadphonesRenderingMode { + HEADPHONES_RENDERING_MODE_WORLD_LOCKED_RESTRICTED = 0, + HEADPHONES_RENDERING_MODE_WORLD_LOCKED, + HEADPHONES_RENDERING_MODE_HEAD_LOCKED, + HEADPHONES_RENDERING_MODE_RESERVED, +} IAMF_HeadphonesRenderingMode; + +typedef enum IAMF_BinauralFilterProfile { + BINAURAL_FILTER_PROFILE_AMBIENT = 0, + BINAURAL_FILTER_PROFILE_DIRECT, + BINAURAL_FILTER_PROFILE_REVERBERANT, + BINAURAL_FILTER_PROFILE_RESERVED, +} IAMF_BinauralFilterProfile; + +#endif /* __IAMF_DEFINES_H__ */ diff --git a/code/src/common/IAMF_debug.h b/code/src/common/IAMF_debug.h deleted file mode 100755 index 80527114..00000000 --- a/code/src/common/IAMF_debug.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file IAMF_debug.h - * @brief Debug APIs. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#ifndef IAMF_DEBUG_H -#define IAMF_DEBUG_H - -#ifndef SUPPORT_VERIFIER -#define SUPPORT_VERIFIER 0 -#endif - -#include -#include - -#if SUPPORT_VERIFIER -#include "vlogging_tool_sr.h" -#endif - -#ifndef __MODULE__ -#define __MODULE__ \ - (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) -#endif - -#ifdef IA_DBG - -#ifndef IA_TAG -#define IA_TAG "IAMF" -#endif - -#define IA_DBG_E 0x01 -#define IA_DBG_W 0x02 -#define IA_DBG_I 0x04 -#define IA_DBG_D 0x08 -#define IA_DBG_T 0x10 - -#define IA_DBG_LEVEL (IA_DBG_E | IA_DBG_W) - -#ifdef IA_DEV -#include "IAMF_debug_dev.h" -#define obu_dump(a, b, c) OBU2F(a, b, c) -#else -#define obu_dump(a, b, c) -#endif - -#ifdef WIN32 -#if SUPPORT_VERIFIER -#define ia_log(level, slevel, fmt, ...) \ - do { \ - if ((IA_DBG_E & level) || (IA_DBG_W & level)) { \ - char text[2048]; \ - sprintf(text, "[%-9s:%s(%4d):%s]>" fmt, slevel, __MODULE__, __LINE__, \ - __FUNCTION__, ##__VA_ARGS__); \ - vlog_decop(text); \ - } \ - if (IA_DBG_LEVEL & level) { \ - fprintf(stderr, "[%-9s:%s:%s(%4d):%s]>" fmt "\n", IA_TAG, slevel, \ - __MODULE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \ - } \ - } while (0) -#else // !SUPPORT_VERIFIER -#define ia_log(level, slevel, fmt, ...) \ - do { \ - if (IA_DBG_LEVEL & level) { \ - fprintf(stderr, "[%-9s:%s:%s(%4d):%s]>" fmt "\n", IA_TAG, slevel, \ - __MODULE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \ - } \ - } while (0) -#endif -#define ia_loge(fmt, ...) ia_log(IA_DBG_E, "ERROR", fmt, __VA_ARGS__) -#define ia_logw(fmt, ...) ia_log(IA_DBG_W, "WARN ", fmt, __VA_ARGS__) -#define ia_logi(fmt, ...) ia_log(IA_DBG_I, "INFO ", fmt, __VA_ARGS__) -#define ia_logd(fmt, ...) ia_log(IA_DBG_D, "DEBUG", fmt, __VA_ARGS__) -#define ia_logt(fmt, ...) ia_log(IA_DBG_T, "TRACE", fmt, __VA_ARGS__) -#else -#if SUPPORT_VERIFIER -#define ia_log(level, slevel, fmt, arg...) \ - do { \ - if ((IA_DBG_E & level) || (IA_DBG_W & level)) { \ - char text[2048]; \ - sprintf(text, "[%-9s:%s(%4d):%s]>" fmt "\n", slevel, __MODULE__, \ - __LINE__, __FUNCTION__, ##arg); \ - vlog_decop(text); \ - } \ - if (IA_DBG_LEVEL & level) { \ - fprintf(stderr, "[%-9s:%s:%s(%4d):%s]>" fmt "\n", IA_TAG, slevel, \ - __MODULE__, __LINE__, __FUNCTION__, ##arg); \ - } \ - } while (0) -#else // !SUPPORT_VERIFIER -#define ia_log(level, slevel, fmt, arg...) \ - do { \ - if (IA_DBG_LEVEL & level) { \ - fprintf(stderr, "[%-9s:%s:%s(%4d):%s]>" fmt "\n", IA_TAG, slevel, \ - __MODULE__, __LINE__, __FUNCTION__, ##arg); \ - } \ - } while (0) -#endif -#define ia_loge(fmt, arg...) ia_log(IA_DBG_E, "ERROR", fmt, ##arg) -#define ia_logw(fmt, arg...) ia_log(IA_DBG_W, "WARN ", fmt, ##arg) -#define ia_logi(fmt, arg...) ia_log(IA_DBG_I, "INFO ", fmt, ##arg) -#define ia_logd(fmt, arg...) ia_log(IA_DBG_D, "DEBUG", fmt, ##arg) -#define ia_logt(fmt, arg...) ia_log(IA_DBG_T, "TRACE", fmt, ##arg) -#endif - -#else -#ifdef WIN32 -#if SUPPORT_VERIFIER -#define ia_log(level, slevel, fmt, ...) \ - do { \ - char text[2048]; \ - sprintf(text, "[%-9s:%s(%4d):%s]>" fmt, slevel, __MODULE__, __LINE__, \ - __FUNCTION__, ##__VA_ARGS__); \ - vlog_decop(text); \ - } while (0) -#define ia_loge(fmt, ...) ia_log(IA_DBG_E, "ERROR", fmt, __VA_ARGS__) -#define ia_logw(fmt, ...) ia_log(IA_DBG_W, "WARN ", fmt, __VA_ARGS__) -#else // !SUPPORT_VERIFIER -#define ia_loge(fmt, ...) -#define ia_logw(fmt, ...) -#endif -#define ia_logi(fmt, ...) -#define ia_logd(fmt, ...) -#define ia_logt(fmt, ...) -#else // !WIN32 -#if SUPPORT_VERIFIER -#define ia_log(level, slevel, fmt, arg...) \ - do { \ - char text[2048]; \ - sprintf(text, "[%-9s:%s(%4d):%s]>" fmt "\n", slevel, __MODULE__, __LINE__, \ - __FUNCTION__, ##arg); \ - } while (0) -#define ia_loge(fmt, arg...) ia_log(IA_DBG_E, "ERROR", fmt, ##arg) -#define ia_logw(fmt, arg...) ia_log(IA_DBG_W, "WARN ", fmt, ##arg) -#else // !SUPPORT_VERIFIER -#define ia_loge(fmt, ...) -#define ia_logw(fmt, ...) -#endif -#define ia_logi(fmt, arg...) -#define ia_logd(fmt, arg...) -#define ia_logt(fmt, arg...) -#endif -#define obu_dump(a, b, c) - -#endif - -#endif /* IAMF_DEBUG_H */ diff --git a/code/src/common/IAMF_debug_dev.h b/code/src/common/IAMF_debug_dev.h deleted file mode 100755 index 39f6ee44..00000000 --- a/code/src/common/IAMF_debug_dev.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file IAMF_debug_dev.h - * @brief Debug APIs. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#ifndef IAMF_DEBUG_DEV_H -#define IAMF_DEBUG_DEV_H - -#ifdef IA_DBG_LEVEL -#undef IA_DBG_LEVEL -#endif - -// #define IA_DBG_LEVEL 0 -#define IA_DBG_LEVEL (IA_DBG_E|IA_DBG_W) -// #define IA_DBG_LEVEL (IA_DBG_E|IA_DBG_W|IA_DBG_I) -// #define IA_DBG_LEVEL (IA_DBG_E | IA_DBG_W | IA_DBG_I | IA_DBG_D) -// #define IA_DBG_LEVEL (IA_DBG_E|IA_DBG_W|IA_DBG_D|IA_DBG_I|IA_DBG_T) - -#define DFN_SIZE 32 - -#define OBU2F(data, size, type) \ - do { \ - static int g_obu_count = 0; \ - static char g_dump[DFN_SIZE]; \ - snprintf(g_dump, DFN_SIZE, "/tmp/obu/obu_%06d_%02d.dat", g_obu_count, \ - type); \ - FILE *f = fopen(g_dump, "w"); \ - if (f) { \ - fwrite(data, 1, size, f); \ - fclose(f); \ - } \ - ++g_obu_count; \ - } while (0) - -#endif /* IAMF_DEBUG_DEV_H */ diff --git a/code/src/common/audio_defines.h b/code/src/common/audio_defines.h deleted file mode 100755 index 91989082..00000000 --- a/code/src/common/audio_defines.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file audio_defines.h - * @brief Audio common definitions - * @version 0.1 - * @date Created 3/3/2023 -**/ - -#ifndef _AUDIO_DEFINES_H_ -#define _AUDIO_DEFINES_H_ - -#define LIMITER_MaximumTruePeak -1.0f -#define LIMITER_AttackSec 0.001f -#define LIMITER_ReleaseSec 0.200f -#define LIMITER_LookAhead 240 - -#define MAX_CHANNELS 28 -#define MAX_OUTPUT_CHANNELS 24 -#define MAX_DELAYSIZE 4096 -#define CHUNK_SIZE 960 -#define FRAME_SIZE 960 - -#define IA_FRAME_MAXSIZE 2048 -#define MAX_PACKET_SIZE \ - (MAX_CHANNELS * sizeof(int16_t) * \ - IA_FRAME_MAXSIZE) // IA_FRAME_MAXSIZE*2/channel - -#endif diff --git a/code/src/common/fixedp11_5.c b/code/src/common/fixedp11_5.c deleted file mode 100755 index 09de99ce..00000000 --- a/code/src/common/fixedp11_5.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file fixedp11_5.c - * @brief Convert to fixed functions - * @version 0.1 - * @date Created 3/3/2023 -**/ - -#include "fixedp11_5.h" - -float q_to_float(q16_t q, int frac) { - return ((float)q) * powf(2.0f, (float)-frac); -} - -float qf2float(qf_t qf, int frac) { - return ((float)qf / (pow(2.0f, (float)frac))); -} - -float qf_to_float(qf_t qf, int frac) { - return ((float)qf / (pow(2.0f, (float)frac) - 1.0)); // f = q / 255 -} - -// dB to linear -float db2lin(float db) { return powf(10.0f, 0.05f * db); } - -// Mapping of wIdx(k) to w(k) -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -static float widx2w_table[11] = {0.0, 0.0179, 0.0391, 0.0658, 0.1038, 0.25, - 0.3962, 0.4342, 0.4609, 0.4821, 0.5}; -float calc_w(int w_idx_offset, int w_idx_prev, int *w_idx) { - if (w_idx_offset > 0) - *w_idx = MIN(w_idx_prev + 1, 10); - else - *w_idx = MAX(w_idx_prev - 1, 0); - - return widx2w_table[*w_idx]; -} - -float get_w(int w_idx) { - if (w_idx < 0) - return widx2w_table[0]; - else if (w_idx > 10) - return widx2w_table[10]; - - return widx2w_table[w_idx]; -} diff --git a/code/src/common/fixedp11_5.h b/code/src/common/fixedp11_5.h deleted file mode 100755 index 6dc08cb9..00000000 --- a/code/src/common/fixedp11_5.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file fixedp11_5.h - * @brief Convert to fixed functions - * @version 0.1 - * @date Created 3/3/2023 - **/ - -#ifndef _FIXEDP11_5_H_ -#define _FIXEDP11_5_H_ -#include -#include - -#define FIXED_POINT_FRACTIONAL_BITS 14 - -/// Fixed-point Format: 2.14 (16-bit) -typedef int16_t fixed16_t; -typedef int16_t q16_t; -typedef uint8_t qf_t; - -/// Converts between double and q16_t -float q_to_float(q16_t q, int frac); - -/// Converts between double and q8_t -// qf/2^frac -float qf2float(qf_t qf, int frac); -// q/(2^frac - 1) -float qf_to_float(qf_t q, int frac); - -float db2lin(float db); - -/// Mapping of wIdx(k) to w(k) for de-mixer -#define MIN_W_INDEX 0 -#define MAX_W_INDEX 10 -float calc_w(int w_idx_offset, int w_idx_prev, int *w_idx); -float get_w(int w_idx); -#endif diff --git a/code/src/iamf_dec/IAMF_OBU.c b/code/src/iamf_dec/IAMF_OBU.c deleted file mode 100755 index d21742f6..00000000 --- a/code/src/iamf_dec/IAMF_OBU.c +++ /dev/null @@ -1,1352 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file IAMF_OBU.c - * @brief OBU Parser. - * @version 0.1 - * @date Created 03/03/2023 - **/ -#include "IAMF_OBU.h" - -#include - -#include "IAMF_debug.h" -#include "IAMF_defines.h" -#include "IAMF_layout.h" -#include "IAMF_utils.h" -#include "bitstream.h" -#include "fixedp11_5.h" - -#ifndef SUPPORT_VERIFIER -#define SUPPORT_VERIFIER 0 -#endif -#if SUPPORT_VERIFIER -#include "vlogging_tool_sr.h" -#endif - -#define IAMF_OBU_MIN_SIZE 2 - -#ifdef IA_TAG -#undef IA_TAG -#endif -#define IA_TAG "IAMF_OBU" - -static uint32_t iamf_obu_get_payload_size(IAMF_OBU *obu); -static IAMF_Version *iamf_version_new(IAMF_OBU *obu); - -static IAMF_CodecConf *iamf_codec_conf_new(IAMF_OBU *obu); -static void iamf_codec_conf_free(IAMF_CodecConf *obj); - -static IAMF_Element *iamf_element_new(IAMF_OBU *obu); -static void iamf_element_free(IAMF_Element *obj); - -static IAMF_MixPresentation *iamf_mix_presentation_new(IAMF_OBU *obu); -static void iamf_mix_presentation_free(IAMF_MixPresentation *obj); - -static IAMF_Parameter *iamf_parameter_new(IAMF_OBU *obu, - IAMF_ParameterParam *param); -static void iamf_parameter_free(IAMF_Parameter *obj); - -static IAMF_Frame *iamf_frame_new(IAMF_OBU *obu); - -static void iamf_parameter_recon_gain_segment_free(ReconGainSegment *seg); - -uint32_t IAMF_OBU_split(const uint8_t *data, uint32_t size, IAMF_OBU *obu) { - BitStream b; - uint64_t ret = 0; - - if (size < IAMF_OBU_MIN_SIZE) { - return 0; - } - - bs(&b, data, size); - - memset(obu, 0, sizeof(IAMF_OBU)); - obu->type = bs_get32b(&b, 5); - obu->redundant = bs_get32b(&b, 1); - obu->trimming = bs_get32b(&b, 1); - obu->extension = bs_get32b(&b, 1); - - ret = bs_getAleb128(&b); - - if (ret == UINT64_MAX || ret + bs_tell(&b) > size) return 0; - - ia_logt("==============================================="); - ia_logt( - "obu header : %s (%d) type, redundant %d, trimming %d, extension %d, " - "payload size %" PRIu64 ", obu size %" PRIu64 " vs size %u", - IAMF_OBU_type_string(obu->type), obu->type, obu->redundant, obu->trimming, - obu->extension, ret, bs_tell(&b) + ret, size); - - if (obu->redundant) { - ia_logd("%s OBU redundant.", IAMF_OBU_type_string(obu->type)); - } - - obu->data = (uint8_t *)data; - obu->size = bs_tell(&b) + (uint32_t)ret; - obu_dump(data, obu->size, obu->type); - - if (obu->trimming) { - obu->trim_end = bs_getAleb128(&b); // num_samples_to_trim_at_end; - obu->trim_start = bs_getAleb128(&b); // num_samples_to_trim_at_start; - ia_logt("trim samples at start %" PRIu64 ", at end %" PRIu64, - obu->trim_start, obu->trim_end); - } - - if (obu->extension) { - obu->ext_size = bs_getAleb128(&b); // extension_header_size; - obu->ext_header = (uint8_t *)obu->data + bs_tell(&b); - ia_logt("obu extension header at %u, size %" PRIu64, bs_tell(&b), - obu->ext_size); - bs_skipABytes(&b, obu->ext_size); // skip extension header - } - - ia_logt("obu payload start at %u", bs_tell(&b)); - obu->payload = (uint8_t *)data + bs_tell(&b); - -#if SUPPORT_VERIFIER - if (obu->type == IAMF_OBU_TEMPORAL_DELIMITER) - vlog_obu(IAMF_OBU_TEMPORAL_DELIMITER, obu, 0, 0); -#endif - - return obu->size; -} - -int IAMF_OBU_is_descrptor_OBU(IAMF_OBU *obu) { - IAMF_OBU_Type type = obu->type; - - if (type == IAMF_OBU_CODEC_CONFIG || type == IAMF_OBU_AUDIO_ELEMENT || - type == IAMF_OBU_MIX_PRESENTATION || type == IAMF_OBU_SEQUENCE_HEADER) { - return 1; - } - return 0; -} - -int IAMF_OBU_is_reserved_OBU(IAMF_OBU *obu) { - IAMF_OBU_Type type = obu->type; - - if (type > IAMF_OBU_AUDIO_FRAME_ID17 && type < IAMF_OBU_SEQUENCE_HEADER) { - return 1; - } - return 0; -} - -uint64_t IAMF_OBU_get_object_id(IAMF_OBU *obu) { - if (obu->type == IAMF_OBU_PARAMETER_BLOCK) { - BitStream b; - bs(&b, obu->payload, iamf_obu_get_payload_size(obu)); - return bs_getAleb128(&b); - } - return (uint64_t)-1; -} - -const char *IAMF_OBU_type_string(IAMF_OBU_Type type) { - static const char *obu_type_string[] = { - "Codec Config", "Audio Element", "Mix Presentation", - "Parameter Block", "Temporal Delimiter", "Audio Frame", - "Audio Frame ID0", "Audio Frame ID1", "Audio Frame ID2", - "Audio Frame ID3", "Audio Frame ID4", "Audio Frame ID5", - "Audio Frame ID6", "Audio Frame ID7", "Audio Frame ID8", - "Audio Frame ID9", "Audio Frame ID10", "Audio Frame ID11", - "Audio Frame ID12", "Audio Frame ID13", "Audio Frame ID14", - "Audio Frame ID15", "Audio Frame ID16", "Audio Frame ID17"}; - static const char *obu_ia_header_string = "IA Sequence Header"; - static const char *obu_invalid_obu_type_string = "Invalid OBU Type"; - - if (type >= IAMF_OBU_CODEC_CONFIG && type <= IAMF_OBU_AUDIO_FRAME_ID17) - return obu_type_string[type]; - - if (type == IAMF_OBU_SEQUENCE_HEADER) return obu_ia_header_string; - - return obu_invalid_obu_type_string; -} - -IAMF_Object *IAMF_object_new(IAMF_OBU *obu, IAMF_ObjectParameter *param) { - IAMF_Object *obj = 0; - - switch (obu->type) { - case IAMF_OBU_SEQUENCE_HEADER: - obj = IAMF_OBJ(iamf_version_new(obu)); - break; - case IAMF_OBU_CODEC_CONFIG: - obj = IAMF_OBJ(iamf_codec_conf_new(obu)); - break; - case IAMF_OBU_AUDIO_ELEMENT: - obj = IAMF_OBJ(iamf_element_new(obu)); - break; - case IAMF_OBU_MIX_PRESENTATION: - obj = IAMF_OBJ(iamf_mix_presentation_new(obu)); - break; - case IAMF_OBU_PARAMETER_BLOCK: { - IAMF_ParameterParam *p = IAMF_PARAMETER_PARAM(param); - obj = IAMF_OBJ(iamf_parameter_new(obu, p)); - } break; - default: - if (obu->type >= IAMF_OBU_AUDIO_FRAME && - obu->type <= IAMF_OBU_AUDIO_FRAME_ID17) { - obj = IAMF_OBJ(iamf_frame_new(obu)); - } else if (obu->type != IAMF_OBU_TEMPORAL_DELIMITER) { - ia_logw("Reserved OBU type %u", obu->type); - } - break; - } - - if (obj && obu->redundant) obj->flags |= IAMF_OBU_FLAG_REDUNDANT; - - return obj; -} - -void IAMF_object_free(IAMF_Object *obj) { - if (obj) { - switch (obj->type) { - case IAMF_OBU_SEQUENCE_HEADER: - free(obj); - break; - case IAMF_OBU_CODEC_CONFIG: - iamf_codec_conf_free((IAMF_CodecConf *)obj); - break; - case IAMF_OBU_AUDIO_ELEMENT: - iamf_element_free((IAMF_Element *)obj); - break; - case IAMF_OBU_MIX_PRESENTATION: - iamf_mix_presentation_free((IAMF_MixPresentation *)obj); - break; - case IAMF_OBU_PARAMETER_BLOCK: - iamf_parameter_free((IAMF_Parameter *)obj); - break; - default: - if (obj->type >= IAMF_OBU_AUDIO_FRAME && - obj->type < IAMF_OBU_SEQUENCE_HEADER) { - free(obj); - } - break; - } - } -} - -void IAMF_parameter_segment_free(ParameterSegment *seg) { - if (seg) { - if (seg->type == IAMF_PARAMETER_TYPE_RECON_GAIN) { - iamf_parameter_recon_gain_segment_free((ReconGainSegment *)seg); - } else - free(seg); - } -} - -uint32_t iamf_obu_get_payload_size(IAMF_OBU *obu) { - return obu->size - (uint32_t)(obu->payload - obu->data); -} - -static int _valid_profile(uint8_t primary, uint8_t addional) { - return primary < IAMF_PROFILE_COUNT && primary <= addional; -} - -IAMF_Version *iamf_version_new(IAMF_OBU *obu) { - IAMF_Version *ver = 0; - BitStream b; - union { - uint32_t _id; - uint8_t _4cc[4]; - } code = {._4cc = {'i', 'a', 'm', 'f'}}; - - ver = IAMF_MALLOCZ(IAMF_Version, 1); - if (!ver) { - ia_loge("fail to allocate memory for Version Object."); - goto version_fail; - } - - bs(&b, obu->payload, iamf_obu_get_payload_size(obu)); - - ver->obj.type = IAMF_OBU_SEQUENCE_HEADER; - bs_read(&b, (uint8_t *)&ver->iamf_code, 4); - ver->primary_profile = bs_getA8b(&b); - ver->additional_profile = bs_getA8b(&b); - - ia_logd( - "ia sequence header object: %.4s, primary profile %u, additional profile " - "%u.", - (char *)&ver->iamf_code, ver->primary_profile, ver->additional_profile); - - if (ver->iamf_code != code._id) { - ia_loge("ia sequence header object: Invalid iamf code %.4s.", - (char *)&ver->iamf_code); - goto version_fail; - } - - if (!_valid_profile(ver->primary_profile, ver->additional_profile)) { - ia_loge( - "ia sequence header object: Invalid primary profile %u or additional " - "profile %u.", - ver->primary_profile, ver->additional_profile); - goto version_fail; - } - -#if SUPPORT_VERIFIER - vlog_obu(IAMF_OBU_SEQUENCE_HEADER, ver, 0, 0); -#endif - - return ver; - -version_fail: - if (ver) free(ver); - return 0; -} - -static int _valid_codec(uint32_t codec) { - return iamf_codec_check(iamf_codec_4cc_get_codecID(codec)); -} - -#define OPUS_VERSION_MAX 15 -static int _valid_decoder_config(uint32_t codec, uint8_t *conf, size_t size) { - if (iamf_codec_4cc_get_codecID(codec) == IAMF_CODEC_OPUS) { - if (conf[0] > OPUS_VERSION_MAX) { - ia_logw("opus config invalid: version %u should less than %u.", conf[0], - OPUS_VERSION_MAX); - return 0; - } - } - - return 1; -} - -IAMF_CodecConf *iamf_codec_conf_new(IAMF_OBU *obu) { - IAMF_CodecConf *conf = 0; - BitStream b; - - conf = IAMF_MALLOCZ(IAMF_CodecConf, 1); - if (!conf) { - ia_loge("fail to allocate memory for Codec Config Object."); - goto codec_conf_fail; - } - - bs(&b, obu->payload, iamf_obu_get_payload_size(obu)); - - conf->obj.type = IAMF_OBU_CODEC_CONFIG; - - conf->codec_conf_id = bs_getAleb128(&b); - bs_read(&b, (uint8_t *)&conf->codec_id, 4); - conf->nb_samples_per_frame = bs_getAleb128(&b); - conf->roll_distance = (int16_t)bs_getA16b(&b); - - conf->decoder_conf_size = iamf_obu_get_payload_size(obu) - bs_tell(&b); - conf->decoder_conf = IAMF_MALLOC(uint8_t, conf->decoder_conf_size); - if (!conf->decoder_conf) { - ia_loge( - "fail to allocate memory for decoder config of Codec Config Object."); - goto codec_conf_fail; - } - bs_read(&b, conf->decoder_conf, conf->decoder_conf_size); - ia_logd("codec configure object: id %" PRIu64 - ", codec %.4s, decoder configure size %d, " - "samples per frame %" PRIu64 ", roll distance %d", - conf->codec_conf_id, (char *)&conf->codec_id, conf->decoder_conf_size, - conf->nb_samples_per_frame, conf->roll_distance); - - if (!_valid_codec(conf->codec_id)) { - ia_logw("codec configure object: id %" PRIu64 ", invalid codec %.4s", - conf->codec_conf_id, (char *)&conf->codec_id); - goto codec_conf_fail; - } - - if (!_valid_decoder_config(conf->codec_id, conf->decoder_conf, - conf->decoder_conf_size)) { - ia_logw("decoder config is invalid, codec: %.4s", (char *)&conf->codec_id); - goto codec_conf_fail; - } - -#if SUPPORT_VERIFIER - vlog_obu(IAMF_OBU_CODEC_CONFIG, conf, 0, 0); -#endif - - return conf; - -codec_conf_fail: - if (conf) iamf_codec_conf_free(conf); - return 0; -} - -void iamf_codec_conf_free(IAMF_CodecConf *obj) { - IAMF_FREE(obj->decoder_conf); - free(obj); -} - -static int iamf_parameter_base_init(ParameterBase *pb, IAMF_ParameterType type, - BitStream *b) { - pb->type = type; - pb->id = bs_getAleb128(b); - pb->rate = bs_getAleb128(b); - pb->mode = bs_get32b(b, 1); - ia_logd("Parameter Base: type %" PRIu64 ", id %" PRIu64 ", rate %" PRIu64 - ", mode %u", - pb->type, pb->id, pb->rate, pb->mode); - if (!pb->mode) { - pb->duration = bs_getAleb128(b); - pb->constant_segment_interval = bs_getAleb128(b); - ia_logd("\tduration %" PRIu64 ", constant segment interval %" PRIu64, - pb->duration, pb->constant_segment_interval); - if (!pb->constant_segment_interval) { - pb->nb_segments = bs_getAleb128(b); - ia_logd("\tnumber of segment %" PRIu64, pb->nb_segments); - pb->segments = IAMF_MALLOCZ(ParameterSegment, pb->nb_segments); - if (!pb->segments) return IAMF_ERR_ALLOC_FAIL; - for (int i = 0; i < pb->nb_segments; ++i) { - ia_logd("\tSegment %d: %" PRIu64, i, pb->segments[i].segment_interval); - pb->segments[i].segment_interval = bs_getAleb128(b); - } - } else { - pb->nb_segments = (pb->duration + pb->constant_segment_interval - 1) / - pb->constant_segment_interval; - ia_logd("\tnumber of segment %" PRIu64, pb->nb_segments); - } - } - - return IAMF_OK; -} - -IAMF_Element *iamf_element_new(IAMF_OBU *obu) { - IAMF_Element *elem = 0; - BitStream b; - uint32_t val; - uint64_t type; - ParameterBase *p = 0; - - elem = IAMF_MALLOCZ(IAMF_Element, 1); - if (!elem) { - ia_loge("fail to allocate memory for Audio Element Object."); - goto element_fail; - } - - bs(&b, obu->payload, iamf_obu_get_payload_size(obu)); - - elem->obj.type = IAMF_OBU_AUDIO_ELEMENT; - elem->element_id = bs_getAleb128(&b); - elem->element_type = bs_get32b(&b, 3); - bs_get32b(&b, 5); - - elem->codec_config_id = bs_getAleb128(&b); - - val = bs_getAleb128(&b); - elem->nb_substreams = val; - ia_logd("element id %" PRIu64 ", type %d, codec config id %" PRIu64 - ", sub-streams count %" PRIu64, - elem->element_id, elem->element_type, elem->codec_config_id, - elem->nb_substreams); - elem->substream_ids = IAMF_MALLOC(uint64_t, val); - if (!elem->substream_ids) { - ia_loge( - "fail to allocate memory for substream ids of Audio Element Object."); - goto element_fail; - } - for (uint32_t i = 0; i < val; ++i) { - elem->substream_ids[i] = bs_getAleb128(&b); - ia_logd("\t > sub-stream id %" PRIu64, elem->substream_ids[i]); - } - - val = bs_getAleb128(&b); - elem->nb_parameters = val; - if (val) { - elem->parameters = IAMF_MALLOCZ(ParameterBase *, val); - if (!elem->parameters) { - ia_loge( - "fail to allocate memory for parameters of Audio Element Object."); - goto element_fail; - } - } - ia_logd("element parameters count %" PRIu64, elem->nb_parameters); - for (uint32_t i = 0; i < val; ++i) { - type = bs_getAleb128(&b); - p = 0; - if (type == IAMF_PARAMETER_TYPE_DEMIXING) { - DemixingParameter *dp = IAMF_MALLOCZ(DemixingParameter, 1); - p = PARAMETER_BASE(dp); - } else if (type == IAMF_PARAMETER_TYPE_RECON_GAIN) { - ReconGainParameter *rgp = IAMF_MALLOCZ(ReconGainParameter, 1); - p = PARAMETER_BASE(rgp); - } else { - uint64_t size = bs_getAleb128(&b); - bs_skipABytes(&b, size); - ia_logw("Don't support parameter type %" PRIu64 - " in Audio Element %" PRId64 - ", parameter definition bytes %" PRIu64 ".", - type, elem->element_id, size); - continue; - } - - if (!p) { - ia_loge( - "fail to allocate memory for parameter object of Audio Element " - "Object."); - goto element_fail; - } - elem->parameters[i] = p; - if (iamf_parameter_base_init(p, type, &b) != IAMF_OK) goto element_fail; - - if (type == IAMF_PARAMETER_TYPE_DEMIXING) { - DemixingParameter *dp = (DemixingParameter *)p; - dp->mode = bs_get32b(&b, 3); - bs_skip(&b, 5); - dp->w = bs_get32b(&b, 4); - bs_skip(&b, 4); - ia_logd("default mode is %d, weight index %d", dp->mode & U8_MASK, - dp->w & U8_MASK); - } - } - - if (elem->element_type == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ScalableChannelLayoutConf *chs_conf; - int channels = 0; - chs_conf = IAMF_MALLOCZ(ScalableChannelLayoutConf, 1); - if (!chs_conf) { - ia_loge( - "fail to allocate memory for scalable channel config of Audio " - "Element Object."); - goto element_fail; - } - elem->channels_conf = chs_conf; - - val = bs_get32b(&b, 3); - bs_skip(&b, 5); - chs_conf->num_layers = val; - ia_logd("scalable channel layers %d", chs_conf->num_layers); - if (val) { - ChannelLayerConf *layer_conf_s; - layer_conf_s = IAMF_MALLOCZ(ChannelLayerConf, val); - if (!layer_conf_s) { - ia_loge( - "fail to allocate memory for channel layer config of Audio Element " - "Object."); - goto element_fail; - } - chs_conf->layer_conf_s = layer_conf_s; - for (uint32_t i = 0; i < val; ++i) { - layer_conf_s[i].loudspeaker_layout = bs_get32b(&b, 4); - layer_conf_s[i].output_gain_flag = bs_get32b(&b, 1); - layer_conf_s[i].recon_gain_flag = bs_get32b(&b, 1); - layer_conf_s[i].nb_substreams = bs_getA8b(&b); - layer_conf_s[i].nb_coupled_substreams = bs_getA8b(&b); - channels += (layer_conf_s[i].nb_substreams + - layer_conf_s[i].nb_coupled_substreams); - if (chs_conf->nb_layers == i) { - uint8_t loudspeaker_layout = layer_conf_s[i].loudspeaker_layout; - if (iamf_audio_layer_base_layout_check(loudspeaker_layout) && - (layer_conf_s[i].nb_substreams > 0) && - (iamf_audio_layer_get_layout_info(loudspeaker_layout)->channels == - channels)) { - ++chs_conf->nb_layers; - } else if (i || - loudspeaker_layout != IAMF_LOUDSPEAKER_LAYOUT_EXPANDED) { - ia_logw("element (%" PRId64 - ") Layer %d: Invalid loudspeaker layout %d", - elem->element_id, i, layer_conf_s[i].loudspeaker_layout); - } - } - - ia_logd( - "\tlayer[%d] info: layout %d, output gain %d, recon gain %d, " - "sub-streams count %d, coupled sub-streams %d", - i, layer_conf_s[i].loudspeaker_layout, - layer_conf_s[i].output_gain_flag, layer_conf_s[i].recon_gain_flag, - layer_conf_s[i].nb_substreams, - layer_conf_s[i].nb_coupled_substreams); - - if (layer_conf_s[i].output_gain_flag) { - OutputGain *g = IAMF_MALLOCZ(OutputGain, 1); - if (!g) { - ia_loge( - "fail to allocate memory for out gain of Audio Element " - "Object."); - goto element_fail; - } - layer_conf_s[i].output_gain_info = g; - g->output_gain_flag = bs_get32b(&b, 6); - g->output_gain = (int16_t)bs_getA16b(&b); - ia_logd("\toutput gain : flag 0x%x, gain 0x%x", - g->output_gain_flag & U8_MASK, g->output_gain & U16_MASK); - } - - if (!i && val == 1 && - layer_conf_s[i].loudspeaker_layout == - IAMF_LOUDSPEAKER_LAYOUT_EXPANDED) { - layer_conf_s[i].expanded_loudspeaker_layout = bs_get32b(&b, 8); - - if (iamf_audio_layer_expanded_layout_check( - layer_conf_s[i].expanded_loudspeaker_layout)) { - chs_conf->nb_layers = 1; - ia_logd("\tlayer[%d] info : expanded layout %d", i, - layer_conf_s[i].expanded_loudspeaker_layout); - } else { - ia_logw("\tlayer[%d] info : invalid expanded layout %d", i, - layer_conf_s[i].expanded_loudspeaker_layout); - } - } - } - ia_logd("valid scalable channel layers %d", chs_conf->nb_layers); - } - } else if (elem->element_type == AUDIO_ELEMENT_TYPE_SCENE_BASED) { - AmbisonicsConf *conf = IAMF_MALLOCZ(AmbisonicsConf, 1); - if (!conf) { - ia_loge( - "fail to allocate memory for ambisonics config of Audio Element " - "Object."); - goto element_fail; - } - - elem->ambisonics_conf = conf; - conf->ambisonics_mode = bs_getAleb128(&b); - if (conf->ambisonics_mode == AMBISONICS_MODE_MONO) { - conf->output_channel_count = bs_getA8b(&b); - conf->substream_count = bs_getA8b(&b); - conf->mapping_size = conf->output_channel_count; - conf->mapping = IAMF_MALLOCZ(uint8_t, conf->mapping_size); - if (!conf->mapping) { - ia_loge( - "fail to allocate memory for mono mapping of Audio Element " - "Object."); - goto element_fail; - } - bs_read(&b, conf->mapping, conf->mapping_size); - ia_logd( - "Ambisonics mode mono, channels %d, sub-stream %d, mapping size %d", - conf->output_channel_count, conf->substream_count, - conf->mapping_size); - } else if (conf->ambisonics_mode == AMBISONICS_MODE_PROJECTION) { - conf->output_channel_count = bs_getA8b(&b); - conf->substream_count = bs_getA8b(&b); - conf->coupled_substream_count = bs_getA8b(&b); - conf->mapping_size = - 2 * conf->output_channel_count * - (conf->substream_count + conf->coupled_substream_count); - conf->mapping = IAMF_MALLOCZ(uint8_t, conf->mapping_size); - if (!conf->mapping) { - ia_loge( - "fail to allocate memory for projection mapping of Audio Element " - "Object."); - goto element_fail; - } - bs_read(&b, conf->mapping, conf->mapping_size); - ia_logd( - "Ambisonics mode projection, channels %d, sub-stream %d, coupled " - "sub-stream %d, matrix (%d x %d) size %d ", - conf->output_channel_count, conf->substream_count, - conf->coupled_substream_count, conf->output_channel_count, - conf->substream_count + conf->coupled_substream_count, - conf->mapping_size); - } else { - ia_logw("audio element object: id %" PRIu64 - ", invalid ambisonics mode %" PRIu64, - elem->element_id, conf->ambisonics_mode); - goto element_fail; - } - } else { - uint64_t size = bs_getAleb128(&b); - bs_skipABytes(&b, size); - ia_logw("audio element object: id %" PRIu64 - ", Don't support type %u, element config " - "bytes %" PRIu64, - elem->element_id, elem->element_type, size); - } - -#if SUPPORT_VERIFIER - vlog_obu(IAMF_OBU_AUDIO_ELEMENT, elem, 0, 0); -#endif - return elem; - -element_fail: - if (elem) iamf_element_free(elem); - return 0; -} - -void iamf_element_free(IAMF_Element *obj) { - IAMF_FREE(obj->substream_ids); - - if (obj->parameters) { - for (int i = 0; i < obj->nb_parameters; ++i) { - if (obj->parameters[i]) { - IAMF_FREE(obj->parameters[i]->segments); - free(obj->parameters[i]); - } - } - free(obj->parameters); - } - - if (obj->element_type == AUDIO_ELEMENT_TYPE_CHANNEL_BASED && - obj->channels_conf) { - ScalableChannelLayoutConf *conf = obj->channels_conf; - if (conf->layer_conf_s) { - for (int i = 0; i < conf->num_layers; ++i) { - IAMF_FREE(conf->layer_conf_s[i].output_gain_info); - } - free(conf->layer_conf_s); - } - free(obj->channels_conf); - } else if (obj->element_type == AUDIO_ELEMENT_TYPE_SCENE_BASED && - obj->ambisonics_conf) { - IAMF_FREE(obj->ambisonics_conf->mapping); - free(obj->ambisonics_conf); - } - - free(obj); -} - -IAMF_MixPresentation *iamf_mix_presentation_new(IAMF_OBU *obu) { - IAMF_MixPresentation *mixp = 0; - SubMixPresentation *sub = 0; - MixGainParameter *output_mix_gain; - ElementConf *conf_s; - BitStream b; - uint32_t val, payload_size; - uint64_t size; - - mixp = IAMF_MALLOCZ(IAMF_MixPresentation, 1); - if (!mixp) { - ia_loge("fail to allocate memory for Mix Presentation Object."); - goto mix_presentation_fail; - } - - payload_size = iamf_obu_get_payload_size(obu); - bs(&b, obu->payload, payload_size); - - mixp->obj.type = IAMF_OBU_MIX_PRESENTATION; - mixp->mix_presentation_id = bs_getAleb128(&b); - mixp->num_labels = bs_getAleb128(&b); - - mixp->annotations_language = IAMF_MALLOCZ(char *, mixp->num_labels); - mixp->localized_presentation_annotations = - IAMF_MALLOCZ(char *, mixp->num_labels); - - if (!mixp->annotations_language || - !mixp->localized_presentation_annotations) { - ia_logd( - "fail to allocate memory for languages or labels of Mix Presentation " - "Object."); - goto mix_presentation_fail; - } - - for (int i = 0; i < mixp->num_labels; ++i) { - mixp->annotations_language[i] = IAMF_MALLOCZ(char, STRING_SIZE); - mixp->localized_presentation_annotations[i] = - IAMF_MALLOCZ(char, STRING_SIZE); - if (!mixp->annotations_language[i] || - !mixp->localized_presentation_annotations[i]) { - ia_logd( - "fail to allocate memory for language or label of Mix Presentation " - "Object."); - goto mix_presentation_fail; - } - } - - for (int i = 0; i < mixp->num_labels; ++i) - bs_readString(&b, mixp->annotations_language[i], STRING_SIZE); - - for (int i = 0; i < mixp->num_labels; ++i) - bs_readString(&b, mixp->localized_presentation_annotations[i], STRING_SIZE); - - mixp->num_sub_mixes = bs_getAleb128(&b); - ia_logd("Mix Presentation Object : id %" PRIu64 ", number of label %" PRIu64 - ", number of sub " - "mixes %" PRIu64 ".", - mixp->mix_presentation_id, mixp->num_labels, mixp->num_sub_mixes); - - if (!mixp->num_sub_mixes) { - ia_logw("Mix Presentation Object: num_sub_mixes should not be set to 0."); - goto mix_presentation_fail; - } else if (mixp->num_sub_mixes > IAMF_MIX_PRESENTATION_MAX_SUBS) { - ia_logw( - "Mix Presentation Object: Do not support num_sub_mixes more than %u.", - IAMF_MIX_PRESENTATION_MAX_SUBS); - goto mix_presentation_fail; - } - - ia_logd("annotations language: "); - for (int i = 0; i < mixp->num_labels; ++i) - ia_logd("\t%s", mixp->annotations_language[i]); - - ia_logd("localized presentation annotations: "); - for (int i = 0; i < mixp->num_labels; ++i) - ia_logd("\t%s", mixp->localized_presentation_annotations[i]); - - if (mixp->num_sub_mixes != 1) { - ia_loge("the total of sub mixes should be 1, not support %" PRIu64, - mixp->num_sub_mixes); - goto mix_presentation_fail; - } - - // sub mixes; - mixp->sub_mixes = IAMF_MALLOCZ(SubMixPresentation, mixp->num_sub_mixes); - if (!mixp->sub_mixes) { - ia_loge( - "fail to allocate memory for sub mix presentation of Mix Presentation " - "Object."); - goto mix_presentation_fail; - } - - for (int n = 0; n < mixp->num_sub_mixes; ++n) { - sub = &mixp->sub_mixes[n]; - - val = bs_getAleb128(&b); - sub->nb_elements = val; - ia_logd("element count %" PRIu64, sub->nb_elements); - if (!val) { - ia_loge( - "Mix Presentation Object: num_audio_elements should not be set to " - "0."); - goto mix_presentation_fail; - } - - conf_s = IAMF_MALLOCZ(ElementConf, val); - if (!conf_s) { - ia_loge( - "fail to allocate memory for mixing and rendering config of Mix " - "Presentation Object."); - goto mix_presentation_fail; - } - sub->conf_s = conf_s; - for (uint32_t i = 0; i < val; ++i) { - conf_s[i].element_id = bs_getAleb128(&b); - conf_s[i].localized_element_annotations = - IAMF_MALLOCZ(char *, mixp->num_labels); - if (!conf_s[i].localized_element_annotations) { - ia_loge( - "fail to allocate memory for audio element labels of mixing and " - "rendering config."); - goto mix_presentation_fail; - } - - for (int k = 0; k < mixp->num_labels; ++k) { - conf_s[i].localized_element_annotations[k] = - IAMF_MALLOCZ(char, STRING_SIZE); - if (!conf_s[i].localized_element_annotations[k]) { - ia_loge( - "fail to allocate memory for audio element label of mixing and " - "rendering config."); - goto mix_presentation_fail; - } - - bs_readString(&b, conf_s[i].localized_element_annotations[k], - STRING_SIZE); - } - ia_logd("rendering info : element id %" PRIu64 - ", localized element annotations:", - conf_s[i].element_id); - - for (int k = 0; k < mixp->num_labels; ++k) - ia_logd("\t%s", conf_s[i].localized_element_annotations[k]); - - // rendering_config - conf_s[i].conf_r.headphones_rendering_mode = bs_get32b(&b, 2); - conf_s[i].conf_r.rendering_config_extension_size = size = - bs_getAleb128(&b); - bs_skipABytes(&b, size); - ia_logd( - "rendering config info: headphones rendering mode %u, extension size " - "%" PRIu64, - conf_s[i].conf_r.headphones_rendering_mode, size); - - // element_mix_config - if (iamf_parameter_base_init(&conf_s[i].element_mix_gain.base, - IAMF_PARAMETER_TYPE_MIX_GAIN, &b) != IAMF_OK) - goto mix_presentation_fail; - conf_s[i].element_mix_gain.mix_gain = (short)bs_getA16b(&b); - ia_logd("element mix info : element mix gain 0x%x", - conf_s[i].element_mix_gain.mix_gain & U16_MASK); - } - - output_mix_gain = &sub->output_mix_gain; - - if (iamf_parameter_base_init(&output_mix_gain->base, - IAMF_PARAMETER_TYPE_MIX_GAIN, &b) != IAMF_OK) - goto mix_presentation_fail; - output_mix_gain->mix_gain = bs_getA16b(&b); - - sub->num_layouts = bs_getAleb128(&b); - ia_logd("Output mix gain: id %" PRIu64 ", time base %" PRIu64 - ", mix gain 0x%x, number layout " - "%" PRIu64, - output_mix_gain->base.id, output_mix_gain->base.rate, - output_mix_gain->mix_gain & U16_MASK, sub->num_layouts); - if (sub->num_layouts > 0) { - TargetLayout **layouts = IAMF_MALLOCZ(TargetLayout *, sub->num_layouts); - IAMF_LoudnessInfo *loudness = - IAMF_MALLOCZ(IAMF_LoudnessInfo, sub->num_layouts); - uint32_t type = 0; - sub->layouts = layouts; - sub->loudness = loudness; - if (!layouts || !loudness) { - ia_loge( - "fail to allocate memory for layout and loudness of Mix " - "Presentation Object."); - goto mix_presentation_fail; - } - for (int i = 0; i < sub->num_layouts; i++) { - // Layout - type = bs_get32b(&b, 2); - if (type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) { - SoundSystemLayout *ss = IAMF_MALLOCZ(SoundSystemLayout, 1); - if (!ss) { - ia_loge( - "fail to allocate memory for sound system layout of Mix " - "Presentation Object."); - goto mix_presentation_fail; - } - layouts[i] = TARGET_LAYOUT(ss); - ss->base.type = IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION; - ss->sound_system = bs_get32b(&b, 4); - ia_logd("\tLayout %d > sound system %d", i, ss->sound_system); - } else if (type == IAMF_LAYOUT_TYPE_BINAURAL) { - BinauralLayout *b = IAMF_MALLOCZ(BinauralLayout, 1); - if (!b) { - ia_loge( - "fail to allocate memory for binaural layout of Mix " - "Presentation Object."); - goto mix_presentation_fail; - } - b->base.type = IAMF_LAYOUT_TYPE_BINAURAL; - layouts[i] = TARGET_LAYOUT(b); - ia_logd("\tLayout %d > binaural.", i); - } else { - ia_logw("Undefine layout type %d in mix presentation %" PRId64 ".", - type, mixp->mix_presentation_id); - } - bs_align(&b); - - // loudness - loudness[i].info_type = bs_getA8b(&b); - loudness[i].integrated_loudness = (int16_t)bs_getA16b(&b); - loudness[i].digital_peak = (int16_t)bs_getA16b(&b); - ia_logd( - "\tLoudness : %d > info type 0x%x, integrated loudness 0x%x, " - "digital peak 0x%x", - i, loudness[i].info_type & U8_MASK, - loudness[i].integrated_loudness & U16_MASK, - loudness[i].digital_peak & U16_MASK); - -#define LOUDNESS_INFO_TYPE_TRUE_PEAK 1 -#define LOUDNESS_INFO_TYPE_ANCHORED 2 -#define LOUDNESS_INFO_TYPE_ALL \ - (LOUDNESS_INFO_TYPE_TRUE_PEAK | LOUDNESS_INFO_TYPE_ANCHORED) - - if (loudness[i].info_type & LOUDNESS_INFO_TYPE_TRUE_PEAK) { - loudness[i].true_peak = bs_getA16b(&b); - ia_logd("\tloudness > %d > true peak 0x%x", i, - loudness[i].true_peak & U16_MASK); - } - - if (loudness[i].info_type & LOUDNESS_INFO_TYPE_ANCHORED) { - loudness[i].num_anchor_loudness = bs_getA8b(&b); - if (loudness[i].num_anchor_loudness > 0) { - loudness[i].anchor_loudness = IAMF_MALLOCZ( - anchor_loudness_t, loudness[i].num_anchor_loudness); - if (!loudness[i].anchor_loudness) { - ia_loge( - "fail to allocate memory anchor loudness in loudness info."); - goto mix_presentation_fail; - } - - ia_logd("\tloudness > %d > number of anchor loudness %d", i, - loudness[i].num_anchor_loudness); - for (int k = 0; k < loudness[i].num_anchor_loudness; ++k) { - loudness[i].anchor_loudness[k].anchor_element = bs_getA8b(&b); - loudness[i].anchor_loudness[k].anchored_loudness = bs_getA16b(&b); - ia_logd("\t\tanchor loudness > %d > anchor element %u", k, - loudness[i].anchor_loudness[k].anchor_element); - ia_logd( - "\t\tanchor loudness > %d > anchored loudness 0x%x", k, - loudness[i].anchor_loudness[k].anchored_loudness & U16_MASK); - } - } - } - - if (loudness[i].info_type & ~LOUDNESS_INFO_TYPE_ALL) { - loudness[i].info_type_size = bs_getAleb128(&b); - loudness[i].info_type_bytes = - IAMF_MALLOC(uint8_t, loudness[i].info_type_size); - bs_read(&b, loudness[i].info_type_bytes, loudness[i].info_type_size); - ia_logd("extension loudness info size %" PRIu64, size); - } - } - } - } - - // Mix Presentation Tags MAY or MAY NOT be present in a Mix Presentation OBU - if (payload_size > bs_tell(&b)) { - mixp->num_name_value_tags = bs_getA8b(&b); - ia_logi("the number of tags is %u", mixp->num_name_value_tags); - if (mixp->num_name_value_tags) { - mixp->tags = IAMF_MALLOCZ(Tag, mixp->num_name_value_tags); - if (!mixp->tags) { - ia_loge("Fail to allocate memory to tags in Mix Presentation."); - goto mix_presentation_fail; - } - - for (uint8_t i = 0; i < mixp->num_name_value_tags; ++i) { - bs_readString(&b, mixp->tags[i].name, STRING_SIZE); - bs_readString(&b, mixp->tags[i].value, STRING_SIZE); - ia_logi("Mix Presentation TAG: %s - %s. ", mixp->tags[i].name, - mixp->tags[i].value); - } - } - - // Mix Presentation Tags Extension. - size = bs_getAleb128(&b); - bs_skipABytes(&b, size); - } - -#if SUPPORT_VERIFIER - vlog_obu(IAMF_OBU_MIX_PRESENTATION, mixp, 0, 0); -#endif - return mixp; - -mix_presentation_fail: - if (mixp) iamf_mix_presentation_free(mixp); - return 0; -} - -void iamf_mix_presentation_free(IAMF_MixPresentation *obj) { - if (obj->annotations_language) { - for (int i = 0; i < obj->num_labels; ++i) - IAMF_FREE(obj->annotations_language[i]); - free(obj->annotations_language); - } - - if (obj->localized_presentation_annotations) { - for (int i = 0; i < obj->num_labels; ++i) - IAMF_FREE(obj->localized_presentation_annotations[i]); - free(obj->localized_presentation_annotations); - } - - if (obj->sub_mixes) { - SubMixPresentation *sub; - for (int i = 0; i < obj->num_sub_mixes; ++i) { - sub = &obj->sub_mixes[i]; - - if (sub->conf_s) { - for (int i = 0; i < sub->nb_elements; ++i) { - if (sub->conf_s[i].localized_element_annotations) { - for (int k = 0; k < obj->num_labels; ++k) - IAMF_FREE(sub->conf_s[i].localized_element_annotations[k]); - free(sub->conf_s[i].localized_element_annotations); - } - IAMF_FREE(sub->conf_s[i].element_mix_gain.base.segments); - } - free(sub->conf_s); - } - - IAMF_FREE(sub->output_mix_gain.base.segments); - - if (sub->layouts) { - for (int i = 0; i < sub->num_layouts; ++i) { - free(sub->layouts[i]); - } - free(sub->layouts); - } - - if (sub->loudness) { - for (int i = 0; i < sub->num_layouts; ++i) { - IAMF_FREE(sub->loudness[i].anchor_loudness); - IAMF_FREE(sub->loudness[i].info_type_bytes); - } - free(sub->loudness); - } - } - - free(obj->sub_mixes); - } - - IAMF_FREE(obj->tags); - - free(obj); -} - -static uint64_t iamf_parameter_get_segment_interval(uint64_t duration, - uint64_t const_interval, - uint64_t interval) { - if (interval) return interval; - return const_interval < duration ? const_interval : duration; -} - -IAMF_Parameter *iamf_parameter_new(IAMF_OBU *obu, - IAMF_ParameterParam *objParam) { - IAMF_Parameter *para = 0; - ParameterSegment *seg; - BitStream b; - uint64_t interval = 0; - uint64_t intervals; - uint64_t segment_interval; - - para = IAMF_MALLOCZ(IAMF_Parameter, 1); - if (!para) { - ia_loge("fail to allocate memory for Parameter Object."); - goto parameter_fail; - } - - bs(&b, obu->payload, iamf_obu_get_payload_size(obu)); - - para->obj.type = IAMF_OBU_PARAMETER_BLOCK; - para->id = bs_getAleb128(&b); - - if (!objParam || !objParam->param_base) { - // ia_loge("parameter object(%" PRIu64 - // "): Invalid object parameters for Parameter " - // "Object.", - // para->id); - goto parameter_fail; - } - - ia_logd("parameter obu arguments: parameter type %" PRIu64, - objParam->param_base->type); - - if (!objParam->param_base->mode) { - intervals = para->duration = objParam->param_base->duration; - para->nb_segments = objParam->param_base->nb_segments; - para->constant_segment_interval = - objParam->param_base->constant_segment_interval; - } else { - intervals = para->duration = bs_getAleb128(&b); - para->constant_segment_interval = bs_getAleb128(&b); - if (!para->constant_segment_interval) { - para->nb_segments = bs_getAleb128(&b); - } else { - para->nb_segments = - (para->duration + para->constant_segment_interval - 1) / - para->constant_segment_interval; - } - } - para->type = objParam->param_base->type; - - ia_logd("parameter id %" PRIu64 ", duration %" PRIu64 - ", segment count %" PRIu64 - ", const segment " - "interval %" PRIu64 ", type %" PRIu64, - para->id, para->duration, para->nb_segments, - para->constant_segment_interval, para->type); - - para->segments = IAMF_MALLOCZ(ParameterSegment *, para->nb_segments); - if (!para->segments) { - ia_loge("fail to allocate segments for Parameter Object."); - goto parameter_fail; - } - - for (int i = 0; i < para->nb_segments; ++i) { - if (!objParam->param_base->mode) { - if (!para->constant_segment_interval) { - interval = objParam->param_base->segments[i].segment_interval; - ia_logd("parameter base segment interval %" PRIu64, interval); - } - } else { - if (!para->constant_segment_interval) { - interval = bs_getAleb128(&b); - ia_logd("segment interval %" PRIu64, interval); - } - } - - segment_interval = iamf_parameter_get_segment_interval( - intervals, para->constant_segment_interval, interval); - intervals -= segment_interval; - - switch (para->type) { - case IAMF_PARAMETER_TYPE_MIX_GAIN: { - MixGainSegment *mg = IAMF_MALLOCZ(MixGainSegment, 1); - float gain_db, gain1_db, gain2_db; - if (!mg) { - ia_loge("fail to allocate mix gain segment for Parameter Object."); - goto parameter_fail; - } - - mg->seg.type = IAMF_PARAMETER_TYPE_MIX_GAIN; - seg = (ParameterSegment *)mg; - para->segments[i] = seg; - seg->segment_interval = segment_interval; - mg->mix_gain_f.animated_type = mg->mix_gain.animated_type = - bs_getAleb128(&b); - mg->mix_gain.start = (short)bs_getA16b(&b); - gain_db = q_to_float(mg->mix_gain.start, 8); - mg->mix_gain_f.start = db2lin(gain_db); - if (mg->mix_gain.animated_type == PARAMETER_ANIMATED_TYPE_STEP) { - ia_logd("\t mix gain seg %d: interval %" PRIu64 - ", step, start %f(%fdb, " - "<0x%02x>)", - i, seg->segment_interval, mg->mix_gain_f.start, gain_db, - mg->mix_gain.start & U16_MASK); - } else { - mg->mix_gain.end = (short)bs_getA16b(&b); - gain2_db = q_to_float(mg->mix_gain.end, 8); - mg->mix_gain_f.end = db2lin(gain2_db); - if (mg->mix_gain.animated_type == PARAMETER_ANIMATED_TYPE_LINEAR) { - ia_logd("\t mix gain seg %d: interval %" PRIu64 - ", linear, start %f(%fdb, " - "<0x%02x>), end %f(%fdb, <0x%02x>)", - i, seg->segment_interval, mg->mix_gain_f.start, gain_db, - mg->mix_gain.start & U16_MASK, mg->mix_gain_f.end, gain2_db, - mg->mix_gain.end & U16_MASK); - } else if (mg->mix_gain.animated_type == - PARAMETER_ANIMATED_TYPE_BEZIER) { - mg->mix_gain.control = bs_getA16b(&b); - gain1_db = q_to_float(mg->mix_gain.control, 8); - mg->mix_gain_f.control = db2lin(gain1_db); - mg->mix_gain.control_relative_time = bs_getA8b(&b); - mg->mix_gain_f.control_relative_time = - qf2float(mg->mix_gain.control_relative_time, 8); - ia_logd("\t mix gain seg %d: interval %" PRIu64 - ", bezier, start %f (%fdb " - "<0x%02x>), end %f (%fdb <0x%02x>), control %f (%fdb " - "<0x%02x>), control relative time %f (0x%x)", - i, seg->segment_interval, mg->mix_gain_f.start, gain_db, - mg->mix_gain.start & U16_MASK, mg->mix_gain_f.end, gain2_db, - mg->mix_gain.end & U16_MASK, mg->mix_gain_f.control, - gain1_db, mg->mix_gain.control & U16_MASK, - mg->mix_gain_f.control_relative_time, - mg->mix_gain.control_relative_time & U8_MASK); - } - } - } break; - case IAMF_PARAMETER_TYPE_DEMIXING: { - DemixingSegment *mode = IAMF_MALLOC(DemixingSegment, 1); - if (!mode) { - ia_loge("fail to allocate demixing segment for Parameter Object."); - goto parameter_fail; - } - mode->seg.type = IAMF_PARAMETER_TYPE_DEMIXING; - seg = (ParameterSegment *)mode; - para->segments[i] = seg; - seg->segment_interval = segment_interval; - mode->demixing_mode = bs_get32b(&b, 3); - ia_logd("segment interval %" PRIu64 ", demixing mode : %d", - seg->segment_interval, mode->demixing_mode); - } break; - case IAMF_PARAMETER_TYPE_RECON_GAIN: { - ia_logd("recon gain, layer count %d", objParam->nb_layers); - - if (objParam->nb_layers > 0) { - int count = objParam->nb_layers; - ReconGainList *list; - ReconGain *recon; - ReconGainSegment *recon_gain; - int channels = 0; - - recon_gain = IAMF_MALLOCZ(ReconGainSegment, 1); - if (!recon_gain) { - ia_loge( - "fail to allocate Recon gain segment for Parameter Object."); - goto parameter_fail; - } - - recon_gain->seg.type = IAMF_PARAMETER_TYPE_RECON_GAIN; - list = &recon_gain->list; - - seg = (ParameterSegment *)recon_gain; - para->segments[i] = seg; - seg->segment_interval = segment_interval; - ia_logd("there are %d recon gain info, list is %p", count, list); - list->count = count; - recon = IAMF_MALLOCZ(ReconGain, list->count); - list->recon = recon; - if (!recon) { - ia_loge("fail to allocate Recon gain for Parameter Object."); - goto parameter_fail; - } - for (int k = 0; k < list->count; ++k) { - if (~objParam->recon_gain_present_flags & RSHIFT(k)) continue; - recon[k].flags = bs_getAleb128(&b); - channels = bit1_count(recon[k].flags); - if (channels > 0) { - recon[k].recon_gain = IAMF_MALLOCZ(uint8_t, channels); - recon[k].recon_gain_f = IAMF_MALLOCZ(float, channels); - if (!recon[k].recon_gain || !recon[k].recon_gain_f) { - ia_loge( - "fail to allocate recon gain value for Parameter Object."); - goto parameter_fail; - } - bs_read(&b, recon[k].recon_gain, channels); - ia_logd("recon gain info %d : flags 0x%x, channels %d", k, - recon[k].flags, channels); - for (int t = 0; t < channels; ++t) { - recon[k].recon_gain_f[t] = - qf_to_float(recon[k].recon_gain[t], 8); - ia_logd("\tch %d gain %f(0x%x)", t, recon[k].recon_gain_f[t], - recon[k].recon_gain[t] & U8_MASK); - } - } - } - } - } break; - default: { - uint64_t size = bs_getAleb128(&b); - bs_skipABytes(&b, size); - ia_logw("parameter %" PRIu64 ", don't support extension type %" PRIu64 - ", and parameter " - "data bytes %" PRIu64 " .", - para->id, para->type, size); - } break; - } - } - -#if SUPPORT_VERIFIER - vlog_obu(IAMF_OBU_PARAMETER_BLOCK, para, 0, 0); -#endif - - return para; - -parameter_fail: - if (para) iamf_parameter_free(para); - return 0; -} - -void iamf_parameter_free(IAMF_Parameter *obj) { - if (obj->segments) { - for (int i = 0; i < obj->nb_segments; ++i) { - IAMF_parameter_segment_free(obj->segments[i]); - } - free(obj->segments); - } - free(obj); -} - -IAMF_Frame *iamf_frame_new(IAMF_OBU *obu) { - IAMF_Frame *pkt = 0; - BitStream b; - - pkt = IAMF_MALLOCZ(IAMF_Frame, 1); - if (!pkt) { - ia_loge("fail to allocate memory for Audio Frame Object."); - return 0; - } - - bs(&b, obu->payload, iamf_obu_get_payload_size(obu)); - - pkt->obj.type = obu->type; - if (obu->type == IAMF_OBU_AUDIO_FRAME) { - pkt->id = bs_getAleb128(&b); - } else { - pkt->id = obu->type - IAMF_OBU_AUDIO_FRAME_ID0; - } - pkt->trim_start = obu->trim_start; - pkt->trim_end = obu->trim_end; - pkt->data = obu->payload + bs_tell(&b); - pkt->size = iamf_obu_get_payload_size(obu) - bs_tell(&b); - -#if SUPPORT_VERIFIER - vlog_obu(IAMF_OBU_AUDIO_FRAME, pkt, obu->trim_start, obu->trim_end); -#endif - return pkt; -} - -void iamf_parameter_recon_gain_segment_free(ReconGainSegment *seg) { - if (seg->list.recon) { - for (int i = 0; i < seg->list.count; ++i) { - IAMF_FREE(seg->list.recon[i].recon_gain); - IAMF_FREE(seg->list.recon[i].recon_gain_f); - } - free(seg->list.recon); - } - free(seg); -} diff --git a/code/src/iamf_dec/IAMF_OBU.h b/code/src/iamf_dec/IAMF_OBU.h deleted file mode 100755 index 8d4ec2ad..00000000 --- a/code/src/iamf_dec/IAMF_OBU.h +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file IAMF_OBU.h - * @brief OBU APIs. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#ifndef IAMF_OBU_H -#define IAMF_OBU_H - -#include - -#include "IAMF_defines.h" - -#define IAMF_OBJ(a) ((IAMF_Object *)(a)) -#define IAMF_ELEMENT(a) ((IAMF_Element *)(a)) -#define IAMF_PARAMETER(a) ((IAMF_Parameter *)(a)) -#define IAMF_MIX_PRESENTATION(a) ((IAMF_MixPresentation *)(a)) - -typedef enum IAMF_OBU_Type { - IAMF_OBU_DEFAULT = -1, - IAMF_OBU_CODEC_CONFIG, - IAMF_OBU_AUDIO_ELEMENT, - IAMF_OBU_MIX_PRESENTATION, - IAMF_OBU_PARAMETER_BLOCK, - IAMF_OBU_TEMPORAL_DELIMITER, - IAMF_OBU_AUDIO_FRAME, - IAMF_OBU_AUDIO_FRAME_ID0, - IAMF_OBU_AUDIO_FRAME_ID17 = 23, - IAMF_OBU_SEQUENCE_HEADER = 31 -} IAMF_OBU_Type; - -typedef enum IAMF_OBU_Flag { - IAMF_OBU_FLAG_REDUNDANT = 0x1, -} IAMF_OBU_Flag; - -typedef enum IAMF_Element_Type { - AUDIO_ELEMENT_TYPE_CHANNEL_BASED, - AUDIO_ELEMENT_TYPE_SCENE_BASED -} IAMF_Element_Type; - -typedef enum IAMF_Parameter_Animated_Type { - PARAMETER_ANIMATED_TYPE_STEP, - PARAMETER_ANIMATED_TYPE_LINEAR, - PARAMETER_ANIMATED_TYPE_BEZIER -} IAMF_Parameter_Animated_Type; - -typedef enum IAMF_Ambisonics_Mode { - AMBISONICS_MODE_MONO, - AMBISONICS_MODE_PROJECTION -} IAMF_Ambisonics_Mode; - -typedef struct IAMF_OBU { - uint8_t *data; - uint32_t size; - - uint8_t type : 5; - uint8_t redundant : 1; - uint8_t trimming : 1; - uint8_t extension : 1; - - uint64_t trim_start; - uint64_t trim_end; - - uint8_t *ext_header; - uint64_t ext_size; - - uint8_t *payload; -} IAMF_OBU; - -typedef struct IAMF_Object { - IAMF_OBU_Type type; - IAMF_OBU_Flag flags; -} IAMF_Object; - -#define IAMF_OBJECT_PARAM(p) ((IAMF_ObjectParameter *)(p)) -#define IAMF_PARAMETER_PARAM(p) ((IAMF_ParameterParam *)(p)) -#define IAMF_MIX_PRESENTATION_PARAM(p) ((IAMF_MixPresentationParam *)p) - -enum { - OPTION_ELEMENT_TYPE = 0x010001, - OPTION_ELEMENT_CHANNELS, -}; - -typedef struct IAMF_ObjectParameter { - IAMF_OBU_Type type; -} IAMF_ObjectParameter; - -typedef struct ParameterBase ParameterBase; -#define PARAMETER_BASE(a) ((ParameterBase *)(a)) - -typedef struct IAMF_ParameterParam { - IAMF_ObjectParameter base; - ParameterBase *param_base; - int nb_layers; - uint32_t recon_gain_present_flags; -} IAMF_ParameterParam; - -/** - * Version Object (Sequence Header OBU). - * */ - -typedef struct IAMF_Version { - IAMF_Object obj; - - uint32_t iamf_code; - uint8_t primary_profile; - uint8_t additional_profile; -} IAMF_Version; - -/** - * CodecConf Object (Codec Config OBU). - * */ - -typedef struct IAMF_CodecConf { - IAMF_Object obj; - - uint64_t codec_conf_id; - - // codec config - uint32_t codec_id; - uint64_t nb_samples_per_frame; - short roll_distance; - - uint8_t *decoder_conf; - uint32_t decoder_conf_size; -} IAMF_CodecConf; - -/** - * Element Object (Audio Element OBU). - * */ - -typedef struct DemixingParameter DemixingParameter; -typedef struct ReconGainParameter ReconGainParameter; - -typedef struct ScalableChannelLayoutConf ScalableChannelLayoutConf; -typedef struct AmbisonicsConf AmbisonicsConf; - -typedef struct IAMF_Element { - IAMF_Object obj; - - uint64_t element_id; - uint8_t element_type; - - uint64_t codec_config_id; - - // substreams - uint64_t nb_substreams; - uint64_t *substream_ids; - - // parameters - uint64_t nb_parameters; - ParameterBase **parameters; - - // config - union { - ScalableChannelLayoutConf *channels_conf; - AmbisonicsConf *ambisonics_conf; - }; -} IAMF_Element; - -typedef struct ParameterSegment ParameterSegment; - -struct ParameterBase { - uint64_t type; - uint64_t id; - uint64_t rate; - uint64_t duration; - uint64_t nb_segments; - uint64_t constant_segment_interval; - uint32_t mode; - - ParameterSegment *segments; -}; - -struct DemixingParameter { - ParameterBase base; - uint8_t mode; - uint8_t w; -}; - -struct ReconGainParameter { - ParameterBase base; -}; - -typedef struct OutputGain { - uint8_t output_gain_flag; - int16_t output_gain; -} OutputGain; - -typedef struct ChannelLayerConf { - uint8_t loudspeaker_layout : 4; - uint8_t output_gain_flag : 1; - uint8_t recon_gain_flag : 1; - uint8_t nb_substreams; - uint8_t nb_coupled_substreams; - OutputGain *output_gain_info; - uint8_t expanded_loudspeaker_layout; -} ChannelLayerConf; - -struct ScalableChannelLayoutConf { - uint32_t nb_layers; // max valid layers - uint32_t num_layers; // total layers - ChannelLayerConf *layer_conf_s; -}; - -struct AmbisonicsConf { - uint64_t ambisonics_mode; - int output_channel_count; - int substream_count; - int coupled_substream_count; - uint8_t *mapping; - int mapping_size; -}; - -/** - * Mix Presentation Object (Mix Presentation OBU) - * */ - -typedef struct SubMixPresentation SubMixPresentation; - -#define TARGET_LAYOUT(a) ((TargetLayout *)(a)) -#define SOUND_SYSTEM_LAYOUT(a) ((SoundSystemLayout *)(a)) - -#define STRING_SIZE 128 - -typedef struct Tag { - char name[STRING_SIZE]; - char value[STRING_SIZE]; -} Tag; - -typedef struct IAMF_MixPresentation { - IAMF_Object obj; - - uint64_t mix_presentation_id; - uint64_t num_labels; - char **annotations_language; - char **localized_presentation_annotations; - - uint64_t num_sub_mixes; - SubMixPresentation *sub_mixes; - - uint8_t num_name_value_tags; - Tag *tags; -} IAMF_MixPresentation; - -typedef struct TargetLayout { - uint32_t type; -} TargetLayout; - -typedef struct SoundSystemLayout { - TargetLayout base; - uint32_t sound_system; -} SoundSystemLayout; - -typedef struct BinauralLayout { - TargetLayout base; -} BinauralLayout; - -typedef struct MixGainParameter { - ParameterBase base; - short mix_gain; -} MixGainParameter; - -typedef struct ElementRenderingConf { - uint8_t headphones_rendering_mode; - uint32_t rendering_config_extension_size; -} ElementRenderingConf; - -typedef struct ElementConf { - uint64_t element_id; - char **localized_element_annotations; - ElementRenderingConf conf_r; - MixGainParameter element_mix_gain; -} ElementConf; - -struct SubMixPresentation { - uint64_t nb_elements; - ElementConf *conf_s; - - MixGainParameter output_mix_gain; - - uint64_t num_layouts; - TargetLayout **layouts; - IAMF_LoudnessInfo *loudness; -}; - -/** - * Parameter Object (Parameter Block OBU). - * */ - -typedef struct IAMF_Parameter { - IAMF_Object obj; - - uint64_t id; - uint64_t duration; - uint64_t nb_segments; - uint64_t constant_segment_interval; - uint64_t type; - - ParameterSegment **segments; -} IAMF_Parameter; - -#define ANIMATED_PARAMETER_DEFINE(T1, T2) \ - typedef struct AnimatedParameter_##T1_##T2 { \ - uint64_t animated_type; \ - T1 start; \ - T1 end; \ - T1 control; \ - T2 control_relative_time; \ - } AnimatedParameter_##T1_##T2 - -ANIMATED_PARAMETER_DEFINE(short, uint8_t); -ANIMATED_PARAMETER_DEFINE(float, float); - -#define AnimatedParameter(T1, T2) AnimatedParameter_##T1_##T2 - -struct ParameterSegment { - uint64_t type; - uint64_t segment_interval; -}; - -typedef struct MixGainSegment { - ParameterSegment seg; - AnimatedParameter(short, uint8_t) mix_gain; - AnimatedParameter(float, float) mix_gain_f; -} MixGainSegment; - -typedef struct DemixingSegment { - ParameterSegment seg; - int demixing_mode; -} DemixingSegment; - -typedef struct ReconGain { - int layout; - uint32_t flags; - uint8_t *recon_gain; - float *recon_gain_f; -} ReconGain; - -typedef struct ReconGainList { - int count; - ReconGain *recon; -} ReconGainList; - -typedef struct ReconGainSegment { - ParameterSegment seg; - ReconGainList list; -} ReconGainSegment; - -/** - * Frame Object (Audio Frame OBU). - * */ - -typedef struct IAMF_Frame { - IAMF_Object obj; - - uint64_t id; - - uint64_t trim_start; - uint64_t trim_end; - - uint8_t *data; - uint32_t size; -} IAMF_Frame; - -/** - * Sync Object (Sync OBU). - * */ - -typedef struct ObjectSync ObjectSync; - -typedef struct IAMF_Sync { - IAMF_Object obj; - uint64_t global_offset; - uint64_t nb_obu_ids; - ObjectSync *objs; -} IAMF_Sync; - -struct ObjectSync { - uint64_t obu_id; - uint8_t obu_data_type; - uint8_t reinitialize_decoder; - int64_t relative_offset; -}; - -uint32_t IAMF_OBU_split(const uint8_t *data, uint32_t size, IAMF_OBU *obu); -int IAMF_OBU_is_descrptor_OBU(IAMF_OBU *obu); -int IAMF_OBU_is_reserved_OBU(IAMF_OBU *obu); -uint64_t IAMF_OBU_get_object_id(IAMF_OBU *obu); -const char *IAMF_OBU_type_string(IAMF_OBU_Type type); -IAMF_Object *IAMF_object_new(IAMF_OBU *obu, IAMF_ObjectParameter *param); -void IAMF_object_free(IAMF_Object *obj); -void IAMF_parameter_segment_free(ParameterSegment *seg); -#endif diff --git a/code/src/iamf_dec/IAMF_decoder.c b/code/src/iamf_dec/IAMF_decoder.c deleted file mode 100755 index 403f6b2e..00000000 --- a/code/src/iamf_dec/IAMF_decoder.c +++ /dev/null @@ -1,4522 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file IAMF_decoder.c - * @brief IAMF decoder. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "IAMF_OBU.h" -#include "IAMF_debug.h" -#include "IAMF_decoder.h" -#include "IAMF_decoder_private.h" -#include "IAMF_layout.h" -#include "IAMF_utils.h" -#include "ae_rdr.h" -#include "bitstream.h" -#include "demixer.h" -#include "fixedp11_5.h" -#include "speex_resampler.h" - -#define INVALID_VALUE -1 -#define INVALID_ID (uint64_t)(-1) -#define INVALID_TIMESTAMP 0xFFFFFFFF -#define OUTPUT_SAMPLERATE 48000 -#define SPEEX_RESAMPLER_QUALITY 4 -#define MAX_LIMITED_NORMALIZATION_LOUDNESS 0.0f - -#define IAMF_DECODER_CONFIG_MIX_PRESENTATION 0x1 -#define IAMF_DECODER_CONFIG_OUTPUT_LAYOUT 0x2 -#define IAMF_DECODER_CONFIG_PRESENTATION 0x4 - -#ifdef IA_TAG -#undef IA_TAG -#endif - -#define IA_TAG "IAMF_DEC" - -#define SR 0 -#if SR -extern void iamf_rec_stream_log(int eid, int chs, float *in, int size); -extern void iamf_ren_stream_log(int eid, int chs, float *out, int size); -extern void iamf_mix_stream_log(int chs, float *out, int size); -extern void iamf_stream_log_free(); -#endif - -/* ----------------------------- Utils ----------------------------- */ - -static void swap(void **p1, void **p2) { - void *p = *p2; - *p2 = *p1; - *p1 = p; -} - -static int64_t time_transform(int64_t t1, int s1, int s2) { - if (s1 == s2) return t1; - double r = t1 * s2; - return r / s1 + 0.5f; -} - -/* ----------------------------- Internal methods ------------------ */ - -static void iamf_decoder_plane2stride_out(const Arch *arch, void *dst, - const float *src, int frame_size, - int channels, uint32_t bit_depth) { - if (!src) { - if (bit_depth == 16 || bit_depth == 24 || bit_depth == 32) - memset(dst, 0x0, frame_size * channels * (bit_depth / 8)); - return; - } - - if (bit_depth == 16) { - (*arch->output.float2int16_zip_channels)(src, frame_size, channels, - (int16_t *)dst, frame_size); - } else if (bit_depth == 24) { - (*arch->output.float2int24_zip_channels)(src, frame_size, channels, - (uint8_t *)dst, frame_size); - } else if (bit_depth == 32) { - (*arch->output.float2int32_zip_channels)(src, frame_size, channels, - (int32_t *)dst, frame_size); - } -} - -static void ia_decoder_stride2plane_out_float(void *dst, const float *src, - int frame_size, int channels) { - float *float_dst = (float *)dst; - - ia_logd("channels %d", channels); - for (int i = 0; i < frame_size; i++) { - if (src) { - for (int c = 0; c < channels; ++c) { - float_dst[c * frame_size + i] = src[channels * i + c]; - } - } else { - for (int c = 0; c < channels; ++c) { - float_dst[c * frame_size + i] = 0; - } - } - } -} - -static void ia_decoder_plane2stride_out_float(void *dst, const float *src, - int frame_size, int channels) { - float *float_dst = (float *)dst; - - ia_logd("channels %d", channels); - for (int c = 0; c < channels; ++c) { - if (src) { - for (int i = 0; i < frame_size; i++) { - float_dst[i * channels + c] = src[frame_size * c + i]; - } - } else { - for (int i = 0; i < frame_size; i++) { - float_dst[i * channels + c] = 0; - } - } - } -} - -static int iamf_sound_system_valid(IAMF_SoundSystem ss) { - return ss > SOUND_SYSTEM_INVALID && ss < SOUND_SYSTEM_END; -} - -static IAMF_SoundMode iamf_sound_mode_combine(IAMF_SoundMode a, - IAMF_SoundMode b) { - int out = IAMF_SOUND_MODE_MULTICHANNEL; - if (a == IAMF_SOUND_MODE_NONE) - out = b; - else if (b == IAMF_SOUND_MODE_NONE) - out = a; - else if (a == b) - out = a; - else if (a == IAMF_SOUND_MODE_BINAURAL || b == IAMF_SOUND_MODE_BINAURAL) - out = IAMF_SOUND_MODE_NA; - - return out; -} - -static int iamf_layout_channels_count(IAMF_Layout *layout) { - int ret = 0; - if (layout->type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) { - ret = IAMF_layout_sound_system_channels_count( - layout->sound_system.sound_system); - ia_logd("sound system %x, channels %d", layout->sound_system.sound_system, - ret); - } else if (layout->type == IAMF_LAYOUT_TYPE_BINAURAL) { - ret = 2; - ia_logd("binaural channels %d", ret); - } - - return ret; -} - -static int iamf_layout_copy(IAMF_Layout *dst, IAMF_Layout *src) { - memcpy(dst, src, sizeof(IAMF_Layout)); - return IAMF_OK; -} - -static int iamf_loudness_info_copy(IAMF_LoudnessInfo *dst, - IAMF_LoudnessInfo *src) { - if (!dst || !src) return IAMF_ERR_BAD_ARG; - - dst->info_type = src->info_type; - dst->integrated_loudness = src->integrated_loudness; - dst->digital_peak = src->digital_peak; - dst->true_peak = src->true_peak; - dst->num_anchor_loudness = src->num_anchor_loudness; - if (src->num_anchor_loudness > 0) { - dst->anchor_loudness = - IAMF_MALLOCZ(anchor_loudness_t, src->num_anchor_loudness); - - if (!dst->anchor_loudness) goto loudness_info_copy_fail; - for (int i = 0; i < src->num_anchor_loudness; i++) { - dst->anchor_loudness[i].anchor_element = - src->anchor_loudness[i].anchor_element; - dst->anchor_loudness[i].anchored_loudness = - src->anchor_loudness[i].anchored_loudness; - } - } - if (src->info_type_bytes) { - dst->info_type_bytes = IAMF_MALLOC(uint8_t, src->info_type_size); - if (!dst->info_type_bytes) goto loudness_info_copy_fail; - memcpy(dst->info_type_bytes, src->info_type_bytes, src->info_type_size); - dst->info_type_size = src->info_type_size; - } - return IAMF_OK; - -loudness_info_copy_fail: - IAMF_FREE(dst->anchor_loudness); - IAMF_FREE(dst->info_type_bytes); - return IAMF_ERR_ALLOC_FAIL; -} - -static int iamf_layout_copy2(IAMF_Layout *dst, TargetLayout *src) { - if (!src) return IAMF_ERR_BAD_ARG; - dst->type = src->type; - if (src->type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) { - SoundSystemLayout *layout = SOUND_SYSTEM_LAYOUT(src); - dst->sound_system.sound_system = layout->sound_system; - } - return IAMF_OK; -} - -static void iamf_layout_dump(IAMF_Layout *layout) { - if (layout) { - ia_logt("layout type %d", layout->type); - if (layout->type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) { - ia_logt("sound system %d", layout->sound_system.sound_system); - } - } -} - -static void iamf_layout_info_free(LayoutInfo *layout) { - if (layout) { - IAMF_FREE(layout->sp.sp_layout.predefined_sp); - free(layout); - } -} - -static IAMF_SoundSystem iamf_layout_get_sound_system(IAMF_Layout *layout) { - IAMF_SoundSystem ss = SOUND_SYSTEM_INVALID; - if (layout->type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) - ss = layout->sound_system.sound_system; - return ss; -} - -static IAMF_SoundMode iamf_layout_get_sound_mode(IAMF_Layout *layout) { - IAMF_SoundMode mode = IAMF_SOUND_MODE_NONE; - if (layout->type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) { - if (layout->sound_system.sound_system == SOUND_SYSTEM_A) - mode = IAMF_SOUND_MODE_STEREO; - else - mode = IAMF_SOUND_MODE_MULTICHANNEL; - } else if (layout->type == IAMF_LAYOUT_TYPE_BINAURAL) - mode = IAMF_SOUND_MODE_BINAURAL; - - return mode; -} - -static uint32_t iamf_recon_channels_get_flags(IAChannelLayoutType l1, - IAChannelLayoutType l2) { - uint32_t s1, s2, t1, t2, flags; - const IAMF_LayoutInfo *info1, *info2; - - if (l1 == l2) return 0; - - info1 = iamf_audio_layer_get_layout_info(l1); - info2 = iamf_audio_layer_get_layout_info(l2); - - s1 = info1->surround; - s2 = info2->surround; - t1 = info1->height; - t2 = info2->height; - flags = 0; - - if (s1 != s2) { - if (s2 <= 3) { - flags |= RSHIFT(IA_CH_RE_L); - flags |= RSHIFT(IA_CH_RE_R); - } else if (s2 == 5) { - flags |= RSHIFT(IA_CH_RE_LS); - flags |= RSHIFT(IA_CH_RE_RS); - } else if (s2 == 7) { - flags |= RSHIFT(IA_CH_RE_LB); - flags |= RSHIFT(IA_CH_RE_RB); - } - } - - if (t2 != t1 && t2 == 4) { - flags |= RSHIFT(IA_CH_RE_LTB); - flags |= RSHIFT(IA_CH_RE_RTB); - } - - if (s2 == 5 && t1 && t2 == t1) { - flags |= RSHIFT(IA_CH_RE_LTF); - flags |= RSHIFT(IA_CH_RE_RTF); - } - - return flags; -} - -static void iamf_recon_channels_order_update(IAChannelLayoutType layout, - IAMF_ReconGain *re) { - int chs = 0; - static IAReconChannel recon_channel_order[] = { - IA_CH_RE_L, IA_CH_RE_C, IA_CH_RE_R, IA_CH_RE_LS, - IA_CH_RE_RS, IA_CH_RE_LTF, IA_CH_RE_RTF, IA_CH_RE_LB, - IA_CH_RE_RB, IA_CH_RE_LTB, IA_CH_RE_RTB, IA_CH_RE_LFE}; - - static IAChannel channel_layout_map[IA_CHANNEL_LAYOUT_COUNT][IA_CH_RE_COUNT] = - {{IA_CH_MONO, IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, - IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, - IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID}, - {IA_CH_L2, IA_CH_INVALID, IA_CH_R2, IA_CH_INVALID, IA_CH_INVALID, - IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, - IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID}, - {IA_CH_L5, IA_CH_C, IA_CH_R5, IA_CH_SL5, IA_CH_SR5, IA_CH_INVALID, - IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, - IA_CH_INVALID, IA_CH_LFE}, - {IA_CH_L5, IA_CH_C, IA_CH_R5, IA_CH_SL5, IA_CH_SR5, IA_CH_HL, IA_CH_HR, - IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, IA_CH_LFE}, - {IA_CH_L5, IA_CH_C, IA_CH_R5, IA_CH_SL5, IA_CH_SR5, IA_CH_HFL, IA_CH_HFR, - IA_CH_INVALID, IA_CH_INVALID, IA_CH_HBL, IA_CH_HBR, IA_CH_LFE}, - {IA_CH_L7, IA_CH_C, IA_CH_R7, IA_CH_SL7, IA_CH_SR7, IA_CH_INVALID, - IA_CH_INVALID, IA_CH_BL7, IA_CH_BR7, IA_CH_INVALID, IA_CH_INVALID, - IA_CH_LFE}, - {IA_CH_L7, IA_CH_C, IA_CH_R7, IA_CH_SL7, IA_CH_SR7, IA_CH_HL, IA_CH_HR, - IA_CH_BL7, IA_CH_BR7, IA_CH_INVALID, IA_CH_INVALID, IA_CH_LFE}, - {IA_CH_L7, IA_CH_C, IA_CH_R7, IA_CH_SL7, IA_CH_SR7, IA_CH_HFL, IA_CH_HFR, - IA_CH_BL7, IA_CH_BR7, IA_CH_HBL, IA_CH_HBR, IA_CH_LFE}, - {IA_CH_L3, IA_CH_C, IA_CH_R3, IA_CH_INVALID, IA_CH_INVALID, IA_CH_TL, - IA_CH_TR, IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, IA_CH_INVALID, - IA_CH_LFE}}; - -#define RECON_CHANNEL_FLAG(c) RSHIFT(c) - - for (int c = 0; c < IA_CH_RE_COUNT; ++c) { - if (re->flags & RECON_CHANNEL_FLAG(recon_channel_order[c])) - re->order[chs++] = channel_layout_map[layout][recon_channel_order[c]]; - } -} - -static int iamf_channel_layout_get_new_channels(IAChannelLayoutType last, - IAChannelLayoutType cur, - IAChannel *new_chs, - uint32_t count) { - uint32_t chs = 0; - - /** - * In ChannelGroup for Channel audio: The order conforms to following rules: - * - * @ Coupled Substream(s) comes first and followed by non-coupled - * Substream(s). - * @ Coupled Substream(s) for surround channels comes first and followed by - * one(s) for top channels. - * @ Coupled Substream(s) for front channels comes first and followed by - * one(s) for side, rear and back channels. - * @ Coupled Substream(s) for side channels comes first and followed by one(s) - * for rear channels. - * @ Center channel comes first and followed by LFE and followed by the other - * one. - * */ - - if (last == IA_CHANNEL_LAYOUT_INVALID) { - chs = iamf_audio_layer_layout_get_decoding_channels(cur, new_chs, count); - } else if (iamf_audio_layer_base_layout_check(last) && - iamf_audio_layer_base_layout_check(cur)) { - const IAMF_LayoutInfo *info1 = iamf_audio_layer_get_layout_info(last); - const IAMF_LayoutInfo *info2 = iamf_audio_layer_get_layout_info(cur); - uint32_t s1 = info1->surround; - uint32_t s2 = info2->surround; - uint32_t t1 = info1->height; - uint32_t t2 = info2->height; - - if (s1 < 5 && 5 <= s2) { - new_chs[chs++] = IA_CH_L5; - new_chs[chs++] = IA_CH_R5; - ia_logd("new channels : l5/r5(l7/r7)"); - } - if (s1 < 7 && 7 <= s2) { - new_chs[chs++] = IA_CH_SL7; - new_chs[chs++] = IA_CH_SR7; - ia_logd("new channels : sl7/sr7"); - } - if (t2 != t1 && t2 == 4) { - new_chs[chs++] = IA_CH_HFL; - new_chs[chs++] = IA_CH_HFR; - ia_logd("new channels : hfl/hfr"); - } - if (t2 - t1 == 4) { - new_chs[chs++] = IA_CH_HBL; - new_chs[chs++] = IA_CH_HBR; - ia_logd("new channels : hbl/hbr"); - } else if (!t1 && t2 - t1 == 2) { - if (s2 < 5) { - new_chs[chs++] = IA_CH_TL; - new_chs[chs++] = IA_CH_TR; - ia_logd("new channels : tl/tr"); - } else { - new_chs[chs++] = IA_CH_HL; - new_chs[chs++] = IA_CH_HR; - ia_logd("new channels : hl/hr"); - } - } - - if (s1 < 3 && 3 <= s2) { - new_chs[chs++] = IA_CH_C; - new_chs[chs++] = IA_CH_LFE; - ia_logd("new channels : c/lfe"); - } - if (s1 < 2 && 2 <= s2) { - new_chs[chs++] = IA_CH_L2; - ia_logd("new channel : l2"); - } - } - - if (chs > count) { - ia_loge("too much new channels %d, we only need less than %d channels", chs, - count); - chs = IAMF_ERR_BUFFER_TOO_SMALL; - } - return chs; -} - -static int iamf_audio_layer_layout_transform_in_plane(IAChannelLayoutType type, - float *in, float *out, - int size) { - const IAMF_LayoutInfo *info = iamf_audio_layer_get_layout_info(type); - for (int i = 0; i < info->channels; i++) - memcpy(&out[info->decoding_map[i] * size], &in[i * size], - size * sizeof(float)); - return IAMF_OK; -} - -static IAChannel iamf_output_gain_channel_map(IAChannelLayoutType type, - IAOutputGainChannel gch) { - IAChannel ch = IA_CH_INVALID; - const IAMF_LayoutInfo *info = iamf_audio_layer_get_layout_info(type); - switch (gch) { - case IA_CH_GAIN_L: { - switch (type) { - case IA_CHANNEL_LAYOUT_MONO: - ch = IA_CH_MONO; - break; - case IA_CHANNEL_LAYOUT_STEREO: - ch = IA_CH_L2; - break; - case IA_CHANNEL_LAYOUT_312: - ch = IA_CH_L3; - break; - default: - break; - } - } break; - - case IA_CH_GAIN_R: { - switch (type) { - case IA_CHANNEL_LAYOUT_STEREO: - ch = IA_CH_R2; - break; - case IA_CHANNEL_LAYOUT_312: - ch = IA_CH_R3; - break; - default: - break; - } - } break; - - case IA_CH_GAIN_LS: { - if (info->surround == 5) { - ch = IA_CH_SL5; - } - } break; - - case IA_CH_GAIN_RS: { - if (info->surround == 5) { - ch = IA_CH_SR5; - } - } break; - - case IA_CH_GAIN_LTF: { - if (info->surround < 5) { - ch = IA_CH_TL; - } else { - ch = IA_CH_HL; - } - } break; - - case IA_CH_GAIN_RTF: { - if (info->surround < 5) { - ch = IA_CH_TR; - } else { - ch = IA_CH_HR; - } - } break; - default: - break; - } - - return ch; -} - -/* ----------------------------- Internal Interfaces--------------- */ - -static uint32_t iamf_decoder_internal_read_descriptors_OBUs( - IAMF_DecoderHandle handle, const uint8_t *data, uint32_t size); -static int32_t iamf_decoder_internal_add_descrptor_OBU( - IAMF_DecoderHandle handle, IAMF_OBU *obu); -static IAMF_StreamDecoder *iamf_stream_decoder_open(IAMF_Stream *stream, - IAMF_CodecConf *conf); -static uint32_t iamf_set_stream_info(IAMF_DecoderHandle handle); -static int iamf_decoder_internal_deliver(IAMF_DecoderHandle handle, - IAMF_Frame *obj); -static int iamf_stream_scale_decoder_decode(IAMF_StreamDecoder *decoder, - float *pcm); -static int iamf_stream_scale_demixer_configure(IAMF_StreamDecoder *decoder); -static int32_t iamf_stream_scale_decoder_demix(IAMF_StreamDecoder *decoder, - float *src, float *dst, - uint32_t frame_size); -static int iamf_stream_ambisonics_decoder_decode(IAMF_StreamDecoder *decoder, - float *pcm); -static uint32_t iamf_stream_ambisionisc_order(int channels); - -/* >>>>>>>>>>>>>>>>>> DATABASE >>>>>>>>>>>>>>>>>> */ - -static void iamf_database_reset(IAMF_DataBase *db); -static IAMF_CodecConf *iamf_database_get_codec_conf(IAMF_DataBase *db, - uint64_t cid); -static ElementItem *iamf_database_element_get_item(IAMF_DataBase *db, - uint64_t eid); - -static void mix_gain_unit_free(MixGainUnit *u) { - if (u) { - IAMF_FREE(u->gains); - free(u); - } -} - -static int mix_gain_bezier_linear(float s, float e, int d, int o, uint32_t l, - float *g) { - int oe = o + l; - for (int i = o, k = 0; i < oe; ++i, ++k) g[k] = s + (e - s) * i / d; - - return IAMF_OK; -} - -static int mix_gain_bezier_quad(float s, float e, int d, float c, int ct, int o, - uint32_t l, float *g) { - int oe = o + l; - int64_t alpha = d - 2 * ct; - float a = 1.0f; - - for (int i = o, k = 0; i < oe; ++i, ++k) { - if (alpha) { - a = (sqrt(pow(ct, 2) + alpha * i) - ct) / alpha; - } else { - a = i; - a /= (2 * ct); - } - g[k] = (s + e - 2 * c) * pow(a, 2) + 2 * a * (c - s) + s; - } - - return IAMF_OK; -} - -static void iamf_object_free(void *obj) { IAMF_object_free(IAMF_OBJ(obj)); } - -static ObjectSet *iamf_object_set_new(IAMF_Free func) { - ObjectSet *s = IAMF_MALLOCZ(ObjectSet, 1); - if (s) { - s->objFree = func; - } - - return s; -} - -static void iamf_object_set_free(ObjectSet *s) { - if (s) { - if (s->objFree) { - for (int i = 0; i < s->count; ++i) s->objFree(s->items[i]); - if (s->items) free(s->items); - } - free(s); - } -} - -#define CAP_DEFAULT 6 -static int iamf_object_set_add(ObjectSet *s, void *item) { - if (!item) return IAMF_ERR_BAD_ARG; - - if (s->count == s->capacity) { - void **cap = 0; - if (!s->count) { - cap = IAMF_MALLOCZ(void *, CAP_DEFAULT); - } else { - cap = IAMF_REALLOC(void *, s->items, s->capacity + CAP_DEFAULT); - } - if (!cap) return IAMF_ERR_ALLOC_FAIL; - s->items = cap; - s->capacity += CAP_DEFAULT; - } - - s->items[s->count++] = item; - return IAMF_OK; -} - -const static struct { - /// @brief The maximum number of elements in a mix-presentation. - const uint32_t max_elements; - /// @brief The maximum number of channels in a mix-presentation. - const uint32_t max_channels; - /// @brief The maximum number of channels in a ambisonics element. - const uint32_t max_amb_channels; -} _profile_limit[IAMF_PROFILE_COUNT] = { - {1, 16, 16}, // simple profile - {2, 18, 16}, // base profile - {28, 28, 25}, // base-enhanced profile -}; - -static int iamf_element_is_valid(IAMF_Profile profile, IAMF_Element *e) { - int ret = IAMF_OK; - - if (e->element_type == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ScalableChannelLayoutConf *c = e->channels_conf; - - if (!c->nb_layers) { - ia_logw("element (%" PRId64 ") doesn't have valid layer.", e->element_id); - ret = IAMF_ERR_INTERNAL; - } else if (c->num_layers == 1 && profile <= IAMF_PROFILE_BASE && - !iamf_audio_layer_base_layout_check( - c->layer_conf_s[0].loudspeaker_layout)) { - ia_logw("element (%" PRId64 ") doesn't support layout %u in profile %u.", - e->element_id, c->layer_conf_s[0].loudspeaker_layout, profile); - ret = IAMF_ERR_INTERNAL; - } - } else if (e->element_type == AUDIO_ELEMENT_TYPE_SCENE_BASED) { - int channels = e->ambisonics_conf->substream_count + - e->ambisonics_conf->coupled_substream_count; - if (iamf_stream_ambisionisc_order( - e->ambisonics_conf->output_channel_count) == UINT32_MAX || - e->ambisonics_conf->output_channel_count < channels || - (channels > _profile_limit[profile].max_amb_channels)) { - ia_logw( - "Invalid output channel count %d or invalid input channels %d in " - "ambisonics mode, it should less than %d", - e->ambisonics_conf->output_channel_count, channels, - _profile_limit[profile].max_amb_channels); - ret = IAMF_ERR_UNIMPLEMENTED; - } - } else - ret = IAMF_ERR_UNIMPLEMENTED; - - return !ret; -} - -static int iamf_codec_conf_get_sampling_rate(IAMF_CodecConf *c) { - uint32_t cid = iamf_codec_4cc_get_codecID(c->codec_id); - if (cid == IAMF_CODEC_PCM) { - if (c->decoder_conf_size < 6) return IAMF_ERR_BAD_ARG; - return reads32be(c->decoder_conf, 2); - } else if (cid == IAMF_CODEC_OPUS) { - // https://aomediacodec.github.io/iamf/v1.1.0.html#opus-specific - // The sample rate used for computing offsets SHALL be 48 kHz. - return 48000; - } else if (cid == IAMF_CODEC_AAC) { - BitStream b; - int ret, type; - static int sf[] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, - 16000, 12000, 11025, 8000, 7350, 0, 0, 0}; - - /* DecoderConfigDescriptor */ - bs(&b, c->decoder_conf, c->decoder_conf_size); - bs_get32b(&b, 8); - bs_getExpandableSize(&b); - bs_skipABytes(&b, 13); - - /* DecSpecificInfoTag */ - bs_get32b(&b, 8); - bs_getExpandableSize(&b); - - type = bs_get32b(&b, 5); - if (type == 31) bs_get32b(&b, 6); - - ret = bs_get32b(&b, 4); - if (ret == 0xf) - return bs_get32b(&b, 24); - else - return sf[ret]; - } else if (cid == IAMF_CODEC_FLAC) { - BitStream b; - int last, type, size; - bs(&b, c->decoder_conf, c->decoder_conf_size); - while (1) { - last = bs_get32b(&b, 1); - type = bs_get32b(&b, 7); - size = bs_get32b(&b, 24); - if (!type) { - bs_skip(&b, 80); - return bs_get32b(&b, 20); - } else - bs_skip(&b, size * 8); - - if (last) break; - } - } - return IAMF_ERR_BAD_ARG; -} - -static int iamf_parameter_item_fill_segment(ParameterItem *pi, - uint64_t duration) { - ParameterSegment *seg = 0; - - ia_logd("fill segment %" PRId64 ", duration %" PRId64, pi->type, duration); - switch (pi->type) { - case IAMF_PARAMETER_TYPE_MIX_GAIN: { - MixGainSegment *mg = IAMF_MALLOCZ(MixGainSegment, 1); - if (!mg) { - ia_loge("fail to allocate mix gain segment for Parameter Object."); - return IAMF_ERR_ALLOC_FAIL; - } - mg->seg.type = IAMF_PARAMETER_TYPE_MIX_GAIN; - seg = (ParameterSegment *)mg; - mg->mix_gain_f.animated_type = PARAMETER_ANIMATED_TYPE_STEP; - mg->mix_gain_f.start = 0.0f; - break; - } - - case IAMF_PARAMETER_TYPE_DEMIXING: { - DemixingSegment *mode = IAMF_MALLOC(DemixingSegment, 1); - if (!mode) { - ia_loge("fail to allocate demixing segment for Parameter Object."); - return IAMF_ERR_ALLOC_FAIL; - } - mode->seg.type = IAMF_PARAMETER_TYPE_DEMIXING; - seg = (ParameterSegment *)mode; - break; - } - case IAMF_PARAMETER_TYPE_RECON_GAIN: { - ReconGainSegment *recon_gain = IAMF_MALLOCZ(ReconGainSegment, 1); - if (!recon_gain) { - ia_loge("fail to allocate recon gain segment for Parameter Object."); - return IAMF_ERR_ALLOC_FAIL; - } - recon_gain->seg.type = IAMF_PARAMETER_TYPE_RECON_GAIN; - seg = (ParameterSegment *)recon_gain; - break; - } - default: - return IAMF_ERR_UNIMPLEMENTED; - } - - if (seg) { - seg->segment_interval = duration; - queue_push(pi->value.params, seg); - pi->duration += duration; - ia_logd("fill segment %" PRId64 ", duration %" PRId64, pi->type, duration); - } - - return IAMF_OK; -} - -static void iamf_parameter_item_clear_segments(ParameterItem *pi) { - if (pi && pi->value.params) { - queue_t *q = pi->value.params; - while (queue_length(q) > 0) { - ParameterSegment *seg = queue_pop(q); - IAMF_parameter_segment_free(seg); - } - pi->duration = pi->elapse = pi->timestamp = 0; - } -} - -static int iamf_parameter_item_enable(ParameterItem *pi, int enable) { - if (pi) pi->enabled = !!enable; - return IAMF_OK; -} - -static void iamf_parameter_item_free(void *e) { - ParameterItem *pi = (ParameterItem *)e; - iamf_parameter_item_clear_segments(pi); - if (pi && pi->value.params) queue_free(pi->value.params); - IAMF_FREE(pi); -} - -static void iamf_database_viewer_reset(Viewer *v) { - if (v->items) { - free_tp ff = v->freeF; - if (!v->freeF) ff = free; - for (int i = 0; i < v->count; ++i) - if (v->items[i]) ff(v->items[i]); - free(v->items); - } - v->count = 0; - v->items = 0; -} - -static ParameterItem *iamf_database_parameter_viewer_get_item(Viewer *viewer, - uint64_t pid) { - ParameterItem *pi = 0, *vpi; - for (int i = 0; i < viewer->count; ++i) { - vpi = (ParameterItem *)viewer->items[i]; - if (vpi->id == pid) { - pi = vpi; - break; - } - } - return pi; -} - -static ParameterItem *iamf_database_parameter_get_item(IAMF_DataBase *db, - uint64_t pid) { - return iamf_database_parameter_viewer_get_item(&db->pViewer, pid); -} - -static int iamf_database_parameter_check_timestamp(IAMF_DataBase *db, - uint64_t pid, uint64_t pts) { - ParameterItem *pi = - iamf_database_parameter_viewer_get_item(&db->pViewer, pid); - if (!pi) return 0; - if (pts > pi->timestamp && pts <= pi->timestamp + pi->duration) return 1; - ia_logw("pid %" PRIu64 ": request pts %" PRIu64 " vs parameter pts %" PRIu64 - ", duration %" PRIu64, - pid, pts, pi->timestamp, pi->duration); - return 0; -} - -static ParameterSegment *iamf_database_parameter_get_segment(IAMF_DataBase *db, - uint64_t pid, - uint64_t pts) { - ParameterItem *pi = - iamf_database_parameter_viewer_get_item(&db->pViewer, pid); - ParameterSegment *seg = 0, *s = 0; - uint64_t start = 0; - int count = 0; - - if (!pi) return 0; - if (!iamf_database_parameter_check_timestamp(db, pi->id, pts)) { - ia_logw("Don't receive parameter %" PRIu64 " at %" PRIu64 - ", current parameter at %" PRIu64, - pi->id, pts, pi->timestamp); - return 0; - } else - start = pts - pi->timestamp; - - count = pi->value.params ? queue_length(pi->value.params) : 0; - for (int i = 0; i < count; ++i) { - s = queue_take(pi->value.params, i); - if (!s) break; - if (start < s->segment_interval) { - seg = s; - break; - } else { - start -= s->segment_interval; - } - } - return seg; -} - -static int iamf_database_parameter_get_demix_mode(IAMF_DataBase *db, - uint64_t pid, uint64_t pts) { - DemixingSegment *dseg = - (DemixingSegment *)iamf_database_parameter_get_segment(db, pid, pts); - return dseg ? dseg->demixing_mode : IAMF_ERR_INTERNAL; -} - -static ReconGainList *iamf_database_parameter_get_recon_gain_list( - IAMF_DataBase *db, uint64_t pid, uint64_t pts) { - ReconGainSegment *rg = - (ReconGainSegment *)iamf_database_parameter_get_segment(db, pid, pts); - return rg ? &rg->list : 0; -} - -static MixGainUnit *iamf_database_parameter_get_mix_gain_unit( - IAMF_DataBase *db, uint64_t pid, uint64_t pt, int duration, int rate) { - ParameterItem *pi = 0; - MixGainUnit *mgu = 0; - uint64_t start = 0; - float ratio = 1.f; - int use_default = 0; - uint64_t tsf_parameter_timestamp = 0; - - pi = iamf_database_parameter_viewer_get_item(&db->pViewer, pid); - if (!pi) return 0; - - tsf_parameter_timestamp = time_transform(pi->timestamp, pi->rate, rate); - ia_logd("pts %" PRIu64 ", duration %d, rate %d, parameter id %" PRIu64 - ", pts %" PRIu64 ", duration %" PRId64 ", rate %d", - pt, duration, rate, pid, pi->timestamp, pi->duration, pi->rate); - if (pt < tsf_parameter_timestamp) { - ia_logw("Don't receive mix gain parameter %" PRIu64 " at %" PRIu64 - ", current parameter at " - "%" PRIu64, - pi->id, pt, tsf_parameter_timestamp); - use_default = 1; - } else - start = pt - tsf_parameter_timestamp; - - mgu = IAMF_MALLOCZ(MixGainUnit, 1); - if (!mgu) return 0; - - if (pi->value.mix_gain.use_default || use_default) { - ia_logd("use default mix gain %f", pi->value.mix_gain.default_mix_gain); - mgu->constant_gain = pi->value.mix_gain.default_mix_gain; - mgu->count = duration; - } else { - int64_t sgd = 0; - int64_t minterval = 0; - int left = duration; - MixGainSegment *seg = 0; - - if (!pi->param.param_base || !pi->value.params) { - mix_gain_unit_free(mgu); - return 0; - } - - if (rate != pi->param.param_base->rate) - ratio = (rate + 0.1f) / pi->param.param_base->rate; - - for (int i = 0; i < queue_length(pi->value.params); ++i) { - seg = (MixGainSegment *)queue_take(pi->value.params, i); - if (!seg) { - ia_loge("Can't find %d-th segment", i); - break; - } - minterval = seg->seg.segment_interval * ratio; - sgd += minterval; - if (start < sgd) { - ia_logd("find segment %d, s(%" PRIu64 ") ~ e(%" PRIu64 ")", i, - sgd - minterval, sgd); - if (seg->mix_gain.animated_type == PARAMETER_ANIMATED_TYPE_STEP) { - if (!mgu->count && start + duration <= sgd) { - mgu->constant_gain = seg->mix_gain_f.start; - mgu->count = duration; - ia_logd("use constant mix gain %f", seg->mix_gain_f.start); - } else if (!mgu->count) { - mgu->gains = IAMF_MALLOC(float, duration); - if (!mgu->gains) { - ia_loge("Fail to allocate gains of mix gain unit."); - mix_gain_unit_free(mgu); - return 0; - } - mgu->count = sgd - start; - for (int i = 0; i < mgu->count; ++i) - mgu->gains[i] = seg->mix_gain_f.start; - start = sgd; - ia_logd("step-1: get %d gains", mgu->count); - left -= mgu->count; - } else { - int e = mgu->count + minterval; - if (e >= duration) - e = duration; - else { - start = sgd; - e = mgu->count + minterval; - } - for (int i = mgu->count; i < e; ++i) - mgu->gains[i] = seg->mix_gain_f.start; - ia_logd("step-2: get %d gains", e - mgu->count); - mgu->count = e; - } - } else { - int off = 0; - int ss = sgd - minterval; - int d = 0; - off = start - ss; - if (!mgu->gains) { - mgu->gains = IAMF_MALLOC(float, duration); - if (!mgu->gains) { - ia_loge("Fail to allocate gains of mix gain unit."); - mix_gain_unit_free(mgu); - return 0; - } - } - - if (start + left <= sgd) { - d = left; - } else { - d = sgd - start; - start = sgd; - left -= d; - } - ia_logd("s %f, e %f, minterval %" PRId64 - ", off %d, duration %d, count %d", - seg->mix_gain_f.start, seg->mix_gain_f.end, minterval, off, d, - mgu->count); - if (seg->mix_gain.animated_type == PARAMETER_ANIMATED_TYPE_LINEAR) - mix_gain_bezier_linear(seg->mix_gain_f.start, seg->mix_gain_f.end, - minterval, off, d, mgu->gains + mgu->count); - else - mix_gain_bezier_quad( - seg->mix_gain_f.start, seg->mix_gain_f.end, minterval, - seg->mix_gain_f.control, - seg->mix_gain_f.control_relative_time * (minterval + .1f), off, - d, mgu->gains + mgu->count); - mgu->count += d; - ia_logd("non-step: get %d gains", d); - } - } - - if (mgu->count == duration) break; - } - } - - return mgu; -} - -static int iamf_database_parameter_add_item(IAMF_DataBase *db, - ParameterBase *base, - uint64_t parent_id, int rate) { - Viewer *pv = &db->pViewer; - ParameterItem *pi = 0; - ParameterItem **pis = 0; - ElementItem *ei = 0; - uint64_t pid, type; - - if (!base) return IAMF_ERR_BAD_ARG; - - pid = base->id; - type = base->type; - pi = iamf_database_parameter_viewer_get_item(pv, pid); - - if (pi) { - ia_logd("parameter %" PRIu64 " is already in database.", pid); - return IAMF_OK; - } - - pis = IAMF_REALLOC(ParameterItem *, pv->items, pv->count + 1); - if (!pis) return IAMF_ERR_ALLOC_FAIL; - pv->items = (void **)pis; - pis[pv->count] = 0; - - pi = IAMF_MALLOCZ(ParameterItem, 1); - if (!pi) return IAMF_ERR_ALLOC_FAIL; - - pi->value.params = queue_new(); - if (!pi->value.params) { - free(pi); - return IAMF_ERR_ALLOC_FAIL; - } - - // use default mix gain. - if (type == IAMF_PARAMETER_TYPE_MIX_GAIN) pi->value.mix_gain.use_default = 1; - - pis[pv->count++] = pi; - ia_logd("add parameter item %p, its id %" PRIu64 ", and count is %d", pi, pid, - pv->count); - - pi->id = pid; - pi->type = base->type; - pi->parent_id = parent_id; - pi->rate = rate; - pi->enabled = 1; - pi->param.base.type = IAMF_OBU_PARAMETER_BLOCK; - pi->param.param_base = base; - ia_logi("sync parameter (%" PRIu64 ") timestamp %" PRIu64, pi->id, - pi->timestamp); - - ei = iamf_database_element_get_item(db, parent_id); - if (ei) { - if (type == IAMF_PARAMETER_TYPE_DEMIXING) { - ei->demixingPid = pid; - } else if (type == IAMF_PARAMETER_TYPE_RECON_GAIN) { - ScalableChannelLayoutConf *conf = ei->element->channels_conf; - ei->reconGainPid = pid; - pi->param.nb_layers = conf->nb_layers; - - for (int i = 0; i < pi->param.nb_layers; ++i) { - if (conf->layer_conf_s[i].recon_gain_flag) - pi->param.recon_gain_present_flags |= RSHIFT(i); - } - } - } - return IAMF_OK; -} - -static int iamf_database_parameter_disable_items(IAMF_DataBase *db) { - for (int i = 0; i < db->pViewer.count; ++i) - iamf_parameter_item_enable((ParameterItem *)db->pViewer.items[i], 0); - return IAMF_OK; -} - -static int iamf_database_parameter_enabled_items_count(IAMF_DataBase *db) { - ParameterItem *vpi = 0; - int count = 0; - for (int i = 0; i < db->pViewer.count; ++i) { - vpi = (ParameterItem *)db->pViewer.items[i]; - if (vpi->enabled) count++; - } - return count; -} - -static int iamf_database_parameter_clear_items(IAMF_DataBase *db) { - int count = 0; - Viewer pv; - ParameterItem *vpi = 0; - ParameterItem **pis = 0; - - count = iamf_database_parameter_enabled_items_count(db); - if (count == db->pViewer.count) return IAMF_OK; - - memset(&pv, 0, sizeof(Viewer)); - pv.freeF = iamf_parameter_item_free; - - pis = IAMF_MALLOCZ(ParameterItem *, count); - if (!pis) return IAMF_ERR_ALLOC_FAIL; - pv.items = (void **)pis; - - for (int i = 0; i < db->pViewer.count; ++i) { - vpi = (ParameterItem *)db->pViewer.items[i]; - if (vpi->enabled) { - pis[pv.count++] = vpi; - db->pViewer.items[i] = 0; - } - } - iamf_database_viewer_reset(&db->pViewer); - db->pViewer = pv; - return IAMF_OK; -} - -static int iamf_database_parameter_add(IAMF_DataBase *db, IAMF_Object *obj) { - Viewer *pv = &db->pViewer; - IAMF_Parameter *p = (IAMF_Parameter *)obj; - ParameterItem *pi = 0; - - pi = iamf_database_parameter_viewer_get_item(pv, p->id); - if (pi) { - if (obj->flags & IAMF_OBU_FLAG_REDUNDANT && pi->duration > 0) { - ia_logd("Ignore redundant parameter obu with id %" PRIu64 ".", p->id); - return IAMF_OK; - } - - if (pi->type == IAMF_PARAMETER_TYPE_MIX_GAIN && - pi->value.mix_gain.use_default) { - pi->value.mix_gain.use_default = 0; - } - - for (int i = 0; i < p->nb_segments; ++i) { - queue_push(pi->value.params, p->segments[i]); - pi->duration += p->segments[i]->segment_interval; - p->segments[i] = 0; - } - ia_logd("New p(%" PRIu64 ")ts(s:%" PRIu64 ", e: %" PRIu64 ").", pi->id, - pi->timestamp, pi->timestamp + pi->duration); - } else { - ia_logw("Can not find parameter item for paramter (%" PRIu64 ")", p->id); - } - - return IAMF_OK; -} - -static int iamf_database_parameters_time_elapse(IAMF_DataBase *db, - uint64_t duration, - uint32_t rate) { - Viewer *pv = &db->pViewer; - ParameterItem *pi; - ParameterSegment *seg; - - for (int i = 0; i < pv->count; ++i) { - pi = (ParameterItem *)pv->items[i]; - ia_logd("S: pid %" PRIu64 " pts %" PRIu64 ", duration %" PRIu64 - ", elapsed %" PRIu64 ", rate %" PRIu64 ", elapse %" PRIu64 - ", rate %u", - pi->id, pi->timestamp, pi->duration, pi->elapse, - pi->param.param_base->rate, duration, rate); - - if (pi->value.params) { - pi->elapse += time_transform(duration, rate, pi->param.param_base->rate); - while (1) { - // ia_logd("pi %p, pid %" PRIu64 ", segment length %d", pi, pi->id, - // queue_length(pi->value.params)); - seg = (ParameterSegment *)queue_take(pi->value.params, 0); - if (seg && seg->segment_interval <= pi->elapse) { - pi->timestamp += seg->segment_interval; - pi->duration -= seg->segment_interval; - pi->elapse -= seg->segment_interval; - // ia_logd("pi %p, pid %" PRIu64 ", pop segment %p", pi, pi->id, seg); - queue_pop(pi->value.params); - IAMF_parameter_segment_free(seg); - } else { - ia_logd("E: pid %" PRIu64 " pts %" PRIu64 ", duration %" PRIu64 - ", elapsed %" PRIu64, - pi->id, pi->timestamp, pi->duration, pi->elapse); - break; - } - } - } - } - return IAMF_OK; -} - -static int iamf_database_parameter_item_segment_copy(IAMF_DataBase *db, - ParameterItem *pi, - uint64_t spid) { - ParameterItem *spi = iamf_database_parameter_get_item(db, spid); - MixGainSegment *mgs = 0, *seg; - int length; - int ret = IAMF_OK; - - if (!spi) return IAMF_ERR_BAD_ARG; - if (pi->type != IAMF_PARAMETER_TYPE_MIX_GAIN || - spi->type != IAMF_PARAMETER_TYPE_MIX_GAIN) { - ia_logw("Unsupport parameter type %" PRId64 ".", - pi->type == IAMF_PARAMETER_TYPE_MIX_GAIN ? spi->type : pi->type); - return IAMF_ERR_UNIMPLEMENTED; - } - - if (pi) iamf_parameter_item_clear_segments(pi); - length = queue_length(spi->value.params); - for (int i = 0; i < length; ++i) { - mgs = queue_take(spi->value.params, 0); - seg = IAMF_MALLOCZ(MixGainSegment, 1); - if (!seg) { - ia_loge("Fail to allocate memory for MixGainSegment."); - ret = IAMF_ERR_ALLOC_FAIL; - break; - } - *seg = *mgs; - queue_push(pi->value.params, seg); - } - - if (ret == IAMF_OK) { - pi->timestamp = spi->timestamp; - pi->elapse = spi->elapse; - pi->duration = spi->duration; - } - ia_logd("Parameter %" PRId64 " Copy info: timestamp %" PRId64 - ", duration %" PRId64 ", elapse %" PRId64 ", segment length %d", - pi->id, pi->timestamp, pi->duration, pi->elapse, - queue_length(pi->value.params)); - - return ret; -} - -static int iamf_database_element_add(IAMF_DataBase *db, IAMF_Object *obj) { - int ret = IAMF_OK; - ElementItem *ei = 0; - ElementItem **eItem = 0; - Viewer *v = &db->eViewer; - IAMF_Element *e = (IAMF_Element *)obj; - IAMF_CodecConf *cc = iamf_database_get_codec_conf(db, e->codec_config_id); - if (!cc) { - ia_logw("Element %" PRId64 " has unsupported codec conf id %" PRId64, - e->element_id, e->codec_config_id); - return IAMF_ERR_UNIMPLEMENTED; - } - - if (!iamf_element_is_valid(db->profile, e)) return IAMF_ERR_UNIMPLEMENTED; - - ei = iamf_database_element_get_item(db, e->element_id); - if (ei) { - ia_logd("element %" PRIu64 " is already in database.", e->element_id); - return IAMF_OK; - } - - eItem = IAMF_REALLOC(ElementItem *, v->items, v->count + 1); - if (!eItem) return IAMF_ERR_ALLOC_FAIL; - eItem[v->count] = 0; - - v->items = (void **)eItem; - ret = iamf_object_set_add(db->element, (void *)obj); - if (ret != IAMF_OK) return ret; - - ei = IAMF_MALLOCZ(ElementItem, 1); - if (!ei) return IAMF_ERR_ALLOC_FAIL; - - v->items[v->count++] = ei; - ei->id = e->element_id; - ei->element = IAMF_ELEMENT(obj); - ei->codecConf = cc; - return ret; -} - -static int iamf_database_mix_presentation_is_valid(IAMF_DataBase *db, - IAMF_MixPresentation *mp) { - int ret = IAMF_OK; - SubMixPresentation *sub; - ElementConf *econf; - int channels = 0; - ElementItem *ei = 0; - - sub = mp->sub_mixes; - if (sub->nb_elements > _profile_limit[db->profile].max_elements) { - ia_logw("Too many elements %" PRIu64 - " (should be <= %u) in mix presentation %" PRIu64 " for profile %u", - sub->nb_elements, _profile_limit[db->profile].max_elements, - mp->mix_presentation_id, db->profile); - return 0; - } - - for (int e = 0; e < sub->nb_elements; ++e) { - econf = &sub->conf_s[e]; - ei = iamf_database_element_get_item(db, econf->element_id); - if (!ei) { - ia_logw("Invalid element %" PRId64 " in mix presentation %" PRId64, - econf->element_id, mp->mix_presentation_id); - ret = IAMF_ERR_UNIMPLEMENTED; - break; - } else if (econf->conf_r.headphones_rendering_mode > 1) { - ia_logw("Invalid headphones rendering mode %d in element %" PRId64 - " of mix presentation %" PRId64, - econf->conf_r.headphones_rendering_mode & U8_MASK, - econf->element_id, mp->mix_presentation_id); - ret = IAMF_ERR_UNIMPLEMENTED; - break; - } - - if (ei->element->element_type == AUDIO_ELEMENT_CHANNEL_BASED) { - ScalableChannelLayoutConf *c = ei->element->channels_conf; - ChannelLayerConf *clc = &c->layer_conf_s[c->nb_layers - 1]; - channels += - iamf_audio_layer_get_layout_info( - iamf_audio_layer_layout_get(clc->loudspeaker_layout, - clc->expanded_loudspeaker_layout)) - ->channels; - } else if (ei->element->element_type == AUDIO_ELEMENT_SCENE_BASED) { - channels += ei->element->ambisonics_conf->output_channel_count; - } - } - - if (ret != IAMF_OK) return !ret; - if (channels > _profile_limit[db->profile].max_channels) { - ia_logw("Mix Presentation %" PRId64 " has %d channels, more than %u", - mp->mix_presentation_id, channels, - _profile_limit[db->profile].max_channels); - return 0; - } - - ret = IAMF_ERR_UNIMPLEMENTED; - for (int l = 0; l < sub->num_layouts; ++l) { - if (!sub->layouts[l]) continue; - if (sub->layouts[l]->type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) { - SoundSystemLayout *layout = SOUND_SYSTEM_LAYOUT(sub->layouts[l]); - if (iamf_sound_system_valid(layout->sound_system)) - ret &= IAMF_OK; - else - ia_logw("Find unsupported sound system %d in mix presentation %" PRId64, - layout->sound_system, mp->mix_presentation_id); - } else if (sub->layouts[l]->type == IAMF_LAYOUT_TYPE_BINAURAL) { - ret &= IAMF_OK; - } - } - - if (ret != IAMF_OK) { - ia_logw("Mix Presentation %" PRId64 - " doesn't have valid layout or sound system.", - mp->mix_presentation_id); - } - - return !ret; -} - -int iamf_database_init(IAMF_DataBase *db) { - memset(db, 0, sizeof(IAMF_DataBase)); - - db->codecConf = iamf_object_set_new(iamf_object_free); - db->element = iamf_object_set_new(iamf_object_free); - db->mixPresentation = iamf_object_set_new(iamf_object_free); - db->eViewer.freeF = free; - db->pViewer.freeF = iamf_parameter_item_free; - db->profile = IAMF_PROFILE_DEFAULT; - - if (!db->codecConf || !db->element || !db->mixPresentation) { - iamf_database_reset(db); - return IAMF_ERR_ALLOC_FAIL; - } - return 0; -} - -void iamf_database_reset(IAMF_DataBase *db) { - if (db) { - if (db->version) iamf_object_free(db->version); - if (db->codecConf) iamf_object_set_free(db->codecConf); - if (db->element) iamf_object_set_free(db->element); - if (db->mixPresentation) iamf_object_set_free(db->mixPresentation); - - iamf_database_viewer_reset(&db->eViewer); - iamf_database_viewer_reset(&db->pViewer); - - memset(db, 0, sizeof(IAMF_DataBase)); - } -} - -static int iamf_database_add_object(IAMF_DataBase *db, IAMF_Object *obj) { - int ret = IAMF_OK; - if (!obj) return IAMF_ERR_BAD_ARG; - - switch (obj->type) { - case IAMF_OBU_SEQUENCE_HEADER: { - IAMF_Version *version = (IAMF_Version *)obj; - - if (version->primary_profile > db->profile) { - ia_loge("Unimplemented profile %u", version->primary_profile); - ret = IAMF_ERR_UNIMPLEMENTED; - break; - } - - if (version->additional_profile < db->profile) - db->profile = version->additional_profile; - - if (db->version) { - ia_logw("WARNING : Receive Multiple START CODE OBUs !!!"); - free(db->version); - } - - db->version = obj; - break; - } - case IAMF_OBU_CODEC_CONFIG: - ret = iamf_object_set_add(db->codecConf, (void *)obj); - break; - case IAMF_OBU_AUDIO_ELEMENT: - ret = iamf_database_element_add(db, obj); - break; - case IAMF_OBU_MIX_PRESENTATION: - if (iamf_database_mix_presentation_is_valid(db, - (IAMF_MixPresentation *)obj)) - ret = iamf_object_set_add(db->mixPresentation, (void *)obj); - else - ret = IAMF_ERR_INTERNAL; - break; - case IAMF_OBU_PARAMETER_BLOCK: - ret = iamf_database_parameter_add(db, obj); - IAMF_object_free(obj); - obj = 0; - break; - default: - ia_logd("IAMF Object %s (%d) is not needed in database.", - IAMF_OBU_type_string(obj->type), obj->type); - ret = IAMF_ERR_UNIMPLEMENTED; - } - - if (ret != IAMF_OK && obj) IAMF_object_free(obj); - return ret; -} - -IAMF_CodecConf *iamf_database_get_codec_conf(IAMF_DataBase *db, uint64_t cid) { - IAMF_CodecConf *ret = 0; - - if (db->codecConf) { - IAMF_CodecConf *c = 0; - for (uint32_t i = 0; i < db->codecConf->count; ++i) { - c = (IAMF_CodecConf *)db->codecConf->items[i]; - if (c->codec_conf_id == cid) { - ret = c; - break; - } - } - } - return ret; -} - -static IAMF_Element *iamf_database_get_element(IAMF_DataBase *db, - uint64_t eid) { - ElementItem *ei = iamf_database_element_get_item(db, eid); - return ei ? ei->element : 0; -} - -static IAMF_Element *iamf_database_get_element_by_parameterID(IAMF_DataBase *db, - uint64_t pid) { - IAMF_Element *elem = 0; - IAMF_Element *e = 0; - ElementItem *ei = 0, *vei; - for (int i = 0; i < db->eViewer.count; ++i) { - vei = (ElementItem *)db->eViewer.items[i]; - e = IAMF_ELEMENT(vei->element); - for (int p = 0; p < e->nb_parameters; ++p) { - if (e->parameters[p] && pid == e->parameters[p]->id) { - elem = e; - break; - } - } - if (!elem) { - ei = iamf_database_element_get_item(db, e->element_id); - if (ei && ei->mixGainPid == pid) { - elem = e; - break; - } - } - } - return elem; -} - -static IAMF_MixPresentation *iamf_database_get_mix_presentation( - IAMF_DataBase *db, uint64_t id) { - IAMF_MixPresentation *ret = 0, *obj; - if (db && db->mixPresentation && db->mixPresentation->count > 0) { - for (int i = 0; i < db->mixPresentation->count; ++i) { - obj = IAMF_MIX_PRESENTATION(db->mixPresentation->items[i]); - if (obj && obj->mix_presentation_id == id) { - ret = obj; - break; - } - } - } - return ret; -} - -ElementItem *iamf_database_element_get_item(IAMF_DataBase *db, uint64_t eid) { - ElementItem *ei = 0, *vei; - for (int i = 0; i < db->eViewer.count; ++i) { - vei = (ElementItem *)db->eViewer.items[i]; - if (vei->id == eid) { - ei = vei; - break; - } - } - return ei; -} - -static int iamf_database_element_get_substream_index(IAMF_DataBase *db, - uint64_t element_id, - uint64_t substream_id) { - IAMF_Element *obj = iamf_database_get_element(db, element_id); - int ret = -1; - - if (obj) { - for (int i = 0; i < obj->nb_substreams; ++i) { - if (obj->substream_ids[i] == substream_id) { - ret = i; - break; - } - } - } - return ret; -} - -static IAMF_CodecConf *iamf_database_element_get_codec_conf(IAMF_DataBase *db, - uint64_t eid) { - ElementItem *ei = iamf_database_element_get_item(db, eid); - return ei ? ei->codecConf : 0; -} - -static int iamf_database_element_set_mix_gain_parameter(IAMF_DataBase *db, - uint64_t eid, - uint64_t pid) { - ElementItem *ei = iamf_database_element_get_item(db, eid); - if (ei) ei->mixGainPid = pid; - return IAMF_OK; -} - -/* <<<<<<<<<<<<<<<<<< DATABASE <<<<<<<<<<<<<<<<<< */ - -/* <<<<<<<<<<<<<<<<<< STREAM DECODER MIXER RESAMPLER <<<<<<<<<<<<<<<<<< */ - -static int iamf_stream_set_output_layout(IAMF_Stream *s, LayoutInfo *layout); -static uint32_t iamf_stream_mode_ambisonics(uint32_t ambisonics_mode); -static void iamf_stream_free(IAMF_Stream *s); -static void iamf_stream_decoder_close(IAMF_StreamDecoder *d); -static IAMF_StreamRenderer *iamf_stream_renderer_open(IAMF_Stream *s, - IAMF_MixPresentation *mp, - int frame_size); -static int iamf_stream_renderer_enable_downmix(IAMF_StreamRenderer *sr); -static void iamf_stream_renderer_close(IAMF_StreamRenderer *sr); -static void iamf_mixer_reset(IAMF_Mixer *m); -static int iamf_stream_scale_decoder_update_recon_gain( - IAMF_StreamDecoder *decoder, ReconGainList *list); -static IAMF_Resampler *iamf_stream_resampler_open(IAMF_Stream *stream, - uint32_t out_rate, - int quality); -static void iamf_stream_resampler_close(IAMF_Resampler *r); - -static int iamf_packet_check_count(Packet *pkt) { - return pkt->count == pkt->nb_sub_packets; -} - -/** - * @brief Trimming the start of end samples after decoding. - * @param [in] f : the input audio frame. - * @param [in] start : the trimming start position in audio frame obu header - * @param [in] end : the trimming end position in audio frame obu header - * @param [in] start_extension : the offset after start - * @return the number of samples after trimming - */ -static int iamf_frame_trim(Frame *f, int start, int end, int start_extension) { - int s, ret; - s = start + start_extension; - ret = f->samples - s - end; - if (start < 0 || end < 0 || start_extension < 0 || ret < 0) { - ia_logw( - "clip start %d, end %d, start extension %d, and the left samples %d", - start, end, start_extension, ret); - return IAMF_ERR_BAD_ARG; - } - - if (ret > 0 && ret != f->samples) { - for (int c = 0; c < f->channels; ++c) { - memmove(&f->data[c * ret], &f->data[c * f->samples + s], - ret * sizeof(float)); - } - } - f->samples = ret; - f->pts += start; - return ret; -} - -/** - * @brief Apply animated gain to audio frame. - * @param [in] f : the input audio frame. - * @param [in] gain : the gain value - * @return @ref IAErrCode. - */ -static int iamf_frame_gain(Frame *f, MixGainUnit *gain) { - int soff; - if (!gain) return IAMF_ERR_BAD_ARG; - if (f->samples > gain->count) { - ia_loge("frame samples should be not greater than gain count %d vs %d", - f->samples, gain->count); - return IAMF_ERR_INTERNAL; - } - - if (!gain->gains) { - ia_logd("use constant gain %f.", gain->constant_gain); - if (gain->constant_gain != 1.f && gain->constant_gain > 0.f) { - int count = f->samples * f->channels; - for (int i = 0; i < count; ++i) f->data[i] *= gain->constant_gain; - } - return IAMF_OK; - } - - ia_logd("use gains %f -> %f", gain->gains[0], gain->gains[gain->count - 1]); - for (int c = 0; c < f->channels; ++c) { - soff = c * f->samples; - for (int i = 0; i < f->samples; ++i) f->data[soff + i] *= gain->gains[i]; - } - - return IAMF_OK; -} - -static void iamf_presentation_free(IAMF_Presentation *pst) { - if (pst) { - for (int i = 0; i < pst->nb_streams; ++i) { - if (pst->decoders[i]) iamf_stream_decoder_close(pst->decoders[i]); - if (pst->renderers[i]) iamf_stream_renderer_close(pst->renderers[i]); - if (pst->streams[i]) iamf_stream_free(pst->streams[i]); - } - if (pst->resampler) iamf_stream_resampler_close(pst->resampler); - - free(pst->renderers); - free(pst->decoders); - free(pst->streams); - iamf_mixer_reset(&pst->mixer); - free(pst); - } -} - -static IAMF_Stream *iamf_presentation_take_stream(IAMF_Presentation *pst, - uint64_t eid) { - IAMF_Stream *stream = 0; - - if (!pst) return 0; - - for (int i = 0; i < pst->nb_streams; ++i) { - if (pst->streams[i] && pst->streams[i]->element_id == eid) { - stream = pst->streams[i]; - pst->streams[i] = 0; - break; - } - } - - return stream; -} - -static IAMF_StreamDecoder *iamf_presentation_take_decoder( - IAMF_Presentation *pst, IAMF_Stream *stream) { - IAMF_StreamDecoder *decoder = 0; - for (int i = 0; i < pst->nb_streams; ++i) { - if (pst->decoders[i] && pst->decoders[i]->stream == stream) { - decoder = pst->decoders[i]; - pst->decoders[i] = 0; - break; - } - } - - return decoder; -} - -static IAMF_StreamRenderer *iamf_presentation_take_renderer( - IAMF_Presentation *pst, IAMF_Stream *stream) { - IAMF_StreamRenderer *renderer = 0; - for (int i = 0; i < pst->nb_streams; ++i) { - if (pst->renderers[i] && pst->renderers[i]->stream == stream) { - renderer = pst->renderers[i]; - pst->renderers[i] = 0; - break; - } - } - - return renderer; -} - -static IAMF_Resampler *iamf_presentation_take_resampler( - IAMF_Presentation *pst) { - IAMF_Resampler *resampler = 0; - resampler = pst->resampler; - pst->resampler = 0; - - return resampler; -} - -static int iamf_presentation_reuse_stream(IAMF_Presentation *dst, - IAMF_Presentation *src, - uint64_t eid) { - IAMF_Stream *stream = 0; - IAMF_StreamDecoder *decoder = 0; - IAMF_StreamRenderer *renderer = 0; - IAMF_Stream **streams; - IAMF_StreamDecoder **decoders; - IAMF_StreamRenderer **renderers; - - if (!dst || !src) return IAMF_ERR_BAD_ARG; - - stream = iamf_presentation_take_stream(src, eid); - if (!stream) return IAMF_ERR_INTERNAL; - - decoder = iamf_presentation_take_decoder(src, stream); - if (!decoder) return IAMF_ERR_INTERNAL; - - renderer = iamf_presentation_take_renderer(src, stream); - if (!renderer) return IAMF_ERR_INTERNAL; - - iamf_stream_renderer_enable_downmix(renderer); - - streams = IAMF_REALLOC(IAMF_Stream *, dst->streams, dst->nb_streams + 1); - if (!streams) return IAMF_ERR_INTERNAL; - dst->streams = streams; - - decoders = - IAMF_REALLOC(IAMF_StreamDecoder *, dst->decoders, dst->nb_streams + 1); - if (!decoders) return IAMF_ERR_INTERNAL; - dst->decoders = decoders; - - renderers = - IAMF_REALLOC(IAMF_StreamRenderer *, dst->renderers, dst->nb_streams + 1); - if (!renderers) return IAMF_ERR_INTERNAL; - dst->renderers = renderers; - - dst->streams[dst->nb_streams] = stream; - dst->decoders[dst->nb_streams] = decoder; - dst->renderers[dst->nb_streams] = renderer; - ++dst->nb_streams; - ia_logd("reuse stream with element id %" PRIu64, eid); - - return 0; -} - -/** - * Output sound mode: - * - * |---------------------------------------------------------------------| - * | Elem B\Elem A | Mono | Stereo | Binaural | > 2-ch | Ambisonic | - * |---------------------------------------------------------------------| - * | Mono | Stereo | Stereo | N/A | M-ch | SPL | - * |---------------------------------------------------------------------| - * | Stereo | Stereo | Stereo | N/A | M-ch | SPL | - * |---------------------------------------------------------------------| - * | Binaural | N/A | N/A | Binaural | N/A | N/A | - * |---------------------------------------------------------------------| - * | > 2-ch | M-ch | M-ch | N/A | M-ch | SPL | - * |---------------------------------------------------------------------| - * | Ambisonic | SPL | SPL | N/A | SPL | SPL | - * |---------------------------------------------------------------------| - * - * 2-ch : 2 channels - * M-ch : Multichannel - * SPL : Same to playback layout, it means: - * - * If (Output_sound_mode == ?Same to playback layout?) - * { - * If (Output_sound_system == ?Sound system A (0+2+0)?) { Output_sound_mode = - * Stereo; } Else { Output_sound_mode = Multichannel; } - * } - * - * */ -static IAMF_SoundMode iamf_presentation_get_output_sound_mode( - IAMF_Presentation *pst) { - IAMF_Stream *st; - IAMF_SoundMode mode = IAMF_SOUND_MODE_NONE, sm; - - for (int s = 0; s < pst->nb_streams; ++s) { - st = pst->streams[s]; - if (st->scheme == AUDIO_ELEMENT_TYPE_SCENE_BASED) - sm = iamf_layout_get_sound_mode(&st->final_layout->layout); - else { - ChannelLayerContext *cctx = (ChannelLayerContext *)st->priv; - int type = cctx->layout; - if (type == IA_CHANNEL_LAYOUT_MONO || type == IA_CHANNEL_LAYOUT_STEREO) - sm = IAMF_SOUND_MODE_STEREO; - else if (type == IA_CHANNEL_LAYOUT_BINAURAL) - sm = IAMF_SOUND_MODE_BINAURAL; - else - sm = IAMF_SOUND_MODE_MULTICHANNEL; - } - mode = iamf_sound_mode_combine(mode, sm); - } - - return mode; -} - -static ElementConf *iamf_mix_presentation_get_element_conf( - IAMF_MixPresentation *mp, uint64_t eid) { - ElementConf *ec = 0; - if (!mp || !mp->sub_mixes || !mp->sub_mixes->conf_s) return 0; - - for (int i = 0; i < mp->sub_mixes->nb_elements; ++i) { - if (mp->sub_mixes->conf_s[i].element_id == eid) { - ec = &mp->sub_mixes->conf_s[i]; - break; - } - } - - return ec; -} - -void iamf_stream_free(IAMF_Stream *s) { - if (s) { - if (s->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ChannelLayerContext *ctx = s->priv; - if (ctx) { - if (ctx->conf_s) { - for (int i = 0; i < ctx->nb_layers; ++i) { - IAMF_FREE(ctx->conf_s[i].output_gain); - IAMF_FREE(ctx->conf_s[i].recon_gain); - } - free(ctx->conf_s); - } - free(ctx); - } - } else if (s->scheme == AUDIO_ELEMENT_TYPE_SCENE_BASED) { - AmbisonicsContext *ctx = s->priv; - free(ctx); - } - free(s); - } -} - -static IAMF_Stream *iamf_stream_new(IAMF_Presentation *pst, IAMF_Element *elem, - IAMF_CodecConf *conf, LayoutInfo *layout) { - IAMF_Stream *stream = IAMF_MALLOCZ(IAMF_Stream, 1); - if (!stream) goto stream_fail; - ElementConf *ec = - iamf_mix_presentation_get_element_conf(pst->obj, elem->element_id); - if (!ec) goto stream_fail; - - stream->element_id = elem->element_id; - stream->scheme = elem->element_type; - stream->codecConf_id = conf->codec_conf_id; - stream->codec_id = iamf_codec_4cc_get_codecID(conf->codec_id); - stream->sampling_rate = iamf_codec_conf_get_sampling_rate(conf); - stream->headphones_rendering_mode = ec->conf_r.headphones_rendering_mode; - - ia_logd("codec conf id %" PRIu64 ", codec id 0x%x (%s), sampling rate is %u", - conf->codec_conf_id, conf->codec_id, - iamf_codec_name(stream->codec_id), stream->sampling_rate); - if (stream->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ChannelLayerContext *ctx = IAMF_MALLOCZ(ChannelLayerContext, 1); - SubLayerConf *sub_conf; - ChannelLayerConf *layer_conf; - ScalableChannelLayoutConf *layers_conf = elem->channels_conf; - float gain_db; - int chs = 0; - IAChannelLayoutType last = IA_CHANNEL_LAYOUT_INVALID; - ParameterBase *pb; - - if (!ctx) goto stream_fail; - - stream->priv = (void *)ctx; - ctx->nb_layers = layers_conf->nb_layers; - ctx->is_scaleable_stream = layers_conf->num_layers > 1; - if (ctx->nb_layers) { - sub_conf = IAMF_MALLOCZ(SubLayerConf, ctx->nb_layers); - if (!sub_conf) goto stream_fail; - - ctx->conf_s = sub_conf; - for (int i = 0; i < ctx->nb_layers; ++i) { - sub_conf = &ctx->conf_s[i]; - layer_conf = &layers_conf->layer_conf_s[i]; - sub_conf->layout = iamf_audio_layer_layout_get( - layer_conf->loudspeaker_layout, - layer_conf->expanded_loudspeaker_layout); - sub_conf->nb_substreams = layer_conf->nb_substreams; - sub_conf->nb_coupled_substreams = layer_conf->nb_coupled_substreams; - sub_conf->nb_channels = - sub_conf->nb_substreams + sub_conf->nb_coupled_substreams; - - ia_logi("audio layer %d :", i); - ia_logi(" > loudspeaker layout %s(%d) .", - iamf_audio_layer_get_layout_info(sub_conf->layout)->name, - sub_conf->layout); - ia_logi(" > sub-stream count %d .", sub_conf->nb_substreams); - ia_logi(" > coupled sub-stream count %d .", - sub_conf->nb_coupled_substreams); - - if (layer_conf->output_gain_flag) { - sub_conf->output_gain = IAMF_MALLOCZ(IAMF_OutputGain, 1); - if (!sub_conf->output_gain) { - ia_loge("Fail to allocate memory for output gain of sub config."); - goto stream_fail; - } - sub_conf->output_gain->flags = - layer_conf->output_gain_info->output_gain_flag; - gain_db = q_to_float(layer_conf->output_gain_info->output_gain, 8); - sub_conf->output_gain->gain = db2lin(gain_db); - ia_logi(" > output gain flags 0x%02x", - sub_conf->output_gain->flags & U8_MASK); - ia_logi(" > output gain %f (0x%04x), linear gain %f", gain_db, - layer_conf->output_gain_info->output_gain & U16_MASK, - sub_conf->output_gain->gain); - } else { - ia_logi(" > no output gain info."); - } - - if (layer_conf->recon_gain_flag) { - sub_conf->recon_gain = IAMF_MALLOCZ(IAMF_ReconGain, 1); - if (!sub_conf->recon_gain) { - ia_loge("Fail to allocate memory for recon gain of sub config."); - goto stream_fail; - } - ia_logi(" > wait recon gain info."); - } else { - ia_logi(" > no recon gain info."); - } - - chs += iamf_channel_layout_get_new_channels( - last, sub_conf->layout, &ctx->channels_order[chs], - IA_CH_LAYOUT_MAX_CHANNELS - chs); - - stream->nb_substreams += sub_conf->nb_substreams; - stream->nb_coupled_substreams += sub_conf->nb_coupled_substreams; - - ia_logi(" > the total of %d channels", chs); - last = sub_conf->layout; - } - } - stream->nb_channels = stream->nb_substreams + stream->nb_coupled_substreams; - - ia_logi("channels %d, streams %d, coupled streams %d.", stream->nb_channels, - stream->nb_substreams, stream->nb_coupled_substreams); - - ia_logi("all channels order:"); - for (int c = 0; c < stream->nb_channels; ++c) - ia_logi("channel %s(%d)", ia_channel_name(ctx->channels_order[c]), - ctx->channels_order[c]); - - ctx->layer = ctx->nb_layers - 1; - iamf_stream_set_output_layout(stream, layout); - ctx->layout = ctx->conf_s[ctx->layer].layout; - ctx->channels = iamf_audio_layer_get_layout_info(ctx->layout)->channels; - ctx->dmx_mode = ctx->dmx_default_w_idx = ctx->dmx_default_mode = - INVALID_VALUE; - for (int i = 0; i < elem->nb_parameters; ++i) { - pb = elem->parameters[i]; - if (pb && pb->type == IAMF_PARAMETER_TYPE_DEMIXING) { - DemixingParameter *dp = (DemixingParameter *)pb; - ctx->dmx_default_mode = dp->mode; - ctx->dmx_default_w_idx = dp->w; - break; - } - } - - ia_logi("initialized layer %d, layout %s (%d), layout channel count %d.", - ctx->layer, iamf_audio_layer_get_layout_info(ctx->layout)->name, - ctx->layout, ctx->channels); - } else if (stream->scheme == AUDIO_ELEMENT_TYPE_SCENE_BASED) { - AmbisonicsConf *aconf = elem->ambisonics_conf; - AmbisonicsContext *ctx; - stream->nb_channels = aconf->output_channel_count; - stream->nb_substreams = aconf->substream_count; - stream->nb_coupled_substreams = aconf->coupled_substream_count; - - ctx = IAMF_MALLOCZ(AmbisonicsContext, 1); - if (!ctx) { - goto stream_fail; - } - - stream->priv = (void *)ctx; - ctx->mode = iamf_stream_mode_ambisonics(aconf->ambisonics_mode); - ctx->mapping = aconf->mapping; - ctx->mapping_size = aconf->mapping_size; - - iamf_stream_set_output_layout(stream, layout); - ia_logi("stream mode %d", ctx->mode); - } - return stream; - -stream_fail: - - if (stream) iamf_stream_free(stream); - return 0; -} - -uint32_t iamf_stream_mode_ambisonics(uint32_t ambisonics_mode) { - if (ambisonics_mode == AMBISONICS_MODE_MONO) - return STREAM_MODE_AMBISONICS_MONO; - else if (ambisonics_mode == AMBISONICS_MODE_PROJECTION) - return STREAM_MODE_AMBISONICS_PROJECTION; - return STREAM_MODE_AMBISONICS_NONE; -} - -int iamf_stream_set_output_layout(IAMF_Stream *s, LayoutInfo *layout) { - s->final_layout = layout; - - if (s->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ChannelLayerContext *ctx = (ChannelLayerContext *)s->priv; - if (ctx) { - if (ctx->nb_layers == 1) return IAMF_OK; - - if (layout->layout.type == IAMF_LAYOUT_TYPE_BINAURAL && - s->headphones_rendering_mode) { - ctx->layer = ctx->nb_layers - 1; - ia_logd("use the highest layout downmix to binaural."); - return IAMF_OK; - } - - uint8_t out_sound_system = - layout->layout.type == IAMF_LAYOUT_TYPE_BINAURAL - ? SOUND_SYSTEM_A - : layout->layout.sound_system.sound_system; - // use the layout that matches the playback layout - for (int i = 0; i < ctx->nb_layers; ++i) { - const IAMF_LayoutInfo *info = - iamf_audio_layer_get_layout_info(ctx->conf_s[i].layout); - if ((info->flags & IAMF_LAYOUT_FLAG_OUT) && - info->sound_system == out_sound_system) { - ctx->layer = i; - ia_logi("scalabel channels layer is %d", i); - return IAMF_OK; - } - } - - // select next highest available layout - int playback_channels = IAMF_layout_sound_system_channels_count( - layout->layout.sound_system.sound_system); - for (int i = 0; i < ctx->nb_layers; ++i) { - int channels = - iamf_audio_layer_get_layout_info(ctx->conf_s[i].layout)->channels; - if (channels > playback_channels) { - ctx->layer = i; - ia_logi("scalabel channels layer is %d", i); - return IAMF_OK; - } - } - } - } - - return IAMF_OK; -} - -static int iamf_stream_set_max_frame_size(IAMF_DecoderHandle handle, - IAMF_Stream *stream) { - if (!handle || !stream) return IAMF_ERR_BAD_ARG; - if (stream->sampling_rate <= 0) return IAMF_ERR_INTERNAL; - IAMF_DecoderContext *ctx = &handle->ctx; - if (!ctx) return IAMF_ERR_INTERNAL; - IAMF_DataBase *db = &ctx->db; - IAMF_CodecConf *conf = - iamf_database_element_get_codec_conf(db, stream->element_id); - if (!conf) return IAMF_ERR_INTERNAL; - - stream->max_frame_size = conf->nb_samples_per_frame; - uint32_t round = ctx->sampling_rate / stream->sampling_rate; - stream->max_frame_size *= - ((ctx->sampling_rate % stream->sampling_rate) ? (round + 1) : round); - if (handle->limiter) stream->max_frame_size += handle->limiter->delaySize; - - return IAMF_OK; -} - -static int iamf_stream_enable(IAMF_DecoderHandle handle, IAMF_Element *elem) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_DataBase *db = &ctx->db; - IAMF_Presentation *pst = ctx->presentation; - uint64_t element_id; - IAMF_Stream *stream = 0; - IAMF_Stream **streams; - IAMF_CodecConf *conf; - IAMF_StreamDecoder *decoder = 0; - IAMF_StreamDecoder **decoders; - IAMF_StreamRenderer *renderer = 0; - IAMF_StreamRenderer **renderers; - int ret = IAMF_ERR_ALLOC_FAIL; - - ia_logd("enable element id %" PRIu64, elem->element_id); - element_id = elem->element_id; - conf = iamf_database_element_get_codec_conf(db, element_id); - ia_logd("codec conf id %" PRIu64, conf->codec_conf_id); - - stream = iamf_stream_new(pst, elem, conf, ctx->output_layout); - if (!stream) goto stream_enable_fail; - - if (iamf_stream_set_max_frame_size(handle, stream) < 0) - goto stream_enable_fail; - - decoder = iamf_stream_decoder_open(stream, conf); - if (!decoder) { - ret = IAMF_ERR_UNIMPLEMENTED; - goto stream_enable_fail; - } - - renderer = iamf_stream_renderer_open(stream, pst->obj, decoder->frame_size); - if (!renderer) { - ret = IAMF_ERR_ALLOC_FAIL; - goto stream_enable_fail; - } - - streams = IAMF_REALLOC(IAMF_Stream *, pst->streams, pst->nb_streams + 1); - if (!streams) goto stream_enable_fail; - pst->streams = streams; - - decoders = - IAMF_REALLOC(IAMF_StreamDecoder *, pst->decoders, pst->nb_streams + 1); - if (!decoders) goto stream_enable_fail; - pst->decoders = decoders; - - renderers = - IAMF_REALLOC(IAMF_StreamRenderer *, pst->renderers, pst->nb_streams + 1); - if (!renderers) goto stream_enable_fail; - pst->renderers = renderers; - - pst->streams[pst->nb_streams] = stream; - pst->decoders[pst->nb_streams] = decoder; - pst->renderers[pst->nb_streams] = renderer; - ++pst->nb_streams; - - return IAMF_OK; - -stream_enable_fail: - if (renderer) iamf_stream_renderer_close(renderer); - - if (decoder) iamf_stream_decoder_close(decoder); - - if (stream) iamf_stream_free(stream); - - return ret; -} - -IAMF_Resampler *iamf_stream_resampler_open(IAMF_Stream *stream, - uint32_t out_rate, int quality) { - IAMF_Resampler *resampler = IAMF_MALLOCZ(IAMF_Resampler, 1); - if (!resampler) goto open_fail; - int err = 0; - uint32_t channels = stream->final_layout->channels; - SpeexResamplerState *speex_resampler = speex_resampler_init( - channels, stream->sampling_rate, out_rate, quality, &err); - ia_logi("in sample rate %u, out sample rate %u", stream->sampling_rate, - out_rate); - resampler->speex_resampler = speex_resampler; - if (err != RESAMPLER_ERR_SUCCESS) goto open_fail; - speex_resampler_skip_zeros(speex_resampler); - resampler->buffer = IAMF_MALLOCZ(float, stream->max_frame_size *channels); - if (!resampler->buffer) goto open_fail; - return resampler; -open_fail: - if (resampler) iamf_stream_resampler_close(resampler); - return 0; -} - -void iamf_stream_resampler_close(IAMF_Resampler *r) { - if (r) { - if (r->buffer) free(r->buffer); - speex_resampler_destroy(r->speex_resampler); - IAMF_FREE(r); - } -} - -static IAMF_CoreDecoder *iamf_stream_sub_decoder_open( - int mode, int channels, int nb_streams, int nb_coupled_streams, - uint8_t *mapping, int mapping_size, IAMF_CodecConf *conf) { - IAMF_CodecID cid; - IAMF_CoreDecoder *cDecoder; - int ret = 0; - - cid = iamf_codec_4cc_get_codecID(conf->codec_id); - cDecoder = iamf_core_decoder_open(cid); - - if (cDecoder) { - iamf_core_decoder_set_codec_conf(cDecoder, conf->decoder_conf, - conf->decoder_conf_size); - ia_logd( - "codec %s, mode %d, channels %d, streams %d, coupled streams %d, " - "mapping size %d", - iamf_codec_name(cid), mode, channels, nb_streams, nb_coupled_streams, - mapping_size); - iamf_core_decoder_set_streams_info(cDecoder, mode, channels, nb_streams, - nb_coupled_streams, mapping, - mapping_size); - ret = iamf_core_decoder_init(cDecoder); - if (ret != IAMF_OK) { - ia_loge("Fail to initalize core decoder."); - iamf_core_decoder_close(cDecoder); - cDecoder = 0; - } - } - - return cDecoder; -} - -static int iamf_stream_decoder_decode_finish(IAMF_StreamDecoder *decoder); - -void iamf_stream_decoder_close(IAMF_StreamDecoder *d) { - if (d) { - IAMF_Stream *s = d->stream; - - if (d->packet.sub_packets) { - for (int i = 0; i < d->packet.nb_sub_packets; ++i) - IAMF_FREE(d->packet.sub_packets[i]); - } - IAMF_FREE(d->packet.sub_packets); - IAMF_FREE(d->packet.sub_packet_sizes); - - for (int i = 0; i < DEC_BUF_CNT; ++i) { - IAMF_FREE(d->buffers[i]); - } - - if (s->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - if (d->scale) { - if (d->scale->sub_decoders) { - for (int i = 0; i < d->scale->nb_layers; ++i) - iamf_core_decoder_close(d->scale->sub_decoders[i]); - free(d->scale->sub_decoders); - } - if (d->scale->demixer) demixer_close(d->scale->demixer); - free(d->scale); - } - } else if (s->scheme == AUDIO_ELEMENT_TYPE_SCENE_BASED) { - if (d->ambisonics) { - if (d->ambisonics->decoder) - iamf_core_decoder_close(d->ambisonics->decoder); - free(d->ambisonics); - } - } - free(d); - } -} - -static uint32_t iamf_set_stream_info(IAMF_DecoderHandle handle) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_Presentation *pst = ctx->presentation; - IAMF_StreamDecoder *decoder = 0; - IAMF_Stream *stream = 0; - uint32_t cur = 0; - for (int i = 0; i < pst->nb_streams; i++) { - cur = pst->streams[i]->max_frame_size; - if (cur > ctx->info.max_frame_size) ctx->info.max_frame_size = cur; - } - for (int i = 0; i < pst->nb_streams; i++) { - decoder = pst->decoders[i]; - stream = pst->streams[i]; - if (ctx->info.max_frame_size > stream->max_frame_size) { - for (int n = 0; n < DEC_BUF_CNT; ++n) { - float *buffer = - IAMF_REALLOC(float, decoder->buffers[n], - ctx->info.max_frame_size * stream->nb_channels); - if (!buffer) goto fail; - decoder->buffers[n] = buffer; - } - } - } - return 0; -fail: - if (decoder) iamf_stream_decoder_close(decoder); - return 0; -} - -IAMF_StreamDecoder *iamf_stream_decoder_open(IAMF_Stream *stream, - IAMF_CodecConf *conf) { - IAMF_StreamDecoder *decoder; - int channels = 0; - - decoder = IAMF_MALLOCZ(IAMF_StreamDecoder, 1); - - if (!decoder) goto open_fail; - - decoder->stream = stream; - decoder->frame_size = conf->nb_samples_per_frame; - decoder->delay = -1; - decoder->packet.nb_sub_packets = stream->nb_substreams; - decoder->packet.sub_packets = IAMF_MALLOCZ(uint8_t *, stream->nb_substreams); - decoder->packet.sub_packet_sizes = - IAMF_MALLOCZ(uint32_t, stream->nb_substreams); - - if (!decoder->packet.sub_packets || !decoder->packet.sub_packet_sizes) - goto open_fail; - - channels = stream->final_layout->channels; - decoder->frame.id = stream->element_id; - decoder->frame.channels = stream->nb_channels; - - if (stream->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ScalableChannelDecoder *scale = IAMF_MALLOCZ(ScalableChannelDecoder, 1); - ChannelLayerContext *ctx = (ChannelLayerContext *)stream->priv; - IAMF_CoreDecoder **sub_decoders; - IAMF_CoreDecoder *sub; - - if (!scale) goto open_fail; - - decoder->scale = scale; - scale->nb_layers = ctx->layer + 1; - sub_decoders = IAMF_MALLOCZ(IAMF_CoreDecoder *, scale->nb_layers); - if (!sub_decoders) goto open_fail; - scale->sub_decoders = sub_decoders; - ia_logi("open sub decdoers for channel-based."); - for (int i = 0; i < scale->nb_layers; ++i) { - sub = iamf_stream_sub_decoder_open( - STREAM_MODE_AMBISONICS_NONE, ctx->conf_s[i].nb_channels, - ctx->conf_s[i].nb_substreams, ctx->conf_s[i].nb_coupled_substreams, 0, - 0, conf); - if (!sub) goto open_fail; - sub_decoders[i] = sub; - } - - if (ctx->channels != decoder->frame.channels) { - ia_logd("frame channels changes from %u to %u", decoder->frame.channels, - ctx->channels); - decoder->frame.channels = ctx->channels; - } - - if (channels < ctx->channels) { - ia_logd("final target channels vs stream original channels (%d vs %d).", - channels, ctx->channels); - channels = ctx->channels; - } - - if (ctx->is_scaleable_stream) { - scale->demixer = demixer_open(conf->nb_samples_per_frame); - if (!scale->demixer) goto open_fail; - iamf_stream_scale_demixer_configure(decoder); - } - - } else if (stream->scheme == AUDIO_ELEMENT_TYPE_SCENE_BASED) { - AmbisonicsDecoder *a = IAMF_MALLOCZ(AmbisonicsDecoder, 1); - AmbisonicsContext *ctx = (AmbisonicsContext *)stream->priv; - if (!a) goto open_fail; - decoder->ambisonics = a; - - ia_logd("open sub decdoers for ambisonics."); - a->decoder = iamf_stream_sub_decoder_open( - ctx->mode, stream->nb_channels, stream->nb_substreams, - stream->nb_coupled_substreams, ctx->mapping, ctx->mapping_size, conf); - - if (!a->decoder) goto open_fail; - } - - if (channels < stream->nb_channels) { - ia_logd("final target channels vs stream channels (%d vs %d).", channels, - stream->nb_channels); - channels = stream->nb_channels; - } - - for (int i = 0; i < DEC_BUF_CNT; ++i) { - decoder->buffers[i] = IAMF_MALLOCZ(float, stream->max_frame_size *channels); - if (!decoder->buffers[i]) goto open_fail; - } - - return decoder; - -open_fail: - if (decoder) iamf_stream_decoder_close(decoder); - return 0; -} - -static int iamf_stream_decoder_receive_packet(IAMF_StreamDecoder *decoder, - int substream_index, - IAMF_Frame *packet) { - if (substream_index > INVALID_VALUE && - substream_index < decoder->packet.nb_sub_packets) { - if (!decoder->packet.sub_packets[substream_index]) { - ++decoder->packet.count; - } - IAMF_FREE(decoder->packet.sub_packets[substream_index]); - decoder->packet.sub_packets[substream_index] = - IAMF_MALLOC(uint8_t, packet->size); - if (!decoder->packet.sub_packets[substream_index]) - return IAMF_ERR_ALLOC_FAIL; - memcpy(decoder->packet.sub_packets[substream_index], packet->data, - packet->size); - decoder->packet.sub_packet_sizes[substream_index] = packet->size; - } - - if (!substream_index) { - decoder->frame.strim = packet->trim_start; - decoder->frame.etrim = packet->trim_end; - } - - return 0; -} - -static int iamf_stream_decoder_update_parameter(IAMF_StreamDecoder *dec, - IAMF_DataBase *db, - uint64_t pid) { - ParameterItem *pi = iamf_database_parameter_get_item(db, pid); - IAMF_Stream *s = dec->stream; - - if (pi) { - if (pi->type == IAMF_PARAMETER_TYPE_DEMIXING) { - ChannelLayerContext *ctx = (ChannelLayerContext *)s->priv; - ctx->dmx_mode = iamf_database_parameter_get_demix_mode( - db, pid, - time_transform(s->timestamp + dec->frame_size / 2, s->sampling_rate, - pi->rate)); - ia_logd("update demix mode %d", ctx->dmx_mode); - } else if (pi->type == IAMF_PARAMETER_TYPE_RECON_GAIN) { - ReconGainList *recon = iamf_database_parameter_get_recon_gain_list( - db, pid, - time_transform(s->timestamp + dec->frame_size / 2, s->sampling_rate, - pi->rate)); - ia_logd("update recon %p", recon); - if (recon) iamf_stream_scale_decoder_update_recon_gain(dec, recon); - } - } - return IAMF_OK; -} - -static int iamf_stream_decoder_update_delay(IAMF_StreamDecoder *dec) { - IAMF_CoreDecoder *cder = 0; - int delay = 0; - if (dec->stream->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - if (dec->scale->sub_decoders) cder = dec->scale->sub_decoders[0]; - } else - cder = dec->ambisonics->decoder; - - if (cder) delay = dec->delay = iamf_core_decoder_get_delay(cder); - - return delay; -} - -static int iamf_stream_decoder_decode(IAMF_StreamDecoder *decoder, float *pcm, - int run) { - int ret = 0; - IAMF_Stream *stream = decoder->stream; - float *buffer = decoder->buffers[2]; - if (stream->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ret = iamf_stream_scale_decoder_decode(decoder, buffer); - } else if (stream->scheme == AUDIO_ELEMENT_TYPE_SCENE_BASED) - ret = iamf_stream_ambisonics_decoder_decode(decoder, pcm); - - if (stream->trimming_start != decoder->frame_size && decoder->delay < 0) { - iamf_stream_decoder_update_delay(decoder); - if (!run) stream->trimming_start += decoder->delay; - ia_logi("decoder delay is %d, trimming start is %" PRIu64, decoder->delay, - stream->trimming_start); - - if (stream->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ScalableChannelDecoder *scale = decoder->scale; - if (scale->demixer) - demixer_set_frame_offset(decoder->scale->demixer, decoder->delay); - } - } - -#if SR - // decoding - // iamf_rec_stream_log(stream->element_id, stream->nb_channels, buffer, ret); -#endif - - if (stream->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ScalableChannelDecoder *scale = decoder->scale; - ChannelLayerContext *ctx = (ChannelLayerContext *)stream->priv; - if (scale->demixer) - iamf_stream_scale_decoder_demix(decoder, buffer, pcm, ret); - else - iamf_audio_layer_layout_transform_in_plane(ctx->layout, buffer, pcm, ret); - } - - return ret; -} - -int iamf_stream_decoder_decode_finish(IAMF_StreamDecoder *decoder) { - for (int i = 0; i < decoder->packet.nb_sub_packets; ++i) { - IAMF_FREEP(&decoder->packet.sub_packets[i]); - } - memset(decoder->packet.sub_packet_sizes, 0, - sizeof(uint32_t) * decoder->packet.nb_sub_packets); - decoder->packet.count = 0; - return 0; -} - -int iamf_stream_scale_decoder_set_default_recon_gain( - IAMF_StreamDecoder *decoder) { - IAMF_Stream *stream = decoder->stream; - Demixer *demixer; - ChannelLayerContext *ctx; - IAMF_ReconGain rg; - - if (stream->scheme != AUDIO_ELEMENT_TYPE_CHANNEL_BASED || !decoder->scale) - return IAMF_ERR_INTERNAL; - - demixer = decoder->scale->demixer; - ctx = (ChannelLayerContext *)stream->priv; - - if (!demixer || !ctx) return IAMF_ERR_INTERNAL; - - memset(&rg, 0, sizeof(IAMF_ReconGain)); - if (ctx->layer > 0) { - uint8_t layout = ctx->conf_s[0].layout; - rg.flags = iamf_recon_channels_get_flags(layout, ctx->layout); - ia_logd("first layer %d, target layout %d", layout, ctx->layout); - ia_logd("default recon gain flags 0x%04x", rg.flags); - rg.nb_channels = bit1_count(rg.flags); - ia_logd("default channel count %d", rg.nb_channels); - iamf_recon_channels_order_update(ctx->layout, &rg); - for (int i = 0; i < rg.nb_channels; ++i) { - rg.recon_gain[i] = 1.f; - ia_logd("channel %s(%d) : default recon gain is 1.", - ia_channel_name(rg.order[i]), rg.order[i]); - } - } - demixer_set_recon_gain(demixer, rg.nb_channels, rg.order, rg.recon_gain, - rg.flags); - - return IAMF_OK; -} - -static int iamf_stream_scale_decoder_update_recon_gain( - IAMF_StreamDecoder *decoder, ReconGainList *list) { - ReconGain *src; - IAMF_ReconGain *dst; - int ret = 0; - IAMF_Stream *stream = decoder->stream; - ChannelLayerContext *ctx = (ChannelLayerContext *)stream->priv; - - if (!list) return IAMF_ERR_BAD_ARG; - - ia_logt("recon gain info : list %p, count %d, recons %p", list, list->count, - list->recon); - for (int i = 0; i < ctx->nb_layers; ++i) { - src = &list->recon[i]; - dst = ctx->conf_s[i].recon_gain; - if (dst) { - ia_logd("audio layer %d :", i); - if (dst->flags ^ src->flags) { - dst->flags = src->flags; - dst->nb_channels = bit1_count(src->flags); - iamf_recon_channels_order_update(ctx->conf_s[i].layout, dst); - } - for (int c = 0; c < dst->nb_channels; ++c) { - dst->recon_gain[c] = src->recon_gain_f[c]; - } - ia_logd(" > recon gain flags 0x%04x", dst->flags); - ia_logd(" > channel count %d", dst->nb_channels); - for (int c = 0; c < dst->nb_channels; ++c) - ia_logd(" > > channel %s(%d) : recon gain %f(0x%02x)", - ia_channel_name(dst->order[c]), dst->order[c], - dst->recon_gain[c], src->recon_gain[c]); - } - } - ia_logt("recon gain info ."); - - return ret; -} - -static int iamf_stream_scale_decoder_decode(IAMF_StreamDecoder *decoder, - float *pcm) { - IAMF_Stream *stream = decoder->stream; - ChannelLayerContext *ctx = (ChannelLayerContext *)stream->priv; - ScalableChannelDecoder *scale = decoder->scale; - int ret = IAMF_OK; - float *out = pcm; - IAMF_CoreDecoder *dec; - uint32_t substream_offset = 0; - - if (!scale->nb_layers) return ret; - - decoder->frame_padding = 0; - - for (int i = 0; i <= ctx->layer; ++i) { - dec = scale->sub_decoders[i]; - ia_logd( - "CG#%d: channels %d, streams %d, decoder %p, out %p, offset %lX, " - "size %lu", - i, ctx->conf_s[i].nb_channels, ctx->conf_s[i].nb_substreams, dec, out, - (float *)out - (float *)pcm, - sizeof(float) * decoder->frame_size * ctx->conf_s[i].nb_channels); - for (int k = 0; k < ctx->conf_s[i].nb_substreams; ++k) { - ia_logd(" > sub-packet %d (%p) size %d", k, - decoder->packet.sub_packets[substream_offset + k], - decoder->packet.sub_packet_sizes[substream_offset + k]); - } - ret = iamf_core_decoder_decode( - dec, &decoder->packet.sub_packets[substream_offset], - &decoder->packet.sub_packet_sizes[substream_offset], - ctx->conf_s[i].nb_substreams, out, decoder->frame_size); - if (ret < 0) { - ia_loge("sub packet %d decode fail.", i); - break; - } - out += (decoder->frame_size * ctx->conf_s[i].nb_channels); - substream_offset += ctx->conf_s[i].nb_substreams; - } - - if (ret > 0 && ret != decoder->frame_size) { - ia_logw("decoded frame size is not %d (%d).", decoder->frame_size, ret); - decoder->frame_padding = decoder->frame_size - ret; - ret = decoder->frame_size; - } - - return ret; -} - -static int32_t iamf_stream_scale_decoder_demix(IAMF_StreamDecoder *decoder, - float *src, float *dst, - uint32_t frame_size) { - IAMF_Stream *stream = decoder->stream; - ScalableChannelDecoder *scale = decoder->scale; - ChannelLayerContext *ctx = (ChannelLayerContext *)stream->priv; - - Demixer *demixer = scale->demixer; - IAMF_ReconGain *re = ctx->conf_s[ctx->layer].recon_gain; - - ia_logt("demixer info update :"); - if (re) { - demixer_set_recon_gain(demixer, re->nb_channels, re->order, re->recon_gain, - re->flags); - ia_logd("channel flags 0x%04x", re->flags & U16_MASK); - for (int c = 0; c < re->nb_channels; ++c) { - ia_logd("channel %s(%d) recon gain %f", ia_channel_name(re->order[c]), - re->order[c], re->recon_gain[c]); - } - } - - if (ctx->dmx_mode > INVALID_VALUE) - demixer_set_demixing_info(scale->demixer, ctx->dmx_mode, -1); - - return demixer_demixing(scale->demixer, dst, src, frame_size); -} - -int iamf_stream_scale_demixer_configure(IAMF_StreamDecoder *decoder) { - IAMF_Stream *stream = decoder->stream; - ScalableChannelDecoder *scale = decoder->scale; - Demixer *demixer = scale->demixer; - IAChannel chs[IA_CH_LAYOUT_MAX_CHANNELS]; - float gains[IA_CH_LAYOUT_MAX_CHANNELS]; - uint8_t flags; - uint32_t count = 0; - SubLayerConf *layer_conf; - ChannelLayerContext *ctx = (ChannelLayerContext *)stream->priv; - - demixer_set_channel_layout(demixer, ctx->layout); - demixer_set_channels_order(demixer, ctx->channels_order, ctx->channels); - - for (int l = 0; l <= ctx->layer; ++l) { - layer_conf = &ctx->conf_s[l]; - if (layer_conf->output_gain) { - flags = layer_conf->output_gain->flags; - for (int c = 0; c < IA_CH_GAIN_COUNT; ++c) { - if (flags & RSHIFT(c)) { - chs[count] = iamf_output_gain_channel_map(layer_conf->layout, c); - if (chs[count] != IA_CH_INVALID) { - gains[count++] = layer_conf->output_gain->gain; - } - } - } - } - } - - demixer_set_output_gain(demixer, chs, gains, count); - demixer_set_demixing_info(demixer, ctx->dmx_default_mode, - ctx->dmx_default_w_idx); - iamf_stream_scale_decoder_set_default_recon_gain(decoder); - - ia_logd("demixer info :"); - ia_logd("layout %s(%d)", iamf_audio_layer_get_layout_info(ctx->layout)->name, - ctx->layout); - ia_logd("input channels order :"); - - for (int c = 0; c < ctx->channels; ++c) { - ia_logd("channel %s(%d)", ia_channel_name(ctx->channels_order[c]), - ctx->channels_order[c]); - } - - ia_logd("output gain info : "); - for (int c = 0; c < count; ++c) { - ia_logd("channel %s(%d) gain %f", ia_channel_name(chs[c]), chs[c], - gains[c]); - } - - return 0; -} - -uint32_t iamf_stream_ambisionisc_order(int channels) { - if (channels == 1) - return IAMF_ZOA; - else if (channels == 4) - return IAMF_FOA; - else if (channels == 9) - return IAMF_SOA; - else if (channels == 16) - return IAMF_TOA; - else if (channels == 25) - return IAMF_H4A; - return UINT32_MAX; -} - -int iamf_stream_ambisonics_decoder_decode(IAMF_StreamDecoder *decoder, - float *pcm) { - AmbisonicsDecoder *amb = decoder->ambisonics; - int ret = 0; - IAMF_CoreDecoder *dec; - - dec = amb->decoder; - for (int k = 0; k < decoder->packet.nb_sub_packets; ++k) { - ia_logd(" > sub-packet %d (%p) size %d", k, decoder->packet.sub_packets[k], - decoder->packet.sub_packet_sizes[k]); - } - ret = iamf_core_decoder_decode( - dec, decoder->packet.sub_packets, decoder->packet.sub_packet_sizes, - decoder->packet.nb_sub_packets, pcm, decoder->frame_size); - if (ret < 0) { - ia_loge("ambisonics stream packet decode fail."); - } else if (ret != decoder->frame_size) { - ia_loge("decoded frame size is not %d (%d).", decoder->frame_size, ret); - } - - return ret; -} - -int iamf_stream_renderer_enable_downmix(IAMF_StreamRenderer *sr) { - IAMF_Stream *s; - ChannelLayerContext *ctx; - int in; - const IAMF_LayoutInfo *info; - - s = sr->stream; - if (s->scheme == AUDIO_ELEMENT_TYPE_SCENE_BASED || !s->final_layout || - (s->final_layout->layout.type != - IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION && - (s->final_layout->layout.type != IAMF_LAYOUT_TYPE_BINAURAL || - s->headphones_rendering_mode))) - return IAMF_ERR_BAD_ARG; - - ctx = (ChannelLayerContext *)s->priv; - if (ctx->dmx_default_mode == INVALID_VALUE) return IAMF_ERR_BAD_ARG; - - in = ctx->conf_s[ctx->layer].layout; - if (!iamf_audio_layer_base_layout_check(in) || - in == IA_CHANNEL_LAYOUT_BINAURAL) - return IAMF_ERR_BAD_ARG; - - if (s->final_layout->layout.type == IAMF_LAYOUT_TYPE_BINAURAL) { - info = iamf_sound_system_get_layout_info(SOUND_SYSTEM_A); - ia_logi("In DmxRenderer, using Sound System A for binaural."); - } else - info = iamf_sound_system_get_layout_info( - s->final_layout->layout.sound_system.sound_system); - - if (info->type == IA_CHANNEL_LAYOUT_INVALID) return IAMF_ERR_BAD_ARG; - - if (sr->downmixer) DMRenderer_close(sr->downmixer); - sr->downmixer = DMRenderer_open(in, info->type); - if (!sr->downmixer) return IAMF_ERR_BAD_ARG; - - DMRenderer_set_mode_weight(sr->downmixer, ctx->dmx_default_mode, - ctx->dmx_default_w_idx); - - return IAMF_OK; -} - -IAMF_StreamRenderer *iamf_stream_renderer_open(IAMF_Stream *s, - IAMF_MixPresentation *mp, - int frame_size) { - IAMF_StreamRenderer *sr = IAMF_MALLOCZ(IAMF_StreamRenderer, 1); - ElementConf *ec = iamf_mix_presentation_get_element_conf(mp, s->element_id); - IAMF_SP_LAYOUT stereo_sp; - IAMF_PREDEFINED_SP_LAYOUT stereo_pout; - IAMF_SP_LAYOUT *out_sp = &s->final_layout->sp; - - if (!sr) return 0; - - sr->stream = s; - if (ec) sr->headphones_rendering_mode = ec->conf_r.headphones_rendering_mode; - sr->frame_size = frame_size; - - sr->renderer.layout = &s->final_layout->sp; - - memset(&stereo_sp, 0, sizeof(IAMF_SP_LAYOUT)); - - if (s->final_layout->layout.type == IAMF_LAYOUT_TYPE_BINAURAL && - !s->headphones_rendering_mode) { - const IAMF_LayoutInfo *stereo_info = - iamf_sound_system_get_layout_info(SOUND_SYSTEM_A); - - memset(&stereo_pout, 0, sizeof(IAMF_PREDEFINED_SP_LAYOUT)); - stereo_sp.sp_layout.predefined_sp = &stereo_pout; - stereo_pout.system = stereo_info->rendering_id_out; - stereo_pout.lfe1 = stereo_info->lfe1; - stereo_pout.lfe2 = stereo_info->lfe2; - out_sp = &stereo_sp; - } - - if (s->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ChannelLayerContext *ctx = (ChannelLayerContext *)s->priv; - const IAMF_LayoutInfo *info = iamf_audio_layer_get_layout_info(ctx->layout); - -#if ENABLE_MULTICHANNEL_TO_BINAURAL - if (s->final_layout->layout.type == IAMF_LAYOUT_TYPE_BINAURAL && - sr->headphones_rendering_mode == 1) { - IAMF_element_renderer_init_M2B( - &sr->renderer.layout->binaural_f, - info->reference_id != IAMF_LAYOUT_ID_NONE - ? iamf_get_layout_info(info->reference_id)->rendering_id_in - : info->rendering_id_in, - info->sp_labels, s->element_id, frame_size, s->sampling_rate); - } else -#endif - if (iamf_stream_renderer_enable_downmix(sr) != IAMF_OK) { - IAMF_SP_LAYOUT sp; - - memset(&sp, 0, sizeof(IAMF_SP_LAYOUT)); - - if (info->rendering_id_in) { - IAMF_PREDEFINED_SP_LAYOUT pin; - - memset(&pin, 0, sizeof(IAMF_PREDEFINED_SP_LAYOUT)); - sp.sp_layout.predefined_sp = &pin; - pin.system = info->rendering_id_in; - pin.lfe1 = info->lfe1; - pin.lfe2 = info->lfe2; - IAMF_element_renderer_get_M2M_matrix(&sp, out_sp, &sr->renderer.mmm); - } else { - IAMF_CUSTOM_SP_LAYOUT cin; - - memset(&cin, 0, sizeof(IAMF_CUSTOM_SP_LAYOUT)); - sp.sp_layout.custom_sp = &cin; - cin.system = iamf_get_layout_info(info->reference_id)->rendering_id_in; - cin.sp_flags = info->sp_labels; - sp.sp_type = 1; - IAMF_element_renderer_get_M2M_custom_matrix( - &sp, out_sp, &sr->renderer.mmm, sr->renderer.in_channel_map); - } - } - } else if (s->scheme == AUDIO_ELEMENT_TYPE_SCENE_BASED) { -#if ENABLE_HOA_TO_BINAURAL - if (s->final_layout->layout.type == IAMF_LAYOUT_TYPE_BINAURAL && - sr->headphones_rendering_mode == 1) { - IAMF_element_renderer_init_H2B(&sr->renderer.layout->binaural_f, - s->nb_channels, s->element_id, frame_size, - s->sampling_rate); - } else { -#endif - IAMF_HOA_LAYOUT hin; - hin.order = iamf_stream_ambisionisc_order(s->nb_channels); -#if DISABLE_LFE_HOA == 1 - hin.lfe_on = 0; - IAMF_element_renderer_get_H2M_matrix( - &hin, out_sp->sp_layout.predefined_sp, &sr->renderer.hmm); -#else - const IAMF_LayoutInfo *ss_info; - if (s->final_layout->layout.type == - IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) - ss_info = iamf_sound_system_get_layout_info( - s->final_layout->layout.sound_system.sound_system); - else - ss_info = NULL; - - hin.lfe_on = 1; - IAMF_element_renderer_get_H2M_matrix(&hin, out_sp->sp_layout.predefined_sp, - &sr->renderer.hmm); - - if (hin.lfe_on && ss_info && ss_info->lfe1) { - lfe_filter_t *plfe = &s->final_layout->sp.lfe_f; - if (plfe->init == 0) lfefilter_init(plfe, 120, s->sampling_rate); - } -#endif -#if ENABLE_HOA_TO_BINAURAL - } -#endif - } - - return sr; -} - -void iamf_stream_renderer_close(IAMF_StreamRenderer *sr) { - if (!sr) return; - - if (sr->downmixer) DMRenderer_close(sr->downmixer); - -#if ENABLE_HOA_TO_BINAURAL || ENABLE_MULTICHANNEL_TO_BINAURAL - IAMF_Stream *s = sr->stream; - if (s->final_layout && - s->final_layout->layout.type == IAMF_LAYOUT_TYPE_BINAURAL) { - if (s->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { -#if ENABLE_MULTICHANNEL_TO_BINAURAL - IAMF_element_renderer_deinit_M2B(&sr->renderer.layout->binaural_f, - s->element_id); - ia_logd("deinit M2B"); -#endif - } else if (s->scheme == AUDIO_ELEMENT_TYPE_SCENE_BASED) { -#if ENABLE_HOA_TO_BINAURAL - IAMF_element_renderer_deinit_H2B(&sr->renderer.layout->binaural_f, - s->element_id); - ia_logd("deinit H2B"); -#endif - } - } -#endif - - free(sr); -} - -/** - * @brief Rendering an Audio Element. - * @param [in] arch : architecture-specific callbacks. - * @param [in] sr : stream render handle. - * @param [in] in : input audio pcm - * @param [in] out : output audio pcm - * @param [in] frame_size : the size of audio frame. - * @return the number of rendering samples - */ -static int iamf_stream_render(const Arch *arch, IAMF_StreamRenderer *sr, - float *in, float *out, int frame_size) { - IAMF_Stream *stream = sr->stream; - int inchs; - int outchs = stream->final_layout->channels; - float *sout[IA_CH_LAYOUT_MAX_CHANNELS] = {0}; - float *sin[IA_CH_LAYOUT_MAX_CHANNELS] = {0}; - - for (int i = 0; i < outchs; ++i) sout[i] = &out[frame_size * i]; - - inchs = stream->nb_channels; - if (stream->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ChannelLayerContext *ctx = (ChannelLayerContext *)stream->priv; - inchs = iamf_audio_layer_get_layout_info(ctx->layout)->channels; - } - for (int i = 0; i < inchs; ++i) sin[i] = &in[frame_size * i]; - - if (stream->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { - ChannelLayerContext *ctx = (ChannelLayerContext *)stream->priv; -#if ENABLE_MULTICHANNEL_TO_BINAURAL - if (stream->final_layout->layout.type == IAMF_LAYOUT_TYPE_BINAURAL && - sr->headphones_rendering_mode == 1) { - IAMF_element_renderer_render_M2B(&sr->renderer.layout->binaural_f, - stream->element_id, sin, sout, - frame_size); - - } else -#endif - if (sr->downmixer) { - ia_logd("rendering: offset %u", sr->offset); - if (sr->offset) - DMRenderer_downmix(sr->downmixer, in, out, 0, sr->offset, frame_size); - if (ctx->dmx_mode > INVALID_VALUE) - DMRenderer_set_mode_weight(sr->downmixer, ctx->dmx_mode, INVALID_VALUE); - if (frame_size > sr->offset) - DMRenderer_downmix(sr->downmixer, in, out, sr->offset, - frame_size - sr->offset, frame_size); - } else { - if (iamf_audio_layer_get_layout_info(ctx->layout)->rendering_id_in) { - IAMF_element_renderer_render_M2M(arch, &sr->renderer.mmm, sin, sout, - frame_size); - } else { - IAMF_element_renderer_render_M2M_custom(arch, &sr->renderer.mmm, sin, - sout, frame_size, - sr->renderer.in_channel_map); - } - } - } else if (stream->scheme == AUDIO_ELEMENT_TYPE_SCENE_BASED) { -#if ENABLE_HOA_TO_BINAURAL - if (stream->final_layout->layout.type == IAMF_LAYOUT_TYPE_BINAURAL && - sr->headphones_rendering_mode == 1) { - IAMF_element_renderer_render_H2B(&sr->renderer.layout->binaural_f, - stream->element_id, sin, sout, - frame_size); - } else { -#endif - IAMF_element_renderer_render_H2M(arch, &sr->renderer.hmm, sin, sout, - frame_size, &sr->renderer.layout->lfe_f); -#if ENABLE_HOA_TO_BINAURAL - } -#endif - } - - return IAMF_OK; -} - -static void iamf_mixer_clear(IAMF_Mixer *m) { - memset(m->frames, 0, m->nb_elements); -} - -void iamf_mixer_reset(IAMF_Mixer *m) { - IAMF_FREE(m->element_ids); - IAMF_FREE(m->frames); - memset(m, 0, sizeof(IAMF_Mixer)); -} - -static int iamf_mixer_init(IAMF_DecoderHandle handle) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_Presentation *pst = ctx->presentation; - IAMF_CodecConf *cc = 0; - IAMF_Mixer *mixer = &pst->mixer; - int cnt = pst->nb_streams; - - if (!cnt) { - return IAMF_ERR_INTERNAL; - } - - iamf_mixer_reset(mixer); - mixer->nb_elements = cnt; - mixer->element_ids = IAMF_MALLOCZ(uint64_t, cnt); - mixer->frames = IAMF_MALLOCZ(Frame *, cnt); - if (!mixer->element_ids || !mixer->frames) { - iamf_mixer_reset(mixer); - return IAMF_ERR_ALLOC_FAIL; - } - for (int i = 0; i < cnt; ++i) { - mixer->element_ids[i] = pst->streams[i]->element_id; - } - - cc = iamf_database_element_get_codec_conf(&ctx->db, - pst->streams[0]->element_id); - if (!cc) { - iamf_mixer_reset(mixer); - return IAMF_ERR_INTERNAL; - } - - return 0; -} - -static int iamf_mixer_add_frame(IAMF_Mixer *mixer, Frame *f) { - for (int i = 0; i < mixer->nb_elements; ++i) { - if (mixer->element_ids[i] == f->id) { - mixer->frames[i] = f; - break; - } - } - return IAMF_OK; -} - -/** - * @brief Mix audio frame from different audio element. - * @param [in] mixer : the mixer handle - * @param [in] f : the input audio frame. - * @return the number of samples after mix - */ -static int iamf_mixer_mix(IAMF_Mixer *mixer, Frame *f) { - int s = mixer->frames[0]->samples; - int64_t pts = mixer->frames[0]->pts; - int chs = mixer->frames[0]->channels; - int soff; - - for (int i = 1; i < mixer->nb_elements; ++i) { - if (s != mixer->frames[i]->samples || pts != mixer->frames[i]->pts) { - ia_loge("Frame ( 0, %d) has different samples (%d, %d) or pts (%" PRId64 - ", %" PRId64 ")", - i, s, mixer->frames[i]->samples, pts, mixer->frames[i]->pts); - return 0; - } - } - - f->pts = pts; - f->samples = s; - f->strim = mixer->frames[0]->strim; - ia_logd("mixed frame pts %" PRId64 ", samples %d", f->pts, s); - memset(f->data, 0, sizeof(float) * s * chs); - - for (int e = 0; e < mixer->nb_elements; ++e) { - for (int c = 0; c < chs; ++c) { - soff = c * f->samples; - for (int i = 0; i < f->samples; ++i) { - f->data[soff + i] += mixer->frames[e]->data[soff + i]; - } - } - } - - return s; -} - -/* >>>>>>>>>>>>>>>>>> STREAM DECODER MIXER >>>>>>>>>>>>>>>>>> */ - -static void iamf_extra_data_reset(IAMF_extradata *data); - -static int32_t iamf_decoder_internal_reset(IAMF_DecoderHandle handle) { - IAMF_DecoderContext *ctx = &handle->ctx; - - iamf_database_reset(&ctx->db); - iamf_extra_data_reset(&ctx->metadata); - if (ctx->presentation) iamf_presentation_free(ctx->presentation); - if (ctx->output_layout) iamf_layout_info_free(ctx->output_layout); - memset(ctx, 0, sizeof(IAMF_DecoderContext)); - if (handle->limiter) audio_effect_peak_limiter_uninit(handle->limiter); - - return 0; -} - -static int iamf_decoder_internal_init(IAMF_DecoderHandle handle, - const uint8_t *data, uint32_t size, - uint32_t *rsize) { - int32_t ret = 0; - uint32_t pos = 0, consume = 0; - IAMF_DecoderContext *ctx = &handle->ctx; - - if (~ctx->flags & IAMF_FLAG_MAGIC_CODE) { - // search magic code obu - IAMF_OBU obj; - ia_logi("Without magic code flag."); - while (pos < size) { - consume = IAMF_OBU_split(data + pos, size - pos, &obj); - if (!consume || obj.type == IAMF_OBU_SEQUENCE_HEADER) { - ia_logi("Get magic code."); - break; - } - pos += consume; - } - } - - if (consume || ctx->flags & IAMF_FLAG_MAGIC_CODE) { - pos += iamf_decoder_internal_read_descriptors_OBUs(handle, data + pos, - size - pos); - } - - if (~ctx->flags & IAMF_FLAG_CONFIG) ret = IAMF_ERR_BUFFER_TOO_SMALL; - - if (rsize) *rsize = pos; - return ret; -} - -uint32_t iamf_decoder_internal_read_descriptors_OBUs(IAMF_DecoderHandle handle, - const uint8_t *data, - uint32_t size) { - IAMF_OBU obu; - uint32_t pos = 0, ret = 0, rsize = 0; - - while (pos < size) { - ret = IAMF_OBU_split(data + pos, size - pos, &obu); - if (!ret) { - ia_logw("consume size is 0."); - break; - } - rsize = ret; - ia_logt("consume size %d, obu type (%d) %s", ret, obu.type, - IAMF_OBU_type_string(obu.type)); - if ((obu.redundant && !(~handle->ctx.flags & IAMF_FLAG_DESCRIPTORS)) || - IAMF_OBU_is_reserved_OBU(&obu)) { - pos += rsize; - continue; - } - if (IAMF_OBU_is_descrptor_OBU(&obu)) { - ret = iamf_decoder_internal_add_descrptor_OBU(handle, &obu); - if (ret == IAMF_OK) { - switch (obu.type) { - case IAMF_OBU_SEQUENCE_HEADER: - handle->ctx.flags = IAMF_FLAG_MAGIC_CODE; - break; - case IAMF_OBU_CODEC_CONFIG: - handle->ctx.flags |= IAMF_FLAG_CODEC_CONFIG; - break; - case IAMF_OBU_AUDIO_ELEMENT: - handle->ctx.flags |= IAMF_FLAG_AUDIO_ELEMENT; - break; - case IAMF_OBU_MIX_PRESENTATION: - handle->ctx.flags |= IAMF_FLAG_MIX_PRESENTATION; - break; - default: - break; - } - } - } else { - handle->ctx.flags |= IAMF_FLAG_FRAME_START; - if (!(~handle->ctx.flags & IAMF_FLAG_DESCRIPTORS)) - handle->ctx.flags |= IAMF_FLAG_CONFIG; - break; - } - pos += rsize; - } - return pos; -} - -static uint32_t iamf_decoder_internal_parameter_prepare( - IAMF_DecoderHandle handle, uint64_t pid) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_Presentation *pst = ctx->presentation; - IAMF_DataBase *db = &ctx->db; - IAMF_StreamDecoder *dec = 0; - IAMF_Element *e; - - e = iamf_database_get_element_by_parameterID(&ctx->db, pid); - if (e) { - for (int i = 0; i < pst->nb_streams; ++i) { - if (pst->streams[i]->element_id == e->element_id) { - dec = pst->decoders[i]; - break; - } - } - if (dec) iamf_stream_decoder_update_parameter(dec, db, pid); - } - return IAMF_OK; -} - -static int iamf_decoder_internal_update_statue(IAMF_DecoderHandle handle) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_Presentation *pst = ctx->presentation; - int ret = 1; - - for (int s = 0; s < pst->nb_streams; ++s) { - if (!iamf_packet_check_count(&pst->decoders[s]->packet)) { - ret &= 0; - break; - } - } - - if (ret) ctx->status = IAMF_DECODER_STATUS_RUN; - - return ret; -} - -uint32_t iamf_decoder_internal_parse_OBUs(IAMF_DecoderHandle handle, - const uint8_t *data, uint32_t size) { - IAMF_OBU obu; - uint32_t pos = 0, ret = 0; - IAMF_DataBase *db = &handle->ctx.db; - - while (pos < size) { - ret = IAMF_OBU_split(data + pos, size - pos, &obu); - if (!ret) { - ia_logt("need more data."); - break; - } - - if (obu.type == IAMF_OBU_PARAMETER_BLOCK) { - uint64_t pid = IAMF_OBU_get_object_id(&obu); - if (pid != INVALID_ID) { - IAMF_Object *obj; - ParameterItem *pi = iamf_database_parameter_get_item(db, pid); - - if (pi) { - obj = IAMF_object_new(&obu, IAMF_OBJECT_PARAM(&pi->param)); - iamf_database_add_object(&handle->ctx.db, obj); - iamf_decoder_internal_parameter_prepare(handle, pid); - } else { - ia_logd("Receive unregister parameter %" PRId64 " OBU.", pid); - } - } - } else if (obu.type >= IAMF_OBU_AUDIO_FRAME && - obu.type <= IAMF_OBU_AUDIO_FRAME_ID17) { - IAMF_Object *obj = IAMF_object_new(&obu, 0); - IAMF_Frame *o = (IAMF_Frame *)obj; - iamf_decoder_internal_deliver(handle, o); - IAMF_object_free(obj); - iamf_decoder_internal_update_statue(handle); - } else if (obu.type == IAMF_OBU_SEQUENCE_HEADER && !obu.redundant) { - ia_logi("*********** FOUND NEW MAGIC CODE **********"); - handle->ctx.status = IAMF_DECODER_STATUS_RECONFIGURE; - break; - } - pos += ret; - - if (handle->ctx.status == IAMF_DECODER_STATUS_RUN) break; - } - return pos; -} - -int32_t iamf_decoder_internal_add_descrptor_OBU(IAMF_DecoderHandle handle, - IAMF_OBU *obu) { - IAMF_DataBase *db; - IAMF_Object *obj; - - db = &handle->ctx.db; - obj = IAMF_object_new(obu, 0); - if (!obj) { - ia_logw("fail to new object for %s(%d)", IAMF_OBU_type_string(obu->type), - obu->type); - return IAMF_ERR_ALLOC_FAIL; - } - - return iamf_database_add_object(db, obj); -} - -int iamf_decoder_internal_deliver(IAMF_DecoderHandle handle, IAMF_Frame *obj) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_DataBase *db = &ctx->db; - IAMF_Presentation *pst = ctx->presentation; - int idx = -1, i; - IAMF_Stream *stream; - IAMF_StreamDecoder *decoder; - - for (i = 0; i < pst->nb_streams; ++i) { - idx = iamf_database_element_get_substream_index( - db, pst->streams[i]->element_id, obj->id); - if (idx > -1) { - break; - } - } - - if (idx > -1) { - stream = pst->streams[i]; - decoder = pst->decoders[i]; - - if (idx == 0) { - ia_logd("frame id %" PRIu64 " and its stream (%d) id %" PRIu64, obj->id, - i, pst->streams[i]->element_id); - - if (obj->trim_start != stream->trimming_start) { - stream->trimming_start = obj->trim_start; - } - - if (obj->trim_end != stream->trimming_end) { - stream->trimming_end = obj->trim_end; - } - - if (obj->trim_start > 0) - ia_logd("trimming start %" PRIu64 " ", obj->trim_start); - if (obj->trim_end > 0) ia_logd("trimming end %" PRIu64, obj->trim_end); - } - iamf_stream_decoder_receive_packet(decoder, idx, obj); - } - - return 0; -} - -static int iamf_target_layout_matching_calculation(TargetLayout *target, - LayoutInfo *layout) { - SoundSystemLayout *ss; - int s = 0; - if (!target) return 0; - if (target->type == layout->layout.type) { - if (layout->layout.type == IAMF_LAYOUT_TYPE_BINAURAL) { - s = 100; - } else if (target->type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) { - ss = SOUND_SYSTEM_LAYOUT(target); - if (ss->sound_system == layout->layout.sound_system.sound_system) s = 100; - } - } - - if (!s) { - int chs = 0; - if (target->type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) { - ss = SOUND_SYSTEM_LAYOUT(target); - if (iamf_sound_system_valid(ss->sound_system)) - chs = IAMF_layout_sound_system_channels_count(ss->sound_system); - } else if (target->type == IAMF_LAYOUT_TYPE_BINAURAL) - chs = IAMF_layout_binaural_channels_count(); - - if (chs > 0) s = 50 + chs - layout->channels; - } - - return s; -} - -static float iamf_mix_presentation_get_best_loudness(IAMF_MixPresentation *obj, - LayoutInfo *layout) { - int score = 0, s, idx = INVALID_VALUE; - SubMixPresentation *sub; - float loudness_db = 0.f; - - if (obj->num_sub_mixes) { - /* for (int n = 0; n < obj->num_sub_mixes; ++n) { */ - /* sub = &obj->sub_mixes[n]; */ - sub = &obj->sub_mixes[0]; // support only 1 sub mix. - - if (sub->num_layouts) { - for (int i = 0; i < sub->num_layouts; ++i) { - s = iamf_target_layout_matching_calculation(sub->layouts[i], layout); - if (s > score) { - score = s; - idx = i; - } - } - if (idx > INVALID_VALUE) { - loudness_db = q_to_float(sub->loudness[idx].integrated_loudness, 8); - ia_logi("selected loudness is %f db <- 0x%x", loudness_db, - sub->loudness[idx].integrated_loudness & U16_MASK); - } - } - /* } */ - } - - return loudness_db; -} - -static int iamf_mix_presentation_matching_calculation(IAMF_DataBase *db, - IAMF_MixPresentation *obj, - LayoutInfo *layout) { - int score = 0, s = 0; - SubMixPresentation *sub; - IAMF_Element *e = 0; - - if (obj->num_sub_mixes) { - /* for (int n = 0; n < obj->num_sub_mixes; ++n) { */ - /* sub = &obj->sub_mixes[n]; */ - sub = &obj->sub_mixes[0]; // support only 1 sub mix. - - if (layout->layout.type == IAMF_LAYOUT_TYPE_BINAURAL) { - for (int i = 0; i < sub->nb_elements; i++) { - e = iamf_database_get_element(db, sub->conf_s[i].element_id); - if (e && e->element_type == AUDIO_ELEMENT_TYPE_CHANNEL_BASED && - e->channels_conf && e->channels_conf->layer_conf_s && - e->channels_conf->layer_conf_s->loudspeaker_layout == - IA_CHANNEL_LAYOUT_BINAURAL) - return 100; - } - } - if (sub->num_layouts) { - for (int i = 0; i < sub->num_layouts; ++i) { - s = iamf_target_layout_matching_calculation(sub->layouts[i], layout); - if (s > score) score = s; - } - } - /* } */ - } - - return score; -} - -static IAMF_MixPresentation *iamf_decoder_get_best_mix_presentation( - IAMF_DecoderHandle handle) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_DataBase *db = &ctx->db; - IAMF_MixPresentation *mp = 0, *obj; - - if (db->mixPresentation->count > 0) { - if (db->mixPresentation->count == 1) { - mp = IAMF_MIX_PRESENTATION(db->mixPresentation->items[0]); - } else { - int max_percentage = 0, sub_percentage; - - for (int i = 0; i < db->mixPresentation->count; ++i) { - obj = IAMF_MIX_PRESENTATION(db->mixPresentation->items[i]); - sub_percentage = iamf_mix_presentation_matching_calculation( - db, obj, ctx->output_layout); - if (max_percentage < sub_percentage) { - max_percentage = sub_percentage; - mp = obj; - } - } - } - } - return mp; -} - -static int iamf_decoder_timestamp_sync(IAMF_DecoderHandle handle, - uint64_t timestamp, int rate, - int delay) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_DataBase *db = &ctx->db; - IAMF_Presentation *pst = ctx->presentation; - IAMF_Stream *stream; - Viewer *pv = &db->pViewer; - ParameterItem *pi; - uint64_t ref_timestamp = timestamp; - uint64_t tsf_timestamp = 0; - - if (!timestamp) return IAMF_OK; - - if (delay > 0 && timestamp > (uint64_t)delay) timestamp -= delay; - - for (int i = 0; i < pv->count; ++i) { - pi = (ParameterItem *)pv->items[i]; - if (!pi) continue; - tsf_timestamp = time_transform(timestamp, rate, pi->rate); - if (!pi->timestamp) { - pi->timestamp = tsf_timestamp; - ia_logi("Parameter (%" PRIu64 ") timestamp sync to %" PRIu64, pi->id, - timestamp); - if (ref_timestamp != timestamp) { - iamf_parameter_item_fill_segment( - pi, time_transform(ref_timestamp - timestamp, rate, pi->rate)); - } - } else - ia_logi("Parameter (%" PRIu64 ") timestamp %" PRIu64, pi->id, - pi->timestamp + pi->elapse); - } - - if (pst) { - for (int i = 0; i < pst->nb_streams; ++i) { - stream = pst->streams[i]; - if (!stream) continue; - if (!stream->timestamp) { - if (stream->sampling_rate != rate) { - ia_logw("Difference rate between stream (%" PRIu64 - ") and reference ( %d vs %d )", - stream->element_id, stream->sampling_rate, rate); - continue; - } - stream->timestamp = ref_timestamp; - ia_logi("Stream (%" PRIu64 ") timestamp sync to %" PRIu64, - stream->element_id, ref_timestamp); - } - } - } - - return IAMF_OK; -} - -static int iamf_decoder_enable_mix_presentation(IAMF_DecoderHandle handle, - IAMF_MixPresentation *mixp) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_DataBase *db = &ctx->db; - IAMF_Element *elem; - IAMF_CodecConf *cc; - IAMF_Presentation *old = ctx->presentation; - IAMF_Presentation *pst; - SubMixPresentation *sub; - uint64_t pid; - ParameterItem *pi = 0; - int ret = IAMF_OK; - int rate = 0; - IAMF_Stream *stream = 0; - IAMF_StreamDecoder *decoder = 0; - IAMF_Resampler *resampler = 0; - - pst = IAMF_MALLOCZ(IAMF_Presentation, 1); - if (!pst) return IAMF_ERR_ALLOC_FAIL; - - pst->obj = mixp; - pst->output_gain_id = INVALID_ID; - ctx->presentation = pst; - - if (old) { - stream = old->streams[0]; - decoder = old->decoders[0]; - ia_logd("Reference stream %p", stream); - } - - ia_logd("enable mix presentation id %" PRIu64 ", %p", - mixp->mix_presentation_id, mixp); - - // There is only one sub mix in the mix presentation for simple and base - // profiles. so the sub mix is selected the first. - sub = mixp->sub_mixes; - - iamf_database_parameter_disable_items(db); - - for (uint32_t i = 0; i < sub->nb_elements; ++i) { - elem = iamf_database_get_element(db, sub->conf_s[i].element_id); - cc = iamf_database_element_get_codec_conf(db, elem->element_id); - rate = iamf_codec_conf_get_sampling_rate(cc); - - for (int k = 0; k < elem->nb_parameters; ++k) { - if (!elem->parameters[k]) continue; - pi = iamf_database_parameter_get_item(db, elem->parameters[k]->id); - if (pi) - iamf_parameter_item_enable(pi, 1); - else - iamf_database_parameter_add_item(db, elem->parameters[k], - elem->element_id, - elem->parameters[k]->rate); - } - - pid = sub->conf_s[i].element_mix_gain.base.id; - pi = iamf_database_parameter_get_item(db, pid); - // the mix gain parameter may be used by multiple stream. - if (pi) - iamf_parameter_item_enable(pi, 1); - else if (iamf_database_parameter_add_item( - db, &sub->conf_s[i].element_mix_gain.base, INVALID_ID, - sub->conf_s[i].element_mix_gain.base.rate) == IAMF_OK) { - float gain_db; - pi = iamf_database_parameter_get_item(db, pid); - gain_db = q_to_float(sub->conf_s[i].element_mix_gain.mix_gain, 8); - pi->value.mix_gain.default_mix_gain = db2lin(gain_db); - ia_logi("element %" PRIu64 " : mix gain %f (%f db) <- 0x%x", - sub->conf_s[i].element_id, pi->value.mix_gain.default_mix_gain, - gain_db, sub->conf_s[i].element_mix_gain.mix_gain & U16_MASK); - } - - iamf_database_element_set_mix_gain_parameter( - db, elem->element_id, sub->conf_s[i].element_mix_gain.base.id); - - if (!old || - iamf_presentation_reuse_stream(pst, old, elem->element_id) != IAMF_OK) - ret = iamf_stream_enable(handle, elem); - if (ret != IAMF_OK) return ret; - } - - pst->frame.channels = ctx->output_layout->channels; - iamf_set_stream_info(handle); - iamf_mixer_init(handle); - - pid = sub->output_mix_gain.base.id; - pi = iamf_database_parameter_get_item(db, pid); - if (pi) - iamf_parameter_item_enable(pi, 1); - else if (iamf_database_parameter_add_item( - db, &sub->output_mix_gain.base, INVALID_ID, - sub->output_mix_gain.base.rate) == IAMF_OK) { - float gain_db; - pi = iamf_database_parameter_get_item(db, pid); - gain_db = q_to_float(sub->output_mix_gain.mix_gain, 8); - pi->value.mix_gain.default_mix_gain = db2lin(gain_db); - ia_logi("output mix gain %f (%f db) <- 0x%x", - pi->value.mix_gain.default_mix_gain, gain_db, - sub->output_mix_gain.mix_gain & U16_MASK); - } - - if (pi) { - pst->output_gain_id = pi->id; - if (old && decoder && decoder->delay > 0 && !pi->timestamp) - iamf_database_parameter_item_segment_copy(db, pi, old->output_gain_id); - } - - iamf_database_parameter_clear_items(db); - - if (stream) { - ia_logd("reference stream timestamp %" PRIu64 ", rate %d", - stream->timestamp, stream->sampling_rate); - iamf_decoder_timestamp_sync(handle, stream->timestamp, - stream->sampling_rate, decoder->delay); - } - - if (old) resampler = iamf_presentation_take_resampler(old); - - stream = pst->streams[0]; - if (!resampler && stream->sampling_rate != ctx->sampling_rate) { - resampler = iamf_stream_resampler_open(stream, ctx->sampling_rate, - SPEEX_RESAMPLER_QUALITY); - if (!resampler) return IAMF_ERR_INTERNAL; - } - pst->resampler = resampler; - - if (old) iamf_presentation_free(old); - - return IAMF_OK; -} - -static int iamf_loudness_process(float *block, int frame_size, int channels, - float gain) { - int idx = 0; - if (!block || frame_size < 0 || channels < 0) return IAMF_ERR_BAD_ARG; - - if (!frame_size || gain == 1.0f) return IAMF_OK; - - for (int c = 0; c < channels; ++c) { - idx = c * frame_size; - for (int i = 0; i < frame_size; ++i) { - block[idx + i] *= gain; - } - } - - return IAMF_OK; -} - -static int iamf_resample(IAMF_Resampler *resampler, float *in, float *out, - int frame_size) { - SpeexResamplerState *speex_resampler = resampler->speex_resampler; - int resample_size = - frame_size * (speex_resampler->out_rate / speex_resampler->in_rate + 1); - ia_logt("input samples %d", frame_size); - if (resampler->rest_flag == 2) { - resample_size = speex_resampler_get_output_latency(speex_resampler); - int input_size = speex_resampler_get_input_latency(speex_resampler); - speex_resampler_process_interleaved_float( - speex_resampler, (const float *)NULL, (uint32_t *)&input_size, - (float *)in, (uint32_t *)&resample_size); - } else { - ia_decoder_plane2stride_out_float(resampler->buffer, in, frame_size, - speex_resampler->nb_channels); - speex_resampler_process_interleaved_float( - speex_resampler, (const float *)resampler->buffer, - (uint32_t *)&frame_size, (float *)in, (uint32_t *)&resample_size); - } - if (!resampler->rest_flag) { - resampler->rest_flag = 1; - } - ia_decoder_stride2plane_out_float(out, in, resample_size, - speex_resampler->nb_channels); - ia_logt("read samples %d, output samples %d", frame_size, resample_size); - return resample_size; -} - -/** - * @brief Handle the buffer delay from limiter or resampler. - * @param [in] handle : the iamf decoder handle - * @param [in] pcm : the audio pcm. - * @return the number of samples after hanlding - */ -static int iamf_delay_buffer_handle(IAMF_DecoderHandle handle, void *pcm) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_Presentation *pst = ctx->presentation; - IAMF_Resampler *resampler = pst->resampler; - AudioEffectPeakLimiter *limiter = handle->limiter; - int frame_size = limiter ? limiter->delaySize : 0; - int buffer_size = ctx->info.max_frame_size * ctx->output_layout->channels; - float *in, *out; - - if (!limiter && !resampler) return 0; - - in = IAMF_MALLOCZ(float, buffer_size); - out = IAMF_MALLOCZ(float, buffer_size); - - if (!in || !out) { - if (in) free(in); - if (out) free(out); - return IAMF_ERR_ALLOC_FAIL; - } - - if (resampler) { - resampler->rest_flag = 2; - int resample_size = iamf_resample(resampler, in, out, 0); - frame_size += resample_size; - swap((void **)&in, (void **)&out); - memset(out, 0, sizeof(float) * buffer_size); - for (int c = 0; c < resampler->speex_resampler->nb_channels; c++) { - memcpy(out + c * frame_size, in + c * resample_size, - sizeof(float) * resample_size); - } - swap((void **)&in, (void **)&out); - } - - if (limiter) { - frame_size = - audio_effect_peak_limiter_process_block(limiter, in, out, frame_size); - } - - iamf_decoder_plane2stride_out(handle->arch, pcm, out, frame_size, - ctx->output_layout->channels, ctx->bit_depth); - free(in); - free(out); - return frame_size; -} - -static int iamf_decoder_internal_decode(IAMF_DecoderHandle handle, - const uint8_t *data, int32_t size, - uint32_t *rsize, void *pcm) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_DataBase *db = &ctx->db; - IAMF_Presentation *pst = ctx->presentation; - IAMF_StreamDecoder *decoder; - IAMF_StreamRenderer *renderer; - IAMF_Stream *stream; - IAMF_Mixer *mixer = &pst->mixer; - IAMF_Resampler *resampler = pst->resampler; - Frame *f = 0; - int ret = 0, lret = 1; - uint32_t r = 0; - int real_frame_size = 0; - float *out = 0; - MixGainUnit *u = 0; - ElementItem *ei = 0; - - if (pst->nb_streams <= 0) return IAMF_ERR_INTERNAL; - - if (data && size) { - r = iamf_decoder_internal_parse_OBUs(handle, data, size); - *rsize = r; - - if (ctx->status == IAMF_DECODER_STATUS_RECONFIGURE) { - return IAMF_ERR_INVALID_STATE; - } else if (ctx->status != IAMF_DECODER_STATUS_RUN) { - return 0; - } - } - - if ((data && size) || pst->decoders[0]->delay > 0) { - for (int s = 0; s < pst->nb_streams; ++s) { - renderer = pst->renderers[s]; - decoder = pst->decoders[s]; - stream = decoder->stream; - f = &decoder->frame; - f->data = decoder->buffers[0]; - out = decoder->buffers[1]; - - f->pts = stream->timestamp; - ia_logd("frame timestamp %" PRIu64, f->pts); - if (decoder->delay > 0) f->pts -= decoder->delay; - ia_logd("frame revision timestamp %" PRIu64, f->pts); - - ret = iamf_stream_decoder_decode(decoder, f->data, ctx->duration > 0); - if (f->pts == stream->timestamp && decoder->delay > 0 && - ctx->duration > 0) - f->pts -= decoder->delay; - iamf_stream_decoder_decode_finish(decoder); - - if (ret > 0) { - ia_logd("strim %" PRIu64 ", etrim %" PRIu64 - ", frame size %u, delay size %d", - f->strim, f->etrim, decoder->frame_size, decoder->delay); - if (f->strim == decoder->frame_size || - f->etrim == decoder->frame_size) { - ret = 0; - ia_logd("The whole frame which size is %d has been cut.", f->samples); - } else { - f->samples = ret; - -#if SR - // decoding - iamf_rec_stream_log(stream->element_id, f->channels, f->data, ret); -#endif - - if (decoder->frame_padding > 0) { - ia_logw("decoded result is %d, different frame size %d", - ret - decoder->frame_padding, decoder->frame_size); - f->etrim += decoder->frame_padding; - } - - renderer->offset = decoder->delay > 0 ? decoder->delay : 0; - if (stream->trimming_start) renderer->offset = 0; - iamf_stream_render(handle->arch, renderer, f->data, out, ret); - -#if SR - // rendering - iamf_ren_stream_log(stream->element_id, - stream->final_layout->channels, out, ret); -#endif - - swap((void **)&f->data, (void **)&out); - f->channels = ctx->output_layout->channels; - - if (!data || size <= 0) { - f->etrim = decoder->frame_size - decoder->delay; - decoder->delay = 0; - } - - if ((f->strim && f->strim < decoder->frame_size) || - (f->etrim && f->etrim < decoder->frame_size) || - stream->trimming_start) { - if (f->etrim > 0 && decoder->delay > 0) { - if (decoder->delay > f->etrim) { - decoder->delay -= f->etrim; - f->etrim = 0; - } else { - f->etrim -= decoder->delay; - decoder->delay = 0; - } - } - ret = iamf_frame_trim(f, f->strim, f->etrim, - stream->trimming_start - f->strim); - - ia_logd("The remaining samples %d after cutting.", ret); - } - } - } else if (!ret) - ia_logd("decoded sample is 0"); - - if (!s && f->strim > 0) { - ia_logd("external pts is %" PRId64, ctx->pts); - ctx->pts += - time_transform(f->strim, stream->sampling_rate, ctx->pts_time_base); - ia_logd("external pts changes to %" PRId64, ctx->pts); - } - - if (ret <= 0) { - if (ret < 0) ia_loge("fail to decode audio packet. error no. %d", ret); - stream->timestamp += decoder->frame_size; - lret = ret; - continue; - } - real_frame_size = ret; - - ei = iamf_database_element_get_item(db, stream->element_id); - if (ei && iamf_database_parameter_get_item(db, ei->mixGainPid)) { - u = iamf_database_parameter_get_mix_gain_unit( - db, ei->mixGainPid, f->pts, f->samples, stream->sampling_rate); - if (u) { - iamf_frame_gain(f, u); - mix_gain_unit_free(u); - } - } - - // metadata - if (decoder->stream->scheme == AUDIO_ELEMENT_TYPE_CHANNEL_BASED && - ctx->metadata.param) { - IAMF_Stream *stream = decoder->stream; - ChannelLayerContext *cctx = (ChannelLayerContext *)stream->priv; - if (cctx->dmx_mode >= 0) - ctx->metadata.param->dmixp_mode = cctx->dmx_mode; - } - - iamf_mixer_add_frame(mixer, f); - - // timestamp - stream->timestamp += decoder->frame_size; - - pst->frame.data = out; - out = f->data; - } - - if (f->strim > 0) { - ia_logd("Skip start trimming samples %" PRId64 " in parameters.", - f->strim); - iamf_database_parameters_time_elapse(db, f->strim, - pst->streams[0]->sampling_rate); - } - - if (lret <= 0) { - ctx->status = IAMF_DECODER_STATUS_RECEIVE; - return lret; - } - - f = &pst->frame; - real_frame_size = iamf_mixer_mix(mixer, f); - - ia_logd("frame pts %" PRIu64 ", id %" PRIu64, f->pts, pst->output_gain_id); - - u = iamf_database_parameter_get_mix_gain_unit( - db, pst->output_gain_id, f->pts, f->samples, - pst->streams[0]->sampling_rate); - if (u) { - iamf_frame_gain(f, u); - mix_gain_unit_free(u); - } - - iamf_database_parameters_time_elapse(db, real_frame_size, - pst->streams[0]->sampling_rate); - - if (resampler) { - real_frame_size = iamf_resample(resampler, f->data, out, real_frame_size); - swap((void **)&f->data, (void **)&out); - } - - if (ctx->normalization_loudness < MAX_LIMITED_NORMALIZATION_LOUDNESS) { - iamf_loudness_process( - f->data, real_frame_size, ctx->output_layout->channels, - db2lin(ctx->normalization_loudness - ctx->loudness)); - } - - if (handle->limiter) { - real_frame_size = audio_effect_peak_limiter_process_block( - handle->limiter, f->data, out, real_frame_size); - swap((void **)&f->data, (void **)&out); - } - - iamf_decoder_plane2stride_out(handle->arch, pcm, f->data, real_frame_size, - ctx->output_layout->channels, ctx->bit_depth); - -#if SR - // mixing - iamf_mix_stream_log(ctx->output_layout->channels, out, real_frame_size); -#endif - } - - if (!data) { - if (real_frame_size > 0) - pcm = (char *)pcm + - ctx->bit_depth / 8 * real_frame_size * ctx->output_layout->channels; - real_frame_size += iamf_delay_buffer_handle(handle, pcm); - } - - ctx->duration += real_frame_size; - ctx->last_frame_size = real_frame_size; - ctx->status = IAMF_DECODER_STATUS_RECEIVE; - return real_frame_size; -} - -static LayoutInfo *iamf_layout_info_new_sound_system(IAMF_SoundSystem ss) { - IAMF_PREDEFINED_SP_LAYOUT *l; - LayoutInfo *t = 0; - const IAMF_LayoutInfo *info = iamf_sound_system_get_layout_info(ss); - - t = IAMF_MALLOCZ(LayoutInfo, 1); - if (!t) { - ia_loge("fail to allocate memory to Layout."); - return t; - } - - t->layout.sound_system.type = IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION; - t->layout.sound_system.sound_system = ss; - t->channels = info->channels; - t->sp.sp_type = 0; - l = IAMF_MALLOCZ(IAMF_PREDEFINED_SP_LAYOUT, 1); - if (!l) { - ia_loge("fail to allocate memory to Predefined SP Layout."); - if (t) free(t); - return 0; - } - l->system = info->rendering_id_out; - l->lfe1 = info->lfe1; - l->lfe2 = info->lfe2; - - t->sp.sp_layout.predefined_sp = l; - - return t; -} - -static LayoutInfo *iamf_layout_info_new_binaural() { - IAMF_PREDEFINED_SP_LAYOUT *l; - LayoutInfo *t = 0; - const IAMF_LayoutInfo *info = iamf_get_layout_info(IAMF_LAYOUT_ID_BINAURAL); - - t = IAMF_MALLOCZ(LayoutInfo, 1); - if (!t) { - ia_loge("fail to allocate memory to Layout."); - return t; - } - - t->layout.binaural.type = IAMF_LAYOUT_TYPE_BINAURAL; - t->channels = info->channels; - t->sp.sp_type = 0; - l = IAMF_MALLOCZ(IAMF_PREDEFINED_SP_LAYOUT, 1); - if (!l) { - ia_loge("fail to allocate memory to Predefined SP Layout."); - if (t) free(t); - return 0; - } - l->system = info->rendering_id_out; - l->lfe1 = info->lfe1; - l->lfe2 = info->lfe2; - - t->sp.sp_layout.predefined_sp = l; - - return t; -} - -static void iamf_extra_data_dump(IAMF_extradata *metadata) { - ia_logt("metadata: target layout >"); - - ia_logt("metadata: sound system %u", metadata->output_sound_system); - ia_logt("metadata: number of samples %u", metadata->number_of_samples); - ia_logt("metadata: bitdepth %u", metadata->bitdepth); - ia_logt("metadata: sampling rate %u", metadata->sampling_rate); - ia_logt("metadata: sound mode %d", metadata->output_sound_mode); - ia_logt("metadata: number loudness layout %d ", - metadata->num_loudness_layouts); - - for (int i = 0; i < metadata->num_loudness_layouts; ++i) { - ia_logt("metadata: loudness layout %d >", i); - iamf_layout_dump(&metadata->loudness_layout[i]); - - ia_logt("metadata: loudness info %d >", i); - ia_logt("\tinfo type %u", metadata->loudness[i].info_type & U8_MASK); - ia_logt("\tintegrated loudness 0x%x", - metadata->loudness[i].integrated_loudness & U16_MASK); - ia_logt("\tdigital peak 0x%d", - metadata->loudness[i].digital_peak & U16_MASK); - if (metadata->loudness[i].info_type & 1) - ia_logt("\ttrue peak %d", metadata->loudness[i].true_peak); - } - ia_logt("metadata: number parameters %d ", metadata->num_parameters); - - for (int i = 0; i < metadata->num_parameters; ++i) { - ia_logt("parameter size %d", metadata->param[i].parameter_length); - ia_logt("parameter type %d", metadata->param[i].parameter_definition_type); - if (metadata->param[i].parameter_definition_type == - IAMF_PARAMETER_TYPE_DEMIXING) - ia_logt("demix mode %d", metadata->param[i].dmixp_mode); - } -} - -static int iamf_extra_data_init(IAMF_DecoderHandle handle) { - IAMF_DecoderContext *ctx = &handle->ctx; - IAMF_Presentation *pst = ctx->presentation; - IAMF_extradata *metadata = &ctx->metadata; - - ia_logt("initialize iamf extra data."); - metadata->output_sound_system = - iamf_layout_get_sound_system(&ctx->output_layout->layout); - metadata->bitdepth = ctx->bit_depth; - metadata->sampling_rate = OUTPUT_SAMPLERATE; - metadata->output_sound_mode = iamf_presentation_get_output_sound_mode(pst); - - ia_logt("mix presentation %p", ctx->presentation->obj); - metadata->num_loudness_layouts = - ctx->presentation->obj->sub_mixes->num_layouts; - metadata->loudness_layout = - IAMF_MALLOCZ(IAMF_Layout, metadata->num_loudness_layouts); - metadata->loudness = - IAMF_MALLOCZ(IAMF_LoudnessInfo, metadata->num_loudness_layouts); - if (!metadata->loudness_layout || !metadata->loudness) - return IAMF_ERR_ALLOC_FAIL; - for (int i = 0; i < metadata->num_loudness_layouts; ++i) { - iamf_layout_copy2(&metadata->loudness_layout[i], - ctx->presentation->obj->sub_mixes->layouts[i]); - iamf_loudness_info_copy(&metadata->loudness[i], - &pst->obj->sub_mixes->loudness[i]); - } - - if (pst) { - ElementItem *ei; - for (int i = 0; i < pst->obj->sub_mixes->nb_elements; ++i) { - ei = iamf_database_element_get_item( - &ctx->db, pst->obj->sub_mixes->conf_s[i].element_id); - if (ei && iamf_database_parameter_get_item(&ctx->db, ei->demixingPid)) { - metadata->num_parameters = 1; - metadata->param = IAMF_MALLOCZ(IAMF_Param, 1); - if (!metadata->param) return IAMF_ERR_ALLOC_FAIL; - metadata->param->parameter_length = 8; - metadata->param->parameter_definition_type = - IAMF_PARAMETER_TYPE_DEMIXING; - break; - } - } - } - - iamf_extra_data_dump(metadata); - return IAMF_OK; -} - -static int iamf_extra_data_copy(IAMF_extradata *dst, IAMF_extradata *src) { - if (!src || !dst) return IAMF_ERR_BAD_ARG; - - dst->output_sound_system = src->output_sound_system; - dst->number_of_samples = src->number_of_samples; - dst->bitdepth = src->bitdepth; - dst->sampling_rate = src->sampling_rate; - dst->num_loudness_layouts = src->num_loudness_layouts; - dst->output_sound_mode = src->output_sound_mode; - dst->loudness_layout = 0; - dst->loudness = 0; - dst->param = 0; - - if (dst->num_loudness_layouts) { - dst->loudness_layout = IAMF_MALLOCZ(IAMF_Layout, dst->num_loudness_layouts); - dst->loudness = IAMF_MALLOCZ(IAMF_LoudnessInfo, dst->num_loudness_layouts); - - if (!dst->loudness_layout || !dst->loudness) goto alloc_fail; - for (int i = 0; i < dst->num_loudness_layouts; ++i) { - iamf_layout_copy(&dst->loudness_layout[i], &src->loudness_layout[i]); - iamf_loudness_info_copy(&dst->loudness[i], &src->loudness[i]); - } - } - - dst->num_parameters = src->num_parameters; - - if (dst->num_parameters) { - dst->param = IAMF_MALLOCZ(IAMF_Param, dst->num_parameters); - if (!dst->param) goto alloc_fail; - for (int i = 0; i < src->num_parameters; ++i) - memcpy(&dst->param[i], &src->param[i], sizeof(IAMF_Param)); - } - - return IAMF_OK; - -alloc_fail: - IAMF_FREE(dst->loudness_layout); - IAMF_FREE(dst->loudness); - IAMF_FREE(dst->param); - return IAMF_ERR_ALLOC_FAIL; -} - -void iamf_extra_data_reset(IAMF_extradata *data) { - if (data) { - IAMF_FREE(data->loudness_layout); - for (int i = 0; i < data->num_loudness_layouts; ++i) { - if (data->loudness) { - IAMF_FREE(data->loudness[i].anchor_loudness); - IAMF_FREE(data->loudness[i].info_type_bytes); - } - } - IAMF_FREE(data->loudness); - if (data->param) free(data->param); - - memset(data, 0, sizeof(IAMF_extradata)); - data->output_sound_mode = IAMF_SOUND_MODE_NONE; - } -} -/* ----------------------------- APIs ----------------------------- */ - -IAMF_DecoderHandle IAMF_decoder_open(void) { - IAMF_DecoderHandle handle = 0; - handle = IAMF_MALLOCZ(struct IAMF_Decoder, 1); - if (handle) { - IAMF_DataBase *db = &handle->ctx.db; - - handle->ctx.time_precision = OUTPUT_SAMPLERATE; - handle->ctx.threshold_db = LIMITER_MaximumTruePeak; - handle->ctx.loudness = 1.0f; - handle->ctx.sampling_rate = OUTPUT_SAMPLERATE; - handle->ctx.normalization_loudness = MAX_LIMITED_NORMALIZATION_LOUDNESS; - handle->ctx.status = IAMF_DECODER_STATUS_INIT; - handle->ctx.mix_presentation_id = INVALID_ID; - handle->limiter = audio_effect_peak_limiter_create(); - handle->arch = arch_create(); - if (!handle->limiter || iamf_database_init(db) != IAMF_OK) { - IAMF_decoder_close(handle); - handle = 0; - } - } - return handle; -} - -int IAMF_decoder_close(IAMF_DecoderHandle handle) { - if (handle) { - iamf_decoder_internal_reset(handle); - if (handle->limiter) audio_effect_peak_limiter_destroy(handle->limiter); - if (handle->arch) arch_destroy(handle->arch); - free(handle); - } -#if SR - iamf_stream_log_free(); -#endif - - return 0; -} - -int iamf_decoder_internal_configure(IAMF_DecoderHandle handle, - const uint8_t *data, uint32_t size, - uint32_t *rsize) { - int ret = IAMF_OK; - IAMF_DecoderContext *ctx; - IAMF_DataBase *db; - - ia_logt("handle %p, data %p, size %d", handle, data, size); - - if (!handle) return IAMF_ERR_BAD_ARG; - - ctx = &handle->ctx; - db = &ctx->db; - if (ctx->need_configure & IAMF_DECODER_CONFIG_OUTPUT_LAYOUT) { - LayoutInfo *old = ctx->output_layout; - ia_logd("old layout %p", old); - if (ctx->layout.type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) - ctx->output_layout = iamf_layout_info_new_sound_system( - ctx->layout.sound_system.sound_system); - else if (ctx->layout.type == IAMF_LAYOUT_TYPE_BINAURAL) - ctx->output_layout = iamf_layout_info_new_binaural(); - - ia_logd("new layout %p", ctx->output_layout); - if (!ctx->output_layout) { - ret = IAMF_ERR_ALLOC_FAIL; - ctx->output_layout = old; - } else if (old) { - if (old == ctx->output_layout) - ret = IAMF_ERR_INTERNAL; - else - iamf_layout_info_free(old); - } - - if (ret < 0) return IAMF_ERR_INTERNAL; - } - - if (data && size > 0) { - if (ctx->status == IAMF_DECODER_STATUS_INIT) - ctx->status = IAMF_DECODER_STATUS_CONFIGURE; - else if (ctx->status == IAMF_DECODER_STATUS_RECEIVE) - ctx->status = IAMF_DECODER_STATUS_RECONFIGURE; - - if (ctx->status == IAMF_DECODER_STATUS_RECONFIGURE) { - ia_logi("Reconfigure decoder."); - iamf_database_reset(db); - iamf_database_init(db); - iamf_extra_data_reset(&ctx->metadata); - ctx->status = IAMF_DECODER_STATUS_CONFIGURE; - } - - if (handle->limiter) { - ia_logi("Initialize limiter."); - audio_effect_peak_limiter_init( - handle->limiter, handle->ctx.threshold_db, OUTPUT_SAMPLERATE, - iamf_layout_channels_count(&handle->ctx.output_layout->layout), - LIMITER_AttackSec, LIMITER_ReleaseSec, LIMITER_LookAhead); - } - ret = iamf_decoder_internal_init(handle, data, size, rsize); - - if (ret == IAMF_OK) ctx->need_configure = 0; - } else if (ctx->need_configure) { - if (ctx->status < IAMF_DECODER_STATUS_RECEIVE) { - ia_loge("Decoder need configure with descriptor obus. status %d", - ctx->status); - return IAMF_ERR_BAD_ARG; - } - - if (ctx->need_configure & IAMF_DECODER_CONFIG_MIX_PRESENTATION) { - if (!ctx->presentation) { - ret = IAMF_ERR_INTERNAL; - } else if (ctx->mix_presentation_id != - ctx->presentation->obj->mix_presentation_id && - !iamf_database_get_mix_presentation( - db, ctx->mix_presentation_id)) { - ia_logw("Invalid mix presentation id %lu.", ctx->mix_presentation_id); - ret = IAMF_ERR_INTERNAL; - } - } - - if (ctx->need_configure & IAMF_DECODER_CONFIG_OUTPUT_LAYOUT) { - if (handle->limiter) { - audio_effect_peak_limiter_uninit(handle->limiter); - audio_effect_peak_limiter_init( - handle->limiter, handle->ctx.threshold_db, OUTPUT_SAMPLERATE, - iamf_layout_channels_count(&handle->ctx.output_layout->layout), - LIMITER_AttackSec, LIMITER_ReleaseSec, LIMITER_LookAhead); - } - } - - ctx->need_configure = 0; - } else { - ia_loge("Decoder need configure with descriptor obus."); - return IAMF_ERR_BAD_ARG; - } - - if (ret == IAMF_OK) { - IAMF_MixPresentation *mixp = 0; - if (ctx->mix_presentation_id != INVALID_ID) - mixp = iamf_database_get_mix_presentation(db, ctx->mix_presentation_id); - else { - mixp = iamf_decoder_get_best_mix_presentation(handle); - ctx->mix_presentation_id = mixp->mix_presentation_id; - } - - if (mixp) { - ia_logi("get mix presentation id %" PRId64, - mixp ? mixp->mix_presentation_id : INVALID_ID); - ret = iamf_decoder_enable_mix_presentation(handle, mixp); - if (ret == IAMF_OK) { - iamf_extra_data_reset(&ctx->metadata); - iamf_extra_data_init(handle); - handle->ctx.status = IAMF_DECODER_STATUS_RECEIVE; - } - handle->ctx.loudness = iamf_mix_presentation_get_best_loudness( - mixp, handle->ctx.output_layout); - } else { - ret = IAMF_ERR_INTERNAL; - if (ctx->mix_presentation_id != INVALID_ID) - ia_logw("Fail to find the mix presentation %" PRId64 " obu.", - ctx->mix_presentation_id); - else - ia_logw("Fail to find the valid mix presentation obu, try again."); - } - } - - return ret; -} - -int IAMF_decoder_configure(IAMF_DecoderHandle handle, const uint8_t *data, - uint32_t size, uint32_t *rsize) { - uint32_t rs = 0; - int ret = iamf_decoder_internal_configure(handle, data, size, &rs); - - if (rsize) { - *rsize = rs; - if ((ret != IAMF_OK && ret != IAMF_ERR_BUFFER_TOO_SMALL) || - (ret == IAMF_ERR_BUFFER_TOO_SMALL && - (handle->ctx.flags & IAMF_FLAG_FRAME_START))) - ia_loge("fail to configure decoder."); - return ret; - } - - if (ret == IAMF_ERR_BUFFER_TOO_SMALL && - !(~handle->ctx.flags & IAMF_FLAG_DESCRIPTORS)) { - handle->ctx.flags |= IAMF_FLAG_CONFIG; - handle->ctx.need_configure = IAMF_DECODER_CONFIG_PRESENTATION; - handle->ctx.status = IAMF_DECODER_STATUS_RECEIVE; - ia_logd("configure with complete descriptor OBUs."); - ret = iamf_decoder_internal_configure(handle, 0, 0, 0); - } - - if (ret != IAMF_OK) ia_loge("fail to configure decoder."); - - return ret; -} - -int IAMF_decoder_decode(IAMF_DecoderHandle handle, const uint8_t *data, - int32_t size, uint32_t *rsize, void *pcm) { - uint32_t rs = 0; - int ret = IAMF_OK; - - if (!handle) return IAMF_ERR_BAD_ARG; - if (handle->ctx.status != IAMF_DECODER_STATUS_RECEIVE) - return IAMF_ERR_INVALID_STATE; - ret = iamf_decoder_internal_decode(handle, data, size, &rs, pcm); - if (rsize) *rsize = rs; - return ret; -} - -int IAMF_decoder_output_layout_set_sound_system(IAMF_DecoderHandle handle, - IAMF_SoundSystem ss) { - IAMF_DecoderContext *ctx; - if (!handle) return IAMF_ERR_BAD_ARG; - if (!iamf_sound_system_valid(ss)) return IAMF_ERR_BAD_ARG; - - ctx = &handle->ctx; - if (ctx->layout.type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION && - ctx->layout.sound_system.sound_system == ss) - return IAMF_OK; - - ia_logd("sound system %d, channels %d", ss, - IAMF_layout_sound_system_channels_count(ss)); - - ctx->layout.type = IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION; - ctx->layout.sound_system.sound_system = ss; - ctx->need_configure |= IAMF_DECODER_CONFIG_OUTPUT_LAYOUT; - return 0; -} - -int IAMF_decoder_output_layout_set_binaural(IAMF_DecoderHandle handle) { - IAMF_DecoderContext *ctx; - - if (!handle) return IAMF_ERR_BAD_ARG; - - ctx = &handle->ctx; - if (ctx->layout.type == IAMF_LAYOUT_TYPE_BINAURAL) return IAMF_OK; - - ia_logd("binaural channels %d", IAMF_layout_binaural_channels_count()); - ctx->layout.type = IAMF_LAYOUT_TYPE_BINAURAL; - ctx->need_configure |= IAMF_DECODER_CONFIG_OUTPUT_LAYOUT; - return 0; -} - -int IAMF_decoder_set_mix_presentation_id(IAMF_DecoderHandle handle, - uint64_t id) { - IAMF_DecoderContext *ctx; - - if (!handle) return IAMF_ERR_BAD_ARG; - - ctx = &handle->ctx; - - if (ctx->mix_presentation_id == id) return IAMF_OK; - - ctx->mix_presentation_id = id; - ctx->need_configure |= IAMF_DECODER_CONFIG_MIX_PRESENTATION; - ia_logd("set new mix presentation id %" PRIu64 ".", id); - return IAMF_OK; -} - -int IAMF_layout_sound_system_channels_count(IAMF_SoundSystem ss) { - const IAMF_LayoutInfo *info = iamf_sound_system_get_layout_info(ss); - if (!iamf_sound_system_valid(ss)) { - ia_loge("invalid sound system %x", ss); - return IAMF_ERR_BAD_ARG; - } - ia_logd("sound system %x, channels %d", ss, info->channels); - return info->channels; -} - -int IAMF_layout_binaural_channels_count() { return 2; } - -#define CC_STR_SIZE 1024 -char *IAMF_decoder_get_codec_capability() { - char *ccs_str = IAMF_MALLOCZ(char, CC_STR_SIZE); - char cc_str[STRING_SIZE]; - - if (!ccs_str) return 0; - - snprintf(cc_str, STRING_SIZE, "iamf.%.03d.%.03d.ipcm", IAMF_PROFILE_DEFAULT, - IAMF_PROFILE_DEFAULT); - strcat(ccs_str, cc_str); - -#ifdef CONFIG_OPUS_CODEC - snprintf(cc_str, STRING_SIZE, ";iamf.%.03d.%.03d.Opus", IAMF_PROFILE_DEFAULT, - IAMF_PROFILE_DEFAULT); - strcat(ccs_str, cc_str); -#endif - -#ifdef CONFIG_AAC_CODEC - snprintf(cc_str, STRING_SIZE, ";iamf.%.03d.%.03d.mp4a.40.2", - IAMF_PROFILE_DEFAULT, IAMF_PROFILE_DEFAULT); - strcat(ccs_str, cc_str); -#endif - -#ifdef CONFIG_FLAC_CODEC - snprintf(cc_str, STRING_SIZE, ";iamf.%.03d.%.03d.fLaC", IAMF_PROFILE_DEFAULT, - IAMF_PROFILE_DEFAULT); - strcat(ccs_str, cc_str); -#endif - - return ccs_str; -} - -int IAMF_decoder_set_normalization_loudness(IAMF_DecoderHandle handle, - float loudness) { - if (!handle) return IAMF_ERR_BAD_ARG; - handle->ctx.normalization_loudness = loudness; - return IAMF_OK; -} - -int IAMF_decoder_set_bit_depth(IAMF_DecoderHandle handle, uint32_t bit_depth) { - if (!handle) return IAMF_ERR_BAD_ARG; - handle->ctx.bit_depth = bit_depth; - return IAMF_OK; -} - -int IAMF_decoder_peak_limiter_enable(IAMF_DecoderHandle handle, - uint32_t enable) { - if (!handle) return IAMF_ERR_BAD_ARG; - if (!!enable && !handle->limiter) { - handle->limiter = audio_effect_peak_limiter_create(); - if (!handle->limiter) return IAMF_ERR_ALLOC_FAIL; - } else if (!enable && handle->limiter) { - audio_effect_peak_limiter_destroy(handle->limiter); - handle->limiter = 0; - } - - return IAMF_OK; -} - -int IAMF_decoder_peak_limiter_set_threshold(IAMF_DecoderHandle handle, - float db) { - if (!handle) return IAMF_ERR_BAD_ARG; - handle->ctx.threshold_db = db; - return IAMF_OK; -} - -float IAMF_decoder_peak_limiter_get_threshold(IAMF_DecoderHandle handle) { - if (!handle) return LIMITER_MaximumTruePeak; - return handle->ctx.threshold_db; -} - -int IAMF_decoder_set_sampling_rate(IAMF_DecoderHandle handle, uint32_t rate) { - uint32_t sampling_rates[] = {8000, 11025, 12000, 16000, 22050, 24000, - 32000, 44100, 48000, 64000, 88200, 96000}; - int ret = IAMF_ERR_BAD_ARG; - - if (!handle) return IAMF_ERR_BAD_ARG; - - for (int i = 0; i < sizeof(sampling_rates) / sizeof(uint32_t); ++i) { - if (rate == sampling_rates[i]) { - if (rate != handle->ctx.sampling_rate) handle->ctx.sampling_rate = rate; - ret = IAMF_OK; - break; - } - } - return ret; -} - -IAMF_StreamInfo *IAMF_decoder_get_stream_info(IAMF_DecoderHandle handle) { - return &handle->ctx.info; -} - -int IAMF_decoder_set_pts(IAMF_DecoderHandle handle, int64_t pts, - uint32_t time_base) { - IAMF_DecoderContext *ctx; - if (!handle) return IAMF_ERR_BAD_ARG; - - ctx = &handle->ctx; - ctx->pts = pts; - ctx->pts_time_base = time_base; - ctx->duration = 0; - ia_logd("set pts %" PRId64 "/%u", pts, time_base); - - return IAMF_OK; -} - -int IAMF_decoder_get_last_metadata(IAMF_DecoderHandle handle, int64_t *pts, - IAMF_extradata *metadata) { - IAMF_DecoderContext *ctx; - int64_t d; - if (!handle || !pts || !metadata) return IAMF_ERR_BAD_ARG; - - ctx = &handle->ctx; - d = time_transform(ctx->duration - ctx->last_frame_size, ctx->sampling_rate, - ctx->pts_time_base); - *pts = ctx->pts + d; - ia_logd("pts %" PRId64 "/%u, last duration %" PRIu64 "/%d", *pts, - ctx->pts_time_base, ctx->duration - ctx->last_frame_size, - ctx->sampling_rate); - - iamf_extra_data_copy(metadata, &ctx->metadata); - metadata->number_of_samples = ctx->last_frame_size; - iamf_extra_data_dump(metadata); - return IAMF_OK; -} diff --git a/code/src/iamf_dec/IAMF_decoder_private.h b/code/src/iamf_dec/IAMF_decoder_private.h deleted file mode 100644 index 297abda3..00000000 --- a/code/src/iamf_dec/IAMF_decoder_private.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file IAMF_decoder_private.h - * @brief IAMF decoder internal APIs. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#ifndef IAMF_DECODER_PRIVATE_H -#define IAMF_DECODER_PRIVATE_H - -#include - -#include "IAMF_OBU.h" -#include "IAMF_core_decoder.h" -#include "IAMF_decoder.h" -#include "IAMF_defines.h" -#include "IAMF_types.h" -#include "ae_rdr.h" -#include "arch.h" -#include "audio_effect_peak_limiter.h" -#include "demixer.h" -#include "downmix_renderer.h" -#include "queue_t.h" -#include "speex_resampler.h" - -#define IAMF_FLAG_MAGIC_CODE 0x01 -#define IAMF_FLAG_CODEC_CONFIG 0x02 -#define IAMF_FLAG_AUDIO_ELEMENT 0x04 -#define IAMF_FLAG_MIX_PRESENTATION 0x08 -#define IAMF_FLAG_CONFIG 0x10 -#define IAMF_FLAG_FRAME_START 0x20 -#define IAMF_FLAG_DESCRIPTORS \ - (IAMF_FLAG_MAGIC_CODE | IAMF_FLAG_CODEC_CONFIG | IAMF_FLAG_AUDIO_ELEMENT | \ - IAMF_FLAG_MIX_PRESENTATION) - -#define DEC_BUF_CNT 3 - -typedef enum { - IA_CH_GAIN_RTF, - IA_CH_GAIN_LTF, - IA_CH_GAIN_RS, - IA_CH_GAIN_LS, - IA_CH_GAIN_R, - IA_CH_GAIN_L, - IA_CH_GAIN_COUNT -} IAOutputGainChannel; - -typedef enum { - IAMF_DECODER_STATUS_UNINIT, - IAMF_DECODER_STATUS_INIT, - IAMF_DECODER_STATUS_CONFIGURE, - IAMF_DECODER_STATUS_RECONFIGURE, - IAMF_DECODER_STATUS_RECEIVE, - IAMF_DECODER_STATUS_RUN, -} IAMF_DecoderStatus; - -/* >>>>>>>>>>>>>>>>>> DATABASE >>>>>>>>>>>>>>>>>> */ - -typedef void (*IAMF_Free)(void *); - -typedef struct ObjectSet { - void **items; - int count; - int capacity; - IAMF_Free objFree; -} ObjectSet; - -typedef struct MixGainUnit { - int count; - float constant_gain; - float *gains; -} MixGainUnit; - -typedef struct MixGain { - float default_mix_gain; - int use_default; -} MixGain; - -typedef struct ParameterValue { - queue_t *params; - union { - MixGain mix_gain; - }; -} ParameterValue; - -typedef struct ParameterItem { - uint64_t id; - uint64_t type; - uint64_t timestamp; - uint64_t duration; - uint64_t elapse; - uint64_t parent_id; - int rate; - int enabled; - - IAMF_ParameterParam param; - ParameterValue value; -} ParameterItem; - -typedef struct ElementItem { - uint64_t id; - - IAMF_CodecConf *codecConf; - IAMF_Element *element; - - uint64_t demixingPid; - uint64_t reconGainPid; - uint64_t mixGainPid; -} ElementItem; - -typedef void (*free_tp)(void *); - -typedef struct Viewer { - void **items; - int count; - free_tp freeF; -} Viewer; - -typedef struct IAMF_DataBase { - IAMF_Object *version; - - ObjectSet *codecConf; - ObjectSet *element; - ObjectSet *mixPresentation; - - Viewer eViewer; - Viewer pViewer; - - IAMF_Profile profile; -} IAMF_DataBase; - -/* <<<<<<<<<<<<<<<<<< DATABASE <<<<<<<<<<<<<<<<<< */ - -typedef struct LayoutInfo { - IAMF_SP_LAYOUT sp; - IAMF_Layout layout; - int channels; -} LayoutInfo; - -typedef struct IAMF_OutputGain { - uint32_t flags; - float gain; -} IAMF_OutputGain; - -typedef struct IAMF_ReconGain { - uint16_t flags; - uint16_t nb_channels; - float recon_gain[IA_CH_RE_COUNT]; - IAChannel order[IA_CH_RE_COUNT]; -} IAMF_ReconGain; - -typedef struct SubLayerConf { - uint32_t layout; - uint8_t nb_channels; - uint8_t nb_substreams; - uint8_t nb_coupled_substreams; - float loudness; - IAMF_OutputGain *output_gain; - IAMF_ReconGain *recon_gain; -} SubLayerConf; - -typedef struct ChannelLayerContext { - int nb_layers; - SubLayerConf *conf_s; - - int is_scaleable_stream; - int layer; - int layout; - int channels; - IAChannel channels_order[IA_CH_LAYOUT_MAX_CHANNELS]; - - int dmx_mode; - int dmx_default_mode; - int dmx_default_w_idx; -} ChannelLayerContext; - -typedef struct AmbisonicsContext { - int mode; - uint8_t *mapping; - int mapping_size; -} AmbisonicsContext; - -typedef struct IAMF_Stream { - uint64_t element_id; - uint64_t codecConf_id; - IAMF_CodecID codec_id; - - int sampling_rate; - uint8_t scheme; // audio element type: 0, CHANNEL_BASED; 1, SCENE_BASED - - int nb_channels; - int nb_substreams; - int nb_coupled_substreams; - - LayoutInfo *final_layout; - void *priv; - - uint64_t timestamp; // sync time - - uint64_t trimming_start; - uint64_t trimming_end; - - uint32_t max_frame_size; - - uint8_t headphones_rendering_mode; -} IAMF_Stream; - -typedef struct ScalableChannelDecoder { - int nb_layers; - IAMF_CoreDecoder **sub_decoders; - Demixer *demixer; -} ScalableChannelDecoder; - -typedef struct AmbisonicsDecoder { - IAMF_CoreDecoder *decoder; -} AmbisonicsDecoder; - -#define IAMF_FRAME_EXTRA_DEMIX_MODE 0x01 -#define IAMF_FRAME_EXTRA_RECON_GAIN 0x02 -#define IAMF_FRAME_EXTRA_MIX_GAIN 0x04 - -typedef struct Packet { - uint8_t **sub_packets; - uint32_t *sub_packet_sizes; - uint32_t nb_sub_packets; - uint32_t count; -} Packet; - -typedef struct Frame { - uint64_t id; - uint64_t pts; - uint32_t samples; - uint64_t strim; - uint64_t etrim; - int channels; - - float *data; -} Frame; - -typedef struct IAMF_StreamDecoder { - union { - ScalableChannelDecoder *scale; - AmbisonicsDecoder *ambisonics; - }; - - IAMF_Stream *stream; - float *buffers[DEC_BUF_CNT]; - - Packet packet; - Frame frame; - - uint32_t frame_size; - int frame_padding; - int delay; - -} IAMF_StreamDecoder; - -typedef struct IAMF_StreamRenderer { - IAMF_Stream *stream; - DMRenderer *downmixer; - uint32_t offset; - uint32_t frame_size; - uint8_t headphones_rendering_mode; - struct { - IAMF_SP_LAYOUT *layout; - union { - struct m2m_rdr_t mmm; - struct h2m_rdr_t hmm; - }; - int in_channel_map[IA_CH_LAYOUT_MAX_CHANNELS]; - } renderer; -} IAMF_StreamRenderer; - -typedef struct IAMF_Mixer { - uint64_t *element_ids; - int nb_elements; - Frame **frames; -} IAMF_Mixer; - -typedef struct IAMF_Resampler { - float *buffer; - uint32_t rest_flag; - SpeexResamplerState *speex_resampler; -} IAMF_Resampler; - -typedef struct IAMF_Presentation { - IAMF_MixPresentation *obj; - - IAMF_Stream **streams; - uint32_t nb_streams; - IAMF_StreamDecoder **decoders; - IAMF_StreamRenderer **renderers; - IAMF_Resampler *resampler; - IAMF_Mixer mixer; - uint64_t output_gain_id; - Frame frame; -} IAMF_Presentation; - -typedef struct IAMF_DecoderContext { - IAMF_DataBase db; - uint32_t flags; - IAMF_DecoderStatus status; - - IAMF_Layout layout; - LayoutInfo *output_layout; - int sampling_rate; - - uint64_t mix_presentation_id; - IAMF_Presentation *presentation; - - float loudness; - float normalization_loudness; - uint32_t bit_depth; - float threshold_db; - IAMF_StreamInfo info; - - uint32_t need_configure; - - // PTS - uint64_t duration; - int64_t pts; - uint32_t pts_time_base; - uint32_t last_frame_size; - uint32_t time_precision; - - IAMF_extradata metadata; - -} IAMF_DecoderContext; - -struct IAMF_Decoder { - IAMF_DecoderContext ctx; - AudioEffectPeakLimiter *limiter; - Arch *arch; -}; - -#endif /* IAMF_DECODER_PRIVATE_H */ diff --git a/code/src/iamf_dec/IAMF_layout.c b/code/src/iamf_dec/IAMF_layout.c deleted file mode 100755 index 67c09d44..00000000 --- a/code/src/iamf_dec/IAMF_layout.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file IAMF_layout.c - * @brief Channel layout. - * @version 0.1 - * @date Created 08/05/2024 - **/ - -#include "IAMF_layout.h" - -static const IAMF_LayoutInfo iamf_layouts[] = { - { - .id = IAMF_LAYOUT_ID_MONO, - .name = "Mono", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_OUT | - IAMF_LAYOUT_FLAG_SCALABLE, - .channels = 1, - .height = 0, - .surround = 1, - .lfe1 = LFE_NONE, - .lfe2 = LFE_NONE, - .sound_system = SOUND_SYSTEM_MONO, - .type = IA_CHANNEL_LAYOUT_MONO, - .rendering_id_in = IAMF_MONO, - .rendering_id_out = IAMF_MONO, - .decoding_map = {0}, - .channel_layout = {IA_CH_MONO}, - }, - { - .id = IAMF_LAYOUT_ID_STEREO, - .name = "Stereo", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_OUT | - IAMF_LAYOUT_FLAG_SCALABLE, - .channels = 2, - .height = 0, - .surround = 2, - .lfe1 = LFE_NONE, - .lfe2 = LFE_NONE, - .sound_system = SOUND_SYSTEM_A, - .type = IA_CHANNEL_LAYOUT_STEREO, - .rendering_id_in = IAMF_STEREO, - .rendering_id_out = BS2051_A, - .decoding_map = {0, 1}, - .channel_layout = {IA_CH_L2, IA_CH_R2}, - }, - { - .id = IAMF_LAYOUT_ID_5_1, - .name = "5.1", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_OUT | - IAMF_LAYOUT_FLAG_SCALABLE, - .channels = 6, - .height = 0, - .surround = 5, - .lfe1 = 3, - .lfe2 = LFE_NONE, - .sound_system = SOUND_SYSTEM_B, - .type = IA_CHANNEL_LAYOUT_510, - .rendering_id_in = IAMF_51, - .rendering_id_out = BS2051_B, - .decoding_map = {0, 1, 4, 5, 2, 3}, - .channel_layout = {IA_CH_L5, IA_CH_R5, IA_CH_C, IA_CH_LFE, IA_CH_SL5, - IA_CH_SR5}, - }, - { - .id = IAMF_LAYOUT_ID_5_1_2, - .name = "5.1.2", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_OUT | - IAMF_LAYOUT_FLAG_SCALABLE, - .channels = 8, - .height = 2, - .surround = 5, - .lfe1 = 3, - .lfe2 = LFE_NONE, - .sound_system = SOUND_SYSTEM_C, - .type = IA_CHANNEL_LAYOUT_512, - .rendering_id_in = IAMF_512, - .rendering_id_out = BS2051_C, - .decoding_map = {0, 1, 4, 5, 6, 7, 2, 3}, - .channel_layout = {IA_CH_L5, IA_CH_R5, IA_CH_C, IA_CH_LFE, IA_CH_SL5, - IA_CH_SR5, IA_CH_HL, IA_CH_HR}, - }, - { - .id = IAMF_LAYOUT_ID_5_1_4, - .name = "5.1.4", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_OUT | - IAMF_LAYOUT_FLAG_SCALABLE, - .channels = 10, - .height = 4, - .surround = 5, - .lfe1 = 3, - .lfe2 = LFE_NONE, - .sound_system = SOUND_SYSTEM_D, - .type = IA_CHANNEL_LAYOUT_514, - .rendering_id_in = IAMF_514, - .rendering_id_out = BS2051_D, - .decoding_map = {0, 1, 4, 5, 6, 7, 8, 9, 2, 3}, - .channel_layout = {IA_CH_L5, IA_CH_R5, IA_CH_C, IA_CH_LFE, IA_CH_SL5, - IA_CH_SR5, IA_CH_HFL, IA_CH_HFR, IA_CH_HBL, - IA_CH_HBR}, - }, - { - .id = IAMF_LAYOUT_ID_7_1, - .name = "7.1", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_OUT | - IAMF_LAYOUT_FLAG_SCALABLE, - .channels = 8, - .height = 0, - .surround = 7, - .lfe1 = 3, - .lfe2 = LFE_NONE, - .sound_system = SOUND_SYSTEM_I, - .type = IA_CHANNEL_LAYOUT_710, - .rendering_id_in = IAMF_71, - .rendering_id_out = BS2051_I, - .decoding_map = {0, 1, 4, 5, 6, 7, 2, 3}, - .channel_layout = {IA_CH_L7, IA_CH_R7, IA_CH_C, IA_CH_LFE, IA_CH_SL7, - IA_CH_SR7, IA_CH_BL7, IA_CH_BR7}, - }, - { - .id = IAMF_LAYOUT_ID_7_1_2, - .name = "7.1.2", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_OUT | - IAMF_LAYOUT_FLAG_SCALABLE, - .channels = 10, - .height = 2, - .surround = 7, - .lfe1 = 3, - .lfe2 = LFE_NONE, - .sound_system = SOUND_SYSTEM_EXT_712, - .type = IA_CHANNEL_LAYOUT_712, - .rendering_id_in = IAMF_712, - .rendering_id_out = IAMF_712, - .decoding_map = {0, 1, 4, 5, 6, 7, 8, 9, 2, 3}, - .channel_layout = {IA_CH_L7, IA_CH_R7, IA_CH_C, IA_CH_LFE, IA_CH_SL7, - IA_CH_SR7, IA_CH_BL7, IA_CH_BR7, IA_CH_HL, IA_CH_HR}, - }, - { - .id = IAMF_LAYOUT_ID_7_1_4, - .name = "7.1.4", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_OUT | - IAMF_LAYOUT_FLAG_SCALABLE, - .channels = 12, - .height = 4, - .surround = 7, - .sound_system = SOUND_SYSTEM_J, - .type = IA_CHANNEL_LAYOUT_714, - .lfe1 = 3, - .lfe2 = LFE_NONE, - .rendering_id_in = IAMF_714, - .rendering_id_out = BS2051_J, - .decoding_map = {0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 2, 3}, - .channel_layout = {IA_CH_L7, IA_CH_R7, IA_CH_C, IA_CH_LFE, IA_CH_SL7, - IA_CH_SR7, IA_CH_BL7, IA_CH_BR7, IA_CH_HFL, - IA_CH_HFR, IA_CH_HBL, IA_CH_HBR}, - }, - { - .id = IAMF_LAYOUT_ID_3_1_2, - .name = "3.1.2", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_OUT | - IAMF_LAYOUT_FLAG_SCALABLE, - .channels = 6, - .height = 2, - .surround = 3, - .lfe1 = 3, - .lfe2 = LFE_NONE, - .sound_system = SOUND_SYSTEM_EXT_312, - .type = IA_CHANNEL_LAYOUT_312, - .rendering_id_in = IAMF_312, - .rendering_id_out = IAMF_312, - .decoding_map = {0, 1, 4, 5, 2, 3}, - .channel_layout = {IA_CH_L3, IA_CH_R3, IA_CH_C, IA_CH_LFE, IA_CH_TL, - IA_CH_TR}, - }, - { - .id = IAMF_LAYOUT_ID_BINAURAL, - .name = "binaural", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_OUT, - .channels = 2, - .lfe1 = LFE_NONE, - .lfe2 = LFE_NONE, - .type = IA_CHANNEL_LAYOUT_BINAURAL, - .rendering_id_in = IAMF_BINAURAL, - .rendering_id_out = IAMF_BINAURAL, - }, - { - .id = IAMF_LAYOUT_ID_SOUND_SYSTEM_E, - .name = "Sound System E", - .flags = IAMF_LAYOUT_FLAG_OUT, - .channels = 11, - .lfe1 = 3, - .lfe2 = LFE_NONE, - .sound_system = SOUND_SYSTEM_E, - .type = IA_CHANNEL_LAYOUT_INVALID, - .rendering_id_out = BS2051_E, - }, - { - .id = IAMF_LAYOUT_ID_SOUND_SYSTEM_F, - .name = "Sound System F", - .flags = IAMF_LAYOUT_FLAG_OUT, - .channels = 12, - .lfe1 = 10, - .lfe2 = 11, - .sound_system = SOUND_SYSTEM_F, - .type = IA_CHANNEL_LAYOUT_INVALID, - .rendering_id_out = BS2051_F, - }, - { - .id = IAMF_LAYOUT_ID_SOUND_SYSTEM_G, - .name = "Sound System G", - .flags = IAMF_LAYOUT_FLAG_OUT, - .channels = 14, - .lfe1 = 3, - .lfe2 = LFE_NONE, - .sound_system = SOUND_SYSTEM_G, - .type = IA_CHANNEL_LAYOUT_INVALID, - .rendering_id_out = BS2051_G, - }, - { - .id = IAMF_LAYOUT_ID_SOUND_SYSTEM_H, - .name = "Sound System H", - .flags = IAMF_LAYOUT_FLAG_OUT, - .channels = 24, - .lfe1 = 3, - .lfe2 = 9, - .sound_system = SOUND_SYSTEM_H, - .type = IA_CHANNEL_LAYOUT_INVALID, - .rendering_id_out = BS2051_H, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_LFE, - .name = "LFE", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 1, - .type = IA_CHANNEL_LAYOUT_EXPANDED_LFE, - .reference_id = IAMF_LAYOUT_ID_7_1_4, - .sp_labels = SP_LFE1, - .decoding_map = {0}, - .channel_layout = {IA_CH_LFE}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_STEREO_S, - .name = "Stereo-S", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 2, - .type = IA_CHANNEL_LAYOUT_EXPANDED_STEREO_S, - .reference_id = IAMF_LAYOUT_ID_5_1_4, - .sp_labels = SP_MP110 | SP_MM110, - .decoding_map = {0, 1}, - .channel_layout = {IA_CH_SL5, IA_CH_SR5}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_STEREO_SS, - .name = "STEREO-SS", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 2, - .type = IA_CHANNEL_LAYOUT_EXPANDED_STEREO_SS, - .reference_id = IAMF_LAYOUT_ID_7_1_4, - .sp_labels = SP_MP090 | SP_MM090, - .decoding_map = {0, 1}, - .channel_layout = {IA_CH_SL7, IA_CH_SR7}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_STEREO_RS, - .name = "STEREO-RS", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 2, - .type = IA_CHANNEL_LAYOUT_EXPANDED_STEREO_RS, - .reference_id = IAMF_LAYOUT_ID_7_1_4, - .sp_labels = SP_MP135 | SP_MM135, - .decoding_map = {0, 1}, - .channel_layout = {IA_CH_BL7, IA_CH_BR7}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_STEREO_TF, - .name = "STEREO-TF", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 2, - .type = IA_CHANNEL_LAYOUT_EXPANDED_STEREO_TF, - .reference_id = IAMF_LAYOUT_ID_7_1_4, - .sp_labels = SP_UP045 | SP_UM045, - .decoding_map = {0, 1}, - .channel_layout = {IA_CH_HFL, IA_CH_HFR}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_STEREO_TB, - .name = "STEREO-TB", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 2, - .type = IA_CHANNEL_LAYOUT_EXPANDED_STEREO_TB, - .reference_id = IAMF_LAYOUT_ID_7_1_4, - .sp_labels = SP_UP135 | SP_UM135, - .decoding_map = {0, 1}, - .channel_layout = {IA_CH_HBL, IA_CH_HBR}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_TOP_4CH, - .name = "Top-4ch", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 4, - .type = IA_CHANNEL_LAYOUT_EXPANDED_TOP_4CH, - .reference_id = IAMF_LAYOUT_ID_7_1_4, - .sp_labels = SP_UP045 | SP_UM045 | SP_UP135 | SP_UM135, - .decoding_map = {0, 1, 2, 3}, - .channel_layout = {IA_CH_HFL, IA_CH_HFR, IA_CH_HBL, IA_CH_HBR}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_3CH, - .name = "3.0ch", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 3, - .type = IA_CHANNEL_LAYOUT_EXPANDED_3CH, - .reference_id = IAMF_LAYOUT_ID_7_1_4, - .sp_labels = SP_MP030 | SP_MP000 | SP_MM030, - .decoding_map = {0, 1, 2}, - .channel_layout = {IA_CH_L7, IA_CH_R7, IA_CH_C}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_9_1_6, - .name = "9.1.6", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_OUT | - IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 16, - .lfe1 = 3, - .lfe2 = LFE_NONE, - .sound_system = SOUND_SYSTEM_EXT_916, - .type = IA_CHANNEL_LAYOUT_EXPANDED_916, - .rendering_id_in = IAMF_916, - .rendering_id_out = IAMF_916, - .decoding_map = {6, 7, 0, 1, 8, 9, 4, 5, 10, 11, 14, 15, 12, 13, 2, 3}, - .channel_layout = {IA_CH_FL, IA_CH_FR, IA_CH_FC, IA_CH_LFE1, IA_CH_BL, - IA_CH_BR, IA_CH_FLC, IA_CH_FRC, IA_CH_SIL, IA_CH_SIR, - IA_CH_TPFL, IA_CH_TPFR, IA_CH_TPBL, IA_CH_TPBR, - IA_CH_TPSIL, IA_CH_TPSIR}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_STEREO_F, - .name = "Stereo-F", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 2, - .type = IA_CHANNEL_LAYOUT_EXPANDED_STEREO_F, - .reference_id = IAMF_LAYOUT_ID_EXPANDED_9_1_6, - .sp_labels = SP_MP060 | SP_MM060, - .decoding_map = {0, 1}, - .channel_layout = {IA_CH_FL, IA_CH_FR}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_STEREO_SI, - .name = "Stereo-Si", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 2, - .type = IA_CHANNEL_LAYOUT_EXPANDED_STEREO_SI, - .reference_id = IAMF_LAYOUT_ID_EXPANDED_9_1_6, - .sp_labels = SP_MP090 | SP_MM090, - .decoding_map = {0, 1}, - .channel_layout = {IA_CH_SIL, IA_CH_SIR}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_STEREO_TPSI, - .name = "Stereo-TpSi", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 2, - .type = IA_CHANNEL_LAYOUT_EXPANDED_STEREO_TPSI, - .reference_id = IAMF_LAYOUT_ID_EXPANDED_9_1_6, - .sp_labels = SP_UP090 | SP_UM090, - .decoding_map = {0, 1}, - .channel_layout = {IA_CH_TPSIL, IA_CH_TPSIR}, - }, - { - .id = IAMF_LAYOUT_ID_EXPANDED_TOP_6CH, - .name = "Top-6ch", - .flags = IAMF_LAYOUT_FLAG_IN | IAMF_LAYOUT_FLAG_EXPANDED, - .channels = 6, - .type = IA_CHANNEL_LAYOUT_EXPANDED_TOP_6CH, - .reference_id = IAMF_LAYOUT_ID_EXPANDED_9_1_6, - .sp_labels = - SP_UP045 | SP_UM045 | SP_UP090 | SP_UM090 | SP_UP135 | SP_UM135, - .decoding_map = {0, 1, 4, 5, 2, 3}, - .channel_layout = {IA_CH_TPFL, IA_CH_TPFR, IA_CH_TPBL, IA_CH_TPBR, - IA_CH_TPSIL, IA_CH_TPSIR}, - }}; - -const IAMF_LayoutInfo *iamf_sound_system_get_layout_info(IAMF_SoundSystem ss) { - const IAMF_LayoutInfo *info = 0; - for (uint32_t i = 0; i < sizeof(iamf_layouts) / sizeof(iamf_layouts[0]); - ++i) { - if (iamf_layouts[i].sound_system == ss && - (iamf_layouts[i].flags & IAMF_LAYOUT_FLAG_OUT)) { - info = &iamf_layouts[i]; - break; - } - } - return info; -} - -const IAMF_LayoutInfo *iamf_audio_layer_get_layout_info( - IAChannelLayoutType type) { - const IAMF_LayoutInfo *info = 0; - for (uint32_t i = 0; i < sizeof(iamf_layouts) / sizeof(iamf_layouts[0]); - ++i) { - if (iamf_layouts[i].type == type && - (iamf_layouts[i].flags & IAMF_LAYOUT_FLAG_IN)) { - info = &iamf_layouts[i]; - break; - } - } - return info; -} - -const IAMF_LayoutInfo *iamf_get_layout_info(IAMF_LayoutID id) { - const IAMF_LayoutInfo *info = 0; - for (uint32_t i = 0; i < sizeof(iamf_layouts) / sizeof(iamf_layouts[0]); - ++i) { - if (iamf_layouts[i].id == id) { - info = &iamf_layouts[i]; - break; - } - } - return info; -} - -int iamf_audio_layer_layout_get_decoding_channels(IAChannelLayoutType type, - IAChannel *channels, - uint32_t count) { - const IAMF_LayoutInfo *info = iamf_audio_layer_get_layout_info(type); - for (uint32_t i = 0; i < info->channels; ++i) - channels[i] = info->channel_layout[info->decoding_map[i]]; - return info->channels; -} - -int iamf_audio_layer_layout_get_rendering_channels(IAChannelLayoutType type, - IAChannel *channels, - uint32_t count) { - const IAMF_LayoutInfo *info = iamf_audio_layer_get_layout_info(type); - if (count < info->channels) return IAMF_ERR_BUFFER_TOO_SMALL; - for (uint32_t i = 0; i < info->channels; ++i) - channels[i] = info->channel_layout[i]; - return info->channels; -} \ No newline at end of file diff --git a/code/src/iamf_dec/IAMF_layout.h b/code/src/iamf_dec/IAMF_layout.h deleted file mode 100755 index b4224269..00000000 --- a/code/src/iamf_dec/IAMF_layout.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file IAMF_layout.h - * @brief Channel Layout APIs. - * @version 0.1 - * @date Created 08/05/2024 - **/ - -#ifndef IAMF_LAYOUT_H -#define IAMF_LAYOUT_H - -#include - -#include "IAMF_utils.h" -#include "ae_rdr.h" - -#define LFE_NONE -1 - -typedef struct IAMF_LayoutInfo IAMF_LayoutInfo; - -typedef enum { - IAMF_LAYOUT_ID_NONE, - - /// @brief output channel layout in version 1.0 - IAMF_LAYOUT_ID_SOUND_SYSTEM_E = 0x01002000, - IAMF_LAYOUT_ID_SOUND_SYSTEM_F, - IAMF_LAYOUT_ID_SOUND_SYSTEM_G, - IAMF_LAYOUT_ID_SOUND_SYSTEM_H, - - /// @brief input/output channel layout in version 1.0 - IAMF_LAYOUT_ID_MONO = 0x01003000, - IAMF_LAYOUT_ID_STEREO, // SOUND_SYSTEM_A - IAMF_LAYOUT_ID_5_1, // SOUND_SYSTEM_B - IAMF_LAYOUT_ID_5_1_2, // SOUND_SYSTEM_C - IAMF_LAYOUT_ID_5_1_4, // SOUND_SYSTEM_D - IAMF_LAYOUT_ID_7_1, // SOUND_SYSTEM_I - IAMF_LAYOUT_ID_7_1_2, - IAMF_LAYOUT_ID_7_1_4, // SOUND_SYSTEM_J - IAMF_LAYOUT_ID_3_1_2, - IAMF_LAYOUT_ID_BINAURAL, - - /// @brief input channel layout in version 1.1 - IAMF_LAYOUT_ID_EXPANDED_LFE = 0x01011000, - IAMF_LAYOUT_ID_EXPANDED_STEREO_S, - IAMF_LAYOUT_ID_EXPANDED_STEREO_SS, - IAMF_LAYOUT_ID_EXPANDED_STEREO_RS, - IAMF_LAYOUT_ID_EXPANDED_STEREO_TF, - IAMF_LAYOUT_ID_EXPANDED_STEREO_TB, - IAMF_LAYOUT_ID_EXPANDED_TOP_4CH, - IAMF_LAYOUT_ID_EXPANDED_3CH, - IAMF_LAYOUT_ID_EXPANDED_STEREO_F, - IAMF_LAYOUT_ID_EXPANDED_STEREO_SI, - IAMF_LAYOUT_ID_EXPANDED_STEREO_TPSI, - IAMF_LAYOUT_ID_EXPANDED_TOP_6CH, - - /// @brief input/output channel layout in version 1.1 - IAMF_LAYOUT_ID_EXPANDED_9_1_6 = 0x01013000, -} IAMF_LayoutID; - -enum IAMF_LayoutFlag { - IAMF_LAYOUT_FLAG_IN = 0x00000001, - IAMF_LAYOUT_FLAG_OUT = 0x00000002, - IAMF_LAYOUT_FLAG_SCALABLE = 0x00000004, - IAMF_LAYOUT_FLAG_EXPANDED = 0x00000008, -}; - -struct IAMF_LayoutInfo { - IAMF_LayoutID id; - const char *name; - uint32_t flags; - uint32_t channels; - - uint32_t surround; - uint32_t height; - - int lfe1; - int lfe2; - - IAMF_SoundSystem sound_system; - IAChannelLayoutType type; - - IAMF_SOUND_SYSTEM rendering_id_in; - IAMF_SOUND_SYSTEM rendering_id_out; - - IAMF_LayoutID reference_id; - BS2051_SPLABEL sp_labels; - - uint8_t decoding_map[IA_CH_LAYOUT_MAX_CHANNELS]; - IAChannel channel_layout[IA_CH_LAYOUT_MAX_CHANNELS]; -}; - -const IAMF_LayoutInfo *iamf_sound_system_get_layout_info(IAMF_SoundSystem); -const IAMF_LayoutInfo *iamf_audio_layer_get_layout_info(IAChannelLayoutType); -const IAMF_LayoutInfo *iamf_get_layout_info(IAMF_LayoutID); - -int iamf_audio_layer_layout_get_decoding_channels(IAChannelLayoutType, - IAChannel *, uint32_t); -int iamf_audio_layer_layout_get_rendering_channels(IAChannelLayoutType, - IAChannel *, uint32_t); -#endif // IAMF_LAYOUT_H \ No newline at end of file diff --git a/code/src/iamf_dec/IAMF_types.h b/code/src/iamf_dec/IAMF_types.h deleted file mode 100755 index b95a7971..00000000 --- a/code/src/iamf_dec/IAMF_types.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file IAMF_types.h - * @brief Internal definition. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#ifndef IAMF_TYPES_H_ -#define IAMF_TYPES_H_ - -typedef enum { - IA_CH_RE_L, - IA_CH_RE_C, - IA_CH_RE_R, - IA_CH_RE_LS, - IA_CH_RE_RS, - IA_CH_RE_LTF, - IA_CH_RE_RTF, - IA_CH_RE_LB, - IA_CH_RE_RB, - IA_CH_RE_LTB, - IA_CH_RE_RTB, - IA_CH_RE_LFE, - IA_CH_RE_COUNT, - - IA_CH_RE_RSS = IA_CH_RE_RS, - IA_CH_RE_LSS = IA_CH_RE_LS, - IA_CH_RE_RTR = IA_CH_RE_RTB, - IA_CH_RE_LTR = IA_CH_RE_LTB, - IA_CH_RE_RSR = IA_CH_RE_RB, - IA_CH_RE_LRS = IA_CH_RE_LB, -} IAReconChannel; - -typedef enum { - IA_CH_INVALID, - IA_CH_L7, - IA_CH_R7, - IA_CH_C, - IA_CH_LFE, - IA_CH_SL7, - IA_CH_SR7, - IA_CH_BL7, - IA_CH_BR7, - IA_CH_HFL, - IA_CH_HFR, - IA_CH_HBL, - IA_CH_HBR, - IA_CH_MONO, - IA_CH_L2, - IA_CH_R2, - IA_CH_TL, - IA_CH_TR, - IA_CH_L3, - IA_CH_R3, - IA_CH_SL5, - IA_CH_SR5, - IA_CH_HL, - IA_CH_HR, - IA_CH_FL, // M+060 in 9.1.6 - IA_CH_FR, // M-060 in 9.1.6 - IA_CH_TPSIL, // U+090 - IA_CH_TPSIR, // U-090 - IA_CH_COUNT, - - IA_CH_L5 = IA_CH_L7, - IA_CH_R5 = IA_CH_R7, - - IA_CH_FLC = IA_CH_L7, // M+030 - IA_CH_FRC = IA_CH_R7, // M-030 - IA_CH_FC = IA_CH_C, // M+000 - IA_CH_SIL = IA_CH_SL7, // M+090 - IA_CH_SIR = IA_CH_SR7, // M-090 - IA_CH_BL = IA_CH_BL7, // M+135 - IA_CH_BR = IA_CH_BR7, // M-135 - IA_CH_TPFL = IA_CH_HFL, // U+045 - IA_CH_TPFR = IA_CH_HFR, // U-045 - IA_CH_TPBL = IA_CH_HBL, // U+135 - IA_CH_TPBR = IA_CH_HBR, // U-135 - IA_CH_LFE1 = IA_CH_LFE, -} IAChannel; - -typedef enum { - AUDIO_FRAME_PLANE = 0x1, -} AFlag; - -typedef enum { - STREAM_MODE_AMBISONICS_NONE, - STREAM_MODE_AMBISONICS_MONO, - STREAM_MODE_AMBISONICS_PROJECTION -} IAMF_Stream_Mode; - -/** - * @brief Expanded loudspeaker layout in @expanded_loudspeaker_layout - */ -typedef enum { - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_LFE = 0, // LFE - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_STEREO_S, // Ls/Rs - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_STEREO_SS, // Lss/Rss - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_STEREO_RS, // Lrs/Rrs - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_STEREO_TF, // Ltf/Rtf - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_STEREO_TB, // Ltb/Rtb - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_TOP_4CH, // Ltf/Rtf/Ltb/Rtb - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_3CH, // L/C/R - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_916, // 9.1.6 - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_STEREO_F, // FL/FR - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_STEREO_Si, // SiL/SiR - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_STEREO_TpSi, // TpSiL/TpSiR - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_TOP_6CH, // TpFL/TpFR/TpSiL/TpSiR/TpBL/TpBR - IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_COUNT, -} IAMFExpandedLayoutType; - -typedef struct MixFactors { - float alpha; - float beta; - float gamma; - float delta; - int w_idx_offset; -} MixFactors; - -/// @brief The IA profile. -typedef enum { - /// @brief the simple profile. - IAMF_PROFILE_SIMPLE, - /// @brief the base profile. - IAMF_PROFILE_BASE, - /// @brief the base-enhanced profile. - IAMF_PROFILE_BASE_ENHANCED, - /// @brief the count of profiles. - IAMF_PROFILE_COUNT, - /// @brief the default profile. - IAMF_PROFILE_DEFAULT = IAMF_PROFILE_BASE_ENHANCED, -} IAMF_Profile; - -#define U8_MASK 0xFF -#define U16_MASK 0xFFFF - -#define IA_CH_LAYOUT_MAX_CHANNELS 25 - -#define OPUS_FRAME_SIZE 960 -#define MAX_OPUS_FRAME_SIZE OPUS_FRAME_SIZE * 6 -#define AAC_FRAME_SIZE 1024 -#define MAX_AAC_FRAME_SIZE 2048 -#define MAX_FRAME_SIZE AAC_FRAME_SIZE * 6 -#define MAX_FLAC_FRAME_SIZE 32768 - -#define MAX_STREAMS 255 - -#define IA_CH_CATE_SURROUND 0x100 -#define IA_CH_CATE_WEIGHT 0X200 -#define IA_CH_CATE_TOP 0X400 - -#define IAMF_LOUDSPEAKER_LAYOUT_EXPANDED 15 -#define IAMF_LOUDSPEAKER_LAYOUT_EXPANDED_MASK 0x10 - -/// @brief The maximun number of sub mixes for the mix presentation. -#define IAMF_MIX_PRESENTATION_MAX_SUBS 1 - -#endif /* IAMF_TYPES_H_ */ diff --git a/code/src/iamf_dec/IAMF_utils.c b/code/src/iamf_dec/IAMF_utils.c deleted file mode 100755 index 9f76a0a8..00000000 --- a/code/src/iamf_dec/IAMF_utils.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file IAMF_utils.c - * @brief Utils. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#include "IAMF_utils.h" - -void iamf_freep(void **p) { - if (p && *p) { - free(*p); - *p = 0; - } -} - -#define TAG(a, b, c, d) ((a) | (b) << 8 | (c) << 16 | (d) << 24) -IAMF_CodecID iamf_codec_4cc_get_codecID(uint32_t id) { - switch (id) { - case TAG('m', 'p', '4', 'a'): - return IAMF_CODEC_AAC; - - case TAG('O', 'p', 'u', 's'): - return IAMF_CODEC_OPUS; - - case TAG('f', 'L', 'a', 'C'): - return IAMF_CODEC_FLAC; - - case TAG('i', 'p', 'c', 'm'): - return IAMF_CODEC_PCM; - - default: - return IAMF_CODEC_UNKNOWN; - } -} - -int iamf_codec_check(IAMF_CodecID cid) { - return cid >= IAMF_CODEC_OPUS && cid < IAMF_CODEC_COUNT; -} - -static const char *gIAMFCodecName[IAMF_CODEC_COUNT] = {"None", "OPUS", "AAC-LC", - "FLAC", "PCM"}; - -const char *iamf_codec_name(IAMF_CodecID cid) { - if (iamf_codec_check(cid)) { - return gIAMFCodecName[cid]; - } - return "UNKNOWN"; -} - -static const char *gIAECString[] = {"Ok", - "Bad argments", - "Unknown", - "Internal error", - "Invalid packet", - "Invalid state", - "Unimplemented", - "Memory allocation failure"}; - -const char *ia_error_code_string(int ec) { - int cnt = sizeof(gIAECString) / sizeof(char *); - int idx = -ec; - if (idx >= 0 && idx < cnt) { - return gIAECString[idx]; - } - return "Unknown"; -} - -int iamf_audio_layer_base_layout_check(IAChannelLayoutType type) { - return type >= IA_CHANNEL_LAYOUT_MONO && type < IA_CHANNEL_LAYOUT_COUNT; -} - -int iamf_audio_layer_expanded_layout_check(IAMFExpandedLayoutType type) { - return type >= IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_LFE && - type < IAMF_EXPANDED_LOUDSPEAKER_LAYOUT_COUNT; -} - -IAChannelLayoutType iamf_audio_layer_layout_get( - IAChannelLayoutType base, IAMFExpandedLayoutType expanded) { - if (iamf_audio_layer_base_layout_check(base)) return base; - if (iamf_audio_layer_expanded_layout_check(expanded) && - base == IAMF_LOUDSPEAKER_LAYOUT_EXPANDED) - return IAMF_LOUDSPEAKER_LAYOUT_EXPANDED_MASK | expanded; - return IA_CHANNEL_LAYOUT_INVALID; -} - -static const char *gIAChName[] = { - "unknown", "l7/l5/l", "r7/r5/r", "c", "lfe", "sl7/sl", "sr7/sr", - "bl7/bl", "br7/br", "hfl", "hfr", "hbl", "hbr", "mono", - "l2", "r2", "tl", "tr", "l3", "r3", "sl5", - "sr5", "hl", "hr", "wl", "wr", "hsl", "hsr"}; - -const char *ia_channel_name(IAChannel ch) { - return ch < IA_CH_COUNT ? gIAChName[ch] : "unknown"; -} - -int bit1_count(uint32_t value) { - int n = 0; - for (; value; ++n) { - value &= (value - 1); - } - return n; -} - -int iamf_valid_mix_mode(int mode) { return mode >= 0 && mode != 3 && mode < 7; } - -const MixFactors mix_factors_mat[] = { - {1.0, 1.0, 0.707, 0.707, -1}, {0.707, 0.707, 0.707, 0.707, -1}, - {1.0, 0.866, 0.866, 0.866, -1}, {0, 0, 0, 0, 0}, - {1.0, 1.0, 0.707, 0.707, 1}, {0.707, 0.707, 0.707, 0.707, 1}, - {1.0, 0.866, 0.866, 0.866, 1}, {0, 0, 0, 0, 0}}; - -const MixFactors *iamf_get_mix_factors(int mode) { - if (iamf_valid_mix_mode(mode)) return &mix_factors_mat[mode]; - return 0; -} diff --git a/code/src/iamf_dec/IAMF_utils.h b/code/src/iamf_dec/IAMF_utils.h deleted file mode 100755 index d4ac85a0..00000000 --- a/code/src/iamf_dec/IAMF_utils.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file IAMF_utils.h - * @brief Utils APIs. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#ifndef IAMF_UITLS_H -#define IAMF_UITLS_H - -#include -#include -#include - -#include "IAMF_defines.h" -#include "IAMF_types.h" - -#define IAMF_MALLOC(type, n) ((type *)malloc(sizeof(type) * (n))) -#define IAMF_REALLOC(type, p, n) ((type *)realloc(p, sizeof(type) * (n))) -#define IAMF_MALLOCZ(type, n) ((type *)calloc(n, sizeof(type))) -#define IAMF_FREE(p) \ - { \ - if (p) free(p); \ - } -#define IAMF_FREEP(p) iamf_freep((void **)p) - -#define RSHIFT(a) (1 << (a)) - -void iamf_freep(void **p); - -IAMF_CodecID iamf_codec_4cc_get_codecID(uint32_t id); -int iamf_codec_check(IAMF_CodecID cid); -const char *iamf_codec_name(IAMF_CodecID cid); - -const char *ia_error_code_string(int ec); - -int iamf_audio_layer_base_layout_check(IAChannelLayoutType type); -int iamf_audio_layer_expanded_layout_check(IAMFExpandedLayoutType type); -IAMFExpandedLayoutType iamf_audio_layer_expanded_layout_get( - IAChannelLayoutType type); -IAChannelLayoutType iamf_audio_layer_layout_get( - IAChannelLayoutType base, IAMFExpandedLayoutType expanded); - -const char *ia_channel_name(IAChannel ch); - -int bit1_count(uint32_t value); - -int iamf_valid_mix_mode(int mode); -const MixFactors *iamf_get_mix_factors(int mode); - -#endif /* IAMF_UITLS_H */ diff --git a/code/src/iamf_dec/ae_rdr.h b/code/src/iamf_dec/ae_rdr.h deleted file mode 100644 index 6cf54c5c..00000000 --- a/code/src/iamf_dec/ae_rdr.h +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file ae_rdr.h - * @brief Rendering APIs. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#ifndef AE_RDR_H_ -#define AE_RDR_H_ - -#include - -#include "arch.h" - -#define BS2051_MAX_CHANNELS 24 // BS2051_H -typedef enum { - BS2051_A = 0x020, // 2ch output - BS2051_B = 0x050, // 6ch output - BS2051_C = 0x250, // 8ch output - BS2051_D = 0x450, // 10ch output - BS2051_E = 0x451, // 11ch output - BS2051_F = 0x370, // 12ch output - BS2051_G = 0x490, // 14ch output - BS2051_H = 0x9A3, // 24ch output - BS2051_I = 0x070, // 8ch output - BS2051_J = 0x470, // 12ch output - IAMF_STEREO = 0x200, // 2ch input - IAMF_51 = 0x510, // 6ch input - IAMF_512 = 0x512, // 8ch input - IAMF_514 = 0x514, // 10ch input - IAMF_71 = 0x710, // 8ch input - IAMF_714 = 0x714, // 12ch input - IAMF_MONO = 0x100, // 1ch input/output, AOM only - IAMF_712 = 0x712, // 10ch input/output, AOM only - IAMF_312 = 0x312, // 6ch input/output, AOM only - IAMF_BINAURAL = 0x1020, // binaural input/output AOM only - IAMF_916 = 0x916 // 16ch input/output, AOM only -} IAMF_SOUND_SYSTEM; - -typedef enum { - SP_MP000 = 0x00000001, - SP_MP030 = 0x00000002, - SP_MM030 = 0x00000004, - SP_MP045 = 0x00000008, - SP_MM045 = 0x00000010, - SP_MP060 = 0x00000020, - SP_MM060 = 0x00000040, - SP_MP090 = 0x00000080, - SP_MM090 = 0x00000100, - SP_MP110 = 0x00000200, - SP_MM110 = 0x00000400, - SP_MP135 = 0x00000800, - SP_MM135 = 0x00001000, - SP_MP180 = 0x00002000, - SP_TP000 = 0x00004000, - SP_UP000 = 0x00008000, - SP_UP030 = 0x00010000, - SP_UM030 = 0x00020000, - SP_UP045 = 0x00040000, - SP_UM045 = 0x00080000, - SP_UP090 = 0x00100000, - SP_UM090 = 0x00200000, - SP_UP110 = 0x00400000, - SP_UM110 = 0x00800000, - SP_UP135 = 0x01000000, - SP_UM135 = 0x02000000, - SP_UP180 = 0x04000000, - SP_BP000 = 0x08000000, - SP_BP045 = 0x10000000, - SP_BM045 = 0x20000000, - SP_LFE1 = 0x40000000, - SP_LFE2 = 0x80000000 -} BS2051_SPLABEL; - -#ifndef DISABLE_LFE_HOA -#define DISABLE_LFE_HOA 1 -#endif - -// BINAURAL feature -#ifndef ENABLE_HOA_TO_BINAURAL -#define ENABLE_HOA_TO_BINAURAL 0 -#endif - -#ifndef ENABLE_MULTICHANNEL_TO_BINAURAL -#define ENABLE_MULTICHANNEL_TO_BINAURAL 0 -#endif - -#if ENABLE_HOA_TO_BINAURAL || ENABLE_MULTICHANNEL_TO_BINAURAL - -/// maximum number of audio element == maximum source id array size -#define N_SOURCE_ELM 28 - -typedef struct { -#if ENABLE_MULTICHANNEL_TO_BINAURAL - int m2b_init; - void *m2b_api; - int m2b_elm_id[N_SOURCE_ELM]; - int m2b_source_id[N_SOURCE_ELM]; -#endif -#if ENABLE_HOA_TO_BINAURAL - int h2b_init; - void *h2b_api; - int h2b_elm_id[N_SOURCE_ELM]; - int h2b_amb_id[N_SOURCE_ELM]; - int h2b_inchs[N_SOURCE_ELM]; -#endif -} binaural_filter_t; -#endif - -typedef struct { - int init; - float c, a1, a2, a3, b1, b2; - float input_history[2], output_history[2]; -} lfe_filter_t; - -typedef struct { - IAMF_SOUND_SYSTEM system; - int lfe1; - int lfe2; -} IAMF_PREDEFINED_SP_LAYOUT; - -typedef struct { - IAMF_SOUND_SYSTEM system; - BS2051_SPLABEL sp_flags; // subset of BS2051_SPLABEL -} IAMF_CUSTOM_SP_LAYOUT; - -typedef struct { - int sp_type; // 0: predefined_sp, 1: custom_sp - union { - IAMF_PREDEFINED_SP_LAYOUT *predefined_sp; - IAMF_CUSTOM_SP_LAYOUT *custom_sp; - } sp_layout; - lfe_filter_t lfe_f; // for H2M lfe -#if ENABLE_HOA_TO_BINAURAL || ENABLE_MULTICHANNEL_TO_BINAURAL - binaural_filter_t binaural_f; -#endif -} IAMF_SP_LAYOUT; - -typedef enum { - IAMF_ZOA = 0, - IAMF_FOA = 1, - IAMF_SOA = 2, - IAMF_TOA = 3, - IAMF_H4A = 4 -} HOA_ORDER; - -typedef struct { - HOA_ORDER order; - int lfe_on; // HOA lfe on/off -} IAMF_HOA_LAYOUT; - -struct m2m_rdr_t { - IAMF_SOUND_SYSTEM in; - IAMF_SOUND_SYSTEM out; - float *mat; - int m; - int n; -}; - -struct h2m_rdr_t { - HOA_ORDER in; - IAMF_SOUND_SYSTEM out; - int channels; - int lfe1; - int lfe2; - float *mat; - int m; - int n; -}; - -// Predefined Multichannel to Multichannel -/** - * @brief Get the ear render conversion matrix of predefined multichannel to - * multichannel according to predefined direct speaker input and output layout. - * @param [in] in : predefined direct speaker input channel layout. - * @param [in] out : predefined direct speaker output channel layout - * @param [in] outMatrix : conversion matrix. - * @return @0: success,@others: fail - */ -int IAMF_element_renderer_get_M2M_matrix(IAMF_SP_LAYOUT *in, - IAMF_SP_LAYOUT *out, - struct m2m_rdr_t *outMatrix); - -/** - * @brief Get the ear render conversion matrix of custom multichannel to - * multichannel according to predefined direct speaker input and custom output - * layout. - * @param [in] in : custom speaker input layout. - * @param [in] out : predefined speaker output layout - * @param [in] outMatrix : conversion matrix. - * @param [in] chmap : speaker subset channel list in input layout. - * @return @0: success,@others: fail - */ -int IAMF_element_renderer_get_M2M_custom_matrix(IAMF_SP_LAYOUT *in, - IAMF_SP_LAYOUT *out, - struct m2m_rdr_t *outMatrix, - int *chmap); - -/** - * @brief Predefined Multichannel to Multichannel Renderer. - * @param [in] arch : architecture-specific callbacks. - * @param [in] in : the pcm signal of input. - * @param [in] out : the pcm signal of output - * @param [in] nsamples : the processed samples of pcm signal. - * @return @0: success,@others: fail - */ -int IAMF_element_renderer_render_M2M(const Arch *arch, - struct m2m_rdr_t *m2mMatrix, float *in[], - float *out[], int nsamples); - -/** - * @brief Custom Multichannel to Multichannel Renderer. - * @param [in] arch : architecture-specific callbacks. - * @param [in] in : the pcm signal of input. - * @param [in] out : the pcm signal of output - * @param [in] nsamples : the processed samples of pcm signal. - * @param [in] chmap : speaker subset channel list in input layout. - * @return @0: success,@others: fail - */ -int IAMF_element_renderer_render_M2M_custom(const Arch *arch, - struct m2m_rdr_t *m2mMatrix, - float *in[], float *out[], - int nsamples, int *chmap); -// HOA to Multichannel -#if DISABLE_LFE_HOA == 0 -void lfefilter_init(lfe_filter_t *lfe_f, float cutoff_freq, - float sampling_rate); -#endif -/** - * @brief Get the ear render conversion matrix of hoa to multichannel - * according to hoa input and direct speaker output layout. - * @param [in] in : HOA channel layout. - * @param [in] out : direct speaker output channel layout - * @param [in] outMatrix : conversion matrix. - * @return @0: success,@others: fail - */ -int IAMF_element_renderer_get_H2M_matrix(IAMF_HOA_LAYOUT *in, - IAMF_PREDEFINED_SP_LAYOUT *out, - struct h2m_rdr_t *outMatrix); - -/** - * @brief Hoa to Multichannel Renderer. - * @param [in] arch : architecture-specific callbacks. - * @param [in] in : the pcm signal of input. - * @param [in] out : the pcm signal of output - * @param [in] nsamples : the processed samples of pcm signal. - * @param [in] lfe : the filter to prcoess lfe channel. - * @return @0: success,@others: fail - */ -int IAMF_element_renderer_render_H2M(const Arch *arch, - struct h2m_rdr_t *h2mMatrix, float *in[], - float *out[], int nsamples, - lfe_filter_t *lfe); - -#if ENABLE_MULTICHANNEL_TO_BINAURAL -// Multichannel to Binaural(BEAR) -/** - * @brief Initialize the conversion filter of multichannel to binaural - * according to predefined direct speaker input layout. - * @param [in] binaural_f : the binaural filter. - * @param [in] in_layout : predefined direct speaker input channel layout - * @param [in] elm_id : the element id. - * @param [in] frame_size : the size of one pcm frame. - * @param [in] sample_rate : the sample rate of pcm signal. - */ -void IAMF_element_renderer_init_M2B(binaural_filter_t *binaural_f, - uint32_t in_layout, int sp_flags, - uint64_t elm_id, int frame_size, - int sample_rate); - -/** - * @brief De-initialize the conversion filter of multichannel to binaural. - * @param [in] binaural_f : the binaural filter. - * @param [in] elm_id : the element id. - */ -void IAMF_element_renderer_deinit_M2B(binaural_filter_t *binaural_f, - uint64_t elm_id); - -/** - * @brief Multichannel to Binaural Renderer. - * @param [in] binaural_f : the binaural filter. - * @param [in] elm_id : the element id. - * @param [in] in : the input pcm signal. - * @param [in] in : the output pcm signal. - */ -int IAMF_element_renderer_render_M2B(binaural_filter_t *binaural_f, - uint64_t elm_id, float *in[], float *out[], - int nsamples); -#endif - -#if ENABLE_HOA_TO_BINAURAL -// HOA to Binaural(Resonance) -/** - * @brief Initialize the conversion filter of hoa to binaural according to - * hoa input. - * @param [in] binaural_f : the binaural filter. - * @param [in] in_channels : the channels of input hoa. - * @param [in] elm_id : the element id. - * @param [in] frame_size : the size of one pcm frame. - * @param [in] sample_rate : the sample rate of pcm signal. - */ -void IAMF_element_renderer_init_H2B(binaural_filter_t *binaural_f, - int in_channels, uint64_t elm_id, - int frame_size, int sample_rate); - -/** - * @brief De-initialize the conversion filter of hoa to binaural. - * @param [in] binaural_f : the binaural filter. - * @param [in] elm_id : the element id. - */ -void IAMF_element_renderer_deinit_H2B(binaural_filter_t *binaural_f, - uint64_t elm_id); - -/** - * @brief HOA to Binaural Renderer. - * @param [in] binaural_f : the binaural filter. - * @param [in] elm_id : the element id. - * @param [in] in : the input pcm signal. - * @param [in] in : the output pcm signal. - */ -int IAMF_element_renderer_render_H2B(binaural_filter_t *binaural_f, - uint64_t elm_id, float *in[], float *out[], - int nsamples); -#endif - -#endif diff --git a/code/src/iamf_dec/arch.c b/code/src/iamf_dec/arch.c deleted file mode 100644 index 6da24f2f..00000000 --- a/code/src/iamf_dec/arch.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file arch.c - * @brief Collection of CPU-specific functions. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#include "arch.h" - -#include - -#include "IAMF_utils.h" -#include "arch/arch_init.h" - -Arch* arch_create() { - Arch* arch = IAMF_MALLOCZ(Arch, 1); - memset(arch, 0x0, sizeof(Arch)); - - arch_init(arch); - - return arch; -} - -void arch_destroy(Arch* arch) { IAMF_FREE(arch); } diff --git a/code/src/iamf_dec/arch.h b/code/src/iamf_dec/arch.h deleted file mode 100644 index e21411ed..00000000 --- a/code/src/iamf_dec/arch.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file arch.h - * @brief Collection of CPU-specific functions. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#ifndef ARCH_H_ -#define ARCH_H_ - -#include - -typedef struct ArchCallbacks { - // Functions with possible architecture-specific optimizations - struct { - void (*multiply_channels_by_matrix)(float *mat, int in_dim, int in_next, - int *in_idx_map, int out_dim, - int out_next, float **in, float **out, - int nsamples); - } rendering; - struct { - void (*float2int16_zip_channels)(const float *src, int next_channel, - int channels, int16_t *int16_dst, - int nsamples); - void (*float2int24_zip_channels)(const float *src, int next_channel, - int channels, uint8_t *int24_dst, - int nsamples); - void (*float2int32_zip_channels)(const float *src, int next_channel, - int channels, int32_t *int32_dst, - int nsamples); - } output; -} Arch; - -Arch *arch_create(); -void arch_destroy(Arch *arch); - -#endif /* ARCH_H_ */ diff --git a/code/src/iamf_dec/arch/arch_common.c b/code/src/iamf_dec/arch/arch_common.c deleted file mode 100644 index 4dc50ab0..00000000 --- a/code/src/iamf_dec/arch/arch_common.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file arch_common.c - * @brief C implementation for CPU-specific functions. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#include "arch_common.h" - -#include - -void multiply_channels_by_matrix_c(float *mat, int in_dim, int in_next, - int *in_idx_map, int out_dim, int out_next, - float **in, float **out, int nsamples) { - int i, in_idx, out_idx; - - if (in_dim <= 0 || out_dim <= 0) return; - - for (in_idx = 0; in_idx < in_dim; in_idx++) { - const int in_mapped_idx = in_idx_map ? in_idx_map[in_idx] : in_idx; - - for (out_idx = 0; out_idx < out_dim; out_idx++) { - const float c = mat[out_idx * out_next + in_mapped_idx * in_next]; - - for (i = 0; i < nsamples; i++) { - if (in_idx == 0) { - out[out_idx][i] = 0; - } - out[out_idx][i] += c * in[in_idx][i]; - } - } - } -} - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -static int16_t FLOAT2INT16(float x) { - x = x * (float)(1 << 15); - x = MAX(x, INT16_MIN); - x = MIN(x, INT16_MAX); - return (int16_t)lrintf(x); -} - -static int32_t FLOAT2INT24(float x) { - #define INT24_MAX (8388607) - #define INT24_MIN (-8388608) - - x = x * (float)(1 << 23); - x = MAX(x, (float)INT24_MIN); - x = MIN(x, (float)INT24_MAX); - return (int32_t)lrintf(x); -} - -static int32_t FLOAT2INT32(float x) { - // unary minus applied to maintain correct signedness - x = x * -(float)(1 << 31); - if (x > (float)INT32_MIN && x < (float)INT32_MAX) - return (int32_t)lrintf(x); - else - return (x > 0.0f ? INT32_MAX : INT32_MIN); -} - -void float2int16_zip_channels_c(const float *src, int next_channel, - int channels, int16_t *int16_dst, - int nsamples) { - int i, c; - - for (c = 0; c < channels; ++c) { - for (i = 0; i < nsamples; i++) { - int16_dst[i * channels + c] = FLOAT2INT16(src[next_channel * c + i]); - } - } -} - -void float2int24_zip_channels_c(const float *src, int next_channel, - int channels, uint8_t *int24_dst, - int nsamples) { - int i, c; - - for (c = 0; c < channels; ++c) { - for (i = 0; i < nsamples; i++) { - int32_t tmp = FLOAT2INT24(src[next_channel * c + i]); - int24_dst[(i * channels + c) * 3 + 0] = tmp & 0xff; - int24_dst[(i * channels + c) * 3 + 1] = (tmp >> 8) & 0xff; - int24_dst[(i * channels + c) * 3 + 2] = (tmp >> 16) & 0xff; - } - } -} - -void float2int32_zip_channels_c(const float *src, int next_channel, - int channels, int32_t *int32_dst, - int nsamples) { - int i, c; - - for (c = 0; c < channels; ++c) { - for (i = 0; i < nsamples; i++) { - int32_dst[i * channels + c] = FLOAT2INT32(src[next_channel * c + i]); - } - } -} diff --git a/code/src/iamf_dec/arch/arch_common.h b/code/src/iamf_dec/arch/arch_common.h deleted file mode 100644 index f3cc7efb..00000000 --- a/code/src/iamf_dec/arch/arch_common.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file arch_common.h - * @brief C implementation for CPU-specific functions. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#ifndef ARCH_COMMON_H_ -#define ARCH_COMMON_H_ - -#include - -void multiply_channels_by_matrix_c(float *mat, int in_dim, int in_next, - int *in_idx_map, int out_dim, int out_next, - float **in, float **out, int nsamples); - -void float2int16_zip_channels_c(const float *src, int next_channel, - int channels, int16_t *int16_dst, int nsamples); - -void float2int24_zip_channels_c(const float *src, int next_channel, - int channels, uint8_t *int24_dst, int nsamples); - -void float2int32_zip_channels_c(const float *src, int next_channel, - int channels, int32_t *int32_dst, int nsamples); - -#endif /* ARCH_COMMON_H_ */ diff --git a/code/src/iamf_dec/arch/arch_init.c b/code/src/iamf_dec/arch/arch_init.c deleted file mode 100644 index 6b6a7ea2..00000000 --- a/code/src/iamf_dec/arch/arch_init.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file arch_init.c - * @brief Init CPU-specific function callbacks. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#include "arch_init.h" - -#include - -#include "arch.h" -#include "arch_common.h" - -// To add new architecture 'ABC', follow the following pattern: -// * add arch/ABC subfolder, with detect_ABC.h -// * inside detect_ABC.h, if ABC target detected, define IAMF_ARCH_DETECTED_ABC, -// and implement arch_override(...) function -// * all files under arch/ABC must include detect_ABC.h, and be surrounded with -// #if defined(IAMF_ARCH_DETECTED_ABC) -#include "arm/detect_arm.h" -#include "x86/detect_x86.h" -#if defined(IAMF_ARCH_DETECTED_ARM) || defined(IAMF_ARCH_DETECTED_X86) -#define HAS_ARCH_OVERRIDE (1) -#endif - -#if defined(HAS_ARCH_OVERRIDE) -// Implemented in each architecture-specific subfolder, -// behind IAMF_ARCH_DETECTED_... ifdef -void arch_override(Arch* arch); -#endif - -void arch_init(Arch* arch) { - memset(arch, 0x0, sizeof(Arch)); - - // Fill with reference implementations - arch->rendering.multiply_channels_by_matrix = &multiply_channels_by_matrix_c; - - arch->output.float2int16_zip_channels = &float2int16_zip_channels_c; - arch->output.float2int24_zip_channels = &float2int24_zip_channels_c; - arch->output.float2int32_zip_channels = &float2int32_zip_channels_c; - -#if defined(HAS_ARCH_OVERRIDE) - // Override with platform-specific functions, if available - arch_override(arch); -#endif -} diff --git a/code/src/iamf_dec/arch/arch_init.h b/code/src/iamf_dec/arch/arch_init.h deleted file mode 100644 index ee101d09..00000000 --- a/code/src/iamf_dec/arch/arch_init.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file arch_init.h - * @brief Init CPU-specific function callbacks. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#ifndef ARCH_INIT_H_ -#define ARCH_INIT_H_ - -typedef struct ArchCallbacks Arch; - -void arch_init(Arch* arch); - -#endif /* ARCH_INIT_H_ */ diff --git a/code/src/iamf_dec/arch/arm/arm_multiply_channels.c b/code/src/iamf_dec/arch/arm/arm_multiply_channels.c deleted file mode 100644 index 0b0bdad2..00000000 --- a/code/src/iamf_dec/arch/arm/arm_multiply_channels.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file arm_multiply_channels.c - * @brief Arm implementation for multiplying channels. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#include "arm_multiply_channels.h" - -#if defined(IAMF_ARCH_DETECTED_ARM) - -#include - -#if defined(__aarch64__) -#define USE_16_ACCUMULATORS (1) -#endif - -void multiply_channels_by_matrix_neon(float* mat, int in_dim, int in_next, - int* in_idx_map, int out_dim, - int out_next, float** in, float** out, - int nsamples) { - int i = 0, out_idx, in_idx; - - if (in_dim <= 0 || out_dim <= 0) return; -#ifdef USE_16_ACCUMULATORS - const int BLOCK_SIZE = 32; -#else - const int BLOCK_SIZE = 16; -#endif - - const int blocked_size = nsamples / BLOCK_SIZE * BLOCK_SIZE; - - for (i = 0; i < blocked_size; i += BLOCK_SIZE) { - for (out_idx = 0; out_idx < (out_dim & ~1); out_idx += 2) { - float* outPtr_a = out[out_idx + 0] + i; - float* outPtr_b = out[out_idx + 1] + i; - - float32x4_t sum_a1 = vdupq_n_f32(0.0f); - float32x4_t sum_a2 = vdupq_n_f32(0.0f); - float32x4_t sum_a3 = vdupq_n_f32(0.0f); - float32x4_t sum_a4 = vdupq_n_f32(0.0f); -#ifdef USE_16_ACCUMULATORS - float32x4_t sum_a5 = vdupq_n_f32(0.0f); - float32x4_t sum_a6 = vdupq_n_f32(0.0f); - float32x4_t sum_a7 = vdupq_n_f32(0.0f); - float32x4_t sum_a8 = vdupq_n_f32(0.0f); -#endif - - float32x4_t sum_b1 = vdupq_n_f32(0.0f); - float32x4_t sum_b2 = vdupq_n_f32(0.0f); - float32x4_t sum_b3 = vdupq_n_f32(0.0f); - float32x4_t sum_b4 = vdupq_n_f32(0.0f); -#ifdef USE_16_ACCUMULATORS - float32x4_t sum_b5 = vdupq_n_f32(0.0f); - float32x4_t sum_b6 = vdupq_n_f32(0.0f); - float32x4_t sum_b7 = vdupq_n_f32(0.0f); - float32x4_t sum_b8 = vdupq_n_f32(0.0f); -#endif - - for (in_idx = 0; in_idx < in_dim; in_idx++) { - const int in_mapped_idx = in_idx_map ? in_idx_map[in_idx] : in_idx; - const int c_a_offset = out_idx * out_next + in_mapped_idx * in_next; - const int c_b_offset = c_a_offset + out_next; - const float* inPtr = in[in_idx] + i; - - float32x4_t c_a = vld1q_dup_f32(&mat[c_a_offset]); - float32x4_t c_b = vld1q_dup_f32(&mat[c_b_offset]); - - float32x4_t in_1 = vld1q_f32(inPtr + 0); - float32x4_t in_2 = vld1q_f32(inPtr + 4); - float32x4_t in_3 = vld1q_f32(inPtr + 8); - float32x4_t in_4 = vld1q_f32(inPtr + 12); -#ifdef USE_16_ACCUMULATORS - float32x4_t in_5 = vld1q_f32(inPtr + 16); - float32x4_t in_6 = vld1q_f32(inPtr + 20); - float32x4_t in_7 = vld1q_f32(inPtr + 24); - float32x4_t in_8 = vld1q_f32(inPtr + 28); -#endif - - sum_a1 = vmlaq_f32(sum_a1, c_a, in_1); - sum_a2 = vmlaq_f32(sum_a2, c_a, in_2); - sum_a3 = vmlaq_f32(sum_a3, c_a, in_3); - sum_a4 = vmlaq_f32(sum_a4, c_a, in_4); -#ifdef USE_16_ACCUMULATORS - sum_a5 = vmlaq_f32(sum_a5, c_a, in_5); - sum_a6 = vmlaq_f32(sum_a6, c_a, in_6); - sum_a7 = vmlaq_f32(sum_a7, c_a, in_7); - sum_a8 = vmlaq_f32(sum_a8, c_a, in_8); -#endif - - sum_b1 = vmlaq_f32(sum_b1, c_b, in_1); - sum_b2 = vmlaq_f32(sum_b2, c_b, in_2); - sum_b3 = vmlaq_f32(sum_b3, c_b, in_3); - sum_b4 = vmlaq_f32(sum_b4, c_b, in_4); -#ifdef USE_16_ACCUMULATORS - sum_b5 = vmlaq_f32(sum_b5, c_b, in_5); - sum_b6 = vmlaq_f32(sum_b6, c_b, in_6); - sum_b7 = vmlaq_f32(sum_b7, c_b, in_7); - sum_b8 = vmlaq_f32(sum_b8, c_b, in_8); -#endif - } - - vst1q_f32(outPtr_a + 0, sum_a1); - vst1q_f32(outPtr_a + 4, sum_a2); - vst1q_f32(outPtr_a + 8, sum_a3); - vst1q_f32(outPtr_a + 12, sum_a4); -#ifdef USE_16_ACCUMULATORS - vst1q_f32(outPtr_a + 16, sum_a5); - vst1q_f32(outPtr_a + 20, sum_a6); - vst1q_f32(outPtr_a + 24, sum_a7); - vst1q_f32(outPtr_a + 28, sum_a8); -#endif - - vst1q_f32(outPtr_b + 0, sum_b1); - vst1q_f32(outPtr_b + 4, sum_b2); - vst1q_f32(outPtr_b + 8, sum_b3); - vst1q_f32(outPtr_b + 12, sum_b4); -#ifdef USE_16_ACCUMULATORS - vst1q_f32(outPtr_b + 16, sum_b5); - vst1q_f32(outPtr_b + 20, sum_b6); - vst1q_f32(outPtr_b + 24, sum_b7); - vst1q_f32(outPtr_b + 28, sum_b8); -#endif - } - - if (out_dim & 1) { - out_idx = out_dim - 1; - float* outPtr = out[out_idx] + i; - - float32x4_t sum_1 = vdupq_n_f32(0.0f); - float32x4_t sum_2 = vdupq_n_f32(0.0f); - float32x4_t sum_3 = vdupq_n_f32(0.0f); - float32x4_t sum_4 = vdupq_n_f32(0.0f); -#ifdef USE_16_ACCUMULATORS - float32x4_t sum_5 = vdupq_n_f32(0.0f); - float32x4_t sum_6 = vdupq_n_f32(0.0f); - float32x4_t sum_7 = vdupq_n_f32(0.0f); - float32x4_t sum_8 = vdupq_n_f32(0.0f); -#endif - - for (in_idx = 0; in_idx < in_dim; in_idx++) { - const int in_mapped_idx = in_idx_map ? in_idx_map[in_idx] : in_idx; - const int c_offset = out_idx * out_next + in_mapped_idx * in_next; - const float* inPtr = in[in_idx] + i; - - float32x4_t c = vld1q_dup_f32(&mat[c_offset]); - - float32x4_t in_1 = vld1q_f32(inPtr + 0); - float32x4_t in_2 = vld1q_f32(inPtr + 4); - float32x4_t in_3 = vld1q_f32(inPtr + 8); - float32x4_t in_4 = vld1q_f32(inPtr + 12); -#ifdef USE_16_ACCUMULATORS - float32x4_t in_5 = vld1q_f32(inPtr + 16); - float32x4_t in_6 = vld1q_f32(inPtr + 20); - float32x4_t in_7 = vld1q_f32(inPtr + 24); - float32x4_t in_8 = vld1q_f32(inPtr + 28); -#endif - - sum_1 = vmlaq_f32(sum_1, c, in_1); - sum_2 = vmlaq_f32(sum_2, c, in_2); - sum_3 = vmlaq_f32(sum_3, c, in_3); - sum_4 = vmlaq_f32(sum_4, c, in_4); -#ifdef USE_16_ACCUMULATORS - sum_5 = vmlaq_f32(sum_5, c, in_5); - sum_6 = vmlaq_f32(sum_6, c, in_6); - sum_7 = vmlaq_f32(sum_7, c, in_7); - sum_8 = vmlaq_f32(sum_8, c, in_8); -#endif - } - vst1q_f32(outPtr + 0, sum_1); - vst1q_f32(outPtr + 4, sum_2); - vst1q_f32(outPtr + 8, sum_3); - vst1q_f32(outPtr + 12, sum_4); -#ifdef USE_16_ACCUMULATORS - vst1q_f32(outPtr + 16, sum_5); - vst1q_f32(outPtr + 20, sum_6); - vst1q_f32(outPtr + 24, sum_7); - vst1q_f32(outPtr + 28, sum_8); -#endif - } - } - - for (in_idx = 0; in_idx < in_dim; in_idx++) { - const int in_mapped_idx = in_idx_map ? in_idx_map[in_idx] : in_idx; - - for (out_idx = 0; out_idx < out_dim; out_idx++) { - const float c = mat[out_idx * out_next + in_mapped_idx * in_next]; - - for (i = blocked_size; i < nsamples; i++) { - if (in_idx == 0) { - out[out_idx][i] = 0; - } - out[out_idx][i] += c * in[in_idx][i]; - } - } - } -} - -#endif /* IAMF_ARCH_DETECTED_ARM */ diff --git a/code/src/iamf_dec/arch/arm/arm_multiply_channels.h b/code/src/iamf_dec/arch/arm/arm_multiply_channels.h deleted file mode 100644 index c1dcd6b4..00000000 --- a/code/src/iamf_dec/arch/arm/arm_multiply_channels.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file arm_multiply_channels.h - * @brief Arm implementation for multiplying channels. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#ifndef ARM_MULTIPLY_CHANNELS_H_ -#define ARM_MULTIPLY_CHANNELS_H_ - -#include "detect_arm.h" - -#if defined(IAMF_ARCH_DETECTED_ARM) - -void multiply_channels_by_matrix_neon(float *mat, int in_dim, int in_next, - int *in_idx_map, int out_dim, - int out_next, float **in, float **out, - int nsamples); - -#endif /* IAMF_ARCH_DETECTED_ARM */ -#endif /* ARM_MULTIPLY_CHANNELS_H_ */ diff --git a/code/src/iamf_dec/arch/arm/arm_zip_channels.c b/code/src/iamf_dec/arch/arm/arm_zip_channels.c deleted file mode 100644 index e2def168..00000000 --- a/code/src/iamf_dec/arch/arm/arm_zip_channels.c +++ /dev/null @@ -1,811 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file arm_zip_channels.c - * @brief Arm implementation for zipping channels. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#include "arm_zip_channels.h" - -#if defined(IAMF_ARCH_DETECTED_ARM) - -#include -#include - -#include "../arch_common.h" - -#define MUL_16BIT 32768.0f - -#define MUL_24BIT 8388608.f -#define RANGE_MIN_24BIT -8388608 -#define RANGE_MAX_24BIT 8388607 - -#define MUL_32BIT 2147483648.f - -static inline int32x4_t vroundf(float32x4_t x) -{ -#if defined(__ARM_ARCH) && __ARM_ARCH >= 8 - return vcvtaq_s32_f32(x); -#else - uint32x4_t sign = vandq_u32(vreinterpretq_u32_f32(x), vdupq_n_u32(0x80000000)); - uint32x4_t bias = vdupq_n_u32(0x3F000000); - return vcvtq_s32_f32(vaddq_f32(x, vreinterpretq_f32_u32(vorrq_u32(bias, sign)))); -#endif -} - -static inline int16x4_t cvt_for_int16(float32x4_t vals) { - return vqmovn_s32(vroundf(vmulq_n_f32(vals, MUL_16BIT))); -} - -static inline int16x8x2_t cvt_for_int16_x2(float32x4x2_t vals0, - float32x4x2_t vals1) { - int16x8x2_t ret; - ret.val[0] = - vcombine_s16(cvt_for_int16(vals0.val[0]), cvt_for_int16(vals0.val[1])); - ret.val[1] = - vcombine_s16(cvt_for_int16(vals1.val[0]), cvt_for_int16(vals1.val[1])); - return ret; -} - -static inline int16x8x3_t cvt_for_int16_x3(float32x4x2_t vals0, - float32x4x2_t vals1, - float32x4x2_t vals2) { - int16x8x3_t ret; - ret.val[0] = - vcombine_s16(cvt_for_int16(vals0.val[0]), cvt_for_int16(vals0.val[1])); - ret.val[1] = - vcombine_s16(cvt_for_int16(vals1.val[0]), cvt_for_int16(vals1.val[1])); - ret.val[2] = - vcombine_s16(cvt_for_int16(vals2.val[0]), cvt_for_int16(vals2.val[1])); - return ret; -} - -static inline int32x4_t cvt_clamp_for_int24_s32(int32x4_t lower, - float32x4_t vals, - int32x4_t upper) { - return vmaxq_s32( - vminq_s32(vroundf(vmulq_n_f32(vals, MUL_24BIT)), upper), lower); -} - -static inline uint8x16_t cvt_clamp_for_int24_u8(int32x4_t lower, - float32x4_t vals, - int32x4_t upper) { - return vreinterpretq_u8_s32(vmaxq_s32( - vminq_s32(vroundf(vmulq_n_f32(vals, MUL_24BIT)), upper), lower)); -} - -static inline void write_consecutive_int24(uint8_t *ptr, uint8x8_t firstPart, - uint8_t secondPart) { - vst1_u8(ptr, firstPart); - ptr[8] = secondPart; -} - -static inline void write_pair_int24(uint8_t *ptr, int step, uint64_t val) { - ptr[0] = (uint8_t)((val >> 0) & 0xff); - ptr[1] = (uint8_t)((val >> 8) & 0xff); - ptr[2] = (uint8_t)((val >> 16) & 0xff); - - ptr[step + 0] = (uint8_t)((val >> 32) & 0xff); - ptr[step + 1] = (uint8_t)((val >> 40) & 0xff); - ptr[step + 2] = (uint8_t)((val >> 48) & 0xff); -} - -static inline int32x4_t cvt_for_int32(float32x4_t vals) { - return vroundf(vmulq_n_f32(vals, MUL_32BIT)); -} - -static inline int32x4x2_t cvt_for_int32_x2(float32x4_t vals0, - float32x4_t vals1) { - int32x4x2_t ret; - ret.val[0] = cvt_for_int32(vals0); - ret.val[1] = cvt_for_int32(vals1); - return ret; -} - -static inline int32x4x3_t cvt_for_int32_x3(float32x4_t vals0, float32x4_t vals1, - float32x4_t vals2) { - int32x4x3_t ret; - ret.val[0] = cvt_for_int32(vals0); - ret.val[1] = cvt_for_int32(vals1); - ret.val[2] = cvt_for_int32(vals2); - return ret; -} - -static inline int16x4x4_t transpose_s16_4x4(const int16x4_t a, const int16x4_t b, const int16x4_t c, - const int16x4_t d) { - int16x8_t aq = vcombine_s16(a, vdup_n_s16(0)); - int16x8_t bq = vcombine_s16(b, vdup_n_s16(0)); - int16x8_t cq = vcombine_s16(c, vdup_n_s16(0)); - int16x8_t dq = vcombine_s16(d, vdup_n_s16(0)); - - int16x8_t ac = vzipq_s16(aq, cq).val[0]; - int16x8_t bd = vzipq_s16(bq, dq).val[0]; - - int16x8x2_t abcd = vzipq_s16(ac, bd); - - int16x4x4_t ret = {{ - vget_low_s16(abcd.val[0]), - vget_high_s16(abcd.val[0]), - vget_low_s16(abcd.val[1]), - vget_high_s16(abcd.val[1]) - }}; - return ret; -} - -static inline int32x4x2_t vtrnq_s64_to_s32(int32x4_t a0, int32x4_t a1) { - int32x4x2_t b0; -#if defined(__aarch64__) - b0.val[0] = vreinterpretq_s32_s64( - vtrn1q_s64(vreinterpretq_s64_s32(a0), vreinterpretq_s64_s32(a1))); - b0.val[1] = vreinterpretq_s32_s64( - vtrn2q_s64(vreinterpretq_s64_s32(a0), vreinterpretq_s64_s32(a1))); -#else - b0.val[0] = vcombine_s32(vget_low_s32(a0), vget_low_s32(a1)); - b0.val[1] = vcombine_s32(vget_high_s32(a0), vget_high_s32(a1)); -#endif - return b0; -} - -static inline int32x4x4_t transpose_s32_4x4(int32x4_t a, int32x4_t b, int32x4_t c, - int32x4_t d) { - const int32x4x2_t trn_ab = vtrnq_s32(a, b); - const int32x4x2_t trn_cd = vtrnq_s32(c, d); - - const int32x4x2_t r0 = vtrnq_s64_to_s32(trn_ab.val[0], trn_cd.val[0]); - const int32x4x2_t r1 = vtrnq_s64_to_s32(trn_ab.val[1], trn_cd.val[1]); - - int32x4x4_t ret; - ret.val[0] = r0.val[0]; - ret.val[1] = r1.val[0]; - ret.val[2] = r0.val[1]; - ret.val[3] = r1.val[1]; - return ret; -} - -static int float2int16_zip_1channels(const float *src, int16_t *int16_dst, - int nsamples) { - const int BLOCK_SIZE = 32; - const int blocked_size = nsamples / BLOCK_SIZE * BLOCK_SIZE; - int i; - - for (i = 0; i < blocked_size; i += BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + i + 0), vld1q_f32(src + i + 4) } }; - float32x4x2_t in_a_23 = { { vld1q_f32(src + i + 8), vld1q_f32(src + i + 12) } }; - float32x4x2_t in_a_45 = { { vld1q_f32(src + i + 16), vld1q_f32(src + i + 20) } }; - float32x4x2_t in_a_67 = { { vld1q_f32(src + i + 24), vld1q_f32(src + i + 28) } }; - - int16x8x2_t out_01 = cvt_for_int16_x2(in_a_01, in_a_23); - int16x8x2_t out_23 = cvt_for_int16_x2(in_a_45, in_a_67); - - vst1q_s16(int16_dst + i + 0, out_01.val[0]); - vst1q_s16(int16_dst + i + 8, out_01.val[1]); - vst1q_s16(int16_dst + i + 16, out_23.val[0]); - vst1q_s16(int16_dst + i + 24, out_23.val[1]); - } - - return blocked_size; -} - -static int float2int16_zip_2channels(const float *src, int next_channel, - int16_t *int16_dst, int nsamples) { - const int BLOCK_SIZE = 16; - const int blocked_size = nsamples / BLOCK_SIZE * BLOCK_SIZE; - int i; - - for (i = 0; i < blocked_size; i += BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + i + 0), vld1q_f32(src + i + 4) } }; - float32x4x2_t in_a_23 = { { vld1q_f32(src + i + 8), vld1q_f32(src + i + 12) } }; - float32x4x2_t in_b_01 = { { vld1q_f32(src + i + next_channel + 0), vld1q_f32(src + i + next_channel + 4) } }; - float32x4x2_t in_b_23 = { { vld1q_f32(src + i + next_channel + 8), vld1q_f32(src + i + next_channel + 12) } }; - - int16x8x2_t out_ab_01 = cvt_for_int16_x2(in_a_01, in_b_01); - int16x8x2_t out_ab_23 = cvt_for_int16_x2(in_a_23, in_b_23); - - vst2q_s16(int16_dst + i * 2 + 0, out_ab_01); - vst2q_s16(int16_dst + i * 2 + 16, out_ab_23); - } - - return blocked_size; -} - -static int float2int16_zip_3channels(const float *src, int next_channel, - int16_t *int16_dst, int nsamples) { - const int BLOCK_SIZE = 16; - const int blocked_size = nsamples / BLOCK_SIZE * BLOCK_SIZE; - int i; - - for (i = 0; i < blocked_size; i += BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + i + 0 * next_channel + 0), vld1q_f32(src + i + 0 * next_channel + 4) } }; - float32x4x2_t in_a_23 = { { vld1q_f32(src + i + 0 * next_channel + 8), vld1q_f32(src + i + 0 * next_channel + 12) } }; - float32x4x2_t in_b_01 = { { vld1q_f32(src + i + 1 * next_channel + 0), vld1q_f32(src + i + 1 * next_channel + 4) } }; - float32x4x2_t in_b_23 = { { vld1q_f32(src + i + 1 * next_channel + 8), vld1q_f32(src + i + 1 * next_channel + 12) } }; - float32x4x2_t in_c_01 = { { vld1q_f32(src + i + 2 * next_channel + 0), vld1q_f32(src + i + 2 * next_channel + 4) } }; - float32x4x2_t in_c_23 = { { vld1q_f32(src + i + 2 * next_channel + 8), vld1q_f32(src + i + 2 * next_channel + 12) } }; - - int16x8x3_t out_abc_01 = cvt_for_int16_x3(in_a_01, in_b_01, in_c_01); - int16x8x3_t out_abc_23 = cvt_for_int16_x3(in_a_23, in_b_23, in_c_23); - - vst3q_s16(int16_dst + i * 3 + 0, out_abc_01); - vst3q_s16(int16_dst + i * 3 + 24, out_abc_23); - } - - return blocked_size; -} - -static int float2int16_zip_nchannels(const float *src, int next_channel, - int channels, int16_t *int16_dst, - int nsamples) { - const int BATCH = 4; - const int BATCHED_BLOCK_SIZE = 8; - const int SINGLE_BLOCK_SIZE = 16; - const int bathed_channels = channels / BATCH * BATCH; - const int blocked_size = nsamples / BATCHED_BLOCK_SIZE * BATCHED_BLOCK_SIZE / - SINGLE_BLOCK_SIZE * SINGLE_BLOCK_SIZE; - - int i, c; - - for (c = 0; c < bathed_channels; c += BATCH) { - for (i = 0; i < blocked_size; i += BATCHED_BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + next_channel * (c + 0) + i), vld1q_f32(src + next_channel * (c + 0) + i + 4) } }; - float32x4x2_t in_b_01 = { { vld1q_f32(src + next_channel * (c + 1) + i), vld1q_f32(src + next_channel * (c + 1) + i + 4) } }; - float32x4x2_t in_c_01 = { { vld1q_f32(src + next_channel * (c + 2) + i), vld1q_f32(src + next_channel * (c + 2) + i + 4) } }; - float32x4x2_t in_d_01 = { { vld1q_f32(src + next_channel * (c + 3) + i), vld1q_f32(src + next_channel * (c + 3) + i + 4) } }; - - int16x4_t s32_a_0 = cvt_for_int16(in_a_01.val[0]); - int16x4_t s32_b_0 = cvt_for_int16(in_b_01.val[0]); - int16x4_t s32_c_0 = cvt_for_int16(in_c_01.val[0]); - int16x4_t s32_d_0 = cvt_for_int16(in_d_01.val[0]); - int16x4_t s32_a_1 = cvt_for_int16(in_a_01.val[1]); - int16x4_t s32_b_1 = cvt_for_int16(in_b_01.val[1]); - int16x4_t s32_c_1 = cvt_for_int16(in_c_01.val[1]); - int16x4_t s32_d_1 = cvt_for_int16(in_d_01.val[1]); - - int16x4x4_t transposed_abcd_0 = - transpose_s16_4x4(s32_a_0, s32_b_0, s32_c_0, s32_d_0); - int16x4x4_t transposed_abcd_1 = - transpose_s16_4x4(s32_a_1, s32_b_1, s32_c_1, s32_d_1); - - int16_t *ptr = int16_dst + i * channels + c; - const int step = channels; - vst1_s16(ptr + step * 0, transposed_abcd_0.val[0]); - vst1_s16(ptr + step * 1, transposed_abcd_0.val[1]); - vst1_s16(ptr + step * 2, transposed_abcd_0.val[2]); - vst1_s16(ptr + step * 3, transposed_abcd_0.val[3]); - vst1_s16(ptr + step * 4, transposed_abcd_1.val[0]); - vst1_s16(ptr + step * 5, transposed_abcd_1.val[1]); - vst1_s16(ptr + step * 6, transposed_abcd_1.val[2]); - vst1_s16(ptr + step * 7, transposed_abcd_1.val[3]); - } - } - - for (c = bathed_channels; c < channels; ++c) { - for (i = 0; i < blocked_size; i += SINGLE_BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + next_channel * c + i + 0), vld1q_f32(src + next_channel * c + i + 4) } }; - float32x4x2_t in_a_23 = { { vld1q_f32(src + next_channel * c + i + 8), vld1q_f32(src + next_channel * c + i + 12) } }; - - uint64_t out_a_0 = - vget_lane_u64(vreinterpret_u64_s16(cvt_for_int16(in_a_01.val[0])), 0); - int64_t out_a_1 = - vget_lane_u64(vreinterpret_u64_s16(cvt_for_int16(in_a_01.val[1])), 0); - int64_t out_a_2 = - vget_lane_u64(vreinterpret_u64_s16(cvt_for_int16(in_a_23.val[0])), 0); - int64_t out_a_3 = - vget_lane_u64(vreinterpret_u64_s16(cvt_for_int16(in_a_23.val[1])), 0); - - int16_t *ptr = int16_dst + i * channels + c; - const int step = channels; - ptr[step * 0] = (int16_t)((out_a_0 >> 0) & 0xffff); - ptr[step * 1] = (int16_t)((out_a_0 >> 16) & 0xffff); - ptr[step * 2] = (int16_t)((out_a_0 >> 32) & 0xffff); - ptr[step * 3] = (int16_t)((out_a_0 >> 48) & 0xffff); - ptr[step * 4] = (int16_t)((out_a_1 >> 0) & 0xffff); - ptr[step * 5] = (int16_t)((out_a_1 >> 16) & 0xffff); - ptr[step * 6] = (int16_t)((out_a_1 >> 32) & 0xffff); - ptr[step * 7] = (int16_t)((out_a_1 >> 48) & 0xffff); - ptr[step * 8] = (int16_t)((out_a_2 >> 0) & 0xffff); - ptr[step * 9] = (int16_t)((out_a_2 >> 16) & 0xffff); - ptr[step * 10] = (int16_t)((out_a_2 >> 32) & 0xffff); - ptr[step * 11] = (int16_t)((out_a_2 >> 48) & 0xffff); - ptr[step * 12] = (int16_t)((out_a_3 >> 0) & 0xffff); - ptr[step * 13] = (int16_t)((out_a_3 >> 16) & 0xffff); - ptr[step * 14] = (int16_t)((out_a_3 >> 32) & 0xffff); - ptr[step * 15] = (int16_t)((out_a_3 >> 48) & 0xffff); - } - } - - return blocked_size; -} - -static inline uint8x8_t tbl2(uint8x16_t a, uint8x16_t b, uint8x8_t idx) { -#if defined(__aarch64__) - uint8x16x2_t table = { { a, b } }; - return vqtbl2_u8(table, idx); -#else - uint8x8x4_t table = { { vget_low_u8(a), vget_high_u8(a), vget_low_u8(b), - vget_high_u8(b) } }; - return vtbl4_u8(table, idx); -#endif -} - -static inline uint8x16_t tbl2q(uint8x16_t a, uint8x16_t b, uint8x16_t idx) { -#if defined(__aarch64__) - uint8x16x2_t table = { { a, b } }; - return vqtbl2q_u8(table, idx); -#else - uint8x8x4_t table = { { vget_low_u8(a), vget_high_u8(a), vget_low_u8(b), - vget_high_u8(b) } }; - return vcombine_u8(vtbl4_u8(table, vget_low_u8(idx)), - vtbl4_u8(table, vget_high_u8(idx))); -#endif -} - -static int float2int24_zip_1channels(const float *src, uint8_t *int24_dst, - int nsamples) { - const int BLOCK_SIZE = 8; - const int blocked_size = nsamples / BLOCK_SIZE * BLOCK_SIZE; - - int i; - - static uint8_t MAP01[] = {0, 1, 2, 4, 5, 6, 8, 9, - 10, 12, 13, 14, 16, 17, 18, 20}; - static uint8_t MAP2[] = {21, 22, 24, 25, 26, 28, 29, 30, - 0, 0, 0, 0, 0, 0, 0, 0}; - uint8x16_t map01 = vld1q_u8(MAP01); - uint8x16_t map2 = vld1q_u8(MAP2); - int32x4_t min24 = vdupq_n_s32(RANGE_MIN_24BIT); - int32x4_t max24 = vdupq_n_s32(RANGE_MAX_24BIT); - - for (i = 0; i < blocked_size; i += BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + i), vld1q_f32(src + i + 4) } }; - - uint8x16x2_t u8_a_01; - u8_a_01.val[0] = cvt_clamp_for_int24_u8(min24, in_a_01.val[0], max24); - u8_a_01.val[1] = cvt_clamp_for_int24_u8(min24, in_a_01.val[1], max24); - - uint8x16_t out_01 = tbl2q(u8_a_01.val[0], u8_a_01.val[1], map01); - uint8x8_t out_2 = vget_low_u8(tbl2q(u8_a_01.val[0], u8_a_01.val[1], map2)); - - vst1q_u8(int24_dst + i * 3 + 0, out_01); - vst1_u8(int24_dst + i * 3 + 16, out_2); - } - - return blocked_size; -} - -static int float2int24_zip_2channels(const float *src, int next_channel, - uint8_t *int24_dst, int nsamples) { - const int BLOCK_SIZE = 4; - const int blocked_size = nsamples / BLOCK_SIZE * BLOCK_SIZE; - - int i; - - static uint8_t MAP01[] = {0, 1, 2, 16, 17, 18, 4, 5, - 6, 20, 21, 22, 8, 9, 10, 24}; - static uint8_t MAP2[] = {25, 26, 12, 13, 14, 28, 29, 30, - 0, 0, 0, 0, 0, 0, 0, 0}; - uint8x16_t map01 = vld1q_u8(MAP01); - uint8x16_t map2 = vld1q_u8(MAP2); - int32x4_t min24 = vdupq_n_s32(RANGE_MIN_24BIT); - int32x4_t max24 = vdupq_n_s32(RANGE_MAX_24BIT); - - for (i = 0; i < blocked_size; i += BLOCK_SIZE) { - float32x4_t in_a_0 = vld1q_f32(src + i); - float32x4_t in_b_0 = vld1q_f32(src + next_channel + i); - - uint8x16x2_t u8_ab_0; - u8_ab_0.val[0] = cvt_clamp_for_int24_u8(min24, in_a_0, max24); - u8_ab_0.val[1] = cvt_clamp_for_int24_u8(min24, in_b_0, max24); - - uint8x16_t out_firstpart_ab_0 = tbl2q(u8_ab_0.val[0], u8_ab_0.val[1], map01); - uint8x8_t out_secondpart_ab_0 = vget_low_u8(tbl2q(u8_ab_0.val[0], u8_ab_0.val[1], map2)); - - vst1q_u8(int24_dst + (i * 2 + 0) * 3 + 0 + 0, out_firstpart_ab_0); - vst1_u8(int24_dst + (i * 2 + 0) * 3 + 15 + 1, out_secondpart_ab_0); - } - - return blocked_size; -} - -static inline uint8x16_t tbl1q(uint8x16_t a, uint8x16_t idx) { -#if defined(__aarch64__) - return vqtbl1q_u8(a, idx); -#else - uint8x8x2_t table = { { vget_low_u8(a), vget_high_u8(a) } }; - uint8x8_t lo = vtbl2_u8(table, vget_low_u8(idx)); - uint8x8_t hi = vtbl2_u8(table, vget_high_u8(idx)); - return vcombine_u8(lo, hi); -#endif -} - -static int float2int24_zip_nchannels(const float *src, int next_channel, - int channels, uint8_t *int24_dst, - int nsamples) { - const int BATCH = 3; - const int BATCHED_BLOCK_SIZE = 8; - const int SINGLE_BLOCK_SIZE = 8; - const int bathed_channels = channels / BATCH * BATCH; - const int blocked_size = nsamples / BATCHED_BLOCK_SIZE * BATCHED_BLOCK_SIZE / - SINGLE_BLOCK_SIZE * SINGLE_BLOCK_SIZE; - - int i, c; - - static uint8_t MAP01[] = {0, 1, 2, 4, 5, 6, 8, 9, - 10, 12, 13, 14, 16, 17, 18, 20}; - uint8x16_t map01 = vld1q_u8(MAP01); - int32x4_t min24 = vdupq_n_s32(RANGE_MIN_24BIT); - int32x4_t max24 = vdupq_n_s32(RANGE_MAX_24BIT); - - for (c = 0; c < bathed_channels; c += BATCH) { - for (i = 0; i < blocked_size; i += BATCHED_BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + next_channel * (c + 0) + i), vld1q_f32(src + next_channel * (c + 0) + i + 4) } }; - float32x4x2_t in_b_01 = { { vld1q_f32(src + next_channel * (c + 1) + i), vld1q_f32(src + next_channel * (c + 1) + i + 4) } }; - float32x4x2_t in_c_01 = { { vld1q_f32(src + next_channel * (c + 2) + i), vld1q_f32(src + next_channel * (c + 2) + i + 4) } }; - - int32x4_t s32_a_0 = cvt_clamp_for_int24_s32(min24, in_a_01.val[0], max24); - int32x4_t s32_b_0 = cvt_clamp_for_int24_s32(min24, in_b_01.val[0], max24); - int32x4_t s32_c_0 = cvt_clamp_for_int24_s32(min24, in_c_01.val[0], max24); - - int32x4_t s32_a_1 = cvt_clamp_for_int24_s32(min24, in_a_01.val[1], max24); - int32x4_t s32_b_1 = cvt_clamp_for_int24_s32(min24, in_b_01.val[1], max24); - int32x4_t s32_c_1 = cvt_clamp_for_int24_s32(min24, in_c_01.val[1], max24); - int32x4_t zeros = vdupq_n_s32(0); - - int32x4x4_t transposed_abcd_0 = - transpose_s32_4x4(s32_a_0, s32_b_0, s32_c_0, zeros); - uint8x16_t out_full_0 = vreinterpretq_u8_s32(transposed_abcd_0.val[0]); - uint8x16_t out_full_1 = vreinterpretq_u8_s32(transposed_abcd_0.val[1]); - uint8x16_t out_full_2 = vreinterpretq_u8_s32(transposed_abcd_0.val[2]); - uint8x16_t out_full_3 = vreinterpretq_u8_s32(transposed_abcd_0.val[3]); - - int32x4x4_t transposed_abcd_1 = - transpose_s32_4x4(s32_a_1, s32_b_1, s32_c_1, zeros); - uint8x16_t out_full_4 = vreinterpretq_u8_s32(transposed_abcd_1.val[0]); - uint8x16_t out_full_5 = vreinterpretq_u8_s32(transposed_abcd_1.val[1]); - uint8x16_t out_full_6 = vreinterpretq_u8_s32(transposed_abcd_1.val[2]); - uint8x16_t out_full_7 = vreinterpretq_u8_s32(transposed_abcd_1.val[3]); - - const uint8_t out_secondpart_0 = vgetq_lane_u8(out_full_0, 10); - const uint8_t out_secondpart_1 = vgetq_lane_u8(out_full_1, 10); - const uint8_t out_secondpart_2 = vgetq_lane_u8(out_full_2, 10); - const uint8_t out_secondpart_3 = vgetq_lane_u8(out_full_3, 10); - const uint8_t out_secondpart_4 = vgetq_lane_u8(out_full_4, 10); - const uint8_t out_secondpart_5 = vgetq_lane_u8(out_full_5, 10); - const uint8_t out_secondpart_6 = vgetq_lane_u8(out_full_6, 10); - const uint8_t out_secondpart_7 = vgetq_lane_u8(out_full_7, 10); - - uint8x8_t out_firstpart_0 = vget_low_u8(tbl1q(out_full_0, map01)); - uint8x8_t out_firstpart_1 = vget_low_u8(tbl1q(out_full_1, map01)); - uint8x8_t out_firstpart_2 = vget_low_u8(tbl1q(out_full_2, map01)); - uint8x8_t out_firstpart_3 = vget_low_u8(tbl1q(out_full_3, map01)); - uint8x8_t out_firstpart_4 = vget_low_u8(tbl1q(out_full_4, map01)); - uint8x8_t out_firstpart_5 = vget_low_u8(tbl1q(out_full_5, map01)); - uint8x8_t out_firstpart_6 = vget_low_u8(tbl1q(out_full_6, map01)); - uint8x8_t out_firstpart_7 = vget_low_u8(tbl1q(out_full_7, map01)); - - uint8_t *ptr = int24_dst + ((i + 0) * channels + c) * 3; - const int step = channels * 3; - write_consecutive_int24(ptr + step * 0, out_firstpart_0, - out_secondpart_0); - write_consecutive_int24(ptr + step * 1, out_firstpart_1, - out_secondpart_1); - write_consecutive_int24(ptr + step * 2, out_firstpart_2, - out_secondpart_2); - write_consecutive_int24(ptr + step * 3, out_firstpart_3, - out_secondpart_3); - write_consecutive_int24(ptr + step * 4, out_firstpart_4, - out_secondpart_4); - write_consecutive_int24(ptr + step * 5, out_firstpart_5, - out_secondpart_5); - write_consecutive_int24(ptr + step * 6, out_firstpart_6, - out_secondpart_6); - write_consecutive_int24(ptr + step * 7, out_firstpart_7, - out_secondpart_7); - } - } - - for (c = bathed_channels; c < channels; ++c) { - for (i = 0; i < blocked_size; i += SINGLE_BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + next_channel * c + i), vld1q_f32(src + next_channel * c + i + 4) } }; - - uint8x16_t out_full_0 = vreinterpretq_u8_s32( - cvt_clamp_for_int24_s32(min24, in_a_01.val[0], max24)); - uint8x16_t out_full_1 = vreinterpretq_u8_s32( - cvt_clamp_for_int24_s32(min24, in_a_01.val[1], max24)); - - uint64_t out_low_0 = vgetq_lane_u64(vreinterpretq_u64_u8(out_full_0), 0); - uint64_t out_high_0 = vgetq_lane_u64(vreinterpretq_u64_u8(out_full_0), 1); - uint64_t out_low_1 = vgetq_lane_u64(vreinterpretq_u64_u8(out_full_1), 0); - uint64_t out_high_1 = vgetq_lane_u64(vreinterpretq_u64_u8(out_full_1), 1); - - uint8_t *ptr = int24_dst + ((i + 0) * channels + c) * 3; - const int step = channels * 3; - write_pair_int24(ptr + step * 0, step, out_low_0); - write_pair_int24(ptr + step * 2, step, out_high_0); - write_pair_int24(ptr + step * 4, step, out_low_1); - write_pair_int24(ptr + step * 6, step, out_high_1); - } - } - - return blocked_size; -} - -static int float2int32_zip_1channels(const float *src, int32_t *int32_dst, - int nsamples) { - const int BLOCK_SIZE = 32; - const int blocked_size = nsamples / BLOCK_SIZE * BLOCK_SIZE; - - int i; - - for (i = 0; i < blocked_size; i += BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + i + 0), vld1q_f32(src + i + 4) } }; - float32x4x2_t in_a_23 = { { vld1q_f32(src + i + 8), vld1q_f32(src + i + 12) } }; - float32x4x2_t in_a_45 = { { vld1q_f32(src + i + 16), vld1q_f32(src + i + 20) } }; - float32x4x2_t in_a_67 = { { vld1q_f32(src + i + 24), vld1q_f32(src + i + 28) } }; - - int32x4x2_t out_01 = cvt_for_int32_x2(in_a_01.val[0], in_a_01.val[1]); - int32x4x2_t out_23 = cvt_for_int32_x2(in_a_23.val[0], in_a_23.val[1]); - int32x4x2_t out_45 = cvt_for_int32_x2(in_a_45.val[0], in_a_45.val[1]); - int32x4x2_t out_67 = cvt_for_int32_x2(in_a_67.val[0], in_a_67.val[1]); - - vst1q_s32(int32_dst + i + 0, out_01.val[0]); - vst1q_s32(int32_dst + i + 4, out_01.val[1]); - vst1q_s32(int32_dst + i + 8, out_23.val[0]); - vst1q_s32(int32_dst + i + 12, out_23.val[1]); - vst1q_s32(int32_dst + i + 16, out_45.val[0]); - vst1q_s32(int32_dst + i + 20, out_45.val[1]); - vst1q_s32(int32_dst + i + 24, out_67.val[0]); - vst1q_s32(int32_dst + i + 28, out_67.val[1]); - } - - return blocked_size; -} - -static int float2int32_zip_2channels(const float *src, int next_channel, - int32_t *int32_dst, int nsamples) { - const int BLOCK_SIZE = 16; - const int blocked_size = nsamples / BLOCK_SIZE * BLOCK_SIZE; - - int i; - - for (i = 0; i < blocked_size; i += BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + i + 0), vld1q_f32(src + i + 4) } }; - float32x4x2_t in_a_23 = { { vld1q_f32(src + i + 8), vld1q_f32(src + i + 12) } }; - float32x4x2_t in_b_01 = { { vld1q_f32(src + next_channel + i + 0), vld1q_f32(src + next_channel + i + 4) } }; - float32x4x2_t in_b_23 = { { vld1q_f32(src + next_channel + i + 8), vld1q_f32(src + next_channel + i + 12) } }; - - int32x4x2_t out_ab_0 = cvt_for_int32_x2(in_a_01.val[0], in_b_01.val[0]); - int32x4x2_t out_ab_1 = cvt_for_int32_x2(in_a_01.val[1], in_b_01.val[1]); - int32x4x2_t out_ab_2 = cvt_for_int32_x2(in_a_23.val[0], in_b_23.val[0]); - int32x4x2_t out_ab_3 = cvt_for_int32_x2(in_a_23.val[1], in_b_23.val[1]); - - vst2q_s32(int32_dst + i * 2 + 0, out_ab_0); - vst2q_s32(int32_dst + i * 2 + 8, out_ab_1); - vst2q_s32(int32_dst + i * 2 + 16, out_ab_2); - vst2q_s32(int32_dst + i * 2 + 24, out_ab_3); - } - - return blocked_size; -} - -static int float2int32_zip_3channels(const float *src, int next_channel, - int32_t *int32_dst, int nsamples) { - const int BLOCK_SIZE = 16; - const int blocked_size = nsamples / BLOCK_SIZE * BLOCK_SIZE; - - int i; - - for (i = 0; i < blocked_size; i += BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + i + 0), vld1q_f32(src + i + 4) } }; - float32x4x2_t in_a_23 = { { vld1q_f32(src + i + 8), vld1q_f32(src + i + 12) } }; - float32x4x2_t in_b_01 = { { vld1q_f32(src + next_channel + i + 0), vld1q_f32(src + next_channel + i + 4) } }; - float32x4x2_t in_b_23 = { { vld1q_f32(src + next_channel + i + 8), vld1q_f32(src + next_channel + i + 12) } }; - float32x4x2_t in_c_01 = { { vld1q_f32(src + next_channel * 2 + i + 0), vld1q_f32(src + next_channel * 2 + i + 4) } }; - float32x4x2_t in_c_23 = { { vld1q_f32(src + next_channel * 2 + i + 8), vld1q_f32(src + next_channel * 2 + i + 12) } }; - - int32x4x3_t out_abc_0 = - cvt_for_int32_x3(in_a_01.val[0], in_b_01.val[0], in_c_01.val[0]); - int32x4x3_t out_abc_1 = - cvt_for_int32_x3(in_a_01.val[1], in_b_01.val[1], in_c_01.val[1]); - int32x4x3_t out_abc_2 = - cvt_for_int32_x3(in_a_23.val[0], in_b_23.val[0], in_c_23.val[0]); - int32x4x3_t out_abc_3 = - cvt_for_int32_x3(in_a_23.val[1], in_b_23.val[1], in_c_23.val[1]); - - vst3q_s32(int32_dst + i * 3 + 0, out_abc_0); - vst3q_s32(int32_dst + i * 3 + 12, out_abc_1); - vst3q_s32(int32_dst + i * 3 + 24, out_abc_2); - vst3q_s32(int32_dst + i * 3 + 36, out_abc_3); - } - - return blocked_size; -} - -static int float2int32_zip_nchannels(const float *src, int next_channel, - int channels, int32_t *int32_dst, - int nsamples) { - const int BATCH = 4; - const int BATCHED_BLOCK_SIZE = 8; - const int SINGLE_BLOCK_SIZE = 16; - const int bathed_channels = channels / BATCH * BATCH; - const int blocked_size = nsamples / BATCHED_BLOCK_SIZE * BATCHED_BLOCK_SIZE / - SINGLE_BLOCK_SIZE * SINGLE_BLOCK_SIZE; - - int i, c; - - for (c = 0; c < bathed_channels; c += BATCH) { - for (i = 0; i < blocked_size; i += BATCHED_BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + next_channel * (c + 0) + i), vld1q_f32(src + next_channel * (c + 0) + i + 4) } }; - float32x4x2_t in_b_01 = { { vld1q_f32(src + next_channel * (c + 1) + i), vld1q_f32(src + next_channel * (c + 1) + i + 4) } }; - float32x4x2_t in_c_01 = { { vld1q_f32(src + next_channel * (c + 2) + i), vld1q_f32(src + next_channel * (c + 2) + i + 4) } }; - float32x4x2_t in_d_01 = { { vld1q_f32(src + next_channel * (c + 3) + i), vld1q_f32(src + next_channel * (c + 3) + i + 4) } }; - - int32x4x2_t s32_a_01 = cvt_for_int32_x2(in_a_01.val[0], in_a_01.val[1]); - int32x4x2_t s32_b_01 = cvt_for_int32_x2(in_b_01.val[0], in_b_01.val[1]); - int32x4x2_t s32_c_01 = cvt_for_int32_x2(in_c_01.val[0], in_c_01.val[1]); - int32x4x2_t s32_d_01 = cvt_for_int32_x2(in_d_01.val[0], in_d_01.val[1]); - - int32x4x4_t transposed_0 = transpose_s32_4x4( - s32_a_01.val[0], s32_b_01.val[0], s32_c_01.val[0], s32_d_01.val[0]); - int32x4x4_t transposed_1 = transpose_s32_4x4( - s32_a_01.val[1], s32_b_01.val[1], s32_c_01.val[1], s32_d_01.val[1]); - - int32_t *ptr = int32_dst + i * channels + c; - const int step = channels; - vst1q_s32(ptr + step * 0, transposed_0.val[0]); - vst1q_s32(ptr + step * 1, transposed_0.val[1]); - vst1q_s32(ptr + step * 2, transposed_0.val[2]); - vst1q_s32(ptr + step * 3, transposed_0.val[3]); - vst1q_s32(ptr + step * 4, transposed_1.val[0]); - vst1q_s32(ptr + step * 5, transposed_1.val[1]); - vst1q_s32(ptr + step * 6, transposed_1.val[2]); - vst1q_s32(ptr + step * 7, transposed_1.val[3]); - } - } - - for (c = bathed_channels; c < channels; ++c) { - for (i = 0; i < blocked_size; i += SINGLE_BLOCK_SIZE) { - float32x4x2_t in_a_01 = { { vld1q_f32(src + next_channel * c + i + 0), vld1q_f32(src + next_channel * c + i + 4) } }; - float32x4x2_t in_a_23 = { { vld1q_f32(src + next_channel * c + i + 8), vld1q_f32(src + next_channel * c + i + 12) } }; - - int32x4_t out_scattered_a_0 = cvt_for_int32(in_a_01.val[0]); - int32x4_t out_scattered_a_1 = cvt_for_int32(in_a_01.val[1]); - int32x4_t out_scattered_a_2 = cvt_for_int32(in_a_23.val[0]); - int32x4_t out_scattered_a_3 = cvt_for_int32(in_a_23.val[1]); - - int64_t out_low_a_0 = - vgetq_lane_u64(vreinterpretq_u64_s32(out_scattered_a_0), 0); - int64_t out_high_a_0 = - vgetq_lane_u64(vreinterpretq_u64_s32(out_scattered_a_0), 1); - int64_t out_low_a_1 = - vgetq_lane_u64(vreinterpretq_u64_s32(out_scattered_a_1), 0); - int64_t out_high_a_1 = - vgetq_lane_u64(vreinterpretq_u64_s32(out_scattered_a_1), 1); - int64_t out_low_a_2 = - vgetq_lane_u64(vreinterpretq_u64_s32(out_scattered_a_2), 0); - int64_t out_high_a_2 = - vgetq_lane_u64(vreinterpretq_u64_s32(out_scattered_a_2), 1); - int64_t out_low_a_3 = - vgetq_lane_u64(vreinterpretq_u64_s32(out_scattered_a_3), 0); - int64_t out_high_a_3 = - vgetq_lane_u64(vreinterpretq_u64_s32(out_scattered_a_3), 1); - - int32_t *ptr = int32_dst + i * channels + c; - const int step = channels; - ptr[step * 0] = (int32_t)((out_low_a_0 >> 0) & 0xffffffff); - ptr[step * 1] = (int32_t)((out_low_a_0 >> 32) & 0xffffffff); - ptr[step * 2] = (int32_t)((out_high_a_0 >> 0) & 0xffffffff); - ptr[step * 3] = (int32_t)((out_high_a_0 >> 32) & 0xffffffff); - ptr[step * 4] = (int32_t)((out_low_a_1 >> 0) & 0xffffffff); - ptr[step * 5] = (int32_t)((out_low_a_1 >> 32) & 0xffffffff); - ptr[step * 6] = (int32_t)((out_high_a_1 >> 0) & 0xffffffff); - ptr[step * 7] = (int32_t)((out_high_a_1 >> 32) & 0xffffffff); - ptr[step * 8] = (int32_t)((out_low_a_2 >> 0) & 0xffffffff); - ptr[step * 9] = (int32_t)((out_low_a_2 >> 32) & 0xffffffff); - ptr[step * 10] = (int32_t)((out_high_a_2 >> 0) & 0xffffffff); - ptr[step * 11] = (int32_t)((out_high_a_2 >> 32) & 0xffffffff); - ptr[step * 12] = (int32_t)((out_low_a_3 >> 0) & 0xffffffff); - ptr[step * 13] = (int32_t)((out_low_a_3 >> 32) & 0xffffffff); - ptr[step * 14] = (int32_t)((out_high_a_3 >> 0) & 0xffffffff); - ptr[step * 15] = (int32_t)((out_high_a_3 >> 32) & 0xffffffff); - } - } - - return blocked_size; -} - -void float2int16_zip_channels_neon(const float *src, int next_channel, - int channels, int16_t *int16_dst, - int nsamples) { - int processed = 0; - - switch (channels) { - case 1: - processed = float2int16_zip_1channels(src, int16_dst, nsamples); - break; - case 2: - processed = - float2int16_zip_2channels(src, next_channel, int16_dst, nsamples); - break; - case 3: - processed = - float2int16_zip_3channels(src, next_channel, int16_dst, nsamples); - break; - default: - processed = float2int16_zip_nchannels(src, next_channel, channels, - int16_dst, nsamples); - break; - } - - // Let C version handle the residuals - float2int16_zip_channels_c(src + processed, next_channel, channels, - int16_dst + processed * channels, - nsamples - processed); -} - -void float2int24_zip_channels_neon(const float *src, int next_channel, - int channels, uint8_t *int24_dst, - int nsamples) { - int processed = 0; - - switch (channels) { - case 1: - processed = float2int24_zip_1channels(src, int24_dst, nsamples); - break; - case 2: - processed = - float2int24_zip_2channels(src, next_channel, int24_dst, nsamples); - break; - default: - processed = float2int24_zip_nchannels(src, next_channel, channels, - int24_dst, nsamples); - break; - } - - // Let C version handle the residuals - float2int24_zip_channels_c(src + processed, next_channel, channels, - int24_dst + processed * channels * 3, - nsamples - processed); -} - -void float2int32_zip_channels_neon(const float *src, int next_channel, - int channels, int32_t *int32_dst, - int nsamples) { - int processed = 0; - - switch (channels) { - case 1: - processed = float2int32_zip_1channels(src, int32_dst, nsamples); - break; - case 2: - processed = - float2int32_zip_2channels(src, next_channel, int32_dst, nsamples); - break; - case 3: - processed = - float2int32_zip_3channels(src, next_channel, int32_dst, nsamples); - break; - default: - processed = float2int32_zip_nchannels(src, next_channel, channels, - int32_dst, nsamples); - break; - } - - // Let C version handle the residuals - float2int32_zip_channels_c(src + processed, next_channel, channels, - int32_dst + processed * channels, - nsamples - processed); -} - -#endif /* IAMF_ARCH_DETECTED_ARM */ diff --git a/code/src/iamf_dec/arch/arm/arm_zip_channels.h b/code/src/iamf_dec/arch/arm/arm_zip_channels.h deleted file mode 100644 index b8ba7b27..00000000 --- a/code/src/iamf_dec/arch/arm/arm_zip_channels.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file arm_zip_channels.h - * @brief Arm implementation for zipping channels. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#ifndef ARM_ZIP_CHANNELS_H_ -#define ARM_ZIP_CHANNELS_H_ - -#include "detect_arm.h" - -#if defined(IAMF_ARCH_DETECTED_ARM) - -#include - -void float2int16_zip_channels_neon(const float *src, int next_channel, - int channels, int16_t *int16_dst, - int nsamples); - -void float2int24_zip_channels_neon(const float *src, int next_channel, - int channels, uint8_t *int24_dst, - int nsamples); - -void float2int32_zip_channels_neon(const float *src, int next_channel, - int channels, int32_t *int32_dst, - int nsamples); - -#endif /* IAMF_ARCH_DETECTED_ARM */ -#endif /* ARM_ZIP_CHANNELS_H_ */ diff --git a/code/src/iamf_dec/arch/arm/detect_arm.h b/code/src/iamf_dec/arch/arm/detect_arm.h deleted file mode 100644 index e67cea12..00000000 --- a/code/src/iamf_dec/arch/arm/detect_arm.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file detect_arm.h - * @brief Detect Arm architecture during compilation. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#ifndef DETECT_ARM_H_ -#define DETECT_ARM_H_ - -#if defined(__ARM_NEON) -#define IAMF_ARCH_DETECTED_ARM (1) -#endif - -#endif /* DETECT_ARM_H_ */ diff --git a/code/src/iamf_dec/arch/arm/override_arm.c b/code/src/iamf_dec/arch/arm/override_arm.c deleted file mode 100644 index d4f16dc1..00000000 --- a/code/src/iamf_dec/arch/arm/override_arm.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file override_arm.c - * @brief Override with Arm function implementations. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#include "detect_arm.h" - -#if defined(IAMF_ARCH_DETECTED_ARM) - -#include - -#include "../../arch.h" -#include "arm_multiply_channels.h" -#include "arm_zip_channels.h" - -void arch_override(Arch *arch) { - // Override functions with Arm implementations here - - arch->rendering.multiply_channels_by_matrix = - &multiply_channels_by_matrix_neon; - - arch->output.float2int16_zip_channels = &float2int16_zip_channels_neon; - arch->output.float2int24_zip_channels = &float2int24_zip_channels_neon; - arch->output.float2int32_zip_channels = &float2int32_zip_channels_neon; -} - -#endif diff --git a/code/src/iamf_dec/arch/x86/detect_x86.h b/code/src/iamf_dec/arch/x86/detect_x86.h deleted file mode 100644 index 05eaa412..00000000 --- a/code/src/iamf_dec/arch/x86/detect_x86.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file detect_x86.h - * @brief Detect x86 architecture during compilation. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#ifndef DETECT_X86_H_ -#define DETECT_X86_H_ - -#if defined(__x86_64__) || defined(__i386__) -#define IAMF_ARCH_DETECTED_X86 (1) -#endif - -#endif /* DETECT_X86_H_ */ diff --git a/code/src/iamf_dec/arch/x86/override_x86.c b/code/src/iamf_dec/arch/x86/override_x86.c deleted file mode 100644 index 9a44c2a4..00000000 --- a/code/src/iamf_dec/arch/x86/override_x86.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file override_x86.c - * @brief Override with x86 function implementations. - * @version 0.1 - * @date Created 10/24/2024 - **/ - -#include "detect_x86.h" - -#if defined(IAMF_ARCH_DETECTED_X86) - -#include "../../arch.h" - -void arch_override(Arch* arch) { - // Override functions with x86 implementations here -} - -#endif /* IAMF_ARCH_DETECTED_X86 */ diff --git a/code/src/iamf_dec/audio_effect_peak_limiter.c b/code/src/iamf_dec/audio_effect_peak_limiter.c index d229b7e4..a13107e3 100755 --- a/code/src/iamf_dec/audio_effect_peak_limiter.c +++ b/code/src/iamf_dec/audio_effect_peak_limiter.c @@ -31,19 +31,19 @@ This software module is out of scope and not part of the IAMF Final Deliverable. #include #include -#include "IAMF_debug.h" +#include "clog.h" static int init_default(AudioEffectPeakLimiter*); static float compute_target_gain(AudioEffectPeakLimiter*, float); inline static float curve_accel(float x); AudioEffectPeakLimiter* audio_effect_peak_limiter_create(void) { - return (AudioEffectPeakLimiter* )calloc(1, sizeof(AudioEffectPeakLimiter)); + return (AudioEffectPeakLimiter*)calloc(1, sizeof(AudioEffectPeakLimiter)); } void audio_effect_peak_limiter_uninit(AudioEffectPeakLimiter* ths) { #if USE_TRUEPEAK - for (int c = 0; c < MAX_OUTPUT_CHANNELS; ++c) { + for (int c = 0; c < MAX_LIMITER_OUTPUT_CHANNELS; ++c) { audio_true_peak_meter_deinit(&ths->truePeakMeters[c]); } #endif @@ -54,32 +54,33 @@ void audio_effect_peak_limiter_destroy(AudioEffectPeakLimiter* ths) { if (ths) free(ths); } -// threashold_db: Peak threshold in dB +// threshold_db: Peak threshold in dB // sample_rate : Sample rate of the samples // num_channels: number of channels in frame // atk_sec : attack duration in seconds // rel_sec : release duration in seconds // delay_size: number of samples in delay buffer void audio_effect_peak_limiter_init(AudioEffectPeakLimiter* ths, - float threashold_db, int sample_rate, + float threshold_db, int sample_rate, int num_channels, float atk_sec, float rel_sec, int delay_size) { init_default(ths); - ths->linearThreashold = pow(10, threashold_db / 20); + ths->linearThreshold = pow(10, threshold_db / 20); ths->attackSec = atk_sec; ths->releaseSec = rel_sec; ths->incTC = (float)1 / (float)sample_rate; ths->numChannels = num_channels; ths->delaySize = delay_size; - ths->delayBufferSize = delay_size; + ths->delayBufferSize = (delay_size > 0) ? delay_size : 1; ths->padsize = delay_size; for (int channel = 0; channel < num_channels; channel++) { for (int i = 0; i < MAX_DELAYSIZE + 1; i++) ths->delayData[channel][i] = 0.0f; } + ths->init = 0; } int audio_effect_peak_limiter_process_block(AudioEffectPeakLimiter* ths, @@ -123,13 +124,13 @@ int audio_effect_peak_limiter_process_block(AudioEffectPeakLimiter* ths, peak = ths->peakData[ths->peak_pos]; } - ia_logt("index %d : peak value %f vs %f", k, peak, - ths->peak_pos < 0 ? 0 : ths->peakData[ths->peak_pos]); + // trace("index %d : peak value %f vs %f", k, peak, + // ths->peak_pos < 0 ? 0 : ths->peakData[ths->peak_pos]); #else - ia_logt("index %d : peak value %f", k, peak); + // trace("index %d : peak value %f", k, peak); #endif gain = compute_target_gain(ths, peak); - ia_logt("index %d : gain value %f", k, gain); + // trace("index %d : gain value %f", k, gain); peakMax = 0; for (int channel = 0; channel < ths->numChannels; channel++) { @@ -140,21 +141,27 @@ int audio_effect_peak_limiter_process_block(AudioEffectPeakLimiter* ths, data = #endif ths->delayData[channel][DB_IDX(idx)] = inblock[pos + k]; - audioBlock[pos + k] = out; } else { // no delay mode + out = inblock[pos + k] * gain; #if USE_TRUEPEAK data = inblock[pos + k]; #endif - audioBlock[pos + k] = inblock[pos + k] * gain; } + + // hard limiter + if (fabs(out) > ths->linearThreshold) { + out = (out > 0) ? ths->linearThreshold : (-ths->linearThreshold); + } + audioBlock[pos + k] = out; + #if USE_TRUEPEAK // compute true peak if you want - ia_logt("data value %f", data); + // trace("data value %f", data); channel_peak = audio_true_peak_meter_next_true_peak( &ths->truePeakMeters[channel], data); channel_peak = fabs(channel_peak); #else - channel_peak = fabs(ths->delayData[channel][DB_IDX(idx)]); + channel_peak = fabs(inblock[pos + k]); #endif if (channel_peak > peakMax) peakMax = channel_peak; } @@ -167,7 +174,7 @@ int audio_effect_peak_limiter_process_block(AudioEffectPeakLimiter* ths, #endif ths->peakData[DB_IDX(idx)] = peakMax; - ia_logt("index %d : peak max value %.10f", k, peakMax); + // trace("index %d : peak max value %.10f", k, peakMax); } if (ths->delaySize > 0) { @@ -187,6 +194,7 @@ int audio_effect_peak_limiter_process_block(AudioEffectPeakLimiter* ths, } frame_size -= ths->padsize; ths->init = 1; + ths->padsize = 0; } } // transmit the block and release memory @@ -214,7 +222,7 @@ int init_default(AudioEffectPeakLimiter* ths) { #endif #if USE_TRUEPEAK - for (int c = 0; c < MAX_OUTPUT_CHANNELS; ++c) { + for (int c = 0; c < MAX_LIMITER_OUTPUT_CHANNELS; ++c) { audio_true_peak_meter_init(&ths->truePeakMeters[c]); } #endif @@ -244,9 +252,9 @@ float compute_target_gain(AudioEffectPeakLimiter* ths, float peak) { ths->currentGain = 1.0; } - if (peak * ths->currentGain > ths->linearThreashold) { // peak detect + if (peak * ths->currentGain > ths->linearThreshold) { // peak detect ths->targetStartGain = ths->currentGain; - ths->targetEndGain = ths->linearThreashold / peak; + ths->targetEndGain = ths->linearThreshold / peak; ths->currentTC = 0.0f; } diff --git a/code/src/iamf_dec/audio_effect_peak_limiter.h b/code/src/iamf_dec/audio_effect_peak_limiter.h index ccf05baf..fd15260f 100755 --- a/code/src/iamf_dec/audio_effect_peak_limiter.h +++ b/code/src/iamf_dec/audio_effect_peak_limiter.h @@ -18,23 +18,27 @@ This software module is out of scope and not part of the IAMF Final Deliverable. /** * @file audio_effect_peak_limiter.h * @brief Peak Limiter APIs. - * @version 0.1 + * @version 1.0.0 * @date Created 03/03/2023 **/ #ifndef __AUDIO_PEAK_LIMITER_H_ #define __AUDIO_PEAK_LIMITER_H_ +#define MAX_LIMITER_OUTPUT_CHANNELS 24 +#define MAX_DELAYSIZE 4096 + #define USE_TRUEPEAK 0 +#define MAX_OUTPUT_CHANNELS 24 +#define MAX_DELAYSIZE 4096 + #if USE_TRUEPEAK #include "audio_true_peak_meter.h" #endif #include -#include "audio_defines.h" - typedef struct AudioEffectPeakLimiter { int init; int padsize; @@ -43,12 +47,12 @@ typedef struct AudioEffectPeakLimiter { float targetEndGain; float attackSec; float releaseSec; - float linearThreashold; + float linearThreshold; float currentTC; float incTC; int numChannels; - float delayData[MAX_OUTPUT_CHANNELS][MAX_DELAYSIZE + 1]; + float delayData[MAX_LIMITER_OUTPUT_CHANNELS][MAX_DELAYSIZE + 1]; float peakData[MAX_DELAYSIZE + 1]; int entryIndex; int delaySize; @@ -59,7 +63,7 @@ typedef struct AudioEffectPeakLimiter { #endif #if USE_TRUEPEAK - AudioTruePeakMeter truePeakMeters[MAX_OUTPUT_CHANNELS]; + AudioTruePeakMeter truePeakMeters[MAX_LIMITER_OUTPUT_CHANNELS]; #endif } AudioEffectPeakLimiter; diff --git a/code/src/iamf_dec/bitstream.c b/code/src/iamf_dec/bitstream.c deleted file mode 100755 index 04672c31..00000000 --- a/code/src/iamf_dec/bitstream.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file bitstream.c - * @brief bitstream reader. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#include "bitstream.h" - -#include -#include - -int32_t bs(BitStream *b, const uint8_t *data, int size) { - b->data = data; - b->size = size; - b->b8sp = b->b8p = 0; - - return 0; -} - -static uint32_t bs_getLastA32b(BitStream *b) { - uint32_t ret = 0; - int n = 4; - - if (b->b8sp >= b->size) return 0; - if (b->b8sp + 4 > b->size) n = b->size - b->b8sp; - - for (int i = 0; i < n; ++i) { - ret <<= INT8_BITS; - ret |= b->data[b->b8sp + i]; - } - - n = 4 - n; - if (n > 0) ret <<= (INT8_BITS * n); - - return ret; -} - -uint32_t bs_get32b(BitStream *b, int n) { - uint32_t ret = 0; - uint32_t nb8p = 0, nn; - - assert(n <= INT32_BITS); - - ret = bs_getLastA32b(b); - if (n + b->b8p > INT32_BITS) { - nb8p = n + b->b8p - INT32_BITS; - nn = INT32_BITS - b->b8p; - } else { - nn = n; - } - - ret >>= INT32_BITS - nn - b->b8p; - if (nn < INT32_BITS) { - ret &= ~((~0U) << nn); - } - b->b8p += nn; - b->b8sp += (b->b8p / INT8_BITS); - b->b8p %= INT8_BITS; - - if (nb8p) { - uint32_t nret = bs_get32b(b, nb8p); - ret <<= nb8p; - ret |= nret; - } - - return ret; -} - -int32_t bs_skip(BitStream *b, int n) { - b->b8p += n; - b->b8sp += (b->b8p / INT8_BITS); - b->b8p %= INT8_BITS; - - return 0; -} - -void bs_align(BitStream *b) { - if (b->b8p) { - ++b->b8sp; - b->b8p = 0; - } -} - -int32_t bs_skipABytes(BitStream *b, int n) { return bs_read(b, 0, n); } - -uint32_t bs_getA8b(BitStream *b) { - uint32_t ret; - - bs_align(b); - ret = b->data[b->b8sp]; - ++b->b8sp; - return ret; -} - -uint32_t bs_getA16b(BitStream *b) { - uint32_t ret = bs_getA8b(b); - ret <<= INT8_BITS; - ret |= bs_getA8b(b); - return ret; -} - -uint32_t bs_getA32b(BitStream *b) { - uint32_t ret = bs_getA16b(b); - ret <<= INT16_BITS; - ret |= bs_getA16b(b); - return ret; -} - -uint64_t bs_getAleb128(BitStream *b) { - uint64_t ret = 0; - uint32_t i; - uint8_t byte; - - bs_align(b); - - if (b->b8sp >= b->size) return 0; - - for (i = 0; i < 8; i++) { - if (b->b8sp + i >= b->size) break; - byte = b->data[b->b8sp + i]; - ret |= (((uint64_t)byte & 0x7f) << (i * 7)); - if (!(byte & 0x80)) { - break; - } - } - ++i; - b->b8sp += i; - return ret; -} - -/// @brief Read descriptor size of ISO/IEC 14496-1. -uint32_t bs_getExpandableSize(BitStream *b) { - uint32_t ret = 0; - uint8_t byte; - - for (uint32_t i = 0; i < 4; i++) { - byte = b->data[b->b8sp + i]; - ret = (ret << 7) | (byte & 0x7f); - if (!(byte & 0x80)) { - b->b8sp += (i + 1); - break; - } - } - - return ret; -} - -int32_t bs_read(BitStream *b, uint8_t *data, int n) { - bs_align(b); - if (data) memcpy(data, &b->data[b->b8sp], n); - b->b8sp += n; - return n; -} - -int32_t bs_readString(BitStream *b, char *data, int n) { - int len = 0, rlen = 0; - bs_align(b); - len = strlen((char *)&b->data[b->b8sp]) + 1; - rlen = len; - if (rlen > n) rlen = n; - memcpy(data, &b->data[b->b8sp], rlen - 1); - data[rlen - 1] = '\0'; - b->b8sp += len; - return len; -} - -uint32_t bs_tell(BitStream *b) { return b->b8p ? b->b8sp + 1 : b->b8sp; } - -uint8_t readu8(uint8_t *data, int offset) { return data[offset]; } - -uint32_t readu16be(uint8_t *data, int offset) { - return data[offset] << 8 | data[offset + 1]; -} - -int reads16be(uint8_t *data, int offset) { - short ret = readu16be(data, offset); - return ret; -} - -uint32_t readu16le(uint8_t *data, int offset) { - return data[offset] | data[offset + 1] << 8; -} - -int reads16le(uint8_t *data, int offset) { - short ret = (short)readu16le(data, offset); - return ret; -} - -uint32_t readu24be(uint8_t *data, int offset) { - return readu16be(data, offset) << 8 | data[offset + 2]; -} - -int reads24be(uint8_t *data, int offset) { - uint32_t ret = readu16le(data, offset) << 8 | data[offset + 2]; - int iret = ret << 8; - return (iret >> 8); -} - -int reads24le(uint8_t *data, int offset) { - uint32_t ret = readu16le(data, offset) | data[offset + 2] << 16; - int iret = (int)(ret << 8); - return (iret >> 8); -} - -uint32_t readu32be(uint8_t *data, int offset) { - return readu16be(data, offset) << 16 | readu16be(data, offset + 2); -} - -int reads32be(uint8_t *data, int offset) { - return (int)readu32be(data, offset); -} - -int reads32le(uint8_t *data, int offset) { - return readu16le(data, offset) | readu16le(data, offset + 2) << 16; -} diff --git a/code/src/iamf_dec/bitstream.h b/code/src/iamf_dec/bitstream.h deleted file mode 100755 index 8a18342c..00000000 --- a/code/src/iamf_dec/bitstream.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file bitstream.h - * @brief bitstream reader APIs. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#ifndef BIT_STREAM_H -#define BIT_STREAM_H - -#include - -#define INT8_BITS 8 -#define INT16_BITS 16 -#define INT32_BITS 32 - -typedef struct { - const uint8_t *data; - uint32_t size; - uint32_t b8sp; // bytes, less than size; - uint32_t b8p; // 0~7 -} BitStream; - -int32_t bs(BitStream *b, const uint8_t *data, int size); -uint32_t bs_get32b(BitStream *b, int n); -int32_t bs_skip(BitStream *b, int n); -void bs_align(BitStream *b); -int32_t bs_skipABytes(BitStream *b, int n); -uint32_t bs_getA8b(BitStream *b); -uint32_t bs_getA16b(BitStream *b); -uint32_t bs_getA32b(BitStream *b); -uint64_t bs_getAleb128(BitStream *b); -uint32_t bs_getExpandableSize(BitStream *b); -int32_t bs_read(BitStream *b, uint8_t *data, int n); -int32_t bs_readString(BitStream *b, char *data, int n); -uint32_t bs_tell(BitStream *b); - -int reads16be(uint8_t *data, int offset); -int reads16le(uint8_t *data, int offset); -int reads24be(uint8_t *data, int offset); -int reads24le(uint8_t *data, int offset); -int reads32be(uint8_t *data, int offset); -int reads32le(uint8_t *data, int offset); - -uint8_t readu8(uint8_t *data, int offset); -uint32_t readu16be(uint8_t *data, int offset); -uint32_t readu24be(uint8_t *data, int offset); -uint32_t readu32be(uint8_t *data, int offset); - -#endif /* BIT_STREAM_H */ diff --git a/code/src/iamf_dec/aac/aac_multistream_decoder.c b/code/src/iamf_dec/codec/aac/aac_multistream_decoder.c similarity index 67% rename from code/src/iamf_dec/aac/aac_multistream_decoder.c rename to code/src/iamf_dec/codec/aac/aac_multistream_decoder.c index c1b03e56..8f6b0c24 100755 --- a/code/src/iamf_dec/aac/aac_multistream_decoder.c +++ b/code/src/iamf_dec/codec/aac/aac_multistream_decoder.c @@ -13,41 +13,43 @@ /** * @file aac_multistream_decoder.c * @brief AAC decoder. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ +#ifdef CONFIG_AAC_CODEC #include "aac_multistream_decoder.h" -#include "fdk-aac/aacdecoder_lib.h" #include #include -#include "IAMF_debug.h" #include "IAMF_defines.h" -#include "IAMF_types.h" -#include "IAMF_utils.h" +#include "clog.h" +#include "fdk-aac/aacdecoder_lib.h" +#include "iamf_private_definitions.h" +#include "iamf_types.h" +#include "iamf_utils.h" -#ifdef IA_TAG -#undef IA_TAG +#ifdef def_log_tag +#undef def_log_tag #endif -#define IA_TAG "AACMS" +#define def_log_tag "AACMS" -#define MAX_BUFFER_SIZE MAX_AAC_FRAME_SIZE * 2 +#define def_max_aac_buffer_size def_max_aac_frame_size * 2 -struct AACMSDecoder { +struct AacMsDecoder { uint32_t flags; int streams; int coupled_streams; int delay; HANDLE_AACDECODER *handles; - INT_PCM buffer[MAX_BUFFER_SIZE]; + INT_PCM buffer[def_max_aac_buffer_size]; }; -typedef void (*aac_copy_channel_out_func)(void *dst, const void *src, - int frame_size, int channes); +typedef void (*func_aac_copy_channel_out_t)(void *dst, const void *src, + int frame_size, int channes); void aac_copy_channel_out_short_plane(void *dst, const void *src, int frame_size, int channels) { @@ -76,7 +78,7 @@ static int aac_config_set_channels(uint8_t *conf, uint32_t size, int channels) { if (byte == 0xf) nbytes += 3; byte = ~(0xf << 3) & conf[nbytes]; byte = (channels & 0xf) << 3 | byte; - ia_logd("%d byte 1 bit: 0x%x->0x%x", nbytes, conf[nbytes], byte); + debug("%d byte 1 bit: 0x%x->0x%x", nbytes, conf[nbytes], byte); if (nbytes < size) conf[nbytes] = byte; else @@ -86,8 +88,8 @@ static int aac_config_set_channels(uint8_t *conf, uint32_t size, int channels) { } static int aac_multistream_decode_native( - AACMSDecoder *st, uint8_t *buffer[], uint32_t size[], void *pcm, - int frame_size, aac_copy_channel_out_func copy_channel_out) { + aac_ms_decoder_t *st, uint8_t *buffer[], uint32_t size[], void *pcm, + int frame_size, func_aac_copy_channel_out_t copy_channel_out) { UINT valid; AAC_DECODER_ERROR err; INT_PCM *out = (INT_PCM *)pcm; @@ -96,7 +98,7 @@ static int aac_multistream_decode_native( CStreamInfo *info = 0; for (int i = 0; i < st->streams; ++i) { - ia_logt("stream %d", i); + trace("stream %d", i); valid = size[i]; flags = buffer[i] ? 0 : AACDEC_FLUSH; if (!flags) { @@ -105,29 +107,30 @@ static int aac_multistream_decode_native( return IAMF_ERR_INVALID_PACKET; } } - err = aacDecoder_DecodeFrame(st->handles[i], st->buffer, MAX_BUFFER_SIZE, - flags); + err = aacDecoder_DecodeFrame(st->handles[i], st->buffer, + def_max_aac_buffer_size, flags); if (err == AAC_DEC_NOT_ENOUGH_BITS) { return IAMF_ERR_BUFFER_TOO_SMALL; } if (err != AAC_DEC_OK) { - ia_loge("stream %d : fail to decode", i); + error("stream %d : fail to decode", i); return IAMF_ERR_INTERNAL; } info = aacDecoder_GetStreamInfo(st->handles[i]); if (info) { fs = info->frameSize; - if (fs > MAX_AAC_FRAME_SIZE) { - ia_logw("frame size %d , is larger than %u", fs, MAX_AAC_FRAME_SIZE); - fs = MAX_AAC_FRAME_SIZE; + if (fs > def_max_aac_frame_size) { + warning("frame size %d , is larger than %u", fs, + def_max_aac_frame_size); + fs = def_max_aac_frame_size; } - ia_logt("aac decoder %d:", i); - ia_logt(" > sampleRate : %d.", info->sampleRate); - ia_logt(" > frameSize : %d.", info->frameSize); - ia_logt(" > numChannels: %d.", info->numChannels); - ia_logt(" > outputDelay: %u.", info->outputDelay); + trace("aac decoder %d:", i); + trace(" > sampleRate : %d.", info->sampleRate); + trace(" > frameSize : %d.", info->frameSize); + trace(" > numChannels: %d.", info->numChannels); + trace(" > outputDelay: %u.", info->outputDelay); } else { fs = frame_size; @@ -137,7 +140,7 @@ static int aac_multistream_decode_native( (*copy_channel_out)(out, st->buffer, fs, info->numChannels); out += (fs * info->numChannels); } else { - ia_logw("Can not get stream info."); + warning("Can not get stream info."); } } @@ -146,10 +149,10 @@ static int aac_multistream_decode_native( return fs; } -AACMSDecoder *aac_multistream_decoder_open(uint8_t *config, uint32_t size, - int streams, int coupled_streams, - uint32_t flags, int *error) { - AACMSDecoder *st = 0; +aac_ms_decoder_t *aac_multistream_decoder_open(uint8_t *config, uint32_t size, + int streams, int coupled_streams, + uint32_t flags, int *error) { + aac_ms_decoder_t *st = 0; HANDLE_AACDECODER *handles = 0; HANDLE_AACDECODER handle; @@ -165,18 +168,18 @@ AACMSDecoder *aac_multistream_decoder_open(uint8_t *config, uint32_t size, conf[0] = config; clen = size; - conf[1] = IAMF_MALLOC(UCHAR, clen); + conf[1] = def_malloc(UCHAR, clen); if (!conf[1]) { ret = IAMF_ERR_ALLOC_FAIL; goto end; } - st = IAMF_MALLOCZ(AACMSDecoder, 1); - handles = IAMF_MALLOCZ(HANDLE_AACDECODER, streams); + st = def_mallocz(aac_ms_decoder_t, 1); + handles = def_mallocz(HANDLE_AACDECODER, streams); if (!st || !handles) { ret = IAMF_ERR_ALLOC_FAIL; - IAMF_FREE(handles); + def_free(handles); goto end; } @@ -202,13 +205,13 @@ AACMSDecoder *aac_multistream_decoder_open(uint8_t *config, uint32_t size, else ret = aacDecoder_ConfigRaw(handle, &conf[1], &clen); if (ret != AAC_DEC_OK) { - ia_loge("aac config raw error code %d", ret); + error("aac config raw error code %d", ret); ret = IAMF_ERR_INTERNAL; break; } ret = aacDecoder_SetParam(handle, AAC_CONCEAL_METHOD, 1); if (ret != AAC_DEC_OK) { - ia_loge("aac set parameter error code %d", ret); + error("aac set parameter error code %d", ret); ret = IAMF_ERR_INTERNAL; break; } @@ -221,21 +224,21 @@ AACMSDecoder *aac_multistream_decoder_open(uint8_t *config, uint32_t size, st = 0; } - IAMF_FREE(conf[1]); + def_free(conf[1]); return st; } -int aac_multistream_decode(AACMSDecoder *st, uint8_t *buffer[], uint32_t size[], - void *pcm, uint32_t frame_size) { - if (st->flags & AUDIO_FRAME_PLANE) +int aac_multistream_decode(aac_ms_decoder_t *st, uint8_t *buffer[], + uint32_t size[], void *pcm, uint32_t frame_size) { + if (st->flags & ck_audio_frame_planar) return aac_multistream_decode_native(st, buffer, size, pcm, frame_size, aac_copy_channel_out_short_plane); - ia_loge("flags is 0x%x, is not implmeneted.", st->flags); + error("flags is 0x%x, is not implmeneted.", st->flags); return IAMF_ERR_UNIMPLEMENTED; } -void aac_multistream_decoder_close(AACMSDecoder *st) { +void aac_multistream_decoder_close(aac_ms_decoder_t *st) { if (st) { if (st->handles) { for (int i = 0; i < st->streams; ++i) { @@ -249,6 +252,7 @@ void aac_multistream_decoder_close(AACMSDecoder *st) { } } -int aac_multistream_decoder_get_delay(AACMSDecoder *st) { +int aac_multistream_decoder_get_delay(aac_ms_decoder_t *st) { return st->delay < 0 ? 0 : st->delay; } +#endif \ No newline at end of file diff --git a/code/src/iamf_dec/aac/aac_multistream_decoder.h b/code/src/iamf_dec/codec/aac/aac_multistream_decoder.h similarity index 71% rename from code/src/iamf_dec/aac/aac_multistream_decoder.h rename to code/src/iamf_dec/codec/aac/aac_multistream_decoder.h index 79ba100d..7d2b34f7 100755 --- a/code/src/iamf_dec/aac/aac_multistream_decoder.h +++ b/code/src/iamf_dec/codec/aac/aac_multistream_decoder.h @@ -13,16 +13,16 @@ /** * @file aac_multistream_decoder.h * @brief AAC decoder APIs. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ -#ifndef _AAC_MULTISTREAM2_DECODER_H_ -#define _AAC_MULTISTREAM2_DECODER_H_ +#ifndef __AAC_MULTISTREAM2_DECODER_H__ +#define __AAC_MULTISTREAM2_DECODER_H__ #include -typedef struct AACMSDecoder AACMSDecoder; +typedef struct AacMsDecoder aac_ms_decoder_t; /** * @brief Open an aac decoder. @@ -34,9 +34,9 @@ typedef struct AACMSDecoder AACMSDecoder; * @param [in] error : the error code when open an aac decoder. * @return return an aac decoder handle. */ -AACMSDecoder *aac_multistream_decoder_open(uint8_t *config, uint32_t size, - int streams, int coupled_streams, - uint32_t flags, int *error); +aac_ms_decoder_t *aac_multistream_decoder_open(uint8_t *config, uint32_t size, + int streams, int coupled_streams, + uint32_t flags, int *error); /** * @brief Decode aac packet. @@ -47,20 +47,20 @@ AACMSDecoder *aac_multistream_decoder_open(uint8_t *config, uint32_t size, * @param [in] frame_size : the frame size of aac. * @return return the number of decoded samples. */ -int aac_multistream_decode(AACMSDecoder *st, uint8_t *buffer[], uint32_t len[], - void *pcm, uint32_t frame_size); +int aac_multistream_decode(aac_ms_decoder_t *st, uint8_t *buffer[], + uint32_t len[], void *pcm, uint32_t frame_size); /** * @brief Close the aac decoder. * @param [in] st : aac decoder handle. */ -void aac_multistream_decoder_close(AACMSDecoder *st); +void aac_multistream_decoder_close(aac_ms_decoder_t *st); /** * @brief Get the decoder delay of aac. * @param [in] st : aac decoder handle. * @return return the decoder delay of aac. */ -int aac_multistream_decoder_get_delay(AACMSDecoder *st); +int aac_multistream_decoder_get_delay(aac_ms_decoder_t *st); -#endif /* _AAC_MULTISTREAM2_DECODER_H_ */ +#endif /* __AAC_MULTISTREAM2_DECODER_H__ */ diff --git a/code/src/iamf_dec/aac/IAMF_aac_decoder.c b/code/src/iamf_dec/codec/aac/iamf_aac_decoder.c similarity index 59% rename from code/src/iamf_dec/aac/IAMF_aac_decoder.c rename to code/src/iamf_dec/codec/aac/iamf_aac_decoder.c index af6b93d2..07e82e21 100755 --- a/code/src/iamf_dec/aac/IAMF_aac_decoder.c +++ b/code/src/iamf_dec/codec/aac/iamf_aac_decoder.c @@ -13,30 +13,32 @@ /** * @file IAMF_aac_decoder.c * @brief aac codec. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ +#ifdef CONFIG_AAC_CODEC #include -#include "IAMF_codec.h" -#include "IAMF_debug.h" -#include "IAMF_types.h" #include "aac_multistream_decoder.h" -#include "bitstream.h" - -#ifdef IA_TAG -#undef IA_TAG +#include "clog.h" +#include "iamf_codec.h" +#include "iamf_private_definitions.h" +#include "iamf_types.h" +#include "iorw.h" + +#ifdef def_log_tag +#undef def_log_tag #endif -#define IA_TAG "IAMF_AAC" +#define def_log_tag "IAMF_AAC" -static int iamf_aac_close(IAMF_CodecContext *ths); +static int iamf_aac_close(iamf_codec_context_t *ths); -typedef struct IAMF_AAC_Context { - AACMSDecoder *dec; +typedef struct IamfAacContext { + aac_ms_decoder_t *dec; short *out; -} IAMF_AAC_Context; +} iamf_aac_context_t; /** * IAC-AAC-LC Specific @@ -56,33 +58,37 @@ typedef struct IAMF_AAC_Context { * 3) extensionFlag = 0 * */ -static int iamf_aac_init(IAMF_CodecContext *ths) { - IAMF_AAC_Context *ctx = (IAMF_AAC_Context *)ths->priv; +static int iamf_aac_init(iamf_codec_context_t *ths) { + iamf_aac_context_t *ctx = (iamf_aac_context_t *)ths->priv; uint8_t *config = ths->cspec; - BitStream b; + io_context_t ioc, *r; int ret = 0; + uint32_t val; - bs(&b, ths->cspec, ths->clen); - if (bs_get32b(&b, 8) != 0x04) return IAMF_ERR_BAD_ARG; - bs_getExpandableSize(&b); + r = &ioc; + ioc_init(r, ths->cspec, ths->clen); + if (ior_8(r) != 0x04) return IAMF_ERR_BAD_ARG; + ior_expandable(r); - if (bs_get32b(&b, 8) != 0x40 || bs_get32b(&b, 6) != 5 || bs_get32b(&b, 1)) - return IAMF_ERR_BAD_ARG; + if (ior_8(r) != 0x40) return IAMF_ERR_BAD_ARG; + + val = ior_8(r); + if (val >> 2 != 5 || val >> 1 & 1) return IAMF_ERR_BAD_ARG; - bs_skipABytes(&b, 11); + ior_skip(r, 11); - if (bs_get32b(&b, 8) != 0x05) return IAMF_ERR_BAD_ARG; + if (ior_8(r) != 0x05) return IAMF_ERR_BAD_ARG; - ths->clen = bs_getExpandableSize(&b); - ths->cspec = config + bs_tell(&b); - ia_logd("aac codec spec info size %d", ths->clen); + ths->clen = ior_expandable(r); + ths->cspec = config + ioc_tell(r); + debug("aac codec spec info size %d", ths->clen); ctx->dec = aac_multistream_decoder_open(ths->cspec, ths->clen, ths->streams, ths->coupled_streams, - AUDIO_FRAME_PLANE, &ret); + ck_audio_frame_planar, &ret); if (!ctx->dec) return IAMF_ERR_INVALID_STATE; - ctx->out = (short *)malloc(sizeof(short) * MAX_AAC_FRAME_SIZE * + ctx->out = (short *)malloc(sizeof(short) * def_max_aac_frame_size * (ths->streams + ths->coupled_streams)); if (!ctx->out) { iamf_aac_close(ths); @@ -92,11 +98,11 @@ static int iamf_aac_init(IAMF_CodecContext *ths) { return IAMF_OK; } -static int iamf_aac_decode(IAMF_CodecContext *ths, uint8_t *buffer[], +static int iamf_aac_decode(iamf_codec_context_t *ths, uint8_t *buffer[], uint32_t size[], uint32_t count, void *pcm, uint32_t frame_size) { - IAMF_AAC_Context *ctx = (IAMF_AAC_Context *)ths->priv; - AACMSDecoder *dec = (AACMSDecoder *)ctx->dec; + iamf_aac_context_t *ctx = (iamf_aac_context_t *)ths->priv; + aac_ms_decoder_t *dec = (aac_ms_decoder_t *)ctx->dec; int ret = IAMF_OK; if (count != ths->streams) { @@ -115,16 +121,16 @@ static int iamf_aac_decode(IAMF_CodecContext *ths, uint8_t *buffer[], return ret; } -int iamf_aac_info(IAMF_CodecContext *ths) { - IAMF_AAC_Context *ctx = (IAMF_AAC_Context *)ths->priv; - AACMSDecoder *dec = (AACMSDecoder *)ctx->dec; +static int iamf_aac_info(iamf_codec_context_t *ths) { + iamf_aac_context_t *ctx = (iamf_aac_context_t *)ths->priv; + aac_ms_decoder_t *dec = (aac_ms_decoder_t *)ctx->dec; ths->delay = aac_multistream_decoder_get_delay(dec); return IAMF_OK; } -int iamf_aac_close(IAMF_CodecContext *ths) { - IAMF_AAC_Context *ctx = (IAMF_AAC_Context *)ths->priv; - AACMSDecoder *dec = (AACMSDecoder *)ctx->dec; +int iamf_aac_close(iamf_codec_context_t *ths) { + iamf_aac_context_t *ctx = (iamf_aac_context_t *)ths->priv; + aac_ms_decoder_t *dec = (aac_ms_decoder_t *)ctx->dec; if (dec) { aac_multistream_decoder_close(dec); @@ -137,11 +143,12 @@ int iamf_aac_close(IAMF_CodecContext *ths) { return IAMF_OK; } -const IAMF_Codec iamf_aac_decoder = { - .cid = IAMF_CODEC_AAC, - .priv_size = sizeof(IAMF_AAC_Context), +const iamf_codec_t iamf_aac_decoder = { + .cid = ck_iamf_codec_id_aac, + .priv_size = sizeof(iamf_aac_context_t), .init = iamf_aac_init, .decode = iamf_aac_decode, .info = iamf_aac_info, .close = iamf_aac_close, }; +#endif \ No newline at end of file diff --git a/code/src/iamf_dec/flac/flac_multistream_decoder.c b/code/src/iamf_dec/codec/flac/flac_multistream_decoder.c similarity index 66% rename from code/src/iamf_dec/flac/flac_multistream_decoder.c rename to code/src/iamf_dec/codec/flac/flac_multistream_decoder.c index 67d7991d..32c81508 100755 --- a/code/src/iamf_dec/flac/flac_multistream_decoder.c +++ b/code/src/iamf_dec/codec/flac/flac_multistream_decoder.c @@ -17,27 +17,27 @@ * @date Created 03/03/2023 **/ +#ifdef CONFIG_FLAC_CODEC #include "flac_multistream_decoder.h" -#include "FLAC/stream_decoder.h" #include #include -#include "IAMF_debug.h" +#include "FLAC/stream_decoder.h" #include "IAMF_defines.h" -#include "IAMF_types.h" -#include "IAMF_utils.h" -#include "bitstream.h" - -#ifdef IA_TAG -#undef IA_TAG +#include "clog.h" +#include "iamf_private_definitions.h" +#include "iamf_types.h" +#include "iamf_utils.h" +#include "iorw.h" + +#ifdef def_log_tag +#undef def_log_tag #endif -#define IA_TAG "FLACMS" +#define def_log_tag "FLACMS" -#define MAX_BUFFER_SIZE MAX_FLAC_FRAME_SIZE * 2 - -typedef struct FLACDecoderHandle { +typedef struct FlacDecoderHandle { FLAC__StreamDecoder *dec; struct { uint32_t depth; @@ -47,29 +47,29 @@ typedef struct FLACDecoderHandle { uint8_t *packet; uint32_t packet_size; uint32_t fs; - int buffer[MAX_FLAC_FRAME_SIZE]; -} FLACDecoderHandle; + int buffer[def_max_flac_frame_size]; +} flac_decoder_handle_t; -typedef struct FLACMSDecoder { +typedef struct FlacMsDecoder { uint32_t flags; int streams; int coupled_streams; - FLACDecoderHandle *handles; -} FLACMSDecoder; + flac_decoder_handle_t *handles; +} flac_ms_decoder_t; static FLAC__StreamDecoderReadStatus flac_stream_read( const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) { - FLACDecoderHandle *handle = (FLACDecoderHandle *)client_data; + flac_decoder_handle_t *handle = (flac_decoder_handle_t *)client_data; if (handle->packet) { - ia_logt("read stream %d data", handle->packet_size); + trace("read stream %d data", handle->packet_size); memcpy(buffer, handle->packet, handle->packet_size); *bytes = handle->packet_size; handle->packet = 0; return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } else { - ia_loge("The data is incomplete."); + error("The data is incomplete."); } return FLAC__STREAM_DECODER_READ_STATUS_ABORT; @@ -78,7 +78,7 @@ static FLAC__StreamDecoderReadStatus flac_stream_read( static FLAC__StreamDecoderWriteStatus flac_stream_write( const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) { - FLACDecoderHandle *handle = (FLACDecoderHandle *)client_data; + flac_decoder_handle_t *handle = (flac_decoder_handle_t *)client_data; char *out = (char *)handle->buffer; int fss = 0; @@ -97,12 +97,12 @@ static void flac_stream_metadata(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) { if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { - FLACDecoderHandle *handle = (FLACDecoderHandle *)client_data; + flac_decoder_handle_t *handle = (flac_decoder_handle_t *)client_data; handle->stream_info.depth = metadata->data.stream_info.bits_per_sample; handle->stream_info.channels = metadata->data.stream_info.channels; handle->stream_info.sample_rate = metadata->data.stream_info.sample_rate; - ia_logi("depth %d, channels %d, sample_rate %d.", handle->stream_info.depth, - handle->stream_info.channels, handle->stream_info.sample_rate); + info("depth %d, channels %d, sample_rate %d.", handle->stream_info.depth, + handle->stream_info.channels, handle->stream_info.sample_rate); } } @@ -111,42 +111,47 @@ static void flac_stream_error(const FLAC__StreamDecoder *decoder, void *client_data) {} static int flac_header_set_channels(uint8_t *h, uint32_t size, int n) { - int last, type, s, offset; - uint8_t byte; + uint32_t last, type, s; + io_context_t ioc, *r, *w; + uint32_t byte, val; + + r = w = &ioc; - offset = 4; + ioc_init(r, h, size); + ior_skip(r, 4); while (1) { - last = h[offset] >> 7 & 0x01; - type = h[offset] & 0x7f; - ++offset; - s = readu24be(h, offset); - offset += 3; + val = ior_8(r); + last = val >> 7 & 0x01; + type = val & 0x7f; + s = ior_b24(r); if (!type) { - offset += 12; - byte = ~(0x7 << 1) & h[offset]; + ior_skip(r, 12); + val = ior_8(r); + byte = ~(0x7 << 1) & val; byte = ((n - 1) & 0x7) << 1 | byte; - ia_logt("%d byte 1 bit: 0x%x->0x%x", offset, h[offset], byte); - if (offset < size) h[offset] = byte; + w->idx--; + debug("%d byte 1 bit: 0x%x->0x%x", ioc_tell(w), val, byte); + iow_8(w, byte); } else - offset += s; + ior_skip(r, s); - if (last || offset >= size) break; + if (last || !ioc_remain(r)) break; } - if (offset >= size) return IAMF_ERR_BAD_ARG; + if (!ioc_remain(r)) return IAMF_ERR_BAD_ARG; return IAMF_OK; } -static int flac_multistream_decode_native(FLACMSDecoder *st, uint8_t *buffer[], - uint32_t size[], void *pcm, - int frame_size) { - FLACDecoderHandle *handle = NULL; +static int flac_multistream_decode_native(flac_ms_decoder_t *st, + uint8_t *buffer[], uint32_t size[], + void *pcm, int frame_size) { + flac_decoder_handle_t *handle = NULL; char *out = (char *)pcm; int ss = 0; for (int i = 0; i < st->streams; ++i) { - ia_logt("stream %d", i); + trace("stream %d", i); handle = &st->handles[i]; handle->packet = buffer[i]; handle->packet_size = size[i]; @@ -156,7 +161,7 @@ static int flac_multistream_decode_native(FLACMSDecoder *st, uint8_t *buffer[], } if (handle->fs != frame_size) - ia_logw("Different frame size %d vs %d", frame_size, handle->fs); + warning("Different frame size %d vs %d", frame_size, handle->fs); ss = handle->fs * handle->stream_info.channels * 4; memcpy(out, handle->buffer, ss); @@ -169,12 +174,13 @@ static int flac_multistream_decode_native(FLACMSDecoder *st, uint8_t *buffer[], } } -FLACMSDecoder *flac_multistream_decoder_open(uint8_t *config, uint32_t size, - int streams, int coupled_streams, - uint32_t flags, int *error) { - FLACMSDecoder *st = 0; - FLACDecoderHandle *handles = 0; - FLACDecoderHandle *handle; +flac_ms_decoder_t *flac_multistream_decoder_open(uint8_t *config, uint32_t size, + int streams, + int coupled_streams, + uint32_t flags, int *error) { + flac_ms_decoder_t *st = 0; + flac_decoder_handle_t *handles = 0; + flac_decoder_handle_t *handle; FLAC__StreamDecoderInitStatus status; uint8_t *header[2]; int i, ret = 0; @@ -185,9 +191,9 @@ FLACMSDecoder *flac_multistream_decoder_open(uint8_t *config, uint32_t size, return 0; } - st = IAMF_MALLOCZ(FLACMSDecoder, 1); - handles = IAMF_MALLOCZ(FLACDecoderHandle, streams); - for (int i = 0; i < 2; ++i) header[i] = IAMF_MALLOCZ(uint8_t, size + 4); + st = def_mallocz(flac_ms_decoder_t, 1); + handles = def_mallocz(flac_decoder_handle_t, streams); + for (int i = 0; i < 2; ++i) header[i] = def_mallocz(uint8_t, size + 4); if (!st || !handles || !header[0] || !header[1]) { if (error) { @@ -196,8 +202,8 @@ FLACMSDecoder *flac_multistream_decoder_open(uint8_t *config, uint32_t size, if (st) { flac_multistream_decoder_close(st); } - IAMF_FREE(handles); - for (int i = 0; i < 2; ++i) IAMF_FREE(header[i]); + def_free(handles); + for (int i = 0; i < 2; ++i) def_free(header[i]); return 0; } @@ -234,14 +240,14 @@ FLACMSDecoder *flac_multistream_decoder_open(uint8_t *config, uint32_t size, flac_stream_write, flac_stream_metadata, flac_stream_error, handle); if (status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { - ia_loge("flac decoder init errno %d (%s)", -status, - FLAC__StreamDecoderInitStatusString[status]); + error("flac decoder init errno %d (%s)", -status, + FLAC__StreamDecoderInitStatusString[status]); ret = IAMF_ERR_INTERNAL; break; } if (!FLAC__stream_decoder_process_until_end_of_metadata(handle->dec)) { - ia_loge("Failed to read meta."); + error("Failed to read meta."); ret = IAMF_ERR_INTERNAL; break; } @@ -255,21 +261,21 @@ FLACMSDecoder *flac_multistream_decoder_open(uint8_t *config, uint32_t size, st = 0; } - for (int i = 0; i < 2; ++i) IAMF_FREE(header[i]); + for (int i = 0; i < 2; ++i) def_free(header[i]); return st; } -int flac_multistream_decode(FLACMSDecoder *st, uint8_t *buffer[], +int flac_multistream_decode(flac_ms_decoder_t *st, uint8_t *buffer[], uint32_t size[], void *pcm, uint32_t frame_size) { - if (st->flags & AUDIO_FRAME_PLANE) + if (st->flags & ck_audio_frame_planar) return flac_multistream_decode_native(st, buffer, size, pcm, frame_size); else { return IAMF_ERR_UNIMPLEMENTED; } } -void flac_multistream_decoder_close(FLACMSDecoder *st) { +void flac_multistream_decoder_close(flac_ms_decoder_t *st) { if (st) { if (st->handles) { for (int i = 0; i < st->streams; ++i) { @@ -284,7 +290,8 @@ void flac_multistream_decoder_close(FLACMSDecoder *st) { } } -int flac_multistream_decoder_get_sample_bits(FLACMSDecoder *st) { +int flac_multistream_decoder_get_sample_bits(flac_ms_decoder_t *st) { if (st && st->handles) return st->handles[0].stream_info.depth; return IAMF_ERR_INTERNAL; } +#endif \ No newline at end of file diff --git a/code/src/iamf_dec/flac/flac_multistream_decoder.h b/code/src/iamf_dec/codec/flac/flac_multistream_decoder.h similarity index 73% rename from code/src/iamf_dec/flac/flac_multistream_decoder.h rename to code/src/iamf_dec/codec/flac/flac_multistream_decoder.h index d7c80e29..7f90f6cb 100755 --- a/code/src/iamf_dec/flac/flac_multistream_decoder.h +++ b/code/src/iamf_dec/codec/flac/flac_multistream_decoder.h @@ -17,12 +17,12 @@ * @date Created 03/03/2023 **/ -#ifndef _FLAC_MULTISTREAM2_DECODER_H_ -#define _FLAC_MULTISTREAM2_DECODER_H_ +#ifndef __FLAC_MULTISTREAM2_DECODER_H__ +#define __FLAC_MULTISTREAM2_DECODER_H__ #include -typedef struct FLACMSDecoder FLACMSDecoder; +typedef struct FlacMsDecoder flac_ms_decoder_t; /** * @brief Open a flac decoder. @@ -34,9 +34,10 @@ typedef struct FLACMSDecoder FLACMSDecoder; * @param [in] error : the error code when open an aac decoder. * @return return a flac decoder handle. */ -FLACMSDecoder *flac_multistream_decoder_open(uint8_t *config, uint32_t size, - int streams, int coupled_streams, - uint32_t flags, int *error); +flac_ms_decoder_t *flac_multistream_decoder_open(uint8_t *config, uint32_t size, + int streams, + int coupled_streams, + uint32_t flags, int *error); /** * @brief Decode flac packet. @@ -47,20 +48,20 @@ FLACMSDecoder *flac_multistream_decoder_open(uint8_t *config, uint32_t size, * @param [in] frame_size : the frame size of aac. * @return return the number of decoded samples. */ -int flac_multistream_decode(FLACMSDecoder *st, uint8_t *buffer[], +int flac_multistream_decode(flac_ms_decoder_t *st, uint8_t *buffer[], uint32_t len[], void *pcm, uint32_t frame_size); /** * @brief Close the flac decoder. * @param [in] st : flac decoder handle. */ -void flac_multistream_decoder_close(FLACMSDecoder *st); +void flac_multistream_decoder_close(flac_ms_decoder_t *st); /** * @brief Get the sample depth of audio. * @param [in] st : flac decoder handle. * @return return the bit-depth. */ -int flac_multistream_decoder_get_sample_bits(FLACMSDecoder *st); +int flac_multistream_decoder_get_sample_bits(flac_ms_decoder_t *st); -#endif /* _FLAC_MULTISTREAM2_DECODER_H_ */ +#endif /* __FLAC_MULTISTREAM2_DECODER_H__ */ diff --git a/code/src/iamf_dec/flac/IAMF_flac_decoder.c b/code/src/iamf_dec/codec/flac/iamf_flac_decoder.c similarity index 62% rename from code/src/iamf_dec/flac/IAMF_flac_decoder.c rename to code/src/iamf_dec/codec/flac/iamf_flac_decoder.c index 7b69f090..39c75c36 100755 --- a/code/src/iamf_dec/flac/IAMF_flac_decoder.c +++ b/code/src/iamf_dec/codec/flac/iamf_flac_decoder.c @@ -17,31 +17,32 @@ * @date Created 03/03/2023 **/ +#ifdef CONFIG_FLAC_CODEC #include -#include "IAMF_codec.h" -#include "IAMF_debug.h" -#include "IAMF_types.h" -#include "IAMF_utils.h" -#include "bitstream.h" +#include "clog.h" #include "flac_multistream_decoder.h" +#include "iamf_codec.h" +#include "iamf_private_definitions.h" +#include "iamf_types.h" +#include "iamf_utils.h" -#ifdef IA_TAG -#undef IA_TAG +#ifdef def_log_tag +#undef def_log_tag #endif -#define IA_TAG "IAMF_FLAC" +#define def_log_tag "IAMF_FLAC" -static int iamf_flac_close(IAMF_CodecContext *ths); +static int iamf_flac_close(iamf_codec_context_t *ths); -typedef struct IAMF_FLAC_Context { - FLACMSDecoder *dec; +typedef struct IamfFlacContext { + flac_ms_decoder_t *dec; int *out; float scale_i2f; -} IAMF_FLAC_Context; +} iamf_flac_context_t; -static int iamf_flac_init(IAMF_CodecContext *ths) { - IAMF_FLAC_Context *ctx = (IAMF_FLAC_Context *)ths->priv; +static int iamf_flac_init(iamf_codec_context_t *ths) { + iamf_flac_context_t *ctx = (iamf_flac_context_t *)ths->priv; int ret = IAMF_OK; int bits = 0; @@ -51,23 +52,23 @@ static int iamf_flac_init(IAMF_CodecContext *ths) { ctx->dec = flac_multistream_decoder_open(ths->cspec, ths->clen, ths->streams, ths->coupled_streams, - AUDIO_FRAME_PLANE, &ret); + ck_audio_frame_planar, &ret); if (!ctx->dec) { return ret; } bits = flac_multistream_decoder_get_sample_bits(ctx->dec); if (bits < 1) { - ia_loge("metadata : Invalid sample bits."); + error("metadata : Invalid sample bits."); iamf_flac_close(ths); return IAMF_ERR_INTERNAL; } ctx->scale_i2f = 1 << (bits - 1); - ia_logd("the scale of i%d to float : %f", bits, ctx->scale_i2f); + debug("the scale of i%d to float : %f", bits, ctx->scale_i2f); - ctx->out = IAMF_MALLOC( - int, MAX_FLAC_FRAME_SIZE *(ths->streams + ths->coupled_streams)); + ctx->out = def_malloc( + int, def_max_flac_frame_size *(ths->streams + ths->coupled_streams)); if (!ctx->out) { iamf_flac_close(ths); return IAMF_ERR_ALLOC_FAIL; @@ -76,11 +77,11 @@ static int iamf_flac_init(IAMF_CodecContext *ths) { return IAMF_OK; } -static int iamf_flac_decode(IAMF_CodecContext *ths, uint8_t *buffer[], +static int iamf_flac_decode(iamf_codec_context_t *ths, uint8_t *buffer[], uint32_t size[], uint32_t count, void *pcm, uint32_t frame_size) { - IAMF_FLAC_Context *ctx = (IAMF_FLAC_Context *)ths->priv; - FLACMSDecoder *dec = (FLACMSDecoder *)ctx->dec; + iamf_flac_context_t *ctx = (iamf_flac_context_t *)ths->priv; + flac_ms_decoder_t *dec = (flac_ms_decoder_t *)ctx->dec; int ret = IAMF_OK; if (count != ths->streams) { @@ -99,9 +100,9 @@ static int iamf_flac_decode(IAMF_CodecContext *ths, uint8_t *buffer[], return ret; } -int iamf_flac_close(IAMF_CodecContext *ths) { - IAMF_FLAC_Context *ctx = (IAMF_FLAC_Context *)ths->priv; - FLACMSDecoder *dec = (FLACMSDecoder *)ctx->dec; +int iamf_flac_close(iamf_codec_context_t *ths) { + iamf_flac_context_t *ctx = (iamf_flac_context_t *)ths->priv; + flac_ms_decoder_t *dec = (flac_ms_decoder_t *)ctx->dec; if (dec) { flac_multistream_decoder_close(dec); @@ -114,10 +115,11 @@ int iamf_flac_close(IAMF_CodecContext *ths) { return IAMF_OK; } -const IAMF_Codec iamf_flac_decoder = { - .cid = IAMF_CODEC_FLAC, - .priv_size = sizeof(IAMF_FLAC_Context), +const iamf_codec_t iamf_flac_decoder = { + .cid = ck_iamf_codec_id_flac, + .priv_size = sizeof(iamf_flac_context_t), .init = iamf_flac_init, .decode = iamf_flac_decode, .close = iamf_flac_close, }; +#endif \ No newline at end of file diff --git a/code/src/iamf_dec/IAMF_codec.h b/code/src/iamf_dec/codec/iamf_codec.h similarity index 68% rename from code/src/iamf_dec/IAMF_codec.h rename to code/src/iamf_dec/codec/iamf_codec.h index ebed1fd5..95f2bb67 100755 --- a/code/src/iamf_dec/IAMF_codec.h +++ b/code/src/iamf_dec/codec/iamf_codec.h @@ -11,20 +11,20 @@ */ /** - * @file IAMF_codec.h + * @file iamf_codec.h * @brief Common codec APIs. * @version 0.1 * @date Created 03/03/2023 **/ -#ifndef IAMF_CODEC_H_ -#define IAMF_CODEC_H_ +#ifndef __IAMF_CODEC_H__ +#define __IAMF_CODEC_H__ #include -#include "IAMF_defines.h" +#include "iamf_types.h" -typedef struct IAMF_CodecContext { +typedef struct IamfCodecContext { void *priv; uint8_t *cspec; @@ -34,22 +34,21 @@ typedef struct IAMF_CodecContext { uint32_t flags; uint32_t sample_rate; uint32_t sample_size; - uint32_t channel_mapping_family; uint8_t streams; uint8_t coupled_streams; uint8_t channels; -} IAMF_CodecContext; +} iamf_codec_context_t; -typedef struct IAMF_Codec { - IAMF_CodecID cid; +typedef struct IamfCodec { + iamf_codec_id_t cid; uint32_t flags; uint32_t priv_size; - int (*init)(IAMF_CodecContext *ths); - int (*decode)(IAMF_CodecContext *ths, uint8_t *buf[], uint32_t len[], + int (*init)(iamf_codec_context_t *ths); + int (*decode)(iamf_codec_context_t *ths, uint8_t *buf[], uint32_t len[], uint32_t count, void *pcm, const uint32_t frame_size); - int (*info)(IAMF_CodecContext *ths); - int (*close)(IAMF_CodecContext *ths); -} IAMF_Codec; + int (*info)(iamf_codec_context_t *ths); + int (*close)(iamf_codec_context_t *ths); +} iamf_codec_t; -#endif /* IAMF_CODEC_H_ */ +#endif /* __IAMF_CODEC_H__ */ diff --git a/code/src/iamf_dec/opus/IAMF_opus_decoder.c b/code/src/iamf_dec/codec/opus/iamf_opus_decoder.c similarity index 71% rename from code/src/iamf_dec/opus/IAMF_opus_decoder.c rename to code/src/iamf_dec/codec/opus/iamf_opus_decoder.c index b7e1221c..83de5f92 100755 --- a/code/src/iamf_dec/opus/IAMF_opus_decoder.c +++ b/code/src/iamf_dec/codec/opus/iamf_opus_decoder.c @@ -13,30 +13,30 @@ /** * @file IAMF_opus_decoder.c * @brief opus codec. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ #include -#include "IAMF_codec.h" -#include "IAMF_debug.h" -#include "IAMF_types.h" -#include "bitstream.h" +#include "clog.h" +#include "iamf_codec.h" +#include "iamf_private_definitions.h" #include "opus_multistream2_decoder.h" -#ifdef IA_TAG -#undef IA_TAG +#ifdef def_log_tag +#undef def_log_tag #endif -#define IA_TAG "IAMF_OPUS" +#define def_log_tag "IAMF_OPUS" -typedef struct IAMF_OPUS_Context { +#ifdef CONFIG_OPUS_CODEC +typedef struct IamfOpusContext { void *dec; short *out; -} IAMF_OPUS_Context; +} iamf_opus_context_t; -static int iamf_opus_close(IAMF_CodecContext *ths); +static int iamf_opus_close(iamf_codec_context_t *ths); /** * IAC-OPUS Specific @@ -70,28 +70,22 @@ static int iamf_opus_close(IAMF_CodecContext *ths); * endian * * */ -static int iamf_opus_init(IAMF_CodecContext *ths) { - IAMF_OPUS_Context *ctx = (IAMF_OPUS_Context *)ths->priv; +static int iamf_opus_init(iamf_codec_context_t *ths) { + iamf_opus_context_t *ctx = (iamf_opus_context_t *)ths->priv; int ec = IAMF_OK; int ret = 0; - uint8_t *config = ths->cspec; - if (!ths->cspec || ths->clen <= 0) { - return IAMF_ERR_BAD_ARG; - } - - ths->sample_rate = 48000; // readu32be(config, 4); - ths->channel_mapping_family = config[10]; + ths->sample_rate = 48000; ctx->dec = opus_multistream2_decoder_create(ths->sample_rate, ths->streams, ths->coupled_streams, - AUDIO_FRAME_PLANE, &ret); + ck_audio_frame_planar, &ret); if (!ctx->dec) { - ia_loge("fail to open opus decoder."); + error("fail to open opus decoder."); ec = IAMF_ERR_INVALID_STATE; } - ctx->out = (short *)malloc(sizeof(short) * MAX_OPUS_FRAME_SIZE * + ctx->out = (short *)malloc(sizeof(short) * def_max_opus_frame_size * (ths->streams + ths->coupled_streams)); if (!ctx->out) { iamf_opus_close(ths); @@ -101,11 +95,11 @@ static int iamf_opus_init(IAMF_CodecContext *ths) { return ec; } -static int iamf_opus_decode(IAMF_CodecContext *ths, uint8_t *buf[], +static int iamf_opus_decode(iamf_codec_context_t *ths, uint8_t *buf[], uint32_t len[], uint32_t count, void *pcm, const uint32_t frame_size) { - IAMF_OPUS_Context *ctx = (IAMF_OPUS_Context *)ths->priv; - OpusMS2Decoder *dec = (OpusMS2Decoder *)ctx->dec; + iamf_opus_context_t *ctx = (iamf_opus_context_t *)ths->priv; + Opus_Ms2_Decoder_t *dec = (Opus_Ms2_Decoder_t *)ctx->dec; int ret = IAMF_OK; if (count != ths->streams) { @@ -122,9 +116,9 @@ static int iamf_opus_decode(IAMF_CodecContext *ths, uint8_t *buf[], return ret; } -int iamf_opus_close(IAMF_CodecContext *ths) { - IAMF_OPUS_Context *ctx = (IAMF_OPUS_Context *)ths->priv; - OpusMS2Decoder *dec = (OpusMS2Decoder *)ctx->dec; +int iamf_opus_close(iamf_codec_context_t *ths) { + iamf_opus_context_t *ctx = (iamf_opus_context_t *)ths->priv; + Opus_Ms2_Decoder_t *dec = (Opus_Ms2_Decoder_t *)ctx->dec; if (dec) { opus_multistream2_decoder_destroy(dec); @@ -137,10 +131,11 @@ int iamf_opus_close(IAMF_CodecContext *ths) { return IAMF_OK; } -const IAMF_Codec iamf_opus_decoder = { - .cid = IAMF_CODEC_OPUS, - .priv_size = sizeof(IAMF_OPUS_Context), +const iamf_codec_t iamf_opus_decoder = { + .cid = ck_iamf_codec_id_opus, + .priv_size = sizeof(iamf_opus_context_t), .init = iamf_opus_init, .decode = iamf_opus_decode, .close = iamf_opus_close, }; +#endif \ No newline at end of file diff --git a/code/src/iamf_dec/opus/opus_multistream2_decoder.c b/code/src/iamf_dec/codec/opus/opus_multistream2_decoder.c similarity index 74% rename from code/src/iamf_dec/opus/opus_multistream2_decoder.c rename to code/src/iamf_dec/codec/opus/opus_multistream2_decoder.c index 92d98e90..95ff4c11 100755 --- a/code/src/iamf_dec/opus/opus_multistream2_decoder.c +++ b/code/src/iamf_dec/codec/opus/opus_multistream2_decoder.c @@ -17,27 +17,28 @@ * @date Created 03/03/2023 **/ +#ifdef CONFIG_OPUS_CODEC #include "opus/opus_multistream2_decoder.h" #include #include #include -#include "IAMF_debug.h" -#include "IAMF_defines.h" -#include "IAMF_types.h" +#include "clog.h" +#include "iamf_private_definitions.h" +#include "iamf_types.h" #include "opus/opus.h" -#ifdef IA_TAG -#undef IA_TAG +#ifdef def_log_tag +#undef def_log_tag #endif -#define IA_TAG "OPUSMS2" +#define def_log_tag "OPUSMS2" -typedef void (*opus_copy_channels_out_func)(void *dst, const short *src, - int frame_size, int channels); +typedef void (*func_opus_copy_channels_out_t)(void *dst, const short *src, + int frame_size, int channels); -struct OpusMS2Decoder { +struct OpusMs2Decoder { uint32_t flags; int streams; @@ -66,12 +67,12 @@ static opus_int32 opus_multistream2_decoder_get_size(int nb_streams, coupled_size = opus_decoder_get_size(2); mono_size = opus_decoder_get_size(1); - return align(sizeof(OpusMS2Decoder)) + + return align(sizeof(Opus_Ms2_Decoder_t)) + nb_coupled_streams * align(coupled_size) + (nb_streams - nb_coupled_streams) * align(mono_size); } -static int opus_multistream2_decoder_init(OpusMS2Decoder *st, opus_int32 Fs, +static int opus_multistream2_decoder_init(Opus_Ms2_Decoder_t *st, opus_int32 Fs, int streams, int coupled_streams, uint32_t flags) { int coupled_size; @@ -83,7 +84,7 @@ static int opus_multistream2_decoder_init(OpusMS2Decoder *st, opus_int32 Fs, st->coupled_streams = coupled_streams; st->flags = flags; - ptr = (char *)st + align(sizeof(OpusMS2Decoder)); + ptr = (char *)st + align(sizeof(Opus_Ms2_Decoder_t)); coupled_size = opus_decoder_get_size(2); mono_size = opus_decoder_get_size(1); @@ -102,14 +103,14 @@ static int opus_multistream2_decoder_init(OpusMS2Decoder *st, opus_int32 Fs, ptr += align(mono_size); } - st->buffer = calloc(1, MAX_OPUS_FRAME_SIZE * 2 * sizeof(short)); + st->buffer = calloc(1, def_max_opus_frame_size * 2 * sizeof(short)); if (!st->buffer) return IAMF_ERR_ALLOC_FAIL; return IAMF_OK; } static int opus_multistream2_decoder_decode_native( - OpusMS2Decoder *st, uint8_t *buffer[], opus_int32 size[], void *pcm, - int frame_size, opus_copy_channels_out_func copy_channel_out) { + Opus_Ms2_Decoder_t *st, uint8_t *buffer[], opus_int32 size[], void *pcm, + int frame_size, func_opus_copy_channels_out_t copy_channel_out) { int coupled_size; int mono_size; int s, ret = 0; @@ -120,7 +121,7 @@ static int opus_multistream2_decoder_decode_native( return IAMF_ERR_BAD_ARG; } - ptr = (char *)st + align(sizeof(OpusMS2Decoder)); + ptr = (char *)st + align(sizeof(Opus_Ms2_Decoder_t)); coupled_size = opus_decoder_get_size(2); mono_size = opus_decoder_get_size(1); @@ -132,7 +133,7 @@ static int opus_multistream2_decoder_decode_native( ret = opus_decode(dec, buffer[s], size[s], st->buffer, frame_size, 0); - ia_logt("stream %d decoded result %d", s, ret); + trace("stream %d decoded result %d", s, ret); if (ret <= 0) { return ret; } @@ -151,8 +152,8 @@ static int opus_multistream2_decoder_decode_native( void opus_copy_channel_out_short_plane(void *dst, const short *src, int frame_size, int channels) { - ia_logt("copy frame %d, channels %d dst %p src %p.", frame_size, channels, - dst, src); + trace("copy frame %d, channels %d dst %p src %p.", frame_size, channels, dst, + src); if (channels == 1) { memcpy(dst, src, sizeof(short) * frame_size); } else if (channels == 2) { @@ -164,11 +165,12 @@ void opus_copy_channel_out_short_plane(void *dst, const short *src, } } -OpusMS2Decoder *opus_multistream2_decoder_create(int Fs, int streams, - int coupled_streams, - uint32_t flags, int *error) { +Opus_Ms2_Decoder_t *opus_multistream2_decoder_create(int Fs, int streams, + int coupled_streams, + uint32_t flags, + int *error) { int ret; - OpusMS2Decoder *st; + Opus_Ms2_Decoder_t *st; int size; if ((coupled_streams > streams) || (streams < 1) || (coupled_streams < 0) || (streams > 255 - coupled_streams)) { @@ -179,7 +181,7 @@ OpusMS2Decoder *opus_multistream2_decoder_create(int Fs, int streams, } size = opus_multistream2_decoder_get_size(streams, coupled_streams); - st = (OpusMS2Decoder *)malloc(size); + st = (Opus_Ms2_Decoder_t *)malloc(size); if (st == NULL) { if (error) { *error = IAMF_ERR_ALLOC_FAIL; @@ -199,19 +201,20 @@ OpusMS2Decoder *opus_multistream2_decoder_create(int Fs, int streams, return st; } -int opus_multistream2_decode(OpusMS2Decoder *st, uint8_t *buffer[], +int opus_multistream2_decode(Opus_Ms2_Decoder_t *st, uint8_t *buffer[], uint32_t size[], void *pcm, uint32_t frame_size) { - if (st->flags & AUDIO_FRAME_PLANE) + if (st->flags & ck_audio_frame_planar) return opus_multistream2_decoder_decode_native( st, buffer, (opus_int32 *)size, pcm, frame_size, opus_copy_channel_out_short_plane); - ia_logw("flag is 0x%x, is not implmented.", st->flags); + warning("flag is 0x%x, is not implmented.", st->flags); return IAMF_ERR_UNIMPLEMENTED; } -void opus_multistream2_decoder_destroy(OpusMS2Decoder *st) { +void opus_multistream2_decoder_destroy(Opus_Ms2_Decoder_t *st) { if (st->buffer) { free(st->buffer); } free(st); } +#endif \ No newline at end of file diff --git a/code/src/iamf_dec/opus/opus_multistream2_decoder.h b/code/src/iamf_dec/codec/opus/opus_multistream2_decoder.h similarity index 72% rename from code/src/iamf_dec/opus/opus_multistream2_decoder.h rename to code/src/iamf_dec/codec/opus/opus_multistream2_decoder.h index 59e2155c..8b3d155c 100755 --- a/code/src/iamf_dec/opus/opus_multistream2_decoder.h +++ b/code/src/iamf_dec/codec/opus/opus_multistream2_decoder.h @@ -17,12 +17,12 @@ * @date Created 03/03/2023 **/ -#ifndef _OPUS_MULTISTREAM2_DECODER_H_ -#define _OPUS_MULTISTREAM2_DECODER_H_ +#ifndef __OPUS_MULTISTREAM2_DECODER_H__ +#define __OPUS_MULTISTREAM2_DECODER_H__ #include -typedef struct OpusMS2Decoder OpusMS2Decoder; +typedef struct OpusMs2Decoder Opus_Ms2_Decoder_t; /** * @brief Create an opus decoder. @@ -33,9 +33,10 @@ typedef struct OpusMS2Decoder OpusMS2Decoder; * @param [in] error : the error code when open an aac decoder. * @return return an opus decoder handle. */ -OpusMS2Decoder *opus_multistream2_decoder_create(int Fs, int streams, - int coupled_streams, - uint32_t flags, int *error); +Opus_Ms2_Decoder_t *opus_multistream2_decoder_create(int Fs, int streams, + int coupled_streams, + uint32_t flags, + int *error); /** * @brief Decode opus packet. @@ -46,13 +47,13 @@ OpusMS2Decoder *opus_multistream2_decoder_create(int Fs, int streams, * @param [in] frame_size : the frame size of aac. * @return return the number of decoded samples. */ -int opus_multistream2_decode(OpusMS2Decoder *st, uint8_t *buffer[], +int opus_multistream2_decode(Opus_Ms2_Decoder_t *st, uint8_t *buffer[], uint32_t len[], void *pcm, uint32_t frame_size); /** * @brief Destroy an opus decoder. * @param [in] st : opus decoder handle. */ -void opus_multistream2_decoder_destroy(OpusMS2Decoder *st); +void opus_multistream2_decoder_destroy(Opus_Ms2_Decoder_t *st); -#endif /* _OPUS_MULTISTREAM2_DECODER_H_ */ +#endif /* __OPUS_MULTISTREAM2_DECODER_H__ */ diff --git a/code/src/iamf_dec/pcm/IAMF_pcm_decoder.c b/code/src/iamf_dec/codec/pcm/iamf_pcm_decoder.c similarity index 53% rename from code/src/iamf_dec/pcm/IAMF_pcm_decoder.c rename to code/src/iamf_dec/codec/pcm/iamf_pcm_decoder.c index bb1669fc..4cbcd23a 100755 --- a/code/src/iamf_dec/pcm/IAMF_pcm_decoder.c +++ b/code/src/iamf_dec/codec/pcm/iamf_pcm_decoder.c @@ -17,25 +17,69 @@ * @date Created 03/03/2023 **/ -#include "IAMF_codec.h" -#include "IAMF_debug.h" -#include "IAMF_types.h" -#include "bitstream.h" +#include "clog.h" +#include "iamf_codec.h" -#ifdef IA_TAG -#undef IA_TAG +#ifdef def_log_tag +#undef def_log_tag #endif -#define IA_TAG "IAMF_PCM" +#define def_log_tag "IAMF_PCM" -typedef int (*readf)(uint8_t *, int); -typedef struct IAMF_PCM_Context { +typedef int (*func_sample_read_t)(uint8_t *, int); +typedef struct IamfPcmContext { float scale_i2f; - readf func; -} IAMF_PCM_Context; + func_sample_read_t func; +} iamf_pcm_context_t; -static int iamf_pcm_init(IAMF_CodecContext *ths) { - IAMF_PCM_Context *ctx = (IAMF_PCM_Context *)ths->priv; +static uint32_t readu16be(uint8_t *data, int offset) { + return data[offset] << 8 | data[offset + 1]; +} + +static int reads16be(uint8_t *data, int offset) { + short ret = readu16be(data, offset); + return ret; +} + +static uint32_t readu16le(uint8_t *data, int offset) { + return data[offset] | data[offset + 1] << 8; +} + +static int reads16le(uint8_t *data, int offset) { + short ret = (short)readu16le(data, offset); + return ret; +} + +static uint32_t readu24be(uint8_t *data, int offset) { + return readu16be(data, offset) << 8 | data[offset + 2]; +} + +static int reads24be(uint8_t *data, int offset) { + uint32_t ret = readu16le(data, offset) << 8 | data[offset + 2]; + int iret = ret << 8; + return (iret >> 8); +} + +static int reads24le(uint8_t *data, int offset) { + uint32_t ret = readu16le(data, offset) | data[offset + 2] << 16; + int iret = (int)(ret << 8); + return (iret >> 8); +} + +static uint32_t readu32be(uint8_t *data, int offset) { + return readu16be(data, offset) << 16 | readu16be(data, offset + 2); +} + +static int reads32be(uint8_t *data, int offset) { + return (int)readu32be(data, offset); +} + +static int reads32le(uint8_t *data, int offset) { + return readu16le(data, offset) | readu16le(data, offset + 2) << 16; +} + +static int iamf_pcm_init(iamf_codec_context_t *ths) { + iamf_pcm_context_t *ctx = (iamf_pcm_context_t *)ths->priv; uint8_t *config = ths->cspec; if (!ths->cspec || ths->clen <= 0) { @@ -46,8 +90,8 @@ static int iamf_pcm_init(IAMF_CodecContext *ths) { ths->sample_size = config[1]; ths->sample_rate = readu32be(config, 2); - ia_logd("sample format flags 0x%x, size %u, rate %u", ths->flags, - ths->sample_size, ths->sample_rate); + debug("sample format flags 0x%x, size %u, rate %u", ths->flags, + ths->sample_size, ths->sample_rate); ctx->func = reads16le; ctx->scale_i2f = 1 << 15; @@ -67,14 +111,14 @@ static int iamf_pcm_init(IAMF_CodecContext *ths) { ctx->func = reads32le; } - ia_logd("the scale of int to float: %f", ctx->scale_i2f); + debug("the scale of int to float: %f", ctx->scale_i2f); return IAMF_OK; } -static int iamf_pcm_decode(IAMF_CodecContext *ths, uint8_t *buf[], +static int iamf_pcm_decode(iamf_codec_context_t *ths, uint8_t *buf[], uint32_t len[], uint32_t count, void *pcm, const uint32_t frame_size) { - IAMF_PCM_Context *ctx = (IAMF_PCM_Context *)ths->priv; + iamf_pcm_context_t *ctx = (iamf_pcm_context_t *)ths->priv; float *fpcm = (float *)pcm; int c = 0, cc; int sample_size_bytes = ths->sample_size / 8; @@ -89,8 +133,8 @@ static int iamf_pcm_decode(IAMF_CodecContext *ths, uint8_t *buf[], for (; c < ths->coupled_streams; ++c) if (len[c] / 2 / sample_size_bytes != samples) { - ia_loge("the length of stream %d and 0 is different %d vs %d", c, - len[c] / 2 / sample_size_bytes, samples); + error("the length of stream %d and 0 is different %d vs %d", c, + len[c] / 2 / sample_size_bytes, samples); samples = -1; break; } @@ -98,8 +142,8 @@ static int iamf_pcm_decode(IAMF_CodecContext *ths, uint8_t *buf[], if (samples > 0) { for (; c < ths->streams; ++c) if (len[c] / sample_size_bytes != samples) { - ia_loge("the length of stream %d and 0 is different %d vs %d", c, - len[c] / sample_size_bytes, samples); + error("the length of stream %d and 0 is different %d vs %d", c, + len[c] / sample_size_bytes, samples); samples = -1; break; } @@ -107,11 +151,11 @@ static int iamf_pcm_decode(IAMF_CodecContext *ths, uint8_t *buf[], if (samples < 0) return IAMF_ERR_INTERNAL; - ia_logd("cs %d, s %d, frame size %d, samples %d", ths->coupled_streams, - ths->streams, frame_size, samples); + debug("cs %d, s %d, frame size %d, samples %d", ths->coupled_streams, + ths->streams, frame_size, samples); if (samples != frame_size) - ia_logw("real samples and frame size are different: %d vs %d", samples, + warning("real samples and frame size are different: %d vs %d", samples, frame_size); c = 0; @@ -135,11 +179,11 @@ static int iamf_pcm_decode(IAMF_CodecContext *ths, uint8_t *buf[], return samples; } -static int iamf_pcm_close(IAMF_CodecContext *ths) { return IAMF_OK; } +static int iamf_pcm_close(iamf_codec_context_t *ths) { return IAMF_OK; } -const IAMF_Codec iamf_pcm_decoder = { - .cid = IAMF_CODEC_PCM, - .priv_size = sizeof(IAMF_PCM_Context), +const iamf_codec_t iamf_pcm_decoder = { + .cid = ck_iamf_codec_id_lpcm, + .priv_size = sizeof(iamf_pcm_context_t), .init = iamf_pcm_init, .decode = iamf_pcm_decode, .close = iamf_pcm_close, diff --git a/code/src/iamf_dec/common/cbuffer.c b/code/src/iamf_dec/common/cbuffer.c new file mode 100755 index 00000000..9fc26871 --- /dev/null +++ b/code/src/iamf_dec/common/cbuffer.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file cbuffer.c + * @brief Circular buffer implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "cbuffer.h" + +#include +#include + +struct CBuffer { + uint8_t* data; + uint32_t size; +}; + +static void _buffer_free(buffer_t* buf) { + if (!buf) return; + + // fprintf(stderr, "freeing buffer %p.\n", buf); + + if (buf->data) free(buf->data); + free(buf); +} + +static buffer_t* _buffer_new(uint32_t size) { + buffer_t* buf = (buffer_t*)calloc(1, sizeof(buffer_t)); + if (buf) { + // fprintf(stderr, "malloc buffer %p.\n", buf); + buf->data = (uint8_t*)malloc(size); + if (!buf->data) { + _buffer_free(buf); + buf = 0; + } else { + buf->size = size; + } + } + return buf; +} + +static int _buffer_wrap_init_buffer(buffer_wrap_t* buf_wrap, buffer_t* buf) { + if (!buf_wrap || !buf) return -22; // -EINVAL + + buf_wrap->buf = buf; + buf_wrap->data = buf->data; + buf_wrap->size = buf->size; + return 0; +} + +buffer_wrap_t* buffer_wrap_default_new() { + buffer_wrap_t* buf_wrap = (buffer_wrap_t*)calloc(1, sizeof(buffer_wrap_t)); + return buf_wrap; +} + +buffer_wrap_t* buffer_wrap_new(uint32_t size) { + buffer_wrap_t* buf_wrap = buffer_wrap_default_new(); + if (buf_wrap) { + buffer_t* buf = _buffer_new(size); + if (!buf) { + buffer_wrap_free(buf_wrap); + buf_wrap = 0; + } else { + _buffer_wrap_init_buffer(buf_wrap, buf); + } + } + + return buf_wrap; +} + +void buffer_wrap_clear(buffer_wrap_t* buf_wrap) { + if (!buf_wrap) return; + if (buf_wrap->buf) _buffer_free(buf_wrap->buf); + memset(buf_wrap, 0, sizeof(buffer_wrap_t)); +} + +void buffer_wrap_free(buffer_wrap_t* buf_wrap) { + if (!buf_wrap) return; + buffer_wrap_clear(buf_wrap); + free(buf_wrap); +} diff --git a/code/src/iamf_dec/common/cbuffer.h b/code/src/iamf_dec/common/cbuffer.h new file mode 100755 index 00000000..2ac111b2 --- /dev/null +++ b/code/src/iamf_dec/common/cbuffer.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file cbuffer.h + * @brief Circular buffer APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __CBUFFER_H__ +#define __CBUFFER_H__ + +#include + +#include "iorw.h" + +typedef struct CBuffer buffer_t; + +typedef struct CBufferWrap { + buffer_t* buf; + + uint8_t* data; + uint32_t size; +} buffer_wrap_t; + +typedef struct CBufferIOWrap { + buffer_t* buf; + io_context_t ioctx; +} buffer_io_wrap_t; + +buffer_wrap_t* buffer_wrap_default_new(); +buffer_wrap_t* buffer_wrap_new(uint32_t size); + +void buffer_wrap_clear(buffer_wrap_t* buf_wrap); +void buffer_wrap_free(buffer_wrap_t* buf_wrap); + +#endif // __CBUFFER_H__ diff --git a/code/src/iamf_dec/common/iorw.c b/code/src/iamf_dec/common/iorw.c new file mode 100755 index 00000000..6a5a2dd5 --- /dev/null +++ b/code/src/iamf_dec/common/iorw.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iorw.c + * @brief iorw APIs. + * @version 2.0.0 + * @date Created 19/02/2025 + **/ + +#include "iorw.h" + +#include +#include +#include +#include + +void ioc_init(io_context_t* c, uint8_t* buffer, uint32_t size) { + c->buffer = buffer; + c->size = size; + c->idx = 0; +} + +uint32_t ioc_tell(io_context_t* ctx) { return ctx->idx; } +uint32_t ioc_remain(io_context_t* ctx) { return ctx->size - ctx->idx; } + +static inline int ioc_precheck(io_context_t* ctx, uint32_t n) { + return ctx->idx + n <= ctx->size; +} + +uint32_t iow_8(io_context_t* ctx, uint32_t value) { + if (!ioc_precheck(ctx, 1)) return 0; + ctx->buffer[ctx->idx++] = (uint8_t)(value & 0xff); + return 1; +} + +uint32_t ior_read(io_context_t* ctx, uint8_t* data, uint32_t n) { + if (!ioc_precheck(ctx, n)) n = ctx->size - ctx->idx; + memcpy(data, &ctx->buffer[ctx->idx], n); + ctx->idx += n; + return n; +} + +uint32_t ior_8(io_context_t* ctx) { + return ioc_precheck(ctx, 1) ? ctx->buffer[ctx->idx++] : 0; +} + +uint32_t ior_b16(io_context_t* ctx) { + uint32_t val = ior_8(ctx) << 8; + val |= ior_8(ctx); + return val; +} + +uint32_t ior_b24(io_context_t* ctx) { + uint32_t val = ior_8(ctx) << 16; + val |= ior_b16(ctx); + return val; +} + +uint32_t ior_b32(io_context_t* ctx) { + uint32_t val = ior_b16(ctx) << 16; + val |= ior_b16(ctx); + return val; +} + +uint64_t ior_leb128(io_context_t* ctx) { + uint64_t val = 0; + uint8_t byte; + for (int n = 0; n < 8; n++) { + byte = ior_8(ctx); + val |= (((uint64_t)byte & 0x7f) << (n * 7)); + if (!(byte & 0x80)) break; + } + return val; +} + +uint32_t ior_leb128_u32(io_context_t* ctx) { + uint64_t val = ior_leb128(ctx); + if (val > UINT32_MAX) val = UINT32_MAX; + return val; +} + +uint32_t ior_expandable(io_context_t* ctx) { + uint32_t val = 0; + uint8_t byte; + for (uint32_t i = 0; i < 4; i++) { + byte = ior_8(ctx); + val <<= 7; + val |= (byte & 0x7f); + if (!(byte & 0x80)) break; + } + return val; +} + +uint32_t ior_skip(io_context_t* ctx, uint32_t n) { + if (!ioc_precheck(ctx, n)) n = ctx->size - ctx->idx; + ctx->idx += n; + return n; +} + +uint32_t ior_string(io_context_t* ctx, char* str, uint32_t n) { + size_t slen = strlen((char*)&ctx->buffer[ctx->idx]); + uint32_t len = n; + if (!ioc_precheck(ctx, len)) len = ctx->size - ctx->idx - 1; + if (slen < len) len = slen; + if (len == n) --len; + memcpy(str, &ctx->buffer[ctx->idx], len); + str[len] = '\0'; + if (!ioc_precheck(ctx, slen + 1)) + ctx->idx = ctx->size; + else + ctx->idx += (slen + 1); + return len + 1; +} + +void bits_ioc_init(bits_io_context_t* bits_ctx, io_context_t* ioc) { + memset(bits_ctx, 0, sizeof(bits_io_context_t)); + bits_ctx->ioc = ioc; +} + +#define def_byte_bits 8 + +uint32_t bits_ior_le32(bits_io_context_t* ctx, uint32_t n) { + io_context_t* r = ctx->ioc; + uint32_t bit_remain; + uint32_t value = 0; + + while (n) { + bit_remain = def_byte_bits - ctx->bit_idx; + if (!ctx->bit_idx) ctx->byte = ior_8(r); + + value <<= n < bit_remain ? n : bit_remain; + if (n < bit_remain) { + value |= (ctx->byte >> (bit_remain - n)) & ((1 << n) - 1); + ctx->bit_idx += n; + break; + } + value |= ctx->byte & ((1 << bit_remain) - 1); + ctx->bit_idx += bit_remain; + ctx->bit_idx %= def_byte_bits; + n -= bit_remain; + } + + return value; +} \ No newline at end of file diff --git a/code/src/iamf_dec/common/iorw.h b/code/src/iamf_dec/common/iorw.h new file mode 100755 index 00000000..33eb1090 --- /dev/null +++ b/code/src/iamf_dec/common/iorw.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iorw.h + * @brief iorw APIs. + * @version 0.1 + * @date Created 19/02/2025 + **/ + +#ifndef __IO_RW_H__ +#define __IO_RW_H__ + +#include +#include + +typedef struct IOContext { + uint8_t* buffer; + uint32_t size; + uint32_t idx; +} io_context_t; + +typedef struct BitsIOContext { + io_context_t* ioc; + uint32_t bit_idx; + uint32_t byte; +} bits_io_context_t; + +void ioc_init(io_context_t* ctx, uint8_t* buffer, uint32_t size); +uint32_t ioc_tell(io_context_t* ctx); +uint32_t ioc_remain(io_context_t* ctx); + +uint32_t iow_8(io_context_t* ctx, uint32_t value); + +uint32_t ior_read(io_context_t* ctx, uint8_t* data, uint32_t n); +uint32_t ior_8(io_context_t* ctx); +uint32_t ior_b16(io_context_t* ctx); +uint32_t ior_b24(io_context_t* ctx); +uint32_t ior_b32(io_context_t* ctx); +uint64_t ior_leb128(io_context_t* ctx); +uint32_t ior_leb128_u32(io_context_t* ctx); +uint32_t ior_expandable(io_context_t* ctx); +uint32_t ior_skip(io_context_t* ctx, uint32_t n); +uint32_t ior_string(io_context_t* ctx, char* str, uint32_t n); + +void bits_ioc_init(bits_io_context_t* bits_ctx, io_context_t* ctx); +uint32_t bits_ior_le32(bits_io_context_t* ctx, uint32_t n); + +#endif // __IO_RW_H__ \ No newline at end of file diff --git a/code/src/iamf_dec/IAMF_debug_sr.c b/code/src/iamf_dec/debug/iamf_debug_sr.c similarity index 95% rename from code/src/iamf_dec/IAMF_debug_sr.c rename to code/src/iamf_dec/debug/iamf_debug_sr.c index 59a356c8..57720bb1 100755 --- a/code/src/iamf_dec/IAMF_debug_sr.c +++ b/code/src/iamf_dec/debug/iamf_debug_sr.c @@ -11,18 +11,18 @@ */ /** - * @file IAMF_debug_sr.c + * @file iamf_debug_sr.c * @brief Debug APIs. * @version 0.1 * @date Created 03/03/2023 **/ - #include -#include "IAMF_utils.h" +#include "iamf_private_definitions.h" +#include "iamf_utils.h" #include "wav/dep_wavwriter.h" -#define N_AUDIO_STREAM 10 +#define N_AUDIO_STREAM 28 static void ia_decoder_plane2stride_out_float(void *dst, const float *src, int frame_size, int channels) { @@ -83,7 +83,7 @@ void iamf_rec_stream_log(int eid, int chs, float *in, int size) { } } - pcm_b = IAMF_MALLOC(float, size *nch); + pcm_b = def_malloc(float, size *nch); ia_decoder_plane2stride_out_float(pcm_b, in, size, nch); dep_wav_write_data(wf, pcm_b, size * nch * sizeof(float)); free(pcm_b); @@ -117,7 +117,7 @@ void iamf_ren_stream_log(int eid, int chs, float *out, int size) { } } - pcm_b = IAMF_MALLOC(float, size *nch); + pcm_b = def_malloc(float, size *nch); ia_decoder_plane2stride_out_float(pcm_b, out, size, nch); dep_wav_write_data(wf, pcm_b, size * nch * sizeof(float)); free(pcm_b); @@ -143,7 +143,7 @@ void iamf_mix_stream_log(int chs, float *out, int size) { _mix_stream_count++; } - pcm_b = IAMF_MALLOC(float, size *nch); + pcm_b = def_malloc(float, size *nch); ia_decoder_plane2stride_out_float(pcm_b, out, size, nch); dep_wav_write_data(wf, pcm_b, size * nch * sizeof(float)); free(pcm_b); diff --git a/code/src/iamf_dec/debug/iamf_obu_debug.h b/code/src/iamf_dec/debug/iamf_obu_debug.h new file mode 100755 index 00000000..0a887bee --- /dev/null +++ b/code/src/iamf_dec/debug/iamf_obu_debug.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_obu_debug.h + * @brief IAMF OBU Debug APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_OBU_DEBUG_H__ +#define __IAMF_OBU_DEBUG_H__ + +#include + +#define def_dfn_size 32 + +#define obu_dump(data, size, type) \ + do { \ + static int _obu_count = 0; \ + static char dfn[def_dfn_size]; \ + snprintf(dfn, def_dfn_size, "/tmp/obu/obu_%02d_%06d.dat", type, \ + _obu_count); \ + FILE *f = fopen(dfn, "w"); \ + if (f) { \ + fwrite(data, 1, size, f); \ + fclose(f); \ + } \ + ++_obu_count; \ + } while (0) + +#endif /* __IAMF_OBU_DEBUG_H__ */ \ No newline at end of file diff --git a/code/src/iamf_dec/demixer.c b/code/src/iamf_dec/demixer.c index 51487e6d..fd8af87a 100755 --- a/code/src/iamf_dec/demixer.c +++ b/code/src/iamf_dec/demixer.c @@ -24,18 +24,17 @@ #define _USE_MATH_DEFINES #include -#include "IAMF_debug.h" #include "IAMF_decoder.h" -#include "IAMF_layout.h" -#include "IAMF_utils.h" +#include "clog.h" #include "demixer.h" -#include "fixedp11_5.h" +#include "iamf_layout.h" +#include "iamf_string.h" -#ifdef IA_TAG -#undef IA_TAG +#ifdef def_log_tag +#undef def_log_tag #endif -#define IA_TAG "IAMF_DMX" +#define def_log_tag "IAMF_DMX" /** * alpha and beta are gain values used for S7to5 down-mixer, @@ -58,7 +57,7 @@ static struct DemixingTypeMat { {1.0, 0.866, 0.866, 0.866, 1}, {0, 0, 0, 0, 0}}; struct Demixer { - float *ch_data[IA_CH_COUNT]; + float *ch_data[ck_iamf_channel_count]; int weight_state_idx; int last_dmixtypenum; int last_weight_state_idx; @@ -69,19 +68,19 @@ struct Demixer { float *start_window; float *stop_window; float *large_buffer; - float ch_last_sf[IA_CH_COUNT]; - float ch_last_sfavg[IA_CH_COUNT]; + float ch_last_sf[ck_iamf_channel_count]; + float ch_last_sfavg[ck_iamf_channel_count]; - IAChannelLayoutType layout; - IAChannel chs_in[IA_CH_LAYOUT_MAX_CHANNELS]; - IAChannel chs_out[IA_CH_LAYOUT_MAX_CHANNELS]; + iamf_loudspeaker_layout_t layout; + iamf_channel_t chs_in[def_max_audio_channels]; + iamf_channel_t chs_out[def_max_audio_channels]; int chs_count; struct { struct { - IAChannel ch; + iamf_channel_t ch; float gain; - } ch_gain[IA_CH_LAYOUT_MAX_CHANNELS]; + } ch_gain[def_max_audio_channels]; uint8_t count; } chs_gain_list; @@ -89,9 +88,9 @@ struct Demixer { struct { struct { - IAChannel ch; + iamf_channel_t ch; float recon_gain; - } ch_recon_gain[IA_CH_RE_COUNT]; + } ch_recon_gain[ck_iamf_channel_recon_count]; uint8_t count; uint32_t flags; } chs_recon_gain_list; @@ -107,28 +106,49 @@ enum { CH_MX_COUNT }; +static float widx2w_table[11] = {0.0, 0.0179, 0.0391, 0.0658, 0.1038, 0.25, + 0.3962, 0.4342, 0.4609, 0.4821, 0.5}; +static float calc_w(int w_idx_offset, int w_idx_prev, int *w_idx) { + if (w_idx_offset > 0) + *w_idx = def_min(w_idx_prev + 1, 10); + else + *w_idx = def_max(w_idx_prev - 1, 0); + + return widx2w_table[*w_idx]; +} + +static float get_w(int w_idx) { + if (w_idx < 0) + return widx2w_table[0]; + else if (w_idx > 10) + return widx2w_table[10]; + + return widx2w_table[w_idx]; +} + /** * S1to2 de-mixer: R2 = 2 x Mono - L2 * */ static int dmx_s2(Demixer *ths) { float *r = 0; - if (!ths->ch_data[IA_CH_L2]) return IAMF_ERR_INTERNAL; - if (ths->ch_data[IA_CH_R2]) return 0; - if (!ths->ch_data[IA_CH_MONO]) return IAMF_ERR_INTERNAL; + if (!ths->ch_data[ck_iamf_channel_l2]) return IAMF_ERR_INTERNAL; + if (ths->ch_data[ck_iamf_channel_r2]) return 0; + if (!ths->ch_data[ck_iamf_channel_mono]) return IAMF_ERR_INTERNAL; - ia_logd("---- s1to2 ----"); + debug("---- s1to2 ----"); r = &ths->large_buffer[ths->frame_size * CH_MX_S_R]; for (int i = 0; i < ths->frame_size; ++i) { - r[i] = 2 * ths->ch_data[IA_CH_MONO][i] - ths->ch_data[IA_CH_L2][i]; + r[i] = 2 * ths->ch_data[ck_iamf_channel_mono][i] - + ths->ch_data[ck_iamf_channel_l2][i]; } - ths->ch_data[IA_CH_R2] = r; + ths->ch_data[ck_iamf_channel_r2] = r; - ia_logd("reconstructed channel %s(%d) at %p, buffer at %p", - ia_channel_name(IA_CH_R2), IA_CH_R2, ths->ch_data[IA_CH_R2], - ths->large_buffer); + debug("reconstructed channel %s(%d) at %p, buffer at %p", + iamf_channel_name(ck_iamf_channel_r2), ck_iamf_channel_r2, + ths->ch_data[ck_iamf_channel_r2], ths->large_buffer); return 0; } @@ -139,28 +159,30 @@ static int dmx_s3(Demixer *ths) { float *l, *r; uint32_t fs = ths->frame_size; - if (ths->ch_data[IA_CH_R3]) return 0; + if (ths->ch_data[ck_iamf_channel_r3]) return 0; if (dmx_s2(ths)) return IAMF_ERR_INTERNAL; - if (!ths->ch_data[IA_CH_C]) return IAMF_ERR_INTERNAL; + if (!ths->ch_data[ck_iamf_channel_c]) return IAMF_ERR_INTERNAL; - ia_logt("---- s2to3 ----"); + trace("---- s2to3 ----"); l = &ths->large_buffer[CH_MX_S_L * fs]; r = &ths->large_buffer[CH_MX_S_R * fs]; for (int i = 0; i < fs; i++) { - l[i] = ths->ch_data[IA_CH_L2][i] - 0.707 * ths->ch_data[IA_CH_C][i]; - r[i] = ths->ch_data[IA_CH_R2][i] - 0.707 * ths->ch_data[IA_CH_C][i]; + l[i] = ths->ch_data[ck_iamf_channel_l2][i] - + 0.707 * ths->ch_data[ck_iamf_channel_c][i]; + r[i] = ths->ch_data[ck_iamf_channel_r2][i] - + 0.707 * ths->ch_data[ck_iamf_channel_c][i]; } - ths->ch_data[IA_CH_L3] = l; - ths->ch_data[IA_CH_R3] = r; + ths->ch_data[ck_iamf_channel_l3] = l; + ths->ch_data[ck_iamf_channel_r3] = r; - ia_logd( + debug( "reconstructed channel %s(%d) at %p, channel %s(%d) at %p, buffer at " "%p", - ia_channel_name(IA_CH_L3), IA_CH_L3, ths->ch_data[IA_CH_L3], - ia_channel_name(IA_CH_R3), IA_CH_R3, ths->ch_data[IA_CH_R3], - ths->large_buffer); + iamf_channel_name(ck_iamf_channel_l3), ck_iamf_channel_l3, + ths->ch_data[ck_iamf_channel_l3], iamf_channel_name(ck_iamf_channel_r3), + ck_iamf_channel_r3, ths->ch_data[ck_iamf_channel_r3], ths->large_buffer); return 0; } @@ -176,39 +198,44 @@ static int dmx_s5(Demixer *ths) { int last_Typeid = ths->last_dmixtypenum; int i = 0; - if (ths->ch_data[IA_CH_SR5]) return 0; + if (ths->ch_data[ck_iamf_channel_sr5]) return 0; if (dmx_s3(ths)) return IAMF_ERR_INTERNAL; - if (!ths->ch_data[IA_CH_L5] || !ths->ch_data[IA_CH_R5]) + if (!ths->ch_data[ck_iamf_channel_l5] || !ths->ch_data[ck_iamf_channel_r5]) return IAMF_ERR_INTERNAL; - ia_logt("---- s3to5 ----"); - ia_logd("Typeid %d, Lasttypeid %d", Typeid, last_Typeid); + trace("---- s3to5 ----"); + debug("Typeid %d, Lasttypeid %d", Typeid, last_Typeid); l = &ths->large_buffer[CH_MX_S5_L * fs]; r = &ths->large_buffer[CH_MX_S5_R * fs]; for (; i < ths->skip; i++) { - l[i] = (ths->ch_data[IA_CH_L3][i] - ths->ch_data[IA_CH_L5][i]) / + l[i] = (ths->ch_data[ck_iamf_channel_l3][i] - + ths->ch_data[ck_iamf_channel_l5][i]) / demixing_type_mat[last_Typeid].delta; - r[i] = (ths->ch_data[IA_CH_R3][i] - ths->ch_data[IA_CH_R5][i]) / + r[i] = (ths->ch_data[ck_iamf_channel_r3][i] - + ths->ch_data[ck_iamf_channel_r5][i]) / demixing_type_mat[last_Typeid].delta; } for (; i < fs; i++) { - l[i] = (ths->ch_data[IA_CH_L3][i] - ths->ch_data[IA_CH_L5][i]) / + l[i] = (ths->ch_data[ck_iamf_channel_l3][i] - + ths->ch_data[ck_iamf_channel_l5][i]) / demixing_type_mat[Typeid].delta; - r[i] = (ths->ch_data[IA_CH_R3][i] - ths->ch_data[IA_CH_R5][i]) / + r[i] = (ths->ch_data[ck_iamf_channel_r3][i] - + ths->ch_data[ck_iamf_channel_r5][i]) / demixing_type_mat[Typeid].delta; } - ths->ch_data[IA_CH_SL5] = l; - ths->ch_data[IA_CH_SR5] = r; + ths->ch_data[ck_iamf_channel_sl5] = l; + ths->ch_data[ck_iamf_channel_sr5] = r; - ia_logd( + debug( "reconstructed channel %s(%d) at %p, channel %s(%d) at %p, buffer at " "%p", - ia_channel_name(IA_CH_SL5), IA_CH_SL5, ths->ch_data[IA_CH_SL5], - ia_channel_name(IA_CH_SR5), IA_CH_SR5, ths->ch_data[IA_CH_SR5], + iamf_channel_name(ck_iamf_channel_sl5), ck_iamf_channel_sl5, + ths->ch_data[ck_iamf_channel_sl5], iamf_channel_name(ck_iamf_channel_sr5), + ck_iamf_channel_sr5, ths->ch_data[ck_iamf_channel_sr5], ths->large_buffer); return 0; } @@ -225,43 +252,48 @@ static int dmx_s7(Demixer *ths) { int Typeid = ths->demixing_mode; int last_Typeid = ths->last_dmixtypenum; - if (ths->ch_data[IA_CH_BR7]) return 0; + if (ths->ch_data[ck_iamf_channel_br7]) return 0; if (dmx_s5(ths) < 0) return IAMF_ERR_INTERNAL; - if (!ths->ch_data[IA_CH_SL7] || !ths->ch_data[IA_CH_SR7]) + if (!ths->ch_data[ck_iamf_channel_sl7] || !ths->ch_data[ck_iamf_channel_sr7]) return IAMF_ERR_INTERNAL; - ia_logt("---- s5to7 ----"); - ia_logd("Typeid %d, Lasttypeid %d", Typeid, last_Typeid); + trace("---- s5to7 ----"); + debug("Typeid %d, Lasttypeid %d", Typeid, last_Typeid); l = &ths->large_buffer[CH_MX_S_L * fs]; r = &ths->large_buffer[CH_MX_S_R * fs]; for (; i < ths->skip; i++) { - l[i] = (ths->ch_data[IA_CH_SL5][i] - - ths->ch_data[IA_CH_SL7][i] * demixing_type_mat[last_Typeid].alpha) / + l[i] = (ths->ch_data[ck_iamf_channel_sl5][i] - + ths->ch_data[ck_iamf_channel_sl7][i] * + demixing_type_mat[last_Typeid].alpha) / demixing_type_mat[last_Typeid].beta; - r[i] = (ths->ch_data[IA_CH_SR5][i] - - ths->ch_data[IA_CH_SR7][i] * demixing_type_mat[last_Typeid].alpha) / + r[i] = (ths->ch_data[ck_iamf_channel_sr5][i] - + ths->ch_data[ck_iamf_channel_sr7][i] * + demixing_type_mat[last_Typeid].alpha) / demixing_type_mat[last_Typeid].beta; } for (; i < ths->frame_size; i++) { - l[i] = (ths->ch_data[IA_CH_SL5][i] - - ths->ch_data[IA_CH_SL7][i] * demixing_type_mat[Typeid].alpha) / + l[i] = (ths->ch_data[ck_iamf_channel_sl5][i] - + ths->ch_data[ck_iamf_channel_sl7][i] * + demixing_type_mat[Typeid].alpha) / demixing_type_mat[Typeid].beta; - r[i] = (ths->ch_data[IA_CH_SR5][i] - - ths->ch_data[IA_CH_SR7][i] * demixing_type_mat[Typeid].alpha) / + r[i] = (ths->ch_data[ck_iamf_channel_sr5][i] - + ths->ch_data[ck_iamf_channel_sr7][i] * + demixing_type_mat[Typeid].alpha) / demixing_type_mat[Typeid].beta; } - ths->ch_data[IA_CH_BL7] = l; - ths->ch_data[IA_CH_BR7] = r; + ths->ch_data[ck_iamf_channel_bl7] = l; + ths->ch_data[ck_iamf_channel_br7] = r; - ia_logd( + debug( "reconstructed channel %s(%d) at %p, channel %s(%d) at %p, buffer at " "%p", - ia_channel_name(IA_CH_BL7), IA_CH_BL7, ths->ch_data[IA_CH_BL7], - ia_channel_name(IA_CH_BR7), IA_CH_BR7, ths->ch_data[IA_CH_BR7], + iamf_channel_name(ck_iamf_channel_bl7), ck_iamf_channel_bl7, + ths->ch_data[ck_iamf_channel_bl7], iamf_channel_name(ck_iamf_channel_br7), + ck_iamf_channel_br7, ths->ch_data[ck_iamf_channel_br7], ths->large_buffer); return 0; } @@ -279,42 +311,47 @@ static int dmx_h2(Demixer *ths) { int Typeid = ths->demixing_mode; int last_Typeid = ths->last_dmixtypenum; - if (ths->ch_data[IA_CH_HR]) return 0; - if (!ths->ch_data[IA_CH_TL] || !ths->ch_data[IA_CH_TR]) + if (ths->ch_data[ck_iamf_channel_hr]) return 0; + if (!ths->ch_data[ck_iamf_channel_tl] || !ths->ch_data[ck_iamf_channel_tr]) return IAMF_ERR_INTERNAL; if (dmx_s5(ths)) return IAMF_ERR_INTERNAL; w = get_w(ths->weight_state_idx); lastW = get_w(ths->last_weight_state_idx); - ia_logt("---- hf2to2 ----"); - ia_logd("Typeid %d, w %f,, Lasttypeid %d, lastW %f", Typeid, w, last_Typeid, - lastW); + trace("---- hf2to2 ----"); + debug("Typeid %d, w %f,, Lasttypeid %d, lastW %f", Typeid, w, last_Typeid, + lastW); l = &ths->large_buffer[CH_MX_T_L * fs]; r = &ths->large_buffer[CH_MX_T_R * fs]; for (; i < ths->skip; i++) { - l[i] = ths->ch_data[IA_CH_TL][i] - demixing_type_mat[last_Typeid].delta * - lastW * ths->ch_data[IA_CH_SL5][i]; - r[i] = ths->ch_data[IA_CH_TR][i] - demixing_type_mat[last_Typeid].delta * - lastW * ths->ch_data[IA_CH_SR5][i]; + l[i] = ths->ch_data[ck_iamf_channel_tl][i] - + demixing_type_mat[last_Typeid].delta * lastW * + ths->ch_data[ck_iamf_channel_sl5][i]; + r[i] = ths->ch_data[ck_iamf_channel_tr][i] - + demixing_type_mat[last_Typeid].delta * lastW * + ths->ch_data[ck_iamf_channel_sr5][i]; } for (; i < ths->frame_size; i++) { - l[i] = ths->ch_data[IA_CH_TL][i] - - demixing_type_mat[Typeid].delta * w * ths->ch_data[IA_CH_SL5][i]; - r[i] = ths->ch_data[IA_CH_TR][i] - - demixing_type_mat[Typeid].delta * w * ths->ch_data[IA_CH_SR5][i]; + l[i] = ths->ch_data[ck_iamf_channel_tl][i] - + demixing_type_mat[Typeid].delta * w * + ths->ch_data[ck_iamf_channel_sl5][i]; + r[i] = ths->ch_data[ck_iamf_channel_tr][i] - + demixing_type_mat[Typeid].delta * w * + ths->ch_data[ck_iamf_channel_sr5][i]; } - ths->ch_data[IA_CH_HL] = l; - ths->ch_data[IA_CH_HR] = r; + ths->ch_data[ck_iamf_channel_hl] = l; + ths->ch_data[ck_iamf_channel_hr] = r; - ia_logt("channel %s(%d) at %p, channel %s(%d) at %p, buffer at %p", - ia_channel_name(IA_CH_HL), IA_CH_HL, ths->ch_data[IA_CH_HL], - ia_channel_name(IA_CH_HR), IA_CH_HR, ths->ch_data[IA_CH_HR], - ths->large_buffer); + trace("channel %s(%d) at %p, channel %s(%d) at %p, buffer at %p", + iamf_channel_name(ck_iamf_channel_hl), ck_iamf_channel_hl, + ths->ch_data[ck_iamf_channel_hl], iamf_channel_name(ck_iamf_channel_hr), + ck_iamf_channel_hr, ths->ch_data[ck_iamf_channel_hr], + ths->large_buffer); return 0; } @@ -328,74 +365,79 @@ static int dmx_h4(Demixer *ths) { int Typeid = ths->demixing_mode; int last_Typeid = ths->last_dmixtypenum; - if (ths->ch_data[IA_CH_HBR]) return 0; + if (ths->ch_data[ck_iamf_channel_hbr]) return 0; if (dmx_h2(ths)) return IAMF_ERR_INTERNAL; - if (!ths->ch_data[IA_CH_HFR] || !ths->ch_data[IA_CH_HFL]) + if (!ths->ch_data[ck_iamf_channel_hfr] || !ths->ch_data[ck_iamf_channel_hfl]) return IAMF_ERR_INTERNAL; - ia_logt("---- h2to4 ----"); - ia_logd("Typeid %d, Lasttypeid %d", Typeid, last_Typeid); + trace("---- h2to4 ----"); + debug("Typeid %d, Lasttypeid %d", Typeid, last_Typeid); l = &ths->large_buffer[CH_MX_T_L * fs]; r = &ths->large_buffer[CH_MX_T_R * fs]; for (; i < ths->skip; i++) { - l[i] = (ths->ch_data[IA_CH_HL][i] - ths->ch_data[IA_CH_HFL][i]) / + l[i] = (ths->ch_data[ck_iamf_channel_hl][i] - + ths->ch_data[ck_iamf_channel_hfl][i]) / demixing_type_mat[last_Typeid].gamma; - r[i] = (ths->ch_data[IA_CH_HR][i] - ths->ch_data[IA_CH_HFR][i]) / + r[i] = (ths->ch_data[ck_iamf_channel_hr][i] - + ths->ch_data[ck_iamf_channel_hfr][i]) / demixing_type_mat[last_Typeid].gamma; } for (; i < ths->frame_size; i++) { - l[i] = (ths->ch_data[IA_CH_HL][i] - ths->ch_data[IA_CH_HFL][i]) / + l[i] = (ths->ch_data[ck_iamf_channel_hl][i] - + ths->ch_data[ck_iamf_channel_hfl][i]) / demixing_type_mat[Typeid].gamma; - r[i] = (ths->ch_data[IA_CH_HR][i] - ths->ch_data[IA_CH_HFR][i]) / + r[i] = (ths->ch_data[ck_iamf_channel_hr][i] - + ths->ch_data[ck_iamf_channel_hfr][i]) / demixing_type_mat[Typeid].gamma; } - ths->ch_data[IA_CH_HBL] = l; - ths->ch_data[IA_CH_HBR] = r; + ths->ch_data[ck_iamf_channel_hbl] = l; + ths->ch_data[ck_iamf_channel_hbr] = r; - ia_logt("channel %s(%d) at %p, channel %s(%d) at %p, buffer at %p", - ia_channel_name(IA_CH_HBL), IA_CH_HBL, ths->ch_data[IA_CH_HBL], - ia_channel_name(IA_CH_HBR), IA_CH_HBR, ths->ch_data[IA_CH_HBR], - ths->large_buffer); + trace("channel %s(%d) at %p, channel %s(%d) at %p, buffer at %p", + iamf_channel_name(ck_iamf_channel_hbl), ck_iamf_channel_hbl, + ths->ch_data[ck_iamf_channel_hbl], + iamf_channel_name(ck_iamf_channel_hbr), ck_iamf_channel_hbr, + ths->ch_data[ck_iamf_channel_hbr], ths->large_buffer); return 0; } -static int dmx_channel(Demixer *ths, IAChannel ch) { +static int dmx_channel(Demixer *ths, iamf_channel_t ch) { int ret = IAMF_ERR_INTERNAL; - ia_logt("demix channel %s(%d) pos %p", ia_channel_name(ch), ch, - ths->ch_data[ch]); + trace("demix channel %s(%d) pos %p", iamf_channel_name(ch), ch, + ths->ch_data[ch]); if (ths->ch_data[ch]) { return IAMF_OK; } - ia_logd("reconstruct channel %s(%d)", ia_channel_name(ch), ch); + debug("reconstruct channel %s(%d)", iamf_channel_name(ch), ch); switch (ch) { - case IA_CH_R2: + case ck_iamf_channel_r2: ret = dmx_s2(ths); break; - case IA_CH_L3: - case IA_CH_R3: + case ck_iamf_channel_l3: + case ck_iamf_channel_r3: ret = dmx_s3(ths); break; - case IA_CH_SL5: - case IA_CH_SR5: + case ck_iamf_channel_sl5: + case ck_iamf_channel_sr5: ret = dmx_s5(ths); break; - case IA_CH_BL7: - case IA_CH_BR7: + case ck_iamf_channel_bl7: + case ck_iamf_channel_br7: ret = dmx_s7(ths); break; - case IA_CH_HL: - case IA_CH_HR: + case ck_iamf_channel_hl: + case ck_iamf_channel_hr: ret = dmx_h2(ths); break; - case IA_CH_HBL: - case IA_CH_HBR: + case ck_iamf_channel_hbl: + case ck_iamf_channel_hbr: ret = dmx_h4(ths); break; default: @@ -416,7 +458,7 @@ static void dmx_gainup(Demixer *ths) { } static int dmx_demix(Demixer *ths) { - int chcnt = iamf_audio_layer_get_layout_info(ths->layout)->channels; + int chcnt = iamf_loudspeaker_layout_get_info(ths->layout)->channels; for (int c = 0; c < chcnt; ++c) { if (dmx_channel(ths, ths->chs_out[c]) < 0) { @@ -431,9 +473,9 @@ static void dmx_rms(Demixer *ths) { float sf, sfavg; float filtBuf; float *out; - IAChannel ch; + iamf_channel_t ch; - ia_logt("---- demixer_equalizeRMS ----"); + trace("---- demixer_equalizeRMS ----"); for (int c = 0; c < ths->chs_recon_gain_list.count; c++) { ch = ths->chs_recon_gain_list.ch_recon_gain[c].ch; @@ -446,8 +488,8 @@ static void dmx_rms(Demixer *ths) { sfavg = sf; } - ia_logd("channel %s(%d) is smoothed within %f.", ia_channel_name(ch), ch, - sf); + debug("channel %s(%d) is smoothed within %f.", iamf_channel_name(ch), ch, + sf); /* different scale factor in overapping area */ for (int i = 0; i < ths->frame_size; i++) { filtBuf = ths->ch_last_sfavg[ch] * ths->stop_window[i] + @@ -463,23 +505,23 @@ static void dmx_rms(Demixer *ths) { Demixer *demixer_open(uint32_t frame_size) { Demixer *ths = 0; int ec = IAMF_OK; - ths = IAMF_MALLOCZ(Demixer, 1); + ths = def_mallocz(Demixer, 1); if (ths) { int windowLen = frame_size / 8; ths->frame_size = frame_size; - ths->layout = IA_CHANNEL_LAYOUT_INVALID; + ths->layout = ck_iamf_loudspeaker_layout_none; - ths->hanning_filter = IAMF_MALLOC(float, windowLen); - ths->start_window = IAMF_MALLOC(float, frame_size); - ths->stop_window = IAMF_MALLOC(float, frame_size); - ths->large_buffer = IAMF_MALLOC(float, CH_MX_COUNT *frame_size); + ths->hanning_filter = def_malloc(float, windowLen); + ths->start_window = def_malloc(float, frame_size); + ths->stop_window = def_malloc(float, frame_size); + ths->large_buffer = def_malloc(float, CH_MX_COUNT *frame_size); if (!ths->hanning_filter || !ths->start_window || !ths->stop_window || !ths->large_buffer) { ec = IAMF_ERR_ALLOC_FAIL; - ia_loge("%s : hanning window, start & stop windows.", - ia_error_code_string(ec)); + error("%s : hanning window, start & stop windows.", + iamf_error_code_string(ec)); goto termination; } /** @@ -495,7 +537,7 @@ Demixer *demixer_open(uint32_t frame_size) { ths->stop_window[i] = 0; } - for (int i = 0; i < IA_CH_COUNT; ++i) { + for (int i = 0; i < ck_iamf_channel_count; ++i) { ths->ch_last_sf[i] = 1.0; ths->ch_last_sfavg[i] = 1.0; } @@ -512,10 +554,10 @@ Demixer *demixer_open(uint32_t frame_size) { void demixer_close(Demixer *ths) { if (ths) { - IAMF_FREE(ths->hanning_filter); - IAMF_FREE(ths->start_window); - IAMF_FREE(ths->stop_window); - IAMF_FREE(ths->large_buffer); + def_free(ths->hanning_filter); + def_free(ths->start_window); + def_free(ths->stop_window); + def_free(ths->large_buffer); free(ths); } } @@ -528,7 +570,7 @@ int demixer_set_frame_offset(Demixer *ths, uint32_t offset) { preskip = offset % ths->frame_size; ths->skip = preskip; - ia_logd("demixer preskip %d, overlayLen %d", preskip, overlapLen); + debug("demixer preskip %d, overlayLen %d", preskip, overlapLen); if (preskip + overlapLen > ths->frame_size) return IAMF_OK; for (int i = 0; i < preskip; i++) { @@ -548,28 +590,28 @@ int demixer_set_frame_offset(Demixer *ths, uint32_t offset) { return IAMF_OK; } -int demixer_set_channel_layout(Demixer *ths, IAChannelLayoutType layout) { - if (iamf_audio_layer_layout_get_rendering_channels( - layout, ths->chs_out, IA_CH_LAYOUT_MAX_CHANNELS) > 0) { +int demixer_set_channel_layout(Demixer *ths, iamf_loudspeaker_layout_t layout) { + if (iamf_loudspeaker_layout_get_rendering_channels( + layout, ths->chs_out, def_max_audio_channels) > 0) { ths->layout = layout; return IAMF_OK; } return IAMF_ERR_BAD_ARG; } -int demixer_set_channels_order(Demixer *ths, IAChannel *chs, int count) { - memcpy(ths->chs_in, chs, sizeof(IAChannel) * count); +int demixer_set_channels_order(Demixer *ths, iamf_channel_t *chs, int count) { + memcpy(ths->chs_in, chs, sizeof(iamf_channel_t) * count); ths->chs_count = count; return IAMF_OK; } -int demixer_set_output_gain(Demixer *ths, IAChannel *chs, float *gain, +int demixer_set_output_gain(Demixer *ths, iamf_channel_t *chs, float *gain, int count) { for (int i = 0; i < count; ++i) { ths->chs_gain_list.ch_gain[i].ch = chs[i]; ths->chs_gain_list.ch_gain[i].gain = gain[i]; - ia_logd("channel %s(%d) gain is %f", ia_channel_name(chs[i]), chs[i], - gain[i]); + debug("channel %s(%d) gain is %f", iamf_channel_name(chs[i]), chs[i], + gain[i]); } ths->chs_gain_list.count = count; return IAMF_OK; @@ -578,33 +620,33 @@ int demixer_set_output_gain(Demixer *ths, IAChannel *chs, float *gain, int demixer_set_demixing_info(Demixer *ths, int mode, int w_idx) { if (mode < 0 || mode == 3 || mode > 6) return IAMF_ERR_BAD_ARG; - if (w_idx < MIN_W_INDEX || w_idx > MAX_W_INDEX) { - ia_logd("dmixtypenum: %d -> %d", ths->demixing_mode, mode); + if (w_idx < 0 || w_idx > 10) { + debug("dmixtypenum: %d -> %d", ths->demixing_mode, mode); ths->last_dmixtypenum = ths->demixing_mode; ths->demixing_mode = mode; - ia_logd("last weight state index : %d -> %d", ths->last_weight_state_idx, - ths->weight_state_idx); + debug("last weight state index : %d -> %d", ths->last_weight_state_idx, + ths->weight_state_idx); ths->last_weight_state_idx = ths->weight_state_idx; calc_w(demixing_type_mat[mode].w_idx_offset, ths->last_weight_state_idx, &ths->weight_state_idx); - ia_logd("weight state index : %d -> %d", ths->last_weight_state_idx, - ths->weight_state_idx); + debug("weight state index : %d -> %d", ths->last_weight_state_idx, + ths->weight_state_idx); } else { if (mode != ths->demixing_mode) { ths->last_dmixtypenum = ths->demixing_mode = mode; - ia_logd("set default demixing mode %d", mode); + debug("set default demixing mode %d", mode); } if (ths->weight_state_idx != w_idx) { ths->last_weight_state_idx = ths->weight_state_idx = w_idx; - ia_logd("set default weight index %d", w_idx); + debug("set default weight index %d", w_idx); } } return 0; } -int demixer_set_recon_gain(Demixer *ths, int count, IAChannel *chs, +int demixer_set_recon_gain(Demixer *ths, int count, iamf_channel_t *chs, float *recon_gain, uint32_t flags) { if (flags && flags ^ ths->chs_recon_gain_list.flags) { for (int i = 0; i < count; ++i) { @@ -620,13 +662,13 @@ int demixer_set_recon_gain(Demixer *ths, int count, IAChannel *chs, } int demixer_demixing(Demixer *ths, float *dst, float *src, uint32_t size) { - IAChannel ch; + iamf_channel_t ch; if (size != ths->frame_size) return IAMF_ERR_BAD_ARG; - if (iamf_audio_layer_get_layout_info(ths->layout)->channels != ths->chs_count) + if (iamf_loudspeaker_layout_get_info(ths->layout)->channels != ths->chs_count) return IAMF_ERR_INTERNAL; - memset(ths->ch_data, 0, sizeof(float *) * IA_CH_COUNT); + memset(ths->ch_data, 0, sizeof(float *) * ck_iamf_channel_count); for (int c = 0; c < ths->chs_count; ++c) { ths->ch_data[ths->chs_in[c]] = src + size * c; } @@ -638,11 +680,11 @@ int demixer_demixing(Demixer *ths, float *dst, float *src, uint32_t size) { for (int c = 0; c < ths->chs_count; ++c) { ch = ths->chs_out[c]; if (!ths->ch_data[ch]) { - ia_loge("channel %s(%d) doesn't has data.", ia_channel_name(ch), ch); + error("channel %s(%d) doesn't has data.", iamf_channel_name(ch), ch); continue; } - ia_logt("output channel %s(%d) at %p", ia_channel_name(ch), ch, - ths->ch_data[ch]); + trace("output channel %s(%d) at %p", iamf_channel_name(ch), ch, + ths->ch_data[ch]); memcpy((void *)&dst[c * size], (void *)ths->ch_data[ch], sizeof(float) * size); } diff --git a/code/src/iamf_dec/demixer.h b/code/src/iamf_dec/demixer.h index 1e0e7b36..7927c66c 100755 --- a/code/src/iamf_dec/demixer.h +++ b/code/src/iamf_dec/demixer.h @@ -23,7 +23,7 @@ #include #include "IAMF_defines.h" -#include "IAMF_types.h" +#include "iamf_types.h" typedef struct Demixer Demixer; @@ -56,7 +56,7 @@ int demixer_set_frame_offset(Demixer *ths, uint32_t offset); * @param [in] layout : the target layout of demixer. * @return @ref IAErrCode. */ -int demixer_set_channel_layout(Demixer *ths, IAChannelLayoutType layout); +int demixer_set_channel_layout(Demixer *ths, iamf_loudspeaker_layout_t layout); /** * @brief Set the channle order in one audio frame. @@ -65,7 +65,7 @@ int demixer_set_channel_layout(Demixer *ths, IAChannelLayoutType layout); * @param [in] count : the number of channels in frame. * @return @ref IAErrCode. */ -int demixer_set_channels_order(Demixer *ths, IAChannel *chs, int count); +int demixer_set_channels_order(Demixer *ths, iamf_channel_t *chs, int count); /** * @brief Set output gain for all scalable audio channel layers. @@ -75,7 +75,7 @@ int demixer_set_channels_order(Demixer *ths, IAChannel *chs, int count); * gain. * @return @ref IAErrCode. */ -int demixer_set_output_gain(Demixer *ths, IAChannel *chs, float *gain, +int demixer_set_output_gain(Demixer *ths, iamf_channel_t *chs, float *gain, int count); /** @@ -96,7 +96,7 @@ int demixer_set_demixing_info(Demixer *ths, int mode, int w_idx); * applied to. * @return @ref IAErrCode. */ -int demixer_set_recon_gain(Demixer *ths, int count, IAChannel *chs, +int demixer_set_recon_gain(Demixer *ths, int count, iamf_channel_t *chs, float *recon_gain, uint32_t flags); /** diff --git a/code/src/iamf_dec/downmix_renderer.c b/code/src/iamf_dec/downmix_renderer.c deleted file mode 100755 index 5fa6536e..00000000 --- a/code/src/iamf_dec/downmix_renderer.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file downmix_renderer.c - * @brief DMRenderer. - * @version 0.1 - * @date Created 06/21/2023 - **/ - -#ifdef IA_TAG -#undef IA_TAG -#endif - -#define IA_TAG "IAMF_DMR" - -#include "downmix_renderer.h" - -#include "IAMF_debug.h" -#include "IAMF_layout.h" -#include "IAMF_utils.h" -#include "fixedp11_5.h" - -typedef struct DependOnChannel { - IAChannel ch; - float s; - float *sp; -} DependOnChannel; - -struct Downmixer { - int mode; - int w_idx; - IAChannel chs_in[IA_CH_LAYOUT_MAX_CHANNELS]; - IAChannel chs_out[IA_CH_LAYOUT_MAX_CHANNELS]; - int chs_icount; - int chs_ocount; - float *chs_data[IA_CH_COUNT]; - DependOnChannel *deps[IA_CH_COUNT]; - MixFactors mix_factors; -}; - -static DependOnChannel chmono[] = {{IA_CH_R2, 0.5f}, {IA_CH_L2, 0.5}, {0}}; -static DependOnChannel chl2[] = {{IA_CH_L3, 1.f}, {IA_CH_C, 0.707}, {0}}; -static DependOnChannel chr2[] = {{IA_CH_R3, 1.f}, {IA_CH_C, 0.707}, {0}}; -static DependOnChannel chtl[] = {{IA_CH_HL, 1.f}, {IA_CH_SL5}, {0}}; -static DependOnChannel chtr[] = {{IA_CH_HR, 1.f}, {IA_CH_SR5}, {0}}; -static DependOnChannel chl3[] = {{IA_CH_L5, 1.f}, {IA_CH_SL5}, {0}}; -static DependOnChannel chr3[] = {{IA_CH_R5, 1.f}, {IA_CH_SR5}, {0}}; -static DependOnChannel chsl5[] = {{IA_CH_SL7}, {IA_CH_BL7}, {0}}; -static DependOnChannel chsr5[] = {{IA_CH_SR7}, {IA_CH_BR7}, {0}}; -static DependOnChannel chhl[] = {{IA_CH_HFL, 1.f}, {IA_CH_HBL}, {0}}; -static DependOnChannel chhr[] = {{IA_CH_HFR, 1.f}, {IA_CH_HBR}, {0}}; - -static int _valid_channel_layout(IAChannelLayoutType in) { - return iamf_audio_layer_base_layout_check(in) && - in != IA_CHANNEL_LAYOUT_BINAURAL; -} - -static int _valid_downmix(IAChannelLayoutType in, IAChannelLayoutType out) { - const IAMF_LayoutInfo *info1 = iamf_audio_layer_get_layout_info(in); - const IAMF_LayoutInfo *info2 = iamf_audio_layer_get_layout_info(out); - - if (info1->height && !info2->height) return 0; - return !(info1->surround < info2->surround || info1->height < info2->height); -} - -static void _downmix_dump(DMRenderer *thisp, IAChannel c) { - DependOnChannel *cs = thisp->deps[c]; - if (thisp->chs_data[c]) return; - if (!thisp->deps[c]) { - ia_loge("channel %s(%d) can not be found.", ia_channel_name(c), c); - return; - } - - while (cs->ch) { - if (cs->sp) { - ia_logd("channel %s(%d), scale point %f%s", ia_channel_name(cs->ch), - cs->ch, *cs->sp, thisp->chs_data[cs->ch] ? ", s." : " m."); - _downmix_dump(thisp, cs->ch); - } else { - ia_logd("channel %s(%d), scale %f%s", ia_channel_name(cs->ch), cs->ch, - cs->s, thisp->chs_data[cs->ch] ? ", s." : " m."); - _downmix_dump(thisp, cs->ch); - } - ++cs; - } -} - -static float _downmix_channel_data(DMRenderer *thisp, IAChannel c, int i) { - DependOnChannel *cs = thisp->deps[c]; - float sum = 0.f; - if (thisp->chs_data[c]) return thisp->chs_data[c][i]; - if (!thisp->deps[c]) return 0.f; - - while (cs->ch) { - if (cs->sp) - sum += _downmix_channel_data(thisp, cs->ch, i) * (*cs->sp); - else - sum += _downmix_channel_data(thisp, cs->ch, i) * cs->s; - ++cs; - } - return sum; -} - -DMRenderer *DMRenderer_open(IAChannelLayoutType in, IAChannelLayoutType out) { - DMRenderer *thisp = 0; - if (in == out || !_valid_channel_layout(in) || !_valid_channel_layout(out)) - return 0; - - ia_logd("%s downmix to %s", iamf_audio_layer_get_layout_info(in)->name, - iamf_audio_layer_get_layout_info(out)->name); - - if (!_valid_downmix(in, out)) return 0; - - thisp = IAMF_MALLOCZ(DMRenderer, 1); - if (!thisp) return 0; - - thisp->chs_icount = iamf_audio_layer_layout_get_rendering_channels( - in, thisp->chs_in, IA_CH_LAYOUT_MAX_CHANNELS); - thisp->chs_ocount = iamf_audio_layer_layout_get_rendering_channels( - out, thisp->chs_out, IA_CH_LAYOUT_MAX_CHANNELS); - - thisp->mode = -1; - thisp->w_idx = -1; - - thisp->deps[IA_CH_MONO] = chmono; - thisp->deps[IA_CH_L2] = chl2; - thisp->deps[IA_CH_R2] = chr2; - thisp->deps[IA_CH_L3] = chl3; - thisp->deps[IA_CH_R3] = chr3; - thisp->deps[IA_CH_SL5] = chsl5; - thisp->deps[IA_CH_SR5] = chsr5; - thisp->deps[IA_CH_TL] = chtl; - thisp->deps[IA_CH_TR] = chtr; - thisp->deps[IA_CH_HL] = chhl; - thisp->deps[IA_CH_HR] = chhr; - - thisp->deps[IA_CH_SR5][0].sp = thisp->deps[IA_CH_SL5][0].sp = - &thisp->mix_factors.alpha; - thisp->deps[IA_CH_SR5][1].sp = thisp->deps[IA_CH_SL5][1].sp = - &thisp->mix_factors.beta; - thisp->deps[IA_CH_L3][1].sp = thisp->deps[IA_CH_R3][1].sp = - &thisp->mix_factors.delta; - thisp->deps[IA_CH_HL][1].sp = thisp->deps[IA_CH_HR][1].sp = - &thisp->mix_factors.gamma; - - for (int i = 0; i < thisp->chs_icount; ++i) thisp->deps[thisp->chs_in[i]] = 0; - - return thisp; -} - -void DMRenderer_close(DMRenderer *thisp) { IAMF_FREE(thisp); } - -int DMRenderer_set_mode_weight(DMRenderer *thisp, int mode, int w_idx) { - if (!thisp || !iamf_valid_mix_mode(mode)) return IAMF_ERR_BAD_ARG; - - if (thisp->mode != mode) { - ia_logd("dmixtypenum: %d -> %d", thisp->mode, mode); - thisp->mode = mode; - thisp->mix_factors = *iamf_get_mix_factors(mode); - ia_logd("mode %d: a %f, b %f, g %f, d %f, w index offset %d", mode, - thisp->mix_factors.alpha, thisp->mix_factors.beta, - thisp->mix_factors.gamma, thisp->mix_factors.delta, - thisp->mix_factors.w_idx_offset); - } - - if (w_idx < MIN_W_INDEX || w_idx > MAX_W_INDEX) { - int new_w_idx; - - calc_w(thisp->mix_factors.w_idx_offset, thisp->w_idx, &new_w_idx); - ia_logd("weight state index : %d (%f) -> %d (%f)", thisp->w_idx, - get_w(thisp->w_idx), new_w_idx, get_w(new_w_idx)); - thisp->w_idx = new_w_idx; - if (thisp->deps[IA_CH_TL] && thisp->deps[IA_CH_TR]) - thisp->deps[IA_CH_TL][1].s = thisp->deps[IA_CH_TR][1].s = - thisp->mix_factors.gamma * get_w(new_w_idx); - } else { - if (mode != thisp->mode) ia_logd("set default demixing mode %d", mode); - if (thisp->w_idx != w_idx) { - thisp->w_idx = w_idx; - ia_logd("set default weight index %d, value %f", w_idx, get_w(w_idx)); - if (thisp->deps[IA_CH_TL] && thisp->deps[IA_CH_TR]) { - thisp->deps[IA_CH_TL][1].s = thisp->deps[IA_CH_TR][1].s = - thisp->mix_factors.gamma * get_w(w_idx); - } - } - } - - return IAMF_OK; -} - -int DMRenderer_downmix(DMRenderer *thisp, float *in, float *out, uint32_t s, - uint32_t duration, uint32_t size) { - int off, e; - if (!thisp || !in || !out || !size || s >= size) return IAMF_ERR_BAD_ARG; - - memset(thisp->chs_data, 0, IA_CH_COUNT * sizeof(float)); - for (int i = 0; i < thisp->chs_icount; ++i) { - thisp->chs_data[thisp->chs_in[i]] = in + size * i; - } - - e = s + duration; - if (e > size) e = size; - - for (int i = 0; i < thisp->chs_ocount; ++i) { - ia_logd("channel %s(%d) checking...", ia_channel_name(thisp->chs_out[i]), - thisp->chs_out[i]); - _downmix_dump(thisp, thisp->chs_out[i]); - off = size * i; - for (int j = s; j < e; ++j) { - out[off + j] = _downmix_channel_data(thisp, thisp->chs_out[i], j); - } - } - - return IAMF_OK; -} diff --git a/code/src/iamf_dec/downmix_renderer.h b/code/src/iamf_dec/downmix_renderer.h deleted file mode 100755 index 05e1d9b3..00000000 --- a/code/src/iamf_dec/downmix_renderer.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file downmix_renderer.h - * @brief DMRenderer APIs. - * @version 0.1 - * @date Created 06/21/2023 - **/ - -#ifndef __DOWNMIX_RENDERER_H_ -#define __DOWNMIX_RENDERER_H_ - -#include - -#include "IAMF_defines.h" - -typedef struct Downmixer DMRenderer; - -/** - * @brief Open a downmix renderer. - * @param [in] in : the input layout of downmix renderer. - * @param [in] out : the output layout of downmix renderer. - * @return return a downmix renderer handle. - */ -DMRenderer *DMRenderer_open(IAChannelLayoutType in, IAChannelLayoutType out); - -/** - * @brief Close the downmix renderer. - * @param [in] thisp : the downmix renderer handle. - */ -void DMRenderer_close(DMRenderer *thisp); - -/** - * @brief Set the demix mode and demix weight index for downmix renderer. - * @param [in] thisp : the downmix renderer handle. - * @param [in] mode : the demix mode. - * @param [in] w_idx : the demix weight index. - * @return @ref IAErrCode. - */ -int DMRenderer_set_mode_weight(DMRenderer *thisp, int mode, int w_idx); - -/** - * @brief Do downmix rendering from input layout to output layout. - * @param [in] thisp : the downmix renderer handle. - * @param [in] in : the input audio pcm. - * @param [in] out : the output audio pcm. - * @param [in] s : the start downmix position. - * @param [in] size : the defined frame size. - * @return @ref IAErrCode. - */ -int DMRenderer_downmix(DMRenderer *thisp, float *in, float *out, uint32_t s, - uint32_t duration, uint32_t size); - -#endif /* __DOWNMIX_RENDERER_H_ */ diff --git a/code/src/iamf_dec/h2b_rdr.c b/code/src/iamf_dec/h2b_rdr.c deleted file mode 100755 index fa962c7e..00000000 --- a/code/src/iamf_dec/h2b_rdr.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/* -AOM-IAMF Standard Deliverable Status: -This software module is out of scope and not part of the IAMF Final Deliverable. -*/ - -/** - * @file h2b_rdr.c - * @brief HOA to Binaural rendering. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#include "ae_rdr.h" - -#if ENABLE_HOA_TO_BINAURAL -#if defined(_WIN32) -#pragma comment(lib, "iamf2resonance.lib") -#endif -#include "resonance/iamf_resonance_api.h" - -// HOA to Binaural Renderer(Resonance) -void IAMF_element_renderer_init_H2B(binaural_filter_t* binaural_f, - int in_channels, uint64_t elm_id, - int nsamples, int sample_rate) { - int inchs = in_channels; - int frame_size = nsamples; - int i; - - if (binaural_f->h2b_init != 1) { - binaural_f->h2b_api = - CreateResonanceAudioApi2(2, frame_size, sample_rate); // 2 = outchs - if (binaural_f->h2b_api) { - for (i = 0; i < N_SOURCE_ELM; i++) { - binaural_f->h2b_elm_id[i] = -1; - binaural_f->h2b_amb_id[i] = -1; - binaural_f->h2b_inchs[i] = -1; - } - binaural_f->h2b_init = 1; - } - } - - if (binaural_f->h2b_api) { - for (i = 0; i < N_SOURCE_ELM; i++) { - if (binaural_f->h2b_elm_id[i] == -1) break; - } - if (i < N_SOURCE_ELM) { - binaural_f->h2b_amb_id[i] = - CreateAmbisonicSource(binaural_f->h2b_api, inchs); - binaural_f->h2b_inchs[i] = in_channels; - binaural_f->h2b_elm_id[i] = elm_id; - } - } -} - -void IAMF_element_renderer_deinit_H2B(binaural_filter_t* binaural_f, - uint64_t elm_id) { - int i; - - if (binaural_f->h2b_init != 0) { - for (i = 0; i < N_SOURCE_ELM; i++) { - if (binaural_f->h2b_elm_id[i] == elm_id) { - if (binaural_f->h2b_amb_id[i] >= 0) { - DestroySource(binaural_f->h2b_api, binaural_f->h2b_amb_id[i]); - binaural_f->h2b_elm_id[i] = -1; - binaural_f->h2b_amb_id[i] = -1; - binaural_f->h2b_inchs[i] = -1; - } - } - } - for (i = 0; i < N_SOURCE_ELM; i++) { - if (binaural_f->h2b_amb_id[i] >= 0) { - break; - } - } - if (i == N_SOURCE_ELM) { - DestroyResonanceAudioApi2(binaural_f->h2b_api); - binaural_f->h2b_init = 0; - } - } -} - -int IAMF_element_renderer_render_H2B(binaural_filter_t* binaural_f, - uint64_t elm_id, float* in[], float* out[], - int nsamples) { - const float* const* sin = (const float* const*)in; - float** sout = (float**)out; - int inchs = 0; - int frame_size = nsamples; - int i; - - if (binaural_f->h2b_init != 0) { - for (i = 0; i < N_SOURCE_ELM; i++) { - if (binaural_f->h2b_elm_id[i] == elm_id) { - inchs = binaural_f->h2b_inchs[i]; - SetPlanarBufferFloat(binaural_f->h2b_api, binaural_f->h2b_amb_id[i], - sin, inchs, frame_size); - FillPlanarOutputBufferFloat(binaural_f->h2b_api, 2, frame_size, - sout); // 2 = outchs - return 0; - } - } - } - return -1; -} -#endif diff --git a/code/src/iamf_dec/h2m_rdr.c b/code/src/iamf_dec/h2m_rdr.c deleted file mode 100644 index ef54d77e..00000000 --- a/code/src/iamf_dec/h2m_rdr.c +++ /dev/null @@ -1,2242 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/* -AOM-IAMF Standard Deliverable Status: -This software module is out of scope and not part of the IAMF Final Deliverable. -*/ - -/** - * @file h2m_rdr.c - * @brief HOA to Multichannels rendering. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#define _USE_MATH_DEFINES -#include -#include - -#include "ae_rdr.h" - -//////////////////////// -float zoa_mono[] = {1.0}; -float zoa_bs020[] = {0.70710082, 0.70711274}; -float zoa_bs050[] = {0.32633555, 0.32633836, 0.21513153, 0.60857786, - 0.60857192}; -float zoa_bs250[] = {0.21545139, 0.21546223, 0.1449662, 0.64532708, - 0.64531899, 0.16319277, 0.16317478}; -float zoa_bs450[] = {0.2589133, 0.25892531, 0.17179246, 0.55582871, 0.5558131, - 0.19678245, 0.19676024, 0.26560468, 0.26561516}; -float zoa_bs451[] = {0.13751009, 0.13752067, 0.05714168, 0.58394492, - 0.58393012, 0.19593844, 0.19591633, 0.26446548, - 0.26447592, 0.24552643}; -float zoa_bs370[] = {0.22198958, 0.24224982, 0.24226476, 0.25750442, - 0.25749822, 0.36089975, 0.36088758, 0.36896943, - 0.36895516, 0.40984723}; -float zoa_bs490[] = {0.21973458, 0.2197658, 0.16838701, 0.31931017, 0.31931294, - 0.37590788, 0.37588103, 0.29771433, 0.29769313, 0.2981131, - 0.29811957, 0.12954642, 0.12949327}; -float zoa_bs9A3[] = {0.09620442, 0.09621115, 0.05768647, 0.34302436, 0.34302036, - 0.09762671, 0.09763078, 0.34302018, 0.31330675, 0.31331476, - 0.12986508, 0.12983092, 0.14535586, 0.31907627, 0.1416214, - 0.14159595, 0.14347565, 0.1434782, 0.14160483, 0.23516451, - 0.21965652, 0.21963451}; -float zoa_bs070[] = {0.33864987, 0.33865386, 0.26375664, 0.37546788, - 0.37545877, 0.45778527, 0.45776575}; -float zoa_bs470[] = {0.25073729, 0.25075275, 0.22976721, 0.31884739, - 0.31885011, 0.37397364, 0.37394729, 0.29063804, - 0.29062113, 0.29112214, 0.29112846}; -float zoa_iamf312[] = {0.67176654, 0.67177166, 0.1449662, 0.16319277, - 0.16317478}; -float zoa_iamf712[] = {0.25073729, 0.25075275, 0.22976721, - 0.31884739, 0.31885011, 0.37397364, - 0.37394729, 0.49649248, 0.49648004}; -// ZOA -> 9+10+3 -> 9.1.6 -float zoa_iamf916[] = {0.09620442, 0.09621115, 0.29285098, 0.58557625, - 0.58557225, 0.42006534, 0.4200474, 0.31330675, - 0.31331476, 0.28940321, 0.28936905, 0.40128927, - 0.40126382, 0.14347565, 0.1434782}; -//////////////////////// -float foa_mono[] = {6.23757933e-01, 3.94900000e-06, -1.95729978e-07, - 7.40278437e-02}; -float foa_bs020[][4] = { - {6.23752675e-01, 5.72103593e-01, -8.58322813e-07, 7.40141262e-02}, - {6.23763190e-01, -5.72095695e-01, 4.66862857e-07, 7.40415612e-02}}; -float foa_bs050[][4] = { - {2.50621545e-01, 3.10682739e-01, 1.70905779e-05, 3.07552345e-01}, - {2.50623704e-01, -3.10685559e-01, 9.90912200e-06, 3.07564230e-01}, - {1.65218271e-01, 9.15556582e-06, -4.07281262e-05, 2.65463910e-01}, - {4.67380043e-01, 4.51128331e-01, -4.40137250e-06, -4.30612876e-01}, - {4.67375481e-01, -4.51105215e-01, 1.07376039e-05, -4.30629805e-01}}; -float foa_bs250[][4] = { - {1.60841247e-01, 2.28393130e-01, -1.95227191e-01, 2.12772300e-01}, - {1.60849339e-01, -2.28399241e-01, -1.95237534e-01, 2.12798095e-01}, - {1.08221836e-01, 1.23793408e-05, -1.40756775e-01, 2.03191820e-01}, - {4.81756995e-01, 4.66864572e-01, 9.06085189e-03, -4.34708249e-01}, - {4.81750954e-01, -4.66841556e-01, 9.07452759e-03, -4.34726837e-01}, - {1.21828541e-01, 1.04337290e-01, 2.37360549e-01, 1.53929699e-01}, - {1.21815110e-01, -1.04327601e-01, 2.37361986e-01, 1.53897349e-01}}; -float foa_bs450[][4] = { - {1.71634590e-01, 2.46697762e-01, -2.03594387e-01, 2.25695454e-01}, - {1.71642551e-01, -2.46702494e-01, -2.03605381e-01, 2.25722757e-01}, - {1.13881860e-01, 1.30267828e-05, -1.48118382e-01, 2.13818793e-01}, - {3.68460920e-01, 3.69873008e-01, -2.91802681e-01, -4.12793734e-01}, - {3.68450573e-01, -3.69846113e-01, -2.91790370e-01, -4.12805228e-01}, - {1.30447818e-01, 1.15594825e-01, 2.52176034e-01, 1.63616077e-01}, - {1.30433098e-01, -1.15583322e-01, 2.52176590e-01, 1.63581427e-01}, - {1.76070328e-01, 1.59994173e-01, 3.48214366e-01, -1.04081210e-01}, - {1.76077278e-01, -1.59999989e-01, 3.48218167e-01, -1.04092952e-01}}; -float foa_bs451[][4] = { - {9.18824460e-02, 1.87559061e-01, -2.01393100e-02, 1.54186748e-01}, - {9.18895163e-02, -1.87560807e-01, -2.01535712e-02, 1.54209327e-01}, - {3.81813250e-02, 1.84868598e-05, 1.07084520e-02, 1.09048612e-01}, - {3.90184366e-01, 4.02043845e-01, -3.32105078e-01, -3.87580982e-01}, - {3.90174479e-01, -4.02030153e-01, -3.32101313e-01, -3.87595245e-01}, - {1.30923506e-01, 1.16016350e-01, 2.53095613e-01, 1.64212715e-01}, - {1.30908732e-01, -1.16004805e-01, 2.53096171e-01, 1.64177939e-01}, - {1.76712381e-01, 1.60577603e-01, 3.49484156e-01, -1.04460750e-01}, - {1.76719357e-01, -1.60583441e-01, 3.49487970e-01, -1.04472535e-01}, - {1.64057551e-01, -7.22175250e-06, -3.26163812e-01, 2.29200020e-01}}; -float foa_bs370[][4] = { - {1.38206404e-01, 6.02514266e-06, -1.61553853e-01, 2.42264116e-01}, - {1.50820038e-01, 1.70413376e-01, -2.18356458e-01, 2.00435931e-01}, - {1.50829336e-01, -1.70423609e-01, -2.18387141e-01, 2.00436456e-01}, - {1.60317253e-01, 1.78965986e-01, 3.05315565e-01, 1.77826945e-01}, - {1.60313394e-01, -1.78937421e-01, 3.05327912e-01, 1.77814872e-01}, - {2.24689177e-01, 4.23617639e-01, -1.59945095e-01, 1.35759805e-03}, - {2.24681599e-01, -4.23610308e-01, -1.59941940e-01, 1.35153285e-03}, - {2.29713205e-01, 1.92419796e-01, -2.52721572e-01, -3.76625410e-01}, - {2.29704317e-01, -1.92402037e-01, -2.52708548e-01, -3.76622035e-01}, - {2.55162929e-01, -1.10118797e-05, 5.02514284e-01, -2.38329457e-01}}; -float foa_bs490[][4] = { - {1.33943127e-01, 1.64268063e-01, -1.97953052e-01, 1.63059290e-01}, - {1.33962159e-01, -1.64296200e-01, -1.97955736e-01, 1.63088985e-01}, - {1.02643305e-01, -9.16057523e-06, -1.21547375e-01, 1.61757921e-01}, - {1.94641205e-01, 3.70767542e-01, -2.10262923e-01, 3.36276209e-02}, - {1.94642893e-01, -3.70776129e-01, -2.10246722e-01, 3.36009643e-02}, - {2.29141347e-01, 1.88657816e-01, -2.58353086e-01, -3.81133768e-01}, - {2.29124977e-01, -1.88631958e-01, -2.58347605e-01, -3.81117999e-01}, - {1.81477072e-01, 1.77425829e-01, 3.49753376e-01, 1.77863734e-01}, - {1.81464148e-01, -1.77390622e-01, 3.49750871e-01, 1.77856484e-01}, - {1.81720149e-01, 1.69730250e-01, 3.50540863e-01, -1.78142797e-01}, - {1.81724096e-01, -1.69748319e-01, 3.50539021e-01, -1.78140331e-01}, - {7.89673255e-02, 2.67506926e-02, -1.43793773e-01, 9.36059741e-02}, - {7.89349279e-02, -2.67030099e-02, -1.43805542e-01, 9.35248174e-02}}; -float foa_bs9A3[][4] = { - {5.63451317e-02, 1.42440516e-01, 4.40516772e-04, 7.46074411e-02}, - {5.63490746e-02, -1.42444765e-01, 4.24451509e-04, 7.46228100e-02}, - {3.37858882e-02, 1.77930252e-05, -3.09890673e-05, 9.84182909e-02}, - {2.00902962e-01, 2.53871239e-01, -2.57111844e-01, -2.53873843e-01}, - {2.00900619e-01, -2.53879197e-01, -2.57092344e-01, -2.53879779e-01}, - {5.71781378e-02, 7.50655473e-02, 3.79085654e-06, 1.44848300e-01}, - {5.71805256e-02, -7.50694338e-02, 2.03476094e-05, 1.44848406e-01}, - {2.00900512e-01, -1.33248436e-05, -2.57083737e-01, -3.59039117e-01}, - {1.83497910e-01, 3.13145196e-01, -2.62363309e-01, -1.99858778e-02}, - {1.83502601e-01, -3.13170023e-01, -2.62350011e-01, -1.99838758e-02}, - {7.60595490e-02, 1.19539396e-01, 1.29523034e-01, 1.19552805e-01}, - {7.60395467e-02, -1.19530648e-01, 1.29487714e-01, 1.19516214e-01}, - {8.51322141e-02, 1.65124185e-05, 1.36630679e-01, 1.92892600e-01}, - {1.86877012e-01, 2.14090778e-05, 4.73682975e-01, -8.70734224e-06}, - {8.29450088e-02, 1.31434397e-01, 1.35361270e-01, -1.31450927e-01}, - {8.29301023e-02, -1.31422769e-01, 1.35323682e-01, -1.31443099e-01}, - {8.40310053e-02, 1.89380427e-01, 1.35987164e-01, -9.79190943e-05}, - {8.40325007e-02, -1.89381150e-01, 1.35986600e-01, -1.04033651e-04}, - {8.29353021e-02, 1.07353149e-05, 1.35337260e-01, -1.85878577e-01}, - {1.37731458e-01, -7.40789286e-06, -2.71046068e-01, 1.84505059e-01}, - {1.28648721e-01, 1.13602275e-01, -2.63895426e-01, 1.13628989e-01}, - {1.28635830e-01, -1.13578477e-01, -2.63913376e-01, 1.13580628e-01}}; -float foa_bs070[][4] = { - {2.50471347e-01, 2.51706779e-01, 3.45308827e-05, 3.00186164e-01}, - {2.50474302e-01, -2.51703690e-01, -9.18024511e-06, 3.00195844e-01}, - {1.95079009e-01, 1.30516353e-05, -4.30110917e-05, 2.70282016e-01}, - {2.77702594e-01, 4.40004517e-01, -1.83458952e-05, 4.98124680e-02}, - {2.77695853e-01, -4.39999590e-01, -2.99177728e-07, 4.97926860e-02}, - {3.38585971e-01, 2.59490910e-01, -8.06273719e-06, -4.75435688e-01}, - {3.38571534e-01, -2.59480618e-01, -1.69746261e-05, -4.75432873e-01}}; -float foa_bs470[][4] = { - {1.53249945e-01, 1.73158957e-01, -2.21874465e-01, 2.03665215e-01}, - {1.53259393e-01, -1.73169355e-01, -2.21905642e-01, 2.03665748e-01}, - {1.40433089e-01, 6.12221555e-06, -1.64156696e-01, 2.46167306e-01}, - {1.94878652e-01, 3.62255148e-01, -2.17027277e-01, 3.29936121e-02}, - {1.94880315e-01, -3.62266326e-01, -2.17011448e-01, 3.29676087e-02}, - {2.28571663e-01, 1.84273980e-01, -2.63877085e-01, -3.72343589e-01}, - {2.28555561e-01, -1.84251275e-01, -2.63871543e-01, -3.72328014e-01}, - {1.77637174e-01, 1.73664822e-01, 3.42431107e-01, 1.74005365e-01}, - {1.77626842e-01, -1.73630948e-01, 3.42431292e-01, 1.74004819e-01}, - {1.77933057e-01, 1.66193030e-01, 3.43235507e-01, -1.74430257e-01}, - {1.77936922e-01, -1.66210723e-01, 3.43233703e-01, -1.74427844e-01}}; -float foa_iamf312[][4] = { - {5.014949e-01, 5.585162e-01, -1.888202e-01, -9.461285e-02}, // L - {5.014987e-01, -5.585061e-01, -1.888209e-01, -9.460020e-02}, // R - {1.08221836e-01, 1.23793408e-05, -1.40756775e-01, 2.03191820e-01}, // C - {1.21828541e-01, 1.04337290e-01, 2.37360549e-01, 1.53929699e-01}, // Hfl - {1.21815110e-01, -1.04327601e-01, 2.37361986e-01, 1.53897349e-01} // Hfr -}; -float foa_iamf712[][4] = { - {1.53249945e-01, 1.73158957e-01, -2.21874465e-01, 2.03665215e-01}, // L - {1.53259393e-01, -1.73169355e-01, -2.21905642e-01, 2.03665748e-01}, // R - {1.40433089e-01, 6.12221555e-06, -1.64156696e-01, 2.46167306e-01}, // C - {1.94878652e-01, 3.62255148e-01, -2.17027277e-01, 3.29936121e-02}, // Ls - {1.94880315e-01, -3.62266326e-01, -2.17011448e-01, 3.29676087e-02}, // Rs - {2.28571663e-01, 1.84273980e-01, -2.63877085e-01, -3.72343589e-01}, // Lb - {2.28555561e-01, -1.84251275e-01, -2.63871543e-01, -3.72328014e-01}, // Rb - {3.034548e-01, 2.911810e-01, 5.851353e-01, 5.066455e-02}, // Hfl - {3.034472e-01, -2.911597e-01, 5.851342e-01, 5.066571e-02} // Hfr -}; -float foa_iamf916[][4] = { // FOA -> 9+10+3 -> 9.1.6 - {5.63451317e-02, 1.42440516e-01, 4.40516772e-04, 7.46074411e-02}, - {5.63490746e-02, -1.42444765e-01, 4.24451509e-04, 7.46228100e-02}, - {1.71517346e-01, 1.03851323e-05, -2.71077057e-01, 2.82923350e-01}, - {3.42961076e-01, 2.53861817e-01, -4.38897497e-01, -5.07752837e-01}, - {3.42958733e-01, -2.53888619e-01, -4.38877997e-01, -5.07758773e-01}, - {2.46024425e-01, 1.88679498e-01, -1.67279156e-01, 3.94872954e-01}, - {2.46013921e-01, -1.88636235e-01, -1.67280549e-01, 3.94824699e-01}, - {1.83497910e-01, 3.13145196e-01, -2.62363309e-01, -1.99858778e-02}, - {1.83502601e-01, -3.13170023e-01, -2.62350011e-01, -1.99838758e-02}, - {1.69498055e-01, 1.19550101e-01, 3.66364521e-01, 1.19548451e-01}, - {1.69478053e-01, -1.19519943e-01, 3.66329202e-01, 1.19511860e-01}, - {2.35027629e-01, 1.31452693e-01, 4.67900652e-01, -2.62891283e-01}, - {2.35012723e-01, -1.31404473e-01, 4.67863064e-01, -2.62883455e-01}, - {8.40310053e-02, 1.89380427e-01, 1.35987164e-01, -9.79190943e-05}, - {8.40325007e-02, -1.89381150e-01, 1.35986600e-01, -1.04033651e-04}}; -/////////////////////////////////////////// -float soa_mono[] = {6.11863808e-01, 3.87350000e-06, -1.91997702e-07, - 7.26162442e-02, 4.09550000e-06, 8.21892714e-06, - 9.24007326e-02, 7.94167407e-07, 1.58538424e-01}; -float soa_bs020[][9] = {{6.11858651e-01, 5.61194439e-01, -8.41955890e-07, - 7.26027883e-02, 2.46501808e-01, 2.35064399e-06, - 9.24039966e-02, -1.44147615e-07, 1.58528890e-01}, - {6.11868965e-01, -5.61186692e-01, 4.57960486e-07, - 7.26297001e-02, -2.46493617e-01, 1.40872103e-05, - 9.23974685e-02, 1.73248243e-06, 1.58547959e-01}}; -float soa_bs050[][9] = {{2.38781287e-01, 2.96004975e-01, 1.62831579e-05, - 2.93022473e-01, 3.78036740e-01, 4.66758981e-06, - 1.24383931e-01, 2.62364822e-05, -3.83109183e-02}, - {2.38783344e-01, -2.96007662e-01, 9.44097964e-06, - 2.93033796e-01, -3.78036479e-01, 1.39362683e-05, - 1.24405269e-01, 2.06627981e-05, -3.82963163e-02}, - {1.57412769e-01, 8.72302414e-06, -3.88039838e-05, - 2.52922445e-01, 3.62084239e-05, -1.34767477e-05, - 1.62861520e-01, -4.44126486e-06, 2.59551352e-01}, - {4.45299338e-01, 4.29815415e-01, -4.19343592e-06, - -4.10269184e-01, -1.01075317e-01, 2.54769115e-06, - 8.73885939e-02, -1.57986343e-06, -7.73670023e-02}, - {4.45294991e-01, -4.29793391e-01, 1.02303211e-05, - -4.10285313e-01, 1.01084942e-01, 1.61423360e-06, - 8.73727819e-02, 9.75122230e-06, -7.73865158e-02}}; -float soa_bs250[][9] = {{1.51598055e-01, 2.15267879e-01, -1.84007913e-01, - 2.00544744e-01, 2.83085414e-01, -1.30926554e-01, - -2.62945588e-03, -1.54142851e-01, -3.80115564e-02}, - {1.51605682e-01, -2.15273639e-01, -1.84017662e-01, - 2.00569056e-01, -2.83094927e-01, 1.30947725e-01, - -2.63063046e-03, -1.54153181e-01, -3.79790034e-02}, - {1.02002565e-01, 1.16679273e-05, -1.32667792e-01, - 1.91514833e-01, 3.22324409e-05, -9.39024240e-06, - 3.59275434e-02, -1.19192733e-01, 2.13323852e-01}, - {4.54071480e-01, 4.40034892e-01, 8.54014466e-03, - -4.09726522e-01, -9.36552906e-02, 4.92427716e-03, - 9.13601796e-02, 4.00474901e-03, -8.49272007e-02}, - {4.54065786e-01, -4.40013199e-01, 8.55303445e-03, - -4.09744042e-01, 9.36608249e-02, -4.92139383e-03, - 9.13448355e-02, 4.01492543e-03, -8.49451616e-02}, - {1.14827322e-01, 9.83412551e-02, 2.23719961e-01, - 1.45083697e-01, 1.25128203e-01, 1.42099909e-01, - 1.27585524e-01, 2.19516595e-01, 3.73507004e-02}, - {1.14814664e-01, -9.83321235e-02, 2.23721315e-01, - 1.45053206e-01, -1.25102102e-01, -1.42105523e-01, - 1.27622359e-01, 2.19520471e-01, 3.73161724e-02}}; -float soa_bs450[][9] = {{1.55892875e-01, 2.24071520e-01, -1.84921433e-01, - 2.04995469e-01, 2.90946585e-01, -1.28529803e-01, - -6.78350592e-03, -1.55087606e-01, -4.49061680e-02}, - {1.55900106e-01, -2.24075818e-01, -1.84931419e-01, - 2.05020268e-01, -2.90956456e-01, 1.28551530e-01, - -6.78357850e-03, -1.55097838e-01, -4.48707303e-02}, - {1.03437020e-01, 1.18320125e-05, -1.34533490e-01, - 1.94208093e-01, 3.26857235e-05, -9.52229673e-06, - 3.64327900e-02, -1.20868932e-01, 2.16323811e-01}, - {3.34666993e-01, 3.35949569e-01, -2.65039576e-01, - -3.74933759e-01, -9.06404678e-02, -1.76442356e-01, - -1.26359175e-01, 8.75017912e-02, -1.63972897e-02}, - {3.34657595e-01, -3.35925141e-01, -2.65028394e-01, - -3.74944199e-01, 9.06382246e-02, 1.76442733e-01, - -1.26363062e-01, 8.75158689e-02, -1.63961409e-02}, - {1.18483608e-01, 1.04992878e-01, 2.29047344e-01, - 1.48609792e-01, 1.30302903e-01, 1.49443981e-01, - 1.26405167e-01, 2.24127334e-01, 3.22718365e-02}, - {1.18470237e-01, -1.04982430e-01, 2.29047849e-01, - 1.48578320e-01, -1.30275316e-01, -1.49447876e-01, - 1.26442637e-01, 2.24130021e-01, 3.22377681e-02}, - {1.59921783e-01, 1.45320075e-01, 3.16277382e-01, - -9.45352513e-02, -2.43103773e-02, 2.13806844e-01, - 1.86508368e-01, -1.52870866e-01, -6.80378961e-02}, - {1.59928096e-01, -1.45325358e-01, 3.16280834e-01, - -9.45459165e-02, 2.43207403e-02, -2.13805205e-01, - 1.86493459e-01, -1.52876317e-01, -6.80666219e-02}}; -float soa_bs451[][9] = {{8.32446468e-02, 1.69926776e-01, -1.82460287e-02, - 1.39691768e-01, 2.29755383e-01, -2.93704718e-02, - -1.59521725e-01, -3.01860697e-02, -4.07334942e-02}, - {8.32510525e-02, -1.69928358e-01, -1.82589493e-02, - 1.39712225e-01, -2.29773824e-01, 2.93929486e-02, - -1.59517194e-01, -3.02000991e-02, -4.07096972e-02}, - {3.45919275e-02, 1.67489241e-05, 9.70175857e-03, - 9.87970342e-02, 4.30971692e-05, -2.54531402e-06, - -7.34629256e-02, 2.52814625e-02, 1.29718510e-01}, - {3.53503429e-01, 3.64248007e-01, -3.00884131e-01, - -3.51144788e-01, -5.10333151e-02, -2.22055306e-01, - -1.07705218e-01, 5.08346917e-02, -1.37189614e-02}, - {3.53494472e-01, -3.64235603e-01, -3.00880720e-01, - -3.51157710e-01, 5.10247076e-02, 2.22088143e-01, - -1.07691970e-01, 5.08380479e-02, -1.37248191e-02}, - {1.18615486e-01, 1.05109741e-01, 2.29302286e-01, - 1.48775202e-01, 1.30447937e-01, 1.49610320e-01, - 1.26545863e-01, 2.24376799e-01, 3.23077568e-02}, - {1.18602101e-01, -1.05099281e-01, 2.29302791e-01, - 1.48743695e-01, -1.30420320e-01, -1.49614220e-01, - 1.26583375e-01, 2.24379490e-01, 3.22736504e-02}, - {1.60099784e-01, 1.45481824e-01, 3.16629415e-01, - -9.46404741e-02, -2.43374360e-02, 2.14044823e-01, - 1.86715962e-01, -1.53041020e-01, -6.81136259e-02}, - {1.60106104e-01, -1.45487113e-01, 3.16632871e-01, - -9.46511512e-02, 2.43478106e-02, -2.14043181e-01, - 1.86701037e-01, -1.53046477e-01, -6.81423837e-02}, - {1.48634625e-01, -6.54284101e-06, -2.95501399e-01, - 2.07653099e-01, 5.14958861e-06, 7.39056671e-06, - 1.77725070e-01, -3.18728232e-01, 1.08034019e-01}}; -float soa_bs370[][9] = {{1.19597834e-01, 5.21389738e-06, -1.39801704e-01, - 2.09644869e-01, 7.81221154e-06, -2.19967134e-05, - 3.26507670e-02, -7.64815983e-02, 2.44533794e-01}, - {1.30513126e-01, 1.47468351e-01, -1.88956217e-01, - 1.73448570e-01, 2.47554931e-01, -1.12115307e-01, - 3.87593682e-02, -1.38038669e-01, 3.49504573e-02}, - {1.30521172e-01, -1.47477207e-01, -1.88982769e-01, - 1.73449024e-01, -2.47560390e-01, 1.12120161e-01, - 3.87993629e-02, -1.38063595e-01, 3.49347937e-02}, - {1.38731604e-01, 1.54869409e-01, 2.64206860e-01, - 1.53883733e-01, 1.32828069e-01, 2.36768375e-01, - 1.34809170e-01, 2.22864964e-01, 1.09857379e-02}, - {1.38728265e-01, -1.54844691e-01, 2.64217544e-01, - 1.53873285e-01, -1.32781727e-01, -2.36751849e-01, - 1.34835471e-01, 2.22880615e-01, 1.09690408e-02}, - {1.94436278e-01, 3.66580349e-01, -1.38409554e-01, - 1.17480653e-03, 1.80759757e-03, -6.28822525e-02, - -1.01595485e-02, -6.61302610e-02, -3.56247192e-01}, - {1.94429720e-01, -3.66574005e-01, -1.38406824e-01, - 1.16955797e-03, -1.80885115e-03, 6.28887758e-02, - -1.01805550e-02, -6.61121746e-02, -3.56257224e-01}, - {1.98783854e-01, 1.66511753e-01, -2.18694298e-01, - -3.25915311e-01, -2.67648708e-01, -1.00953081e-01, - -2.64081829e-02, 1.64760537e-01, 1.86028975e-01}, - {1.98776163e-01, -1.66496386e-01, -2.18683027e-01, - -3.25912389e-01, 2.67633260e-01, 1.00954678e-01, - -2.64183768e-02, 1.64751630e-01, 1.86047327e-01}, - {2.20806942e-01, -9.52920353e-06, 4.34854087e-01, - -2.06239985e-01, -9.61099334e-06, -3.57955766e-07, - 2.54441146e-01, -3.00795134e-01, -2.91279468e-03}}; -float soa_bs490[][9] = {{1.14596505e-01, 1.40541335e-01, -1.69360895e-01, - 1.39507156e-01, 2.26914719e-01, -1.08934809e-01, - 4.19699941e-02, -1.12363457e-01, -7.25055022e-03}, - {1.14612788e-01, -1.40565408e-01, -1.69363192e-01, - 1.39532562e-01, -2.26952623e-01, 1.08919576e-01, - 4.19791762e-02, -1.12348025e-01, -7.24881666e-03}, - {8.78176001e-02, -7.83743018e-06, -1.03991184e-01, - 1.38393755e-01, -1.36260909e-05, -2.07458844e-05, - 4.96907853e-02, -1.94112385e-02, 1.66976280e-01}, - {1.66527408e-01, 3.17214220e-01, -1.79892740e-01, - 2.87704783e-02, 4.95676471e-02, -1.55496364e-01, - -2.01033216e-02, -2.67686983e-02, -3.27369086e-01}, - {1.66528853e-01, -3.17221566e-01, -1.79878879e-01, - 2.87476720e-02, -4.95281112e-02, 1.55472679e-01, - -2.01305783e-02, -2.67636380e-02, -3.27374799e-01}, - {1.96044382e-01, 1.61408255e-01, -2.21036804e-01, - -3.26083157e-01, -2.54581373e-01, -1.14945984e-01, - -3.59322612e-02, 1.83757663e-01, 1.85989771e-01}, - {1.96030376e-01, -1.61386132e-01, -2.21032115e-01, - -3.26069667e-01, 2.54566263e-01, 1.14950859e-01, - -3.59291926e-02, 1.83759382e-01, 1.86016437e-01}, - {1.55264691e-01, 1.51798606e-01, 2.99235320e-01, - 1.52173260e-01, 1.40211449e-01, 2.16324251e-01, - 1.61198289e-01, 2.16493097e-01, 6.72163691e-04}, - {1.55253633e-01, -1.51768484e-01, 2.99233177e-01, - 1.52167057e-01, -1.40173798e-01, -2.16300471e-01, - 1.61223918e-01, 2.16520410e-01, 6.53665667e-04}, - {1.55472658e-01, 1.45214569e-01, 2.99909064e-01, - -1.52412015e-01, -1.23751887e-01, 2.10947489e-01, - 1.61552498e-01, -2.17948734e-01, 3.20098658e-04}, - {1.55476035e-01, -1.45230028e-01, 2.99907488e-01, - -1.52409906e-01, 1.23745252e-01, -2.10950077e-01, - 1.61538661e-01, -2.17952375e-01, 2.91259737e-04}, - {6.75613578e-02, 2.28868472e-02, -1.23024332e-01, - 8.00856134e-02, 5.62366139e-02, -1.43607730e-02, - 8.27190315e-02, -6.63142220e-02, 8.33496514e-02}, - {6.75336396e-02, -2.28460518e-02, -1.23034402e-01, - 8.00161789e-02, -5.61568825e-02, 1.43479187e-02, - 8.27542807e-02, -6.63280776e-02, 8.32935706e-02}}; -float soa_bs9A3[][22] = {{4.52721627e-02, 1.14448046e-01, 3.53946231e-04, - 5.99455554e-02, 1.39696686e-01, 9.73068888e-04, - -9.50450826e-02, 1.74119959e-04, -9.64195234e-02}, - {4.52753308e-02, -1.14451460e-01, 3.41038120e-04, - 5.99579040e-02, -1.39715675e-01, -9.48293629e-04, - -9.50603875e-02, 1.55550928e-04, -9.64018582e-02}, - {2.71462712e-02, 1.42963324e-05, -2.48990828e-05, - 7.90770870e-02, 3.70602871e-05, -8.16074892e-07, - -6.20921099e-02, -6.44091255e-05, 1.07554921e-01}, - {1.61421427e-01, 2.03980356e-01, -2.06584116e-01, - -2.03982448e-01, -3.18974090e-01, -1.22757396e-01, - 1.96056507e-02, 1.22746896e-01, -1.30468617e-06}, - {1.61419545e-01, -2.03986750e-01, -2.06568448e-01, - -2.03987218e-01, 3.18978111e-01, 1.22757945e-01, - 1.95881353e-02, 1.22731732e-01, 8.84552201e-06}, - {4.59414661e-02, 6.03136343e-02, 3.04587581e-06, - 1.16382651e-01, 1.40724143e-01, -3.08458899e-06, - -9.65518361e-02, 7.84037002e-06, 9.89926750e-02}, - {4.59433846e-02, -6.03167571e-02, 1.63488886e-05, - 1.16382736e-01, -1.40724631e-01, -1.40374356e-05, - -9.65427557e-02, 3.56278847e-05, 9.89823549e-02}, - {1.61419459e-01, -1.07062397e-05, -2.06561533e-01, - -2.88480598e-01, 9.66961104e-06, 3.90486793e-06, - 1.95933453e-02, 1.73570349e-01, 3.18985553e-01}, - {1.47436823e-01, 2.51605770e-01, -2.10803561e-01, - -1.60582447e-02, -3.98175469e-02, -1.84558174e-01, - 4.87506224e-02, -3.19208287e-03, -2.82121142e-01}, - {1.47440593e-01, -2.51625718e-01, -2.10792876e-01, - -1.60566361e-02, 3.98013481e-02, 1.84550564e-01, - 4.87268705e-02, -3.18147635e-03, -2.82134307e-01}, - {6.11122944e-02, 9.60474637e-02, 1.04069113e-01, - 9.60582373e-02, 1.40585922e-01, 1.43834600e-01, - 1.64851356e-02, 1.43843791e-01, 1.88606270e-05}, - {6.10962230e-02, -9.60404348e-02, 1.04040734e-01, - 9.60288374e-02, -1.40568654e-01, -1.43811561e-01, - 1.64697833e-02, 1.43826948e-01, -3.24016341e-05}, - {6.84019955e-02, 1.32673911e-05, 1.09779960e-01, - 1.54985265e-01, 2.25537789e-05, 2.18005966e-05, - 2.65392258e-03, 2.17606389e-01, 1.60125942e-01}, - {1.50151863e-01, 1.72017569e-05, 3.80594597e-01, - -6.99617168e-06, 6.37185631e-06, 3.07362564e-05, - 4.42130993e-01, -8.34850911e-06, 2.11431624e-06}, - {6.66446207e-02, 1.05604854e-01, 1.08760016e-01, - -1.05618136e-01, -1.50684757e-01, 1.51541507e-01, - 6.44221302e-03, -1.51546648e-01, 2.23570110e-05}, - {6.66326437e-02, -1.05595511e-01, 1.08729815e-01, - -1.05611846e-01, 1.50684412e-01, -1.51507684e-01, - 6.40693399e-03, -1.51547370e-01, 1.34060100e-05}, - {6.75171968e-02, 1.52163306e-01, 1.09262910e-01, - -7.86759927e-05, 3.36443992e-04, 2.15965568e-01, - 4.54626945e-03, -1.94411121e-04, -1.55401066e-01}, - {6.75183983e-02, -1.52163887e-01, 1.09262456e-01, - -8.35889137e-05, -3.23237739e-04, -2.15952302e-01, - 4.54658040e-03, -1.92269097e-04, -1.55408121e-01}, - {6.66368216e-02, 8.62560626e-06, 1.08740724e-01, - -1.49349641e-01, -1.55479356e-05, 1.48152922e-05, - 6.42477314e-03, -2.14296775e-01, 1.50688974e-01}, - {1.10664414e-01, -5.95209064e-06, -2.17779981e-01, - 1.48246047e-01, -7.55921292e-06, 8.28798061e-06, - 1.30861236e-01, -2.03089711e-01, 1.54857082e-01}, - {1.03366621e-01, 9.12771082e-02, -2.12034586e-01, - 9.12985726e-02, 1.35304270e-01, -1.33555054e-01, - 1.44613579e-01, -1.33579556e-01, 2.37599422e-05}, - {1.03356263e-01, -9.12579867e-02, -2.12049009e-01, - 9.12597150e-02, -1.35251074e-01, 1.33562410e-01, - 1.44689537e-01, -1.33569871e-01, 5.60848982e-07}}; -float soa_bs070[][9] = {{2.20936629e-01, 2.22026383e-01, 3.04591200e-05, - 2.64789246e-01, 3.57259728e-01, 1.98002096e-06, - 1.58397345e-01, 1.92029163e-05, 5.31768690e-02}, - {2.20939236e-01, -2.22023658e-01, -8.09774224e-06, - 2.64797784e-01, -3.57256273e-01, 2.28619221e-05, - 1.58418498e-01, 8.66238043e-06, 5.31963521e-02}, - {1.72075965e-01, 1.15126315e-05, -3.79393720e-05, - 2.38411292e-01, 3.42696679e-05, -2.28462025e-05, - 1.83381426e-01, -1.93589998e-05, 2.69336030e-01}, - {2.44956861e-01, 3.88120701e-01, -1.61826105e-05, - 4.39387534e-02, 7.05828630e-02, -7.90413711e-06, - 1.45406936e-01, -1.28291232e-05, -3.86613744e-01}, - {2.44950915e-01, -3.88116354e-01, -2.63899721e-07, - 4.39213041e-02, -7.05500443e-02, -9.68145753e-06, - 1.45415895e-01, 1.39441345e-05, -3.86622604e-01}, - {2.98661080e-01, 2.28892636e-01, -7.11200700e-06, - -4.19373950e-01, -3.38029257e-01, -1.22966786e-06, - 1.27129832e-01, 7.00346311e-06, 2.00395289e-01}, - {2.98648345e-01, -2.28883557e-01, -1.49730367e-05, - -4.19371467e-01, 3.38034641e-01, 2.56207948e-05, - 1.27095276e-01, -5.24844814e-06, 2.00406818e-01}}; -float soa_bs470[][9] = {{1.31381003e-01, 1.48448976e-01, -1.90212725e-01, - 1.74601956e-01, 2.49201104e-01, -1.12860844e-01, - 3.90171076e-02, -1.38956589e-01, 3.51828684e-02}, - {1.31389103e-01, -1.48457890e-01, -1.90239454e-01, - 1.74602413e-01, -2.49206600e-01, 1.12865730e-01, - 3.90573682e-02, -1.38981681e-01, 3.51671007e-02}, - {1.20393127e-01, 5.24856840e-06, -1.40731348e-01, - 2.11038951e-01, 7.86416065e-06, -2.21429856e-05, - 3.28678858e-02, -7.69901804e-02, 2.46159877e-01}, - {1.67069246e-01, 3.10560924e-01, -1.86057237e-01, - 2.82853860e-02, 4.85579932e-02, -1.51114465e-01, - -7.96156218e-03, -2.64000841e-02, -3.21143174e-01}, - {1.67070671e-01, -3.10570508e-01, -1.86043667e-01, - 2.82630933e-02, -4.85219695e-02, 1.51097035e-01, - -7.98825644e-03, -2.63953706e-02, -3.21148690e-01}, - {1.95954226e-01, 1.57977872e-01, -2.26221524e-01, - -3.19209734e-01, -2.49382537e-01, -1.11942235e-01, - -2.37575885e-02, 1.78661396e-01, 1.81921116e-01}, - {1.95940422e-01, -1.57958407e-01, -2.26216773e-01, - -3.19196381e-01, 2.49364660e-01, 1.11952482e-01, - -2.37547295e-02, 1.78662882e-01, 1.81947077e-01}, - {1.52288146e-01, 1.48882653e-01, 2.93565797e-01, - 1.49174601e-01, 1.37440496e-01, 2.12213855e-01, - 1.58266499e-01, 2.12341431e-01, 5.32551336e-04}, - {1.52279289e-01, -1.48853614e-01, 2.93565956e-01, - 1.49174133e-01, -1.37404714e-01, -2.12192383e-01, - 1.58288661e-01, 2.12373741e-01, 5.22608321e-04}, - {1.52541806e-01, 1.42477095e-01, 2.94255408e-01, - -1.49538860e-01, -1.21419011e-01, 2.06970868e-01, - 1.58507034e-01, -2.13840131e-01, 3.14064403e-04}, - {1.52545120e-01, -1.42492263e-01, 2.94253861e-01, - -1.49536791e-01, 1.21412501e-01, -2.06973407e-01, - 1.58493458e-01, -2.13843703e-01, 2.85769131e-04}}; -float soa_iamf312[][9] = { - {4.726751e-01, 5.264195e-01, -1.779691e-01, -8.917566e-02, 2.168611e-01, - -1.274446e-01, 6.197195e-02, -1.513111e-01, -9.806416e-02}, - {4.726787e-01, -5.264100e-01, -1.779698e-01, -8.916373e-02, -2.168667e-01, - 1.274678e-01, 6.195992e-02, -1.513142e-01, -9.804430e-02}, - {1.020026e-01, 1.166793e-05, -1.326678e-01, 1.915148e-01, 3.223244e-05, - -9.390242e-06, 3.592754e-02, -1.191927e-01, 2.133239e-01}, - {1.148273e-01, 9.834126e-02, 2.237200e-01, 1.450837e-01, 1.251282e-01, - 1.420999e-01, 1.275855e-01, 2.195166e-01, 3.735070e-02}, - {1.148147e-01, -9.833212e-02, 2.237213e-01, 1.450532e-01, -1.251021e-01, - -1.421055e-01, 1.276224e-01, 2.195205e-01, 3.731617e-02}}; -float soa_iamf712[][9] = { - {1.31381003e-01, 1.48448976e-01, -1.90212725e-01, 1.74601956e-01, - 2.49201104e-01, -1.12860844e-01, 3.90171076e-02, -1.38956589e-01, - 3.51828684e-02}, // L - {1.31389103e-01, -1.48457890e-01, -1.90239454e-01, 1.74602413e-01, - -2.49206600e-01, 1.12865730e-01, 3.90573682e-02, -1.38981681e-01, - 3.51671007e-02}, // R - {1.20393127e-01, 5.24856840e-06, -1.40731348e-01, 2.11038951e-01, - 7.86416065e-06, -2.21429856e-05, 3.28678858e-02, -7.69901804e-02, - 2.46159877e-01}, // C - {1.67069246e-01, 3.10560924e-01, -1.86057237e-01, 2.82853860e-02, - 4.85579932e-02, -1.51114465e-01, -7.96156218e-03, -2.64000841e-02, - -3.21143174e-01}, // Ls - {1.67070671e-01, -3.10570508e-01, -1.86043667e-01, 2.82630933e-02, - -4.85219695e-02, 1.51097035e-01, -7.98825644e-03, -2.63953706e-02, - -3.21148690e-01}, // Rs - {1.95954226e-01, 1.57977872e-01, -2.26221524e-01, -3.19209734e-01, - -2.49382537e-01, -1.11942235e-01, -2.37575885e-02, 1.78661396e-01, - 1.81921116e-01}, // Lb - {1.95940422e-01, -1.57958407e-01, -2.26216773e-01, -3.19196381e-01, - 2.49364660e-01, 1.11952482e-01, -2.37547295e-02, 1.78662882e-01, - 1.81947077e-01}, // Rb - {2.601515e-01, 2.496292e-01, 5.016358e-01, 4.343466e-02, 5.158429e-02, - 3.585644e-01, 2.703479e-01, 6.113362e-02, 7.546284e-04}, // Hfl - {2.601450e-01, -2.496109e-01, 5.016349e-01, 4.343565e-02, -5.155311e-02, - -3.585447e-01, 2.703605e-01, 6.116341e-02, 7.246776e-04} // Hfr -}; -float soa_iamf916[][9] = { // SOA -> 9+10+3 -> 9.1.6 - {4.52721627e-02, 1.14448046e-01, 3.53946231e-04, 5.99455554e-02, - 1.39696686e-01, 9.73068888e-04, -9.50450826e-02, 1.74119959e-04, - -9.64195234e-02}, - {4.52753308e-02, -1.14451460e-01, 3.41038120e-04, 5.99579040e-02, - -1.39715675e-01, -9.48293629e-04, -9.50603875e-02, 1.55550928e-04, - -9.64018582e-02}, - {1.37810685e-01, 8.34424176e-06, -2.17804880e-01, 2.27323134e-01, - 2.95010742e-05, 7.47190572e-06, 6.87691261e-02, -2.03154120e-01, - 2.62412003e-01}, - {2.75562221e-01, 2.03972786e-01, -3.52645176e-01, -4.07969035e-01, - -3.18967253e-01, -1.22754635e-01, 3.34602380e-02, 2.45479667e-01, - 2.25555543e-01}, - {2.75560339e-01, -2.03994320e-01, -3.52629508e-01, -4.07973805e-01, - 3.18984948e-01, 1.22760706e-01, 3.34427226e-02, 2.45464503e-01, - 2.25565693e-01}, - {1.97675602e-01, 1.51600124e-01, -1.34405386e-01, 3.17272355e-01, - 2.76044361e-01, -1.33542723e-01, 4.99383495e-02, 2.02992374e-02, - 2.12242574e-01}, - {1.97667162e-01, -1.51565362e-01, -1.34406506e-01, 3.17233583e-01, - -2.75959757e-01, 1.33563788e-01, 5.00233879e-02, 2.03367099e-02, - 2.12209055e-01}, - {1.47436823e-01, 2.51605770e-01, -2.10803561e-01, -1.60582447e-02, - -3.98175469e-02, -1.84558174e-01, 4.87506224e-02, -3.19208287e-03, - -2.82121142e-01}, - {1.47440593e-01, -2.51625718e-01, -2.10792876e-01, -1.60566361e-02, - 3.98013481e-02, 1.84550564e-01, 4.87268705e-02, -3.18147635e-03, - -2.82134307e-01}, - {1.36188226e-01, 9.60560646e-02, 2.94366411e-01, 9.60547392e-02, - 1.40589108e-01, 1.43849968e-01, 2.37550632e-01, 1.43839617e-01, - 1.99177851e-05}, - {1.36172155e-01, -9.60318339e-02, 2.94338033e-01, 9.60253393e-02, - -1.40565468e-01, -1.43796193e-01, 2.37535280e-01, 1.43822774e-01, - -3.13444760e-05}, - {1.88839901e-01, 1.05619554e-01, 3.75948618e-01, -2.11227778e-01, - -1.50692565e-01, 1.51567351e-01, 2.32050710e-01, -3.03081525e-01, - 1.06576609e-01}, - {1.88827924e-01, -1.05580811e-01, 3.75918417e-01, -2.11221488e-01, - 1.50676604e-01, -1.51481840e-01, 2.32015431e-01, -3.03082247e-01, - 1.06567658e-01}, - {6.75171968e-02, 1.52163306e-01, 1.09262910e-01, -7.86759927e-05, - 3.36443992e-04, 2.15965568e-01, 4.54626945e-03, -1.94411121e-04, - -1.55401066e-01}, - {6.75183983e-02, -1.52163887e-01, 1.09262456e-01, -8.35889137e-05, - -3.23237739e-04, -2.15952302e-01, 4.54658040e-03, -1.92269097e-04, - -1.55408121e-01}}; -//////////////////////////////////////////////////// -float toa_mono[] = { - 6.10511935e-01, 3.86500000e-06, -1.91573496e-07, 7.24558034e-02, - 4.08650000e-06, 8.20076800e-06, 9.21965792e-02, 7.92412745e-07, - 1.58188144e-01, 5.33100000e-06, 3.17888835e-07, -1.05779500e-05, - -8.21749078e-06, 3.96539739e-02, -1.52839265e-05, 4.95221244e-02}; -float toa_bs020[][16] = { - {6.10506790e-01, 5.59954517e-01, -8.40095644e-07, 7.24423772e-02, - 2.45957178e-01, 2.34545040e-06, 9.21998360e-02, -1.43829130e-07, - 1.58178631e-01, 1.05906734e-01, -9.21200162e-06, 1.44451230e-02, - 6.21297703e-06, 3.96432134e-02, -1.75258363e-05, 4.95199472e-02}, - {6.10517081e-01, -5.59946787e-01, 4.56948652e-07, 7.24692296e-02, - -2.45949005e-01, 1.40560856e-05, 9.21933224e-02, 1.72865462e-06, - 1.58197658e-01, -1.05896072e-01, 9.84777929e-06, -1.44662789e-02, - -2.26479586e-05, 3.96647344e-02, -1.30420167e-05, 4.95243016e-02}}; -float toa_bs050[][16] = { - {2.33807835e-01, 2.89839640e-01, 1.59440044e-05, 2.86919259e-01, - 3.70162807e-01, 4.57037099e-06, 1.21793202e-01, 2.56900160e-05, - -3.75129600e-02, 1.72536788e-01, 5.77929061e-06, 2.46229266e-02, - 2.48058818e-05, 9.99408784e-02, -1.01778940e-05, -1.79109959e-01}, - {2.33809849e-01, -2.89842271e-01, 9.24433834e-06, 2.86930346e-01, - -3.70162552e-01, 1.36459969e-05, 1.21814096e-01, 2.02324234e-05, - -3.74986621e-02, -1.72537539e-01, 5.10770603e-06, -2.46484608e-02, - 2.24040235e-05, 9.99579906e-02, 3.96795780e-07, -1.79124343e-01}, - {1.54134100e-01, 8.54133677e-06, -3.79957556e-05, 2.47654454e-01, - 3.54542573e-05, -1.31960475e-05, 1.59469362e-01, -4.34876004e-06, - 2.54145291e-01, 4.07532571e-05, -1.49779726e-05, -1.85696065e-06, - -8.99311763e-05, 8.95494788e-02, -2.56455737e-05, 2.70100462e-01}, - {4.36024428e-01, 4.20863012e-01, -4.10609301e-06, -4.01723899e-01, - -9.89700716e-02, 2.49462661e-06, 8.55684219e-02, -1.54695727e-06, - -7.57555649e-02, -1.63523625e-01, -1.51969313e-05, 5.18447306e-02, - 9.60991661e-06, -3.99600042e-02, 7.87290152e-06, -1.78541741e-02}, - {4.36020172e-01, -4.20841446e-01, 1.00172390e-05, -4.01739692e-01, - 9.89794955e-02, 1.58061156e-06, 8.55529393e-02, 9.54811912e-06, - -7.57746720e-02, 1.63538437e-01, 5.10898762e-06, -5.18386067e-02, - 2.64968798e-06, -3.99650766e-02, -4.18470864e-06, -1.78397549e-02}}; -float toa_bs250[][16] = { - {1.47543221e-01, 2.09510051e-01, -1.79086204e-01, 1.95180720e-01, - 2.75513653e-01, -1.27424627e-01, -2.55912511e-03, -1.50019951e-01, - -3.69948511e-02, 1.26116466e-01, -1.52740939e-01, -5.38908230e-02, - -1.86836021e-02, -5.84077120e-03, 1.14490176e-02, -1.53960650e-01}, - {1.47550644e-01, -2.09515657e-01, -1.79095692e-01, 1.95204382e-01, - -2.75522911e-01, 1.27445231e-01, -2.56026828e-03, -1.50030004e-01, - -3.69631688e-02, -1.26133552e-01, 1.52742883e-01, 5.38742783e-02, - -1.86963736e-02, -5.84701382e-03, 1.14562599e-02, -1.53935681e-01}, - {9.92742752e-02, 1.13558421e-05, -1.29119291e-01, 1.86392335e-01, - 3.13703112e-05, -9.13907907e-06, 3.49665798e-02, -1.16004653e-01, - 2.07618022e-01, 3.94596117e-05, -2.87941415e-05, 4.17936507e-06, - -6.57885105e-02, -1.79100086e-02, -8.36478901e-02, 2.21708712e-01}, - {4.41926308e-01, 4.28265161e-01, 8.31171912e-03, -3.98767457e-01, - -9.11502674e-02, 4.79256619e-03, 8.89165443e-02, 3.89763292e-03, - -8.26556301e-02, -1.64741393e-01, 7.34130565e-03, 4.55127066e-02, - 1.57174239e-03, -4.06651499e-02, -7.74208653e-03, -2.84149500e-02}, - {4.41920767e-01, -4.28244047e-01, 8.32426414e-03, -3.98784508e-01, - 9.11556537e-02, -4.78975999e-03, 8.89016107e-02, 3.90753714e-03, - -8.26731106e-02, 1.64745462e-01, -7.35804577e-03, -4.55056466e-02, - 1.56664042e-03, -4.06703815e-02, -7.75179027e-03, -2.83998198e-02}, - {1.11756005e-01, 9.57108952e-02, 2.17736063e-01, 1.41203105e-01, - 1.21781365e-01, 1.38299125e-01, 1.24172960e-01, 2.13645126e-01, - 3.63516712e-02, 6.78595476e-02, 1.73251505e-01, 6.48593533e-02, - -1.12965067e-02, 1.23632115e-01, 4.36275209e-02, -5.88275782e-03}, - {1.11743685e-01, -9.57020079e-02, 2.17737381e-01, 1.41173429e-01, - -1.21755963e-01, -1.38304589e-01, 1.24208809e-01, 2.13648898e-01, - 3.63180668e-02, -6.78220761e-02, -1.73246378e-01, -6.48820658e-02, - -1.12875031e-02, 1.23676703e-01, 4.36323797e-02, -5.93294284e-03}}; -float toa_bs450[][16] = { - {1.50756115e-01, 2.16688234e-01, -1.78828165e-01, 1.98240750e-01, - 2.81359727e-01, -1.24294672e-01, -6.55998548e-03, -1.49977379e-01, - -4.34264838e-02, 1.22063156e-01, -1.50883522e-01, -5.91933853e-02, - -2.34899275e-02, -7.23463536e-03, 6.72194463e-03, -1.60458394e-01}, - {1.50763107e-01, -2.16692390e-01, -1.78837822e-01, 1.98264732e-01, - -2.81369272e-01, 1.24315683e-01, -6.56005567e-03, -1.49987274e-01, - -4.33922138e-02, -1.22083706e-01, 1.50884847e-01, 5.91749258e-02, - -2.35025549e-02, -7.24101236e-03, 6.72957338e-03, -1.60433126e-01}, - {1.00028711e-01, 1.14421409e-05, -1.30100534e-01, 1.87808824e-01, - 3.16087100e-05, -9.20853155e-06, 3.52323085e-02, -1.16886231e-01, - 2.09195816e-01, 3.97594852e-05, -2.90129627e-05, 4.21112618e-06, - -6.62884707e-02, -1.80461159e-02, -8.42835727e-02, 2.23393588e-01}, - {3.23639522e-01, 3.24879837e-01, -2.56306369e-01, -3.62579475e-01, - -8.76538120e-02, -1.70628478e-01, -1.22195567e-01, 8.46185566e-02, - -1.58569895e-02, -1.20092226e-01, 2.49064662e-02, -7.69746815e-02, - -5.42917543e-02, 5.02503105e-02, 9.56172948e-02, -3.56423229e-02}, - {3.23630434e-01, -3.24856213e-01, -2.56295555e-01, -3.62589571e-01, - 8.76516427e-02, 1.70628843e-01, -1.22199326e-01, 8.46321704e-02, - -1.58558786e-02, 1.20090014e-01, -2.49258113e-02, 7.69681562e-02, - -5.42803328e-02, 5.02315396e-02, 9.56269403e-02, -3.56466601e-02}, - {1.14579504e-01, 1.01533302e-01, 2.21500102e-01, 1.43713013e-01, - 1.26009347e-01, 1.44519716e-01, 1.22240044e-01, 2.16742208e-01, - 3.12084608e-02, 6.41137549e-02, 1.78205228e-01, 6.30138341e-02, - -1.67658863e-02, 1.23938253e-01, 3.80694246e-02, -1.04491802e-02}, - {1.14566575e-01, -1.01523198e-01, 2.21500590e-01, 1.43682578e-01, - -1.25982669e-01, -1.44523483e-01, 1.22276279e-01, 2.16744807e-01, - 3.11755150e-02, -6.40761826e-02, -1.78197281e-01, -6.30360121e-02, - -1.67555250e-02, 1.23982022e-01, 3.80756937e-02, -1.04983585e-02}, - {1.54652267e-01, 1.40531695e-01, 3.05855859e-01, -9.14202601e-02, - -2.35093363e-02, 2.06761785e-01, 1.80362810e-01, -1.47833683e-01, - -6.57960081e-02, -6.16566732e-02, -3.96750859e-02, 1.04145646e-01, - -2.22431797e-02, -1.02998270e-01, -8.35279117e-02, 1.50958693e-02}, - {1.54658373e-01, -1.40536804e-01, 3.05859197e-01, -9.14305739e-02, - 2.35193579e-02, -2.06760200e-01, 1.80348392e-01, -1.47838954e-01, - -6.58237874e-02, 6.16762274e-02, 3.96788703e-02, -1.04135571e-01, - -2.22583948e-02, -1.02984409e-01, -8.35499005e-02, 1.51327090e-02}}; -float toa_bs451[][16] = { - {8.04315613e-02, 1.64184442e-01, -1.76294409e-02, 1.34971166e-01, - 2.21991261e-01, -2.83779557e-02, -1.54131009e-01, -2.91659921e-02, - -3.93569876e-02, 9.30067741e-02, -4.04155618e-02, -1.44645215e-01, - 4.00210665e-02, -1.25601429e-01, -3.86631951e-03, -1.40125542e-01}, - {8.04377505e-02, -1.64185970e-01, -1.76419248e-02, 1.34990931e-01, - -2.22009079e-01, 2.83996730e-02, -1.54126631e-01, -2.91795474e-02, - -3.93339948e-02, -9.30254203e-02, 4.04454636e-02, 1.44620064e-01, - 4.00219977e-02, -1.25600671e-01, -3.85146382e-03, -1.40121616e-01}, - {3.34229628e-02, 1.61829279e-05, 9.37390714e-03, 9.54583869e-02, - 4.16407869e-05, -2.45930024e-06, -7.09803936e-02, 2.44271263e-02, - 1.25334934e-01, 6.57182335e-05, -7.34799017e-06, -2.07748352e-05, - -2.61867129e-02, -1.03438162e-01, 3.19394229e-02, 1.38924382e-01}, - {3.41557491e-01, 3.51938978e-01, -2.90716357e-01, -3.39278556e-01, - -4.93087468e-02, -2.14551393e-01, -1.04065537e-01, 4.91168355e-02, - -1.32553566e-02, -9.47887971e-02, -3.79537286e-02, -4.69442143e-02, - -5.03329397e-02, 6.95665632e-02, 9.20953397e-02, -5.02538839e-02}, - {3.41548837e-01, -3.51926992e-01, -2.90713061e-01, -3.39291041e-01, - 4.93004302e-02, 2.14583120e-01, -1.04052737e-01, 4.91200782e-02, - -1.32610165e-02, 9.47943477e-02, 3.79667218e-02, 4.68937528e-02, - -5.03321709e-02, 6.95752261e-02, 9.21012239e-02, -5.02658277e-02}, - {1.14607114e-01, 1.01557768e-01, 2.21553476e-01, 1.43747644e-01, - 1.26039711e-01, 1.44554540e-01, 1.22269500e-01, 2.16794436e-01, - 3.12159811e-02, 6.41292043e-02, 1.78248170e-01, 6.30290184e-02, - -1.67699264e-02, 1.23968118e-01, 3.80785981e-02, -1.04516982e-02}, - {1.14594182e-01, -1.01547662e-01, 2.21553964e-01, 1.43717201e-01, - -1.26013027e-01, -1.44558308e-01, 1.22305744e-01, 2.16797036e-01, - 3.11830273e-02, -6.40916229e-02, -1.78240221e-01, -6.30512018e-02, - -1.67595625e-02, 1.24011897e-01, 3.80848687e-02, -1.05008883e-02}, - {1.54689534e-01, 1.40565559e-01, 3.05929561e-01, -9.14422894e-02, - -2.35150013e-02, 2.06811608e-01, 1.80406271e-01, -1.47869306e-01, - -6.58118628e-02, -6.16715305e-02, -3.96846463e-02, 1.04170741e-01, - -2.22485396e-02, -1.03023089e-01, -8.35480392e-02, 1.50995069e-02}, - {1.54695640e-01, -1.40570669e-01, 3.05932900e-01, -9.14526057e-02, - 2.35250253e-02, -2.06810022e-01, 1.80391850e-01, -1.47874579e-01, - -6.58396488e-02, 6.16910894e-02, 3.96884316e-02, -1.04160665e-01, - -2.22637584e-02, -1.03009225e-01, -8.35700333e-02, 1.51363555e-02}, - {1.43611816e-01, -6.32173885e-06, -2.85515523e-01, 2.00635880e-01, - 4.97556861e-06, 7.14081736e-06, 1.71719209e-01, -3.07957452e-01, - 1.04383227e-01, 8.04645161e-06, -1.20867740e-05, 2.20219271e-06, - 1.59144307e-02, 1.85790283e-01, -1.19381206e-01, 5.15775831e-02}}; -float toa_bs370[][16] = { - {1.14029613e-01, 4.97114940e-06, -1.33292834e-01, 1.99884249e-01, - 7.44849157e-06, -2.09725931e-05, 3.11306167e-02, -7.29207776e-02, - 2.33148820e-01, 4.96897682e-06, -3.86227009e-05, 2.55401441e-05, - -8.44932543e-02, -6.06040323e-02, -6.67155950e-02, 2.38388301e-01}, - {1.24436712e-01, 1.40602538e-01, -1.80158817e-01, 1.65373173e-01, - 2.36029299e-01, -1.06895457e-01, 3.69548143e-02, -1.31611882e-01, - 3.33232383e-02, 1.82868381e-01, -1.62513697e-01, -3.31009778e-02, - -9.98733531e-03, -2.99676476e-02, -2.29988162e-02, -1.07254125e-01}, - {1.24444383e-01, -1.40610981e-01, -1.80184133e-01, 1.65373606e-01, - -2.36034505e-01, 1.06900085e-01, 3.69929470e-02, -1.31635647e-01, - 3.33083039e-02, -1.82858844e-01, 1.62518733e-01, 3.30841745e-02, - -1.00266536e-02, -2.99412648e-02, -2.30342154e-02, -1.07283316e-01}, - {1.32272555e-01, 1.47659018e-01, 2.51905950e-01, 1.46719233e-01, - 1.26643876e-01, 2.25744942e-01, 1.28532741e-01, 2.12488845e-01, - 1.04742653e-02, 3.83603792e-02, 1.59366152e-01, 1.40150638e-01, - -3.88684321e-02, 1.02769366e-01, 1.44091478e-02, -3.03188576e-02}, - {1.32269371e-01, -1.47635451e-01, 2.51916137e-01, 1.46709272e-01, - -1.26599692e-01, -2.25729186e-01, 1.28557818e-01, 2.12503767e-01, - 1.04583456e-02, -3.83083913e-02, -1.59340067e-01, -1.40161905e-01, - -3.88708599e-02, 1.02798263e-01, 1.44052554e-02, -3.03287027e-02}, - {1.85383738e-01, 3.49513147e-01, -1.31965500e-01, 1.12011003e-03, - 1.72343966e-03, -5.99545884e-02, -9.68654153e-03, -6.30513765e-02, - -3.39661080e-01, -2.34148530e-01, -9.92115511e-02, -4.90985547e-02, - -1.02584029e-01, -1.45209104e-02, 7.36520768e-02, -4.63003386e-03}, - {1.85377485e-01, -3.49507098e-01, -1.31962897e-01, 1.11510583e-03, - -1.72463488e-03, 5.99608080e-02, -9.70657000e-03, -6.30341322e-02, - -3.39670645e-01, 2.34170460e-01, 9.91863760e-02, 4.91495813e-02, - -1.02584392e-01, -1.45744903e-02, 7.36625547e-02, -4.62045647e-03}, - {1.89528900e-01, 1.58759320e-01, -2.08512356e-01, -3.10741386e-01, - -2.55187553e-01, -9.62529197e-02, -2.51786740e-02, 1.57089636e-01, - 1.77367861e-01, 1.72065899e-01, 1.20256870e-01, -3.91284012e-02, - -1.75630480e-02, 8.06131907e-02, -4.47292129e-02, -2.92861521e-03}, - {1.89521567e-01, -1.58744668e-01, -2.08501610e-01, -3.10738601e-01, - 2.55172824e-01, 9.62544425e-02, -2.51883933e-02, 1.57081144e-01, - 1.77385359e-01, -1.72080613e-01, -1.20253672e-01, 3.90984366e-02, - -1.75531061e-02, 8.06306128e-02, -4.47276082e-02, -2.93657860e-03}, - {2.10526640e-01, -9.08554406e-06, 4.14608204e-01, -1.96637889e-01, - -9.16352591e-06, -3.41290106e-07, 2.42594906e-01, -2.86790751e-01, - -2.77718114e-03, 2.82969445e-05, -1.32321826e-05, 1.77791692e-05, - -2.66120808e-02, -1.39421728e-01, -5.67531532e-03, 4.02574449e-02}}; -float toa_bs490[][16] = { - {1.08791442e-01, 1.33421997e-01, -1.60781658e-01, 1.32440206e-01, - 2.15420004e-01, -1.03416548e-01, 3.98439393e-02, -1.06671513e-01, - -6.88326242e-03, 1.45215921e-01, -1.51809773e-01, -2.95538775e-02, - -1.39828416e-02, -2.12209800e-02, 7.43032829e-03, -1.46807095e-01}, - {1.08806901e-01, -1.33444851e-01, -1.60783838e-01, 1.32464325e-01, - -2.15455988e-01, 1.03402087e-01, 3.98526564e-02, -1.06656862e-01, - -6.88161668e-03, -1.45244141e-01, 1.51766124e-01, 2.95421404e-02, - -1.40466155e-02, -2.12139637e-02, 7.43058034e-03, -1.46837350e-01}, - {8.33690642e-02, -7.44041307e-06, -9.87233504e-02, 1.31383206e-01, - -1.29358403e-05, -1.96949696e-05, 4.71736219e-02, -1.84279323e-02, - 1.58517839e-01, -1.19848829e-05, -4.41056479e-05, 5.54153757e-06, - -1.03597852e-01, -4.43128901e-02, -7.39563482e-03, 1.75483259e-01}, - {1.58091706e-01, 3.01145245e-01, -1.70779996e-01, 2.73130654e-02, - 4.70567215e-02, -1.47619456e-01, -1.90849569e-02, -2.54126886e-02, - -3.10785700e-01, -2.34224637e-01, -3.37407892e-02, -8.80185728e-02, - -3.54299901e-02, 2.88138742e-03, 1.32105899e-01, -4.56042261e-02}, - {1.58093077e-01, -3.01152219e-01, -1.70766837e-01, 2.72914143e-02, - -4.70191884e-02, 1.47596971e-01, -1.91108329e-02, -2.54078847e-02, - -3.10791124e-01, 2.34216016e-01, 3.37506972e-02, 8.80672378e-02, - -3.54443118e-02, 2.84555378e-03, 1.32111952e-01, -4.55701879e-02}, - {1.86113451e-01, 1.53231871e-01, -2.09839844e-01, -3.09564912e-01, - -2.41685161e-01, -1.09123218e-01, -3.41120571e-02, 1.74449136e-01, - 1.76568172e-01, 1.53202125e-01, 1.46186228e-01, -3.58968180e-02, - 3.30876484e-03, 8.34511883e-02, -5.62621888e-02, -2.97493717e-03}, - {1.86100155e-01, -1.53210869e-01, -2.09835392e-01, -3.09552105e-01, - 2.41670817e-01, 1.09127846e-01, -3.41091440e-02, 1.74450767e-01, - 1.76593487e-01, -1.53224355e-01, -1.46197809e-01, 3.58766817e-02, - 3.34631381e-03, 8.34557218e-02, -5.62486140e-02, -3.01128694e-03}, - {1.47399519e-01, 1.44109013e-01, 2.84077094e-01, 1.44464689e-01, - 1.33108822e-01, 2.05366013e-01, 1.53032541e-01, 2.05526306e-01, - 6.38114203e-04, 2.98928362e-02, 1.74272551e-01, 9.15891765e-02, - -3.27879401e-02, 9.11493814e-02, 3.40484012e-04, -2.85703311e-02}, - {1.47389021e-01, -1.44080417e-01, 2.84075059e-01, 1.44458800e-01, - -1.33073078e-01, -2.05343438e-01, 1.53056872e-01, 2.05552235e-01, - 6.20553225e-04, -2.98353285e-02, -1.74252846e-01, -9.16015847e-02, - -3.27783548e-02, 9.11944274e-02, 3.45241780e-04, -2.86139713e-02}, - {1.47596951e-01, 1.37858501e-01, 2.84716708e-01, -1.44691350e-01, - -1.17483044e-01, 2.00261618e-01, 1.53368808e-01, -2.06908205e-01, - 3.03883567e-04, 6.00175758e-03, -1.60858273e-01, 9.62946811e-02, - -3.41084048e-02, -9.26824244e-02, 1.36010486e-03, 2.90059554e-02}, - {1.47600157e-01, -1.37873177e-01, 2.84715212e-01, -1.44689347e-01, - 1.17476745e-01, -2.00264075e-01, 1.53355671e-01, -2.06911661e-01, - 2.76505526e-04, -5.97141897e-03, 1.60843621e-01, -9.62698043e-02, - -3.41166774e-02, -9.27015685e-02, 1.35194209e-03, 2.90205732e-02}, - {6.41389330e-02, 2.17274787e-02, -1.16792345e-01, 7.60287532e-02, - 5.33878615e-02, -1.36333059e-02, 7.85287715e-02, -6.29549728e-02, - 7.91274464e-02, 8.45496272e-02, -3.14411738e-02, -7.01468017e-03, - -5.58275686e-02, -9.83582064e-03, -5.88008992e-02, 7.25960399e-02}, - {6.41126190e-02, -2.16887498e-02, -1.16801905e-01, 7.59628360e-02, - -5.33121690e-02, 1.36211028e-02, 7.85622350e-02, -6.29681266e-02, - 7.90742064e-02, -8.44618248e-02, 3.14413574e-02, 7.06426959e-03, - -5.58051464e-02, -9.84207867e-03, -5.88266901e-02, 7.25710260e-02}}; -float toa_bs9A3[][16] = { - {4.04576287e-02, 1.02276902e-01, 3.16305304e-04, 5.35705581e-02, - 1.24840439e-01, 8.69586461e-04, -8.49373750e-02, 1.55602919e-04, - -8.61656489e-02, -1.99113803e-02, 4.59578590e-04, -1.07672132e-01, - -1.00584229e-03, -5.80424713e-02, -1.24512586e-03, -1.67195449e-01}, - {4.04604598e-02, -1.02279953e-01, 3.04769925e-04, 5.35815935e-02, - -1.24857409e-01, -8.47445963e-04, -8.49510523e-02, 1.39008638e-04, - -8.61498623e-02, 1.98737596e-02, -4.23839742e-04, 1.07688993e-01, - -9.86892094e-04, -5.80707244e-02, -1.23581553e-03, -1.67194266e-01}, - {2.42593615e-02, 1.27759681e-05, -2.22511536e-05, 7.06675191e-02, - 3.31190569e-05, -7.29288220e-07, -5.54888342e-02, -5.75594434e-05, - 9.61168360e-02, 5.34761744e-05, -2.08445060e-06, -1.41471343e-05, - 5.40168531e-05, -8.68975091e-02, -7.94580100e-05, 1.12200494e-01}, - {1.44254831e-01, 1.82287768e-01, -1.84614628e-01, -1.82289638e-01, - -2.85052327e-01, -1.09702582e-01, 1.75206593e-02, 1.09693199e-01, - -1.16593742e-06, 1.75755167e-01, 1.54649417e-01, -5.44214736e-02, - -2.90973425e-02, 5.44258679e-02, 2.16559686e-05, 1.75746369e-01}, - {1.44253148e-01, -1.82293483e-01, -1.84600626e-01, -1.82293900e-01, - 2.85055919e-01, 1.09703072e-01, 1.75050066e-02, 1.09679648e-01, - 7.90483210e-06, -1.75761802e-01, -1.54628896e-01, 5.44167186e-02, - -2.90891782e-02, 5.44369320e-02, 2.29363675e-05, 1.75746293e-01}, - {4.10557540e-02, 5.38994932e-02, 2.72195772e-06, 1.04005769e-01, - 1.25758629e-01, -2.75655388e-06, -8.62838906e-02, 7.00657447e-06, - 8.84651549e-02, 1.68860718e-01, -6.78892917e-06, -5.84644783e-02, - -3.24528797e-06, -1.09724858e-01, 1.19009702e-05, 2.24786259e-02}, - {4.10574686e-02, -5.39022838e-02, 1.46102423e-05, 1.04005845e-01, - -1.25759065e-01, -1.25446041e-05, -8.62757759e-02, 3.18389854e-05, - 8.84559323e-02, -1.68848099e-01, -2.27705392e-05, 5.84611983e-02, - -3.51127111e-05, -1.09696895e-01, 2.44870439e-05, 2.24619237e-02}, - {1.44253072e-01, -9.56766908e-06, -1.84594446e-01, -2.57801710e-01, - 8.64128219e-06, 3.48959907e-06, 1.75096625e-02, 1.55111758e-01, - 2.85062570e-01, -5.84924373e-06, 1.53350141e-05, -1.27155811e-05, - -2.91096380e-02, 7.69598214e-02, -1.54618594e-01, -2.48570195e-01}, - {1.31757440e-01, 2.24848388e-01, -1.88385350e-01, -1.43505073e-02, - -3.55830919e-02, -1.64931067e-01, 4.35661665e-02, -2.85261618e-03, - -2.52118559e-01, -2.30174605e-01, -7.95010361e-03, -4.26527825e-02, - -1.83854620e-02, 1.54535957e-02, 1.67110504e-01, 5.34036132e-02}, - {1.31760808e-01, -2.24866215e-01, -1.88375801e-01, -1.43490698e-02, - 3.55686158e-02, 1.64924266e-01, 4.35449406e-02, -2.84313762e-03, - -2.52130324e-01, 2.30189900e-01, 7.94353088e-03, 4.26780776e-02, - -1.83949062e-02, 1.54348167e-02, 1.67098535e-01, 5.33791880e-02}, - {5.46132185e-02, 8.58331564e-02, 9.30017320e-02, 8.58427843e-02, - 1.25635108e-01, 1.28538300e-01, 1.47319998e-02, 1.28546514e-01, - 1.68548662e-05, 7.78214512e-02, 1.86713054e-01, 6.88190732e-02, - -7.57587907e-02, 6.88154210e-02, 1.37678330e-05, -7.77835818e-02}, - {5.45988563e-02, -8.58268751e-02, 9.29763705e-02, 8.58165110e-02, - -1.25619676e-01, -1.28517712e-01, 1.47182803e-02, 1.28531462e-01, - -2.89558352e-05, -7.77589946e-02, -1.86712591e-01, -6.87831667e-02, - -7.57667306e-02, 6.88420404e-02, -6.82053548e-08, -7.78339431e-02}, - {6.11276858e-02, 1.18564511e-05, 9.81052509e-02, 1.38503132e-01, - 2.01552645e-05, 1.94821804e-05, 2.37168732e-03, 1.94464721e-01, - 1.43097116e-01, 2.06384756e-05, 3.00249563e-05, 1.64138024e-05, - -9.05561062e-02, 8.24571561e-02, 2.00250670e-01, 1.20667590e-01}, - {1.34183745e-01, 1.53724110e-05, 3.40119711e-01, -6.25215362e-06, - 5.69423198e-06, 2.74675645e-05, 3.95111929e-01, -7.46067477e-06, - 1.88946620e-06, -1.08879508e-05, 9.44167688e-06, 2.31814191e-05, - 2.95866750e-01, 3.75221202e-06, 5.51441629e-06, -9.91996045e-06}, - {5.95572016e-02, 9.43741521e-02, 9.71937743e-02, -9.43860214e-02, - -1.34659967e-01, 1.35425605e-01, 5.75710650e-03, -1.35430199e-01, - 1.99794221e-05, 7.68969299e-02, -1.94510974e-01, 6.20782748e-02, - -8.76721022e-02, -6.20594490e-02, 1.15500220e-05, 7.68630056e-02}, - {5.95464983e-02, -9.43658029e-02, 9.71667844e-02, -9.43804002e-02, - 1.34659659e-01, -1.35395379e-01, 5.72557927e-03, -1.35430845e-01, - 1.19803283e-05, -7.68849646e-02, 1.94511297e-01, -6.20333654e-02, - -8.76988258e-02, -6.20701988e-02, 4.00940343e-05, 7.68851721e-02}, - {6.03369822e-02, 1.35981277e-01, 9.76431864e-02, -7.03090798e-05, - 3.00664366e-04, 1.92998395e-01, 4.06278981e-03, -1.73736188e-04, - -1.38874714e-01, -1.14705421e-01, -9.56222736e-05, 8.51432034e-02, - -8.91337556e-02, -6.91484919e-05, -1.97380720e-01, -1.74083460e-03}, - {6.03380560e-02, -1.35981797e-01, 9.76427813e-02, -7.46995291e-05, - -2.88862552e-04, -1.92986540e-01, 4.06306769e-03, -1.71821960e-04, - -1.38881019e-01, 1.14707469e-01, 9.12626892e-05, -8.51092373e-02, - -8.91063144e-02, -6.04101296e-05, -1.97392527e-01, -1.72110956e-03}, - {5.95502319e-02, 7.70830361e-06, 9.71765339e-02, -1.33466836e-01, - -1.38944677e-05, 1.32397384e-05, 5.74152129e-03, -1.91507073e-01, - 1.34663736e-01, 1.87089724e-05, -1.85117850e-05, 1.69907754e-05, - -8.76746159e-02, -8.77632010e-02, 1.94511330e-01, -1.08739420e-01}, - {9.88956459e-02, -5.31910690e-06, -1.94619852e-01, 1.32480606e-01, - -6.75531742e-06, 7.40658325e-06, 1.16944607e-01, -1.81491840e-01, - 1.38388581e-01, 2.64755154e-06, 1.45602211e-05, 3.61030626e-06, - -1.58811295e-04, 6.67049063e-02, -1.89508028e-01, 1.17758575e-01}, - {9.23739469e-02, 8.15701114e-02, -1.89485459e-01, 8.15892931e-02, - 1.20915140e-01, -1.19351948e-01, 1.29234438e-01, -1.19373843e-01, - 2.12331566e-05, 7.57395725e-02, -1.75960925e-01, 5.76489647e-02, - -1.48511480e-02, 5.76490938e-02, -1.86570551e-05, -7.56894366e-02}, - {9.23646906e-02, -8.15530234e-02, -1.89498348e-01, 8.15545678e-02, - -1.20867601e-01, 1.19358521e-01, 1.29302317e-01, -1.19365189e-01, - 5.01204681e-07, -7.56741025e-02, 1.75948842e-01, -5.77015223e-02, - -1.49149636e-02, 5.77026590e-02, -1.32548363e-05, -7.56851607e-02}}; -float toa_bs070[][16] = { - {2.13372111e-01, 2.14424553e-01, 2.94162482e-05, 2.55723284e-01, - 3.45027724e-01, 1.91222820e-06, 1.52974072e-01, 1.85454390e-05, - 5.13561776e-02, 2.55146288e-01, 1.29179779e-05, 1.42644435e-02, - 8.54541193e-05, 3.08761389e-02, 1.58130072e-05, -1.39695202e-01}, - {2.13374628e-01, -2.14421922e-01, -7.82048844e-06, 2.55731530e-01, - -3.45024387e-01, 2.20791663e-05, 1.52994501e-01, 8.36579432e-06, - 5.13749937e-02, -2.55161157e-01, 4.42598123e-06, -1.42601113e-02, - 2.62321225e-05, 3.08964355e-02, 3.78724296e-05, -1.39691308e-01}, - {1.66184358e-01, 1.11184573e-05, -3.66403883e-05, 2.30248469e-01, - 3.30963290e-05, -2.20639849e-05, 1.77102738e-01, -1.86961785e-05, - 2.60114393e-01, 3.88156714e-05, -1.68517101e-05, 7.32964547e-06, - -5.08503538e-05, 2.55430592e-02, -4.75572678e-06, 2.74143570e-01}, - {2.36569928e-01, 3.74832066e-01, -1.56285437e-05, 4.24343604e-02, - 6.81662182e-02, -7.63351205e-06, 1.40428434e-01, -1.23898745e-05, - -3.73376705e-01, -2.69943350e-01, -5.81525049e-07, 2.43874398e-02, - -1.39257439e-05, 1.92273189e-02, -2.52231898e-06, -6.29389348e-02}, - {2.36564185e-01, -3.74827868e-01, -2.54864215e-07, 4.24175086e-02, - -6.81345231e-02, -9.34997984e-06, 1.40437087e-01, 1.34667096e-05, - -3.73385262e-01, 2.69967023e-01, -3.32825354e-06, -2.43764672e-02, - 1.12151973e-05, 1.92243912e-02, -8.14447825e-07, -6.29289088e-02}, - {2.88435400e-01, 2.21055717e-01, -6.86850321e-06, -4.05015254e-01, - -3.26455673e-01, -1.18756599e-06, 1.22777109e-01, 6.76367569e-06, - 1.93534074e-01, 1.77532443e-01, -1.67302684e-06, 1.60930709e-02, - 2.02380038e-05, -3.00239800e-02, 1.46102312e-05, 3.75304962e-02}, - {2.88423101e-01, -2.21046949e-01, -1.44603837e-05, -4.05012856e-01, - 3.26460873e-01, 2.47435796e-05, 1.22743736e-01, -5.06874964e-06, - 1.93545207e-01, -1.77534762e-01, 1.10284864e-05, -1.60647731e-02, - 1.84954718e-05, -3.00256524e-02, 3.54098237e-05, 3.75303538e-02}}; -float toa_bs470[][16] = { - {1.24843144e-01, 1.41061771e-01, -1.80747248e-01, 1.65913311e-01, - 2.36800212e-01, -1.07244596e-01, 3.70755153e-02, -1.32041749e-01, - 3.34320779e-02, 1.83465662e-01, -1.63044496e-01, -3.32090915e-02, - -1.00199557e-02, -3.00655273e-02, -2.30739344e-02, -1.07604436e-01}, - {1.24850841e-01, -1.41070242e-01, -1.80772646e-01, 1.65913745e-01, - -2.36805435e-01, 1.07249239e-01, 3.71137725e-02, -1.32065593e-01, - 3.34170948e-02, -1.83456094e-01, 1.63049548e-01, 3.31922333e-02, - -1.00594025e-02, -3.00390583e-02, -2.31094492e-02, -1.07633723e-01}, - {1.14402054e-01, 4.98738605e-06, -1.33728192e-01, 2.00537106e-01, - 7.47281967e-06, -2.10410933e-05, 3.12322948e-02, -7.31589498e-02, - 2.33910325e-01, 4.98520638e-06, -3.87488495e-05, 2.56235628e-05, - -8.47692243e-02, -6.08019759e-02, -6.69334999e-02, 2.39166920e-01}, - {1.58755448e-01, 2.95106609e-01, -1.76798547e-01, 2.68778320e-02, - 4.61416218e-02, -1.43594618e-01, -7.56537425e-03, -2.50863476e-02, - -3.05162259e-01, -2.29775448e-01, -3.29644305e-02, -8.81169950e-02, - -4.43186023e-02, 3.01020148e-03, 1.29563335e-01, -4.45753224e-02}, - {1.58756803e-01, -2.95115716e-01, -1.76785653e-01, 2.68566486e-02, - -4.61073907e-02, 1.43578055e-01, -7.59074013e-03, -2.50818687e-02, - -3.05167500e-01, 2.29764496e-01, 3.29816574e-02, 8.81563559e-02, - -4.43327008e-02, 2.97545574e-03, 1.29569118e-01, -4.45418085e-02}, - {1.86203037e-01, 1.50116485e-01, -2.14964156e-01, -3.03325032e-01, - -2.36972616e-01, -1.06371699e-01, -2.25753494e-02, 1.69770743e-01, - 1.72868251e-01, 1.50335469e-01, 1.42695099e-01, -3.62253139e-02, - -6.06157227e-03, 8.39919748e-02, -5.40499752e-02, -2.87551740e-03}, - {1.86189919e-01, -1.50097988e-01, -2.14959641e-01, -3.03312344e-01, - 2.36955630e-01, 1.06381437e-01, -2.25726327e-02, 1.69772154e-01, - 1.72892919e-01, -1.50359207e-01, -1.42698526e-01, 3.61976127e-02, - -6.02462292e-03, 8.39965538e-02, -5.40363302e-02, -2.91104068e-03}, - {1.44709894e-01, 1.41473867e-01, 2.78957203e-01, 1.41751287e-01, - 1.30601102e-01, 2.01653545e-01, 1.50390749e-01, 2.01774772e-01, - 5.06050203e-04, 2.91925392e-02, 1.71070673e-01, 9.00016580e-02, - -3.21155894e-02, 8.96531863e-02, 2.67123550e-04, -2.81262986e-02}, - {1.44701477e-01, -1.41446273e-01, 2.78957354e-01, 1.41750842e-01, - -1.30567100e-01, -2.01633141e-01, 1.50411808e-01, 2.01805474e-01, - 4.96601979e-04, -2.91385143e-02, -1.71055278e-01, -9.00154625e-02, - -3.21118007e-02, 8.96938931e-02, 2.77978977e-04, -2.81581190e-02}, - {1.44950932e-01, 1.35387066e-01, 2.79612497e-01, -1.42097420e-01, - -1.15376887e-01, 1.96671462e-01, 1.50619314e-01, -2.03198893e-01, - 2.98435746e-04, 5.89416209e-03, -1.57974514e-01, 9.45683744e-02, - -3.34969322e-02, -9.10208758e-02, 1.33572181e-03, 2.84859560e-02}, - {1.44954080e-01, -1.35401479e-01, 2.79611028e-01, -1.42095453e-01, - 1.15370701e-01, -1.96673875e-01, 1.50606414e-01, -2.03202287e-01, - 2.71548519e-04, -5.86436737e-03, 1.57960124e-01, -9.45439437e-02, - -3.35050564e-02, -9.10396767e-02, 1.32770538e-03, 2.85003118e-02}}; -float toa_iamf312[][16] = { - {4.600323e-01, 5.123393e-01, -1.732089e-01, -8.679045e-02, 2.110607e-01, - -1.240358e-01, 6.031437e-02, -1.472639e-01, -9.544121e-02, 9.626709e-03, - -1.475499e-01, -2.170848e-02, -1.757221e-02, -3.459537e-02, 5.974536e-03, - -1.740531e-01}, - {4.600358e-01, -5.123299e-01, -1.732095e-01, -8.677885e-02, -2.110661e-01, - 1.240584e-01, 6.030266e-02, -1.472670e-01, -9.542189e-02, -9.640919e-03, - 1.475400e-01, 2.169693e-02, -1.758859e-02, -3.460532e-02, 5.974916e-03, - -1.740174e-01}, - {9.927428e-02, 1.135584e-05, -1.291193e-01, 1.863923e-01, 3.137031e-05, - -9.139079e-06, 3.496658e-02, -1.160047e-01, 2.076180e-01, 3.945961e-05, - -2.879414e-05, 4.179365e-06, -6.578851e-02, -1.791001e-02, -8.364789e-02, - 2.217087e-01}, - {1.117560e-01, 9.571090e-02, 2.177361e-01, 1.412031e-01, 1.217814e-01, - 1.382991e-01, 1.241730e-01, 2.136451e-01, 3.635167e-02, 6.785955e-02, - 1.732515e-01, 6.485935e-02, -1.129651e-02, 1.236321e-01, 4.362752e-02, - -5.882758e-03}, - {1.117437e-01, -9.570201e-02, 2.177374e-01, 1.411734e-01, -1.217560e-01, - -1.383046e-01, 1.242088e-01, 2.136489e-01, 3.631807e-02, -6.782208e-02, - -1.732464e-01, -6.488207e-02, -1.128750e-02, 1.236767e-01, 4.363238e-02, - -5.932943e-03}, -}; -float toa_iamf712[][16] = { - {1.24843144e-01, 1.41061771e-01, -1.80747248e-01, 1.65913311e-01, - 2.36800212e-01, -1.07244596e-01, 3.70755153e-02, -1.32041749e-01, - 3.34320779e-02, 1.83465662e-01, -1.63044496e-01, -3.32090915e-02, - -1.00199557e-02, -3.00655273e-02, -2.30739344e-02, -1.07604436e-01}, - {1.24850841e-01, -1.41070242e-01, -1.80772646e-01, 1.65913745e-01, - -2.36805435e-01, 1.07249239e-01, 3.71137725e-02, -1.32065593e-01, - 3.34170948e-02, -1.83456094e-01, 1.63049548e-01, 3.31922333e-02, - -1.00594025e-02, -3.00390583e-02, -2.31094492e-02, -1.07633723e-01}, - {1.14402054e-01, 4.98738605e-06, -1.33728192e-01, 2.00537106e-01, - 7.47281967e-06, -2.10410933e-05, 3.12322948e-02, -7.31589498e-02, - 2.33910325e-01, 4.98520638e-06, -3.87488495e-05, 2.56235628e-05, - -8.47692243e-02, -6.08019759e-02, -6.69334999e-02, 2.39166920e-01}, - {1.58755448e-01, 2.95106609e-01, -1.76798547e-01, 2.68778320e-02, - 4.61416218e-02, -1.43594618e-01, -7.56537425e-03, -2.50863476e-02, - -3.05162259e-01, -2.29775448e-01, -3.29644305e-02, -8.81169950e-02, - -4.43186023e-02, 3.01020148e-03, 1.29563335e-01, -4.45753224e-02}, - {1.58756803e-01, -2.95115716e-01, -1.76785653e-01, 2.68566486e-02, - -4.61073907e-02, 1.43578055e-01, -7.59074013e-03, -2.50818687e-02, - -3.05167500e-01, 2.29764496e-01, 3.29816574e-02, 8.81563559e-02, - -4.43327008e-02, 2.97545574e-03, 1.29569118e-01, -4.45418085e-02}, - {1.86203037e-01, 1.50116485e-01, -2.14964156e-01, -3.03325032e-01, - -2.36972616e-01, -1.06371699e-01, -2.25753494e-02, 1.69770743e-01, - 1.72868251e-01, 1.50335469e-01, 1.42695099e-01, -3.62253139e-02, - -6.06157227e-03, 8.39919748e-02, -5.40499752e-02, -2.87551740e-03}, - {1.86189919e-01, -1.50097988e-01, -2.14959641e-01, -3.03312344e-01, - 2.36955630e-01, 1.06381437e-01, -2.25726327e-02, 1.69772154e-01, - 1.72892919e-01, -1.50359207e-01, -1.42698526e-01, 3.61976127e-02, - -6.02462292e-03, 8.39965538e-02, -5.40363302e-02, -2.91104068e-03}, - {2.472057e-01, 2.372070e-01, 4.766731e-01, 4.127324e-02, 4.901732e-02, - 3.407213e-01, 2.568947e-01, 5.809146e-02, 7.170761e-04, 3.336034e-02, - 5.936582e-02, 1.568716e-01, -5.580150e-02, 2.529171e-02, 1.211621e-03, - -7.983686e-03}, - {2.471995e-01, -2.371896e-01, 4.766722e-01, 4.127418e-02, -4.898770e-02, - -3.407026e-01, 2.569066e-01, 5.811976e-02, 6.886158e-04, -3.328525e-02, - -5.936060e-02, -1.568681e-01, -5.580345e-02, 2.531912e-02, 1.216808e-03, - -8.005355e-03}}; -float toa_iamf916[][16] = { // TOA -> 9+10+3 -> 9.1.6 - {4.04576287e-02, 1.02276902e-01, 3.16305304e-04, 5.35705581e-02, - 1.24840439e-01, 8.69586461e-04, -8.49373750e-02, 1.55602919e-04, - -8.61656489e-02, -1.99113803e-02, 4.59578590e-04, -1.07672132e-01, - -1.00584229e-03, -5.80424713e-02, -1.24512586e-03, -1.67195449e-01}, - {4.04604598e-02, -1.02279953e-01, 3.04769925e-04, 5.35815935e-02, - -1.24857409e-01, -8.47445963e-04, -8.49510523e-02, 1.39008638e-04, - -8.61498623e-02, 1.98737596e-02, -4.23839742e-04, 1.07688993e-01, - -9.86892094e-04, -5.80707244e-02, -1.23581553e-03, -1.67194266e-01}, - {1.23155007e-01, 7.45686120e-06, -1.94642103e-01, 2.03148125e-01, - 2.63637395e-05, 6.67729503e-06, 6.14557728e-02, -1.81549399e-01, - 2.34505417e-01, 5.61237259e-05, 1.24757705e-05, -1.05368280e-05, - -1.04794442e-04, -2.01926028e-02, -1.89587486e-01, 2.29959069e-01}, - {2.46257156e-01, 1.82281003e-01, -3.15142612e-01, -3.64582975e-01, - -2.85046217e-01, -1.09700114e-01, 2.99018604e-02, 2.19373775e-01, - 2.01568510e-01, 1.75751031e-01, 1.54660260e-01, -5.44304649e-02, - -4.96809649e-02, 1.08844679e-01, -1.09310200e-01, -1.93011904e-05}, - {2.46255473e-01, -1.82300248e-01, -3.15128610e-01, -3.64587237e-01, - 2.85062029e-01, 1.09705540e-01, 2.98862077e-02, 2.19360224e-01, - 2.01577581e-01, -1.75765938e-01, -1.54618053e-01, 5.44077273e-02, - -4.96728006e-02, 1.08855743e-01, -1.09308920e-01, -1.93771904e-05}, - {1.76653502e-01, 1.35477988e-01, -1.20111849e-01, 2.83531566e-01, - 2.46688021e-01, -1.19340929e-01, 4.46275836e-02, 1.81404863e-02, - 1.89671329e-01, 2.44614884e-01, -1.75946483e-01, -8.03907289e-04, - -7.88872300e-02, 6.23024994e-03, 1.41591850e-01, 3.21140603e-02}, - {1.76645960e-01, -1.35446923e-01, -1.20112850e-01, 2.83496916e-01, - -2.46612414e-01, 1.19359752e-01, 4.47035773e-02, 1.81739727e-02, - 1.89641374e-01, -2.44507608e-01, 1.75947302e-01, 7.71282311e-04, - -7.89829130e-02, 6.31177814e-03, 1.41609839e-01, 3.21016340e-02}, - {1.31757440e-01, 2.24848388e-01, -1.88385350e-01, -1.43505073e-02, - -3.55830919e-02, -1.64931067e-01, 4.35661665e-02, -2.85261618e-03, - -2.52118559e-01, -2.30174605e-01, -7.95010361e-03, -4.26527825e-02, - -1.83854620e-02, 1.54535957e-02, 1.67110504e-01, 5.34036132e-02}, - {1.31760808e-01, -2.24866215e-01, -1.88375801e-01, -1.43490698e-02, - 3.55686158e-02, 1.64924266e-01, 4.35449406e-02, -2.84313762e-03, - -2.52130324e-01, 2.30189900e-01, 7.94353088e-03, 4.26780776e-02, - -1.83949062e-02, 1.54348167e-02, 1.67098535e-01, 5.33791880e-02}, - {1.21705091e-01, 8.58408426e-02, 2.63061587e-01, 8.58396582e-02, - 1.25637955e-01, 1.28552034e-01, 2.12287964e-01, 1.28542784e-01, - 1.77995993e-05, 7.78160072e-02, 1.86717775e-01, 6.88306639e-02, - 7.21745843e-02, 6.88172971e-02, 1.65250411e-05, -7.77885418e-02}, - {1.21690729e-01, -8.58191889e-02, 2.63036226e-01, 8.58133849e-02, - -1.25616829e-01, -1.28503978e-01, 2.12274245e-01, 1.28527732e-01, - -2.80111021e-05, -7.77644386e-02, -1.86707870e-01, -6.87715760e-02, - 7.21666444e-02, 6.88439165e-02, 2.68900279e-06, -7.78389031e-02}, - {1.68757447e-01, 9.43872889e-02, 3.35967816e-01, -1.88764452e-01, - -1.34666945e-01, 1.35448701e-01, 2.07372940e-01, -2.70849879e-01, - 9.52425649e-02, 7.69047152e-02, -1.94519343e-01, 6.21018798e-02, - -1.73404254e-03, -1.24115527e-01, 1.37554587e-01, -3.23355155e-05}, - {1.68746744e-01, -9.43526661e-02, 3.35940826e-01, -1.88758831e-01, - 1.34652681e-01, -1.35372283e-01, 2.07341412e-01, -2.70850525e-01, - 9.52345658e-02, -7.68771793e-02, 1.94502928e-01, -6.20097604e-02, - -1.76076614e-03, -1.24126277e-01, 1.37583131e-01, -1.01690155e-05}, - {6.03369822e-02, 1.35981277e-01, 9.76431864e-02, -7.03090798e-05, - 3.00664366e-04, 1.92998395e-01, 4.06278981e-03, -1.73736188e-04, - -1.38874714e-01, -1.14705421e-01, -9.56222736e-05, 8.51432034e-02, - -8.91337556e-02, -6.91484919e-05, -1.97380720e-01, -1.74083460e-03}, - {6.03380560e-02, -1.35981797e-01, 9.76427813e-02, -7.46995291e-05, - -2.88862552e-04, -1.92986540e-01, 4.06306769e-03, -1.71821960e-04, - -1.38881019e-01, 1.14707469e-01, 9.12626892e-05, -8.51092373e-02, - -8.91063144e-02, -6.04101296e-05, -1.97392527e-01, -1.72110956e-03}}; -/////////////////////////////// -float h4a_mono[] = { // h4a_020 -> stereo_mono - 6.09331121e-01, 3.85700000e-06, -1.91202966e-07, 7.23156638e-02, - 4.07900000e-06, 8.18490653e-06, 9.20182582e-02, 7.90880113e-07, - 1.57882187e-01, 5.32100000e-06, 3.17273995e-07, -1.05575000e-05, - -8.20159697e-06, 3.95772776e-02, -1.52543653e-05, 4.94263417e-02, - 1.27015000e-05, -1.78367850e-07, 1.33780000e-05, -6.37105140e-06, - 3.07440885e-02, -6.36642250e-06, 1.16670616e-02, -9.93439079e-06, - 3.18608616e-02}; -float h4a_bs020[][25] = { - {6.09325985e-01, 5.58871486e-01, -8.38470782e-07, 7.23022635e-02, - 2.45481463e-01, 2.34091397e-06, 9.20215087e-02, -1.43550945e-07, - 1.57872691e-01, 1.05701896e-01, -9.19418432e-06, 1.44171841e-02, - 6.20096026e-06, 3.95665379e-02, -1.74919389e-05, 4.94241687e-02, - 1.17564010e-01, 1.01196642e-05, 3.84279075e-02, 1.21175563e-05, - 3.07369788e-02, 1.37835928e-05, 1.16515529e-02, -2.01716844e-05, - 3.18682823e-02}, - {6.09336256e-01, -5.58863772e-01, 4.56064850e-07, 7.23290640e-02, - -2.45473305e-01, 1.40288991e-05, 9.20150077e-02, 1.72531117e-06, - 1.57891682e-01, -1.05691254e-01, 9.82873231e-06, -1.44382991e-02, - -2.26041542e-05, 3.95880173e-02, -1.30167916e-05, 4.94285147e-02, - -1.17538607e-01, -1.04763999e-05, -3.84011515e-02, -2.48596591e-05, - 3.07511983e-02, -2.65164378e-05, 1.16825703e-02, 3.02902829e-07, - 3.18534408e-02}}; -float h4a_bs050[][25] = { - {2.32067077e-01, 2.87681712e-01, 1.58252973e-05, 2.84783073e-01, - 3.67406853e-01, 4.53634344e-06, 1.20886421e-01, 2.54987474e-05, - -3.72336666e-02, 1.71252208e-01, 5.73626235e-06, 2.44396028e-02, - 2.46211959e-05, 9.91967937e-02, -1.01021170e-05, -1.77776441e-01, - 3.77615229e-02, 8.37226581e-06, 1.01177294e-01, 3.12880916e-05, - 6.77780104e-02, 7.20085369e-05, -4.28514137e-02, 4.63126089e-06, - -1.07408281e-01}, - {2.32069076e-01, -2.87684323e-01, 9.17551194e-06, 2.84794078e-01, - -3.67406600e-01, 1.35443991e-05, 1.20907160e-01, 2.00817879e-05, - -3.72194752e-02, -1.71252954e-01, 5.06967788e-06, -2.44649469e-02, - 2.22372199e-05, 9.92137784e-02, 3.93841537e-07, -1.77790718e-01, - -3.77525758e-02, 1.07820823e-06, -1.01160036e-01, -1.84696904e-05, - 6.77924449e-02, 2.27945886e-05, -4.28428326e-02, -3.87257310e-06, - -1.07411582e-01}, - {1.52986533e-01, 8.47774439e-06, -3.77128678e-05, 2.45810605e-01, - 3.51902915e-05, -1.30977996e-05, 1.58282073e-01, -4.31638244e-06, - 2.52253116e-01, 4.04498390e-05, -1.48664579e-05, -1.84313511e-06, - -8.92616162e-05, 8.88827606e-02, -2.54546360e-05, 2.68089497e-01, - 2.70687367e-05, -1.00427942e-05, 3.82379916e-05, -2.37786562e-05, - 9.40559401e-02, -1.52893417e-05, 3.35047248e-02, -8.40750098e-08, - 2.44509728e-01}, - {4.32778117e-01, 4.17729582e-01, -4.07552212e-06, -3.98732964e-01, - -9.82332147e-02, 2.47605349e-06, 8.49313437e-02, -1.53543979e-06, - -7.51915459e-02, -1.62306151e-01, -1.50837864e-05, 5.14587336e-02, - 9.53836838e-06, -3.96624920e-02, 7.81428580e-06, -1.77212453e-02, - 3.72500434e-03, -6.09454358e-06, -4.45948964e-02, -3.55617926e-05, - 1.22689406e-02, -2.25968056e-05, -3.38939803e-03, -1.98654840e-05, - 9.31007554e-03}, - {4.32773893e-01, -4.17708177e-01, 9.94265816e-06, -3.98748640e-01, - 9.82425685e-02, 1.56884352e-06, 8.49159764e-02, 9.47703099e-06, - -7.52105107e-02, 1.62320852e-01, 5.07094993e-06, -5.14526554e-02, - 2.62996039e-06, -3.96675266e-02, -4.15355245e-06, -1.77069335e-02, - -3.68162328e-03, 1.45915292e-06, 4.46224104e-02, -1.89061763e-05, - 1.22709568e-02, 1.30189591e-05, -3.38713969e-03, -8.88736414e-06, - 9.31982588e-03}}; -float h4a_bs250[][25] = { - {1.46201810e-01, 2.07605260e-01, -1.77458016e-01, 1.93406206e-01, - 2.73008780e-01, -1.26266127e-01, -2.53585845e-03, -1.48656023e-01, - -3.66585070e-02, 1.24969859e-01, -1.51352272e-01, -5.34008667e-02, - -1.85137374e-02, -5.78766897e-03, 1.13449271e-02, -1.52560894e-01, - 1.41232385e-02, -7.38524283e-02, -1.62813327e-02, 1.26649462e-02, - 8.86331125e-02, -1.43446464e-02, -1.39598476e-02, 5.06447242e-02, - -9.90625261e-02}, - {1.46209166e-01, -2.07610815e-01, -1.77467418e-01, 1.93429653e-01, - -2.73017954e-01, 1.26286544e-01, -2.53699123e-03, -1.48665984e-01, - -3.66271128e-02, -1.24986790e-01, 1.51354199e-01, 5.33844724e-02, - -1.85263928e-02, -5.79385484e-03, 1.13521037e-02, -1.52536152e-01, - -1.41425427e-02, 7.38448932e-02, 1.62928067e-02, -1.26518996e-02, - 8.86596575e-02, -1.43843676e-02, -1.39767297e-02, 5.06593993e-02, - -9.90314550e-02}, - {9.83717086e-02, 1.12525988e-05, -1.27945384e-01, 1.84697722e-01, - 3.10851034e-05, -9.05598979e-06, 3.46486760e-02, -1.14949980e-01, - 2.05730432e-01, 3.91008588e-05, -2.85323553e-05, 4.14136776e-06, - -6.51903847e-02, -1.77471772e-02, -8.28873930e-02, 2.19693014e-01, - 3.65974139e-05, -2.56549232e-05, 2.56025984e-05, -1.22458309e-05, - 8.23314872e-02, -4.03156122e-02, -3.90021649e-02, -9.32963081e-02, - 2.03357639e-01}, - {4.37908471e-01, 4.24371525e-01, 8.23615191e-03, -3.95142005e-01, - -9.03215614e-02, 4.74899388e-03, 8.81081466e-02, 3.86219702e-03, - -8.19041543e-02, -1.63243623e-01, 7.27456110e-03, 4.50989212e-02, - 1.55745266e-03, -4.02954367e-02, -7.67169822e-03, -2.81566113e-02, - -4.14743203e-03, -6.96637038e-04, -4.72702928e-02, -1.15757400e-02, - 2.07941728e-02, -2.07283763e-03, -5.12566336e-03, -1.11187528e-02, - 5.34509538e-03}, - {4.37902979e-01, -4.24350604e-01, 8.24858287e-03, -3.95158901e-01, - 9.03268987e-02, -4.74621319e-03, 8.80933487e-02, 3.87201119e-03, - -8.19214759e-02, 1.63247655e-01, -7.29114902e-03, -4.50919254e-02, - 1.55239708e-03, -4.03006207e-02, -7.68131374e-03, -2.81416186e-02, - 4.17780629e-03, 6.73979936e-04, 4.72956053e-02, 1.15276141e-02, - 2.07982314e-02, -2.03660090e-03, -5.12132098e-03, -1.11050116e-02, - 5.35219408e-03}, - {1.10739959e-01, 9.48407255e-02, 2.15756484e-01, 1.39919336e-01, - 1.20674172e-01, 1.37041758e-01, 1.23044023e-01, 2.11702740e-01, - 3.60211746e-02, 6.72425926e-02, 1.71676364e-01, 6.42696750e-02, - -1.11938029e-02, 1.22508096e-01, 4.32308749e-02, -5.82927386e-03, - 2.99387418e-02, 8.94186401e-02, 1.01845907e-01, -3.54355013e-02, - -2.95814307e-02, -1.39686735e-02, 7.49153415e-03, -9.42221054e-03, - 2.87383917e-03}, - {1.10727751e-01, -9.48319190e-02, 2.15757790e-01, 1.39889931e-01, - -1.20649000e-01, -1.37047172e-01, 1.23079547e-01, 2.11706478e-01, - 3.59878757e-02, -6.72054617e-02, -1.71671283e-01, -6.42921810e-02, - -1.11848811e-02, 1.22552278e-01, 4.32356896e-02, -5.87900262e-03, - -2.98887416e-02, -8.94134031e-02, -1.01861627e-01, 3.54313251e-02, - -2.96121365e-02, -1.39825296e-02, 7.53781267e-03, -9.44686457e-03, - 2.83843409e-03}}; -float h4a_bs450[][25] = { - {1.48800342e-01, 2.13877118e-01, -1.76508211e-01, 1.95668955e-01, - 2.77709622e-01, -1.22682186e-01, -6.47488220e-03, -1.48031709e-01, - -4.28631082e-02, 1.20479620e-01, -1.48926097e-01, -5.84254642e-02, - -2.31851906e-02, -7.14077979e-03, 6.63474024e-03, -1.58376753e-01, - 8.63700349e-03, -7.82420887e-02, -1.82759651e-02, 5.15471735e-03, - 9.12104459e-02, -1.65613617e-02, -1.06711416e-02, 4.62729755e-02, - -9.64376469e-02}, - {1.48807244e-01, -2.13881220e-01, -1.76517743e-01, 1.95692625e-01, - -2.77719044e-01, 1.22702924e-01, -6.47495148e-03, -1.48041476e-01, - -4.28292828e-02, -1.20499903e-01, 1.48927405e-01, 5.84072442e-02, - -2.31976541e-02, -7.14707406e-03, 6.64227002e-03, -1.58351813e-01, - -8.65752517e-03, 7.82342106e-02, 1.82873893e-02, -5.14199913e-03, - 9.12359995e-02, -1.66017384e-02, -1.06903619e-02, 4.62866616e-02, - -9.64106974e-02}, - {9.87310293e-02, 1.12937010e-05, -1.28412728e-01, 1.85372364e-01, - 3.11986474e-05, -9.08906845e-06, 3.47752366e-02, -1.15369855e-01, - 2.06481900e-01, 3.92436819e-05, -2.86365750e-05, 4.15649486e-06, - -6.54285044e-02, -1.78120020e-02, -8.31901544e-02, 2.20495483e-01, - 3.67310927e-05, -2.57486325e-05, 2.56961166e-05, -1.22905611e-05, - 8.26322180e-02, -4.04628723e-02, -3.91446274e-02, -9.36370899e-02, - 2.04100440e-01}, - {3.19440918e-01, 3.20665142e-01, -2.52981283e-01, -3.57875700e-01, - -8.65166712e-02, -1.68414900e-01, -1.20610313e-01, 8.35207925e-02, - -1.56512754e-02, -1.18534259e-01, 2.45833524e-02, -7.59760821e-02, - -5.35874225e-02, 4.95984088e-02, 9.43768431e-02, -3.51799318e-02, - -6.36479179e-03, 7.53812828e-02, -1.43299929e-02, -1.48970841e-02, - 7.00692921e-02, 5.95057034e-02, 6.13926063e-02, -3.07257679e-02, - 3.04148439e-04}, - {3.19431947e-01, -3.20641825e-01, -2.52970610e-01, -3.57885664e-01, - 8.65145301e-02, 1.68415260e-01, -1.20614024e-01, 8.35342297e-02, - -1.56501789e-02, 1.18532076e-01, -2.46024465e-02, 7.59696414e-02, - -5.35761492e-02, 4.95798813e-02, 9.43863635e-02, -3.51842128e-02, - 6.40830581e-03, -7.54085441e-02, 1.43715440e-02, 1.48356024e-02, - 7.00751394e-02, 5.95170870e-02, 6.13915420e-02, -3.07292563e-02, - 3.13371698e-04}, - {1.13093054e-01, 1.00216102e-01, 2.18626561e-01, 1.41848612e-01, - 1.24374617e-01, 1.42644848e-01, 1.20654213e-01, 2.13930392e-01, - 3.08035907e-02, 6.32820015e-02, 1.75893356e-01, 6.21963500e-02, - -1.65483810e-02, 1.22330391e-01, 3.75755465e-02, -1.03136221e-02, - 2.55311056e-02, 8.48422289e-02, 1.02033314e-01, -4.34671421e-02, - -3.03211480e-02, -1.62526524e-02, 7.95647231e-03, -1.47625950e-02, - 5.33105555e-03}, - {1.13080292e-01, -1.00206129e-01, 2.18627043e-01, 1.41818571e-01, - -1.24348285e-01, -1.42648567e-01, 1.20689978e-01, 2.13932958e-01, - 3.07710722e-02, -6.32449166e-02, -1.75885512e-01, -6.22182403e-02, - -1.65381540e-02, 1.22373592e-01, 3.75817343e-02, -1.03621624e-02, - -2.54822981e-02, -8.48370421e-02, -1.02045652e-01, 4.34619363e-02, - -3.03507254e-02, -1.62663383e-02, 8.00369907e-03, -1.47833160e-02, - 5.29635439e-03}, - {1.52645950e-01, 1.38708565e-01, 3.01887964e-01, -9.02342569e-02, - -2.32043476e-02, 2.04079446e-01, 1.78022947e-01, -1.45915823e-01, - -6.49424306e-02, -6.08567957e-02, -3.91603775e-02, 1.02794555e-01, - -2.19546169e-02, -1.01662064e-01, -8.24442967e-02, 1.49000292e-02, - 9.88255574e-03, -8.57853411e-02, -3.61391023e-02, -4.32767081e-02, - -7.88243727e-02, -1.10682855e-02, -2.67793411e-02, 1.98163262e-02, - 6.29885745e-03}, - {1.52651976e-01, -1.38713607e-01, 3.01891259e-01, -9.02444369e-02, - 2.32142391e-02, -2.04077881e-01, 1.78008716e-01, -1.45921026e-01, - -6.49698495e-02, 6.08760962e-02, 3.91641128e-02, -1.02784611e-01, - -2.19696347e-02, -1.01648383e-01, -8.24660002e-02, 1.49363910e-02, - -9.92759414e-03, 8.57884626e-02, 3.61313121e-02, 4.32738943e-02, - -7.88209093e-02, -1.10476858e-02, -2.67678422e-02, 1.98337103e-02, - 6.29964039e-03}}; -float h4a_bs451[][25] = { - {7.94007126e-02, 1.62080177e-01, -1.74034937e-02, 1.33241312e-01, - 2.19146117e-01, -2.80142505e-02, -1.52155593e-01, -2.87921870e-02, - -3.88525700e-02, 9.18147556e-02, -3.98975770e-02, -1.42791374e-01, - 3.95081378e-02, -1.23991662e-01, -3.81676695e-03, -1.38329627e-01, - -1.70099181e-03, -2.44909296e-02, -1.30554695e-01, 3.31858577e-02, - 1.02033320e-01, 3.95135078e-02, 9.71421024e-03, 9.94761153e-03, - -8.13867544e-02}, - {7.94068225e-02, -1.62081686e-01, -1.74158176e-02, 1.33260824e-01, - -2.19163706e-01, 2.80356895e-02, -1.52151272e-01, -2.88055686e-02, - -3.88298718e-02, -9.18331629e-02, 3.99270955e-02, 1.42766545e-01, - 3.95090570e-02, -1.23990913e-01, -3.80210165e-03, -1.38325752e-01, - 1.70332662e-03, 2.44979407e-02, 1.30526588e-01, -3.31717090e-02, - 1.02021712e-01, 3.94936829e-02, 9.69062521e-03, 9.98796223e-03, - -8.13784700e-02}, - {3.29945985e-02, 1.59755199e-05, 9.25376674e-03, 9.42349474e-02, - 4.11070991e-05, -2.42778070e-06, -7.00706756e-02, 2.41140568e-02, - 1.23728582e-01, 6.48759578e-05, -7.25381488e-06, -2.05085752e-05, - -2.58510917e-02, -1.02112450e-01, 3.15300723e-02, 1.37143862e-01, - 7.76472552e-05, -1.39623419e-05, -4.08010822e-05, 5.77867517e-06, - 6.30199835e-02, -4.29361778e-02, -9.70269189e-02, 3.33228301e-02, - 1.35814574e-01}, - {3.37179930e-01, 3.47428363e-01, -2.86990399e-01, -3.34930202e-01, - -4.86767828e-02, -2.11801602e-01, -1.02731784e-01, 4.84873311e-02, - -1.30854698e-02, -9.35739394e-02, -3.74672958e-02, -4.63425552e-02, - -4.96878491e-02, 6.86749655e-02, 9.09150025e-02, -4.96098065e-02, - 1.47389432e-03, 3.46697859e-02, 3.71218224e-02, -1.53364864e-02, - 6.71366745e-02, 6.62237612e-02, 6.25668564e-02, -9.37739150e-03, - -1.83892023e-02}, - {3.37171387e-01, -3.47416531e-01, -2.86987145e-01, -3.34942527e-01, - 4.86685727e-02, 2.11832922e-01, -1.02719148e-01, 4.84905323e-02, - -1.30910570e-02, 9.35794189e-02, 3.74801224e-02, 4.62927404e-02, - -4.96870902e-02, 6.86835173e-02, 9.09208113e-02, -4.96215972e-02, - -1.40720107e-03, -3.46818188e-02, -3.71383876e-02, 1.53075376e-02, - 6.71404673e-02, 6.62136070e-02, 6.25863435e-02, -9.37908337e-03, - -1.83779588e-02}, - {1.13138256e-01, 1.00256156e-01, 2.18713943e-01, 1.41905306e-01, - 1.24424327e-01, 1.42701861e-01, 1.20702437e-01, 2.14015897e-01, - 3.08159024e-02, 6.33072943e-02, 1.75963658e-01, 6.22212089e-02, - -1.65549951e-02, 1.22379284e-01, 3.75905649e-02, -1.03177443e-02, - 2.55413100e-02, 8.48761390e-02, 1.02074095e-01, -4.34845153e-02, - -3.03332668e-02, -1.62591484e-02, 7.95965238e-03, -1.47684954e-02, - 5.33318629e-03}, - {1.13125489e-01, -1.00246179e-01, 2.18714425e-01, 1.41875254e-01, - -1.24397985e-01, -1.42705581e-01, 1.20738216e-01, 2.14018463e-01, - 3.07833709e-02, -6.32701946e-02, -1.75955810e-01, -6.22431079e-02, - -1.65447641e-02, 1.22422503e-01, 3.75967551e-02, -1.03663040e-02, - -2.54924829e-02, -8.48709501e-02, -1.02086438e-01, 4.34793073e-02, - -3.03628561e-02, -1.62728397e-02, 8.00689803e-03, -1.47892246e-02, - 5.29847126e-03}, - {1.52706960e-01, 1.38764004e-01, 3.02008624e-01, -9.02703221e-02, - -2.32136220e-02, 2.04161013e-01, 1.78094100e-01, -1.45974143e-01, - -6.49683871e-02, -6.08811192e-02, -3.91760293e-02, 1.02835640e-01, - -2.19633918e-02, -1.01702697e-01, -8.24772483e-02, 1.49059845e-02, - 9.88650565e-03, -8.58196282e-02, -3.61535466e-02, -4.32940052e-02, - -7.88558776e-02, -1.10727093e-02, -2.67900444e-02, 1.98242465e-02, - 6.30137500e-03}, - {1.52712988e-01, -1.38769049e-01, 3.02011920e-01, -9.02805062e-02, - 2.32235175e-02, -2.04159448e-01, 1.78079864e-01, -1.45979349e-01, - -6.49958169e-02, 6.09004274e-02, 3.91797660e-02, -1.02825693e-01, - -2.19784156e-02, -1.01689010e-01, -8.24989606e-02, 1.49423608e-02, - -9.93156205e-03, 8.58227509e-02, 3.61457532e-02, 4.32911902e-02, - -7.88524128e-02, -1.10521014e-02, -2.67785408e-02, 1.98416376e-02, - 6.30215826e-03}, - {1.41771220e-01, -6.24071648e-06, -2.81856222e-01, 1.98064437e-01, - 4.91179939e-06, 7.04929730e-06, 1.69518375e-01, -3.04010525e-01, - 1.03045402e-01, 7.94332451e-06, -1.19318642e-05, 2.17396838e-06, - 1.57104639e-02, 1.83409108e-01, -1.17851160e-01, 5.09165406e-02, - 6.69124432e-06, -7.52591028e-06, 1.88782867e-05, -1.02614860e-05, - -6.93407625e-02, 1.23561279e-02, 1.33509092e-02, -4.31725697e-02, - 2.58636545e-02}}; -float h4a_bs370[][25] = { - {1.12360411e-01, 4.89838014e-06, -1.31341651e-01, 1.96958280e-01, - 7.33945819e-06, -2.06655897e-05, 3.06749169e-02, -7.18533402e-02, - 2.29735913e-01, 4.89623936e-06, -3.80573296e-05, 2.51662794e-05, - -8.32564153e-02, -5.97168913e-02, -6.57389910e-02, 2.34898698e-01, - 1.16223714e-05, -4.01365298e-05, 4.14857075e-05, -1.65239025e-05, - 6.43131764e-02, -3.97819672e-02, -3.11369902e-02, -7.90727904e-02, - 2.03601513e-01}, - {1.22615168e-01, 1.38544354e-01, -1.77521595e-01, 1.62952388e-01, - 2.32574227e-01, -1.05330687e-01, 3.64138581e-02, -1.29685305e-01, - 3.28354422e-02, 1.80191496e-01, -1.60134770e-01, -3.26164352e-02, - -9.84113753e-03, -2.95289717e-02, -2.26621522e-02, -1.05684105e-01, - 5.73146462e-02, -1.12291047e-01, -1.18396220e-02, 3.28756229e-02, - 6.57114302e-02, 3.55648971e-02, -6.77167497e-03, 5.38023279e-02, - -1.45368962e-01}, - {1.22622727e-01, -1.38552673e-01, -1.77546541e-01, 1.62952815e-01, - -2.32579357e-01, 1.05335247e-01, 3.64514325e-02, -1.29708723e-01, - 3.28207265e-02, -1.80182099e-01, 1.60139733e-01, 3.25998779e-02, - -9.87988030e-03, -2.95029751e-02, -2.26970333e-02, -1.05712869e-01, - -5.72647877e-02, 1.12330479e-01, 1.18270332e-02, -3.28388058e-02, - 6.57521864e-02, 3.55550008e-02, -6.76382964e-03, 5.37618647e-02, - -1.45385365e-01}, - {1.30336308e-01, 1.45497539e-01, 2.48218471e-01, 1.44571510e-01, - 1.24790023e-01, 2.22440416e-01, 1.26651239e-01, 2.09378366e-01, - 1.03209397e-02, 3.77988478e-02, 1.57033300e-01, 1.38099068e-01, - -3.82994637e-02, 1.01264996e-01, 1.41982221e-02, -2.98750406e-02, - -2.69859111e-03, 3.88254921e-02, 5.31080994e-02, 9.36615530e-03, - -5.58370364e-02, -4.53247891e-02, 6.61510053e-03, -2.82106183e-02, - -4.83087754e-04}, - {1.30333170e-01, -1.45474316e-01, 2.48228509e-01, 1.44561695e-01, - -1.24746486e-01, -2.22424890e-01, 1.26675948e-01, 2.09393070e-01, - 1.03052530e-02, -3.77476209e-02, -1.57007597e-01, -1.38110171e-01, - -3.83018559e-02, 1.01293469e-01, 1.41943867e-02, -2.98847415e-02, - 2.76065441e-03, -3.88039134e-02, -5.31260958e-02, -9.37417058e-03, - -5.58598816e-02, -4.53442990e-02, 6.61197069e-03, -2.82018141e-02, - -4.99925665e-04}, - {1.82670032e-01, 3.44396863e-01, -1.30033747e-01, 1.10371351e-03, - 1.69821141e-03, -5.90769541e-02, -9.54474687e-03, -6.21284105e-02, - -3.34689014e-01, -2.30720990e-01, -9.77592611e-02, -4.83798345e-02, - -1.01082371e-01, -1.43083487e-02, 7.25739344e-02, -4.56225795e-03, - -4.76964067e-03, 6.88462621e-02, -4.26927105e-02, -4.97463869e-02, - 1.42872764e-02, 1.58574251e-02, -2.00510057e-02, 8.34592661e-02, - 1.05619208e-01}, - {1.82663871e-01, -3.44390902e-01, -1.30031182e-01, 1.09878256e-03, - -1.69938913e-03, 5.90830827e-02, -9.56448215e-03, -6.21114186e-02, - -3.34698438e-01, 2.30742599e-01, 9.77344545e-02, 4.84301142e-02, - -1.01082729e-01, -1.43611443e-02, 7.25842589e-02, -4.55282077e-03, - 4.74094841e-03, -6.88274393e-02, 4.27327868e-02, 4.97484881e-02, - 1.43158784e-02, 1.58839879e-02, -2.00286236e-02, 8.34638609e-02, - 1.05632102e-01}, - {1.86754516e-01, 1.56435351e-01, -2.05460086e-01, -3.06192655e-01, - -2.51452036e-01, -9.48439390e-02, -2.48101006e-02, 1.54790108e-01, - 1.74771495e-01, 1.69547144e-01, 1.18496512e-01, -3.85556273e-02, - -1.73059546e-02, 7.94331493e-02, -4.40744526e-02, -2.88574521e-03, - -1.74259219e-02, -3.04282133e-02, 1.09540624e-02, 1.23910439e-02, - 7.04724651e-02, 5.49408160e-03, -5.70241937e-03, -5.09562960e-02, - -4.29708906e-02}, - {1.86747290e-01, -1.56420913e-01, -2.05449497e-01, -3.06189911e-01, - 2.51437524e-01, 9.48454395e-02, -2.48196777e-02, 1.54781741e-01, - 1.74788736e-01, -1.69561643e-01, -1.18493361e-01, 3.85261013e-02, - -1.72961582e-02, 7.94503163e-02, -4.40728713e-02, -2.89359203e-03, - 1.74480695e-02, 3.04310284e-02, -1.09393189e-02, -1.23702356e-02, - 7.04362535e-02, 5.49216941e-03, -5.73268085e-03, -5.09591204e-02, - -4.29987773e-02}, - {2.07444884e-01, -8.95254699e-06, 4.08539038e-01, -1.93759442e-01, - -9.02938732e-06, -3.36294193e-07, 2.39043725e-01, -2.82592618e-01, - -2.73652789e-03, 2.78827249e-05, -1.30384857e-05, 1.75189121e-05, - -2.62225247e-02, -1.37380829e-01, -5.59223826e-03, 3.96681437e-02, - -4.23574696e-05, 5.34807700e-06, -2.45864976e-06, 1.37310458e-05, - -9.13025014e-02, 6.77835436e-02, -6.97985162e-03, 4.15736981e-02, - 2.75118289e-03}}; -float h4a_bs490[][25] = { - {1.06743649e-01, 1.30910581e-01, -1.57755248e-01, 1.29947270e-01, - 2.11365131e-01, -1.01469927e-01, 3.90939527e-02, -1.04663624e-01, - -6.75369804e-03, 1.42482507e-01, -1.48952242e-01, -2.89975817e-02, - -1.37196411e-02, -2.08215353e-02, 7.29046643e-03, -1.44043729e-01, - 5.18392117e-03, -9.10560528e-02, -8.02199043e-03, 3.18963743e-02, - 5.72676085e-02, 2.62124185e-02, -4.84361254e-03, 8.64102934e-02, - -1.72814457e-01}, - {1.06758817e-01, -1.30933004e-01, -1.57757387e-01, 1.29970935e-01, - -2.11400437e-01, 1.01455739e-01, 3.91025056e-02, -1.04649249e-01, - -6.75208328e-03, -1.42510196e-01, 1.48909414e-01, 2.89860656e-02, - -1.37822146e-02, -2.08146511e-02, 7.29071374e-03, -1.44073415e-01, - -5.16630551e-03, 9.10283853e-02, 8.01730519e-03, -3.18246901e-02, - 5.72815110e-02, 2.61456503e-02, -4.85083674e-03, 8.63836832e-02, - -1.72848347e-01}, - {8.17997995e-02, -7.30036139e-06, -9.68650704e-02, 1.28910166e-01, - -1.26923476e-05, -1.93242491e-05, 4.62856679e-02, -1.80810613e-02, - 1.55534041e-01, -1.17592902e-05, -4.32754426e-05, 5.43722862e-06, - -1.01647818e-01, -4.34787839e-02, -7.25642600e-03, 1.72180119e-01, - 7.58509013e-06, -4.83898813e-05, -1.06352322e-06, 1.12031436e-05, - 5.19323933e-02, -5.96635023e-02, -2.86473669e-02, -2.25833129e-02, - 1.67298488e-01}, - {1.55115929e-01, 2.95476756e-01, -1.67565386e-01, 2.67989487e-02, - 4.61709679e-02, -1.44840800e-01, -1.87257187e-02, -2.49343429e-02, - -3.04935748e-01, -2.29815802e-01, -3.31056828e-02, -8.63617899e-02, - -3.47630876e-02, 2.82715076e-03, 1.29619256e-01, -4.47458129e-02, - -2.44753677e-02, 8.12383634e-02, -4.75279445e-04, -1.36256803e-02, - 7.06596260e-02, 2.94462653e-04, 1.72796971e-02, 2.63146309e-02, - 1.22134501e-01}, - {1.55117274e-01, -2.95483599e-01, -1.67552475e-01, 2.67777052e-02, - -4.61341412e-02, 1.44818738e-01, -1.87511076e-02, -2.49296294e-02, - -3.04941070e-01, 2.29807344e-01, 3.31154043e-02, 8.64095389e-02, - -3.47771398e-02, 2.79199162e-03, 1.29625195e-01, -4.47124155e-02, - 2.44583091e-02, -8.12657507e-02, 5.33525007e-04, 1.36197168e-02, - 7.06932546e-02, 3.62292259e-04, 1.72746049e-02, 2.63534728e-02, - 1.22119446e-01}, - {1.82610218e-01, 1.50347571e-01, -2.05890006e-01, -3.03737939e-01, - -2.37135896e-01, -1.07069180e-01, -3.34699623e-02, 1.71165461e-01, - 1.73244611e-01, 1.50318386e-01, 1.43434549e-01, -3.52211284e-02, - 3.24648361e-03, 8.18803777e-02, -5.52031597e-02, -2.91893961e-03, - 7.15903761e-04, -5.93085078e-02, 1.15517930e-02, 2.55528199e-02, - 7.47417973e-02, -4.32168838e-03, -1.13495302e-02, -4.96609678e-02, - -4.17349709e-02}, - {1.82597172e-01, -1.50326964e-01, -2.05885638e-01, -3.03725373e-01, - 2.37121821e-01, 1.07073721e-01, -3.34671039e-02, 1.71167062e-01, - 1.73269450e-01, -1.50340196e-01, -1.43445913e-01, 3.52013711e-02, - 3.28332580e-03, 8.18848260e-02, -5.51898404e-02, -2.95460517e-03, - -6.72854414e-04, 5.92889897e-02, -1.15262256e-02, -2.55542592e-02, - 7.47094602e-02, -4.36080769e-03, -1.13670517e-02, -4.97004814e-02, - -4.17341337e-02}, - {1.44625002e-01, 1.41396434e-01, 2.78729881e-01, 1.41745415e-01, - 1.30603301e-01, 2.01500387e-01, 1.50151993e-01, 2.01657662e-01, - 6.26102912e-04, 2.93301601e-02, 1.70992200e-01, 8.98651837e-02, - -3.21707692e-02, 8.94336670e-02, 3.34075045e-04, -2.80325488e-02, - 9.49386000e-04, 2.61739307e-02, 7.64617670e-02, -5.59336816e-02, - -5.94694852e-02, -5.63059029e-02, -5.39216163e-04, -2.53888000e-02, - 5.62975097e-03}, - {1.44614702e-01, -1.41368376e-01, 2.78727885e-01, 1.41739637e-01, - -1.30568229e-01, -2.01478236e-01, 1.50175866e-01, 2.01683104e-01, - 6.08872486e-04, -2.92737350e-02, -1.70972866e-01, -8.98773584e-02, - -3.21613643e-02, 8.94778651e-02, 3.38743257e-04, -2.80753675e-02, - -8.64462359e-04, -2.61418394e-02, -7.64723951e-02, 5.59122325e-02, - -5.94820314e-02, -5.63129293e-02, -5.16634067e-04, -2.54222008e-02, - 5.60944607e-03}, - {1.44818718e-01, 1.35263576e-01, 2.79357455e-01, -1.41967809e-01, - -1.15271648e-01, 1.96492073e-01, 1.50481930e-01, -2.03013550e-01, - 2.98163535e-04, 5.88878587e-03, -1.57830421e-01, 9.44821161e-02, - -3.34663787e-02, -9.09378533e-02, 1.33450346e-03, 2.84599732e-02, - 2.57204009e-02, 4.99803046e-03, -8.30810646e-02, -4.71655441e-02, - -6.15259349e-02, 5.76244634e-02, 1.45601037e-03, 2.51209188e-02, - 6.11680147e-03}, - {1.44821863e-01, -1.35277976e-01, 2.79355987e-01, -1.41965844e-01, - 1.15265468e-01, -1.96494483e-01, 1.50469041e-01, -2.03016941e-01, - 2.71300833e-04, -5.85901832e-03, 1.57816044e-01, -9.44577076e-02, - -3.34744955e-02, -9.09566370e-02, 1.32649434e-03, 2.84743159e-02, - -2.57686482e-02, -4.99705752e-03, 8.30677745e-02, 4.71843727e-02, - -6.15240156e-02, 5.75965678e-02, 1.47968445e-03, 2.51067065e-02, - 6.11549248e-03}, - {6.29316391e-02, 2.13185001e-02, -1.14593951e-01, 7.45976560e-02, - 5.23829361e-02, -1.33766847e-02, 7.70506161e-02, -6.17699647e-02, - 7.76380221e-02, 8.29581407e-02, -3.08493533e-02, -6.88264211e-03, - -5.47767204e-02, -9.65067995e-03, -5.76940837e-02, 7.12295570e-02, - 1.05649696e-01, -4.85520220e-02, -5.83259688e-03, 2.39589582e-03, - 4.67591449e-02, 1.47888645e-02, -6.32363748e-03, -6.51037914e-02, - 4.35696250e-02}, - {6.29058204e-02, -2.12805002e-02, -1.14603330e-01, 7.45329796e-02, - -5.23086685e-02, 1.33647113e-02, 7.70834498e-02, -6.17828709e-02, - 7.75857843e-02, -8.28719910e-02, 3.08495334e-02, 6.93129810e-03, - -5.47547202e-02, -9.65682018e-03, -5.77193891e-02, 7.12050139e-02, - -1.05557418e-01, 4.85771676e-02, 5.92120028e-03, -2.48782563e-03, - 4.68222198e-02, 1.48815468e-02, -6.31082426e-03, -6.51257924e-02, - 4.35694991e-02}}; -float h4a_bs9A3[][25] = { - {3.82321028e-02, 9.66507715e-02, 2.98905726e-04, 5.06237055e-02, - 1.17973115e-01, 8.21751547e-04, -8.02650713e-02, 1.47043388e-04, - -8.14257793e-02, -1.88160790e-02, 4.34297719e-04, -1.01749217e-01, - -9.50512105e-04, -5.48496241e-02, -1.17663297e-03, -1.57998227e-01, - -1.47199965e-01, -1.43526017e-03, -9.11501540e-02, -1.76945522e-03, - 6.93101449e-02, -3.24381488e-04, 5.80536065e-02, -8.37557917e-04, - -5.67856759e-02}, - {3.82347782e-02, -9.66536547e-02, 2.88004895e-04, 5.06341339e-02, - -1.17989152e-01, -8.00828971e-04, -8.02779962e-02, 1.31361939e-04, - -8.14108611e-02, 1.87805278e-02, -4.00524824e-04, 1.01765150e-01, - -9.32604336e-04, -5.48763231e-02, -1.16783479e-03, -1.57997109e-01, - 1.47165507e-01, 1.45147492e-03, 9.11947851e-02, 1.76013301e-03, - 6.93410995e-02, -3.07404235e-04, 5.80388390e-02, -7.98274280e-04, - -5.68189565e-02}, - {2.29248830e-02, 1.20731773e-05, -2.10271442e-05, 6.67801832e-02, - 3.12972171e-05, -6.89170945e-07, -5.24364596e-02, -5.43931670e-05, - 9.08295635e-02, 5.05345138e-05, -1.96978746e-06, -1.33689173e-05, - 5.10454505e-05, -8.21173807e-02, -7.50871196e-05, 1.06028479e-01, - 6.31349090e-05, -2.93970683e-06, -2.46895441e-05, 3.14936204e-06, - 5.72997751e-02, 7.68509054e-05, -8.49952380e-02, -9.02693730e-05, - 1.12703428e-01}, - {1.36319544e-01, 1.72260336e-01, -1.74459197e-01, -1.72262102e-01, - -2.69371938e-01, -1.03667974e-01, 1.65568687e-02, 1.03659107e-01, - -1.10180059e-06, 1.66087084e-01, 1.46142337e-01, -5.14278133e-02, - -2.74967324e-02, 5.14319658e-02, 2.04646996e-05, 1.66078770e-01, - -4.74528464e-06, -8.34752709e-02, 2.41005211e-02, 1.22671829e-02, - 6.97161447e-02, -1.22551758e-02, -1.11983964e-05, -8.34915717e-02, - -1.62936299e-01}, - {1.36317955e-01, -1.72265736e-01, -1.74445966e-01, -1.72266130e-01, - 2.69375333e-01, 1.03668437e-01, 1.65420770e-02, 1.03646301e-01, - 7.46999671e-06, -1.66093355e-01, -1.46122945e-01, 5.14233198e-02, - -2.74890172e-02, 5.14424213e-02, 2.16746653e-05, 1.66078699e-01, - 1.21702684e-05, 8.34517555e-02, -2.41098672e-02, -1.22579735e-02, - 6.96904345e-02, -1.22645830e-02, -1.06891782e-05, -8.34871106e-02, - -1.62947617e-01}, - {3.87973260e-02, 5.09345463e-02, 2.57222607e-06, 9.82845353e-02, - 1.18840797e-01, -2.60491914e-06, -8.15375167e-02, 6.62115116e-06, - 8.35987922e-02, 1.59571891e-01, -6.41547827e-06, -5.52484170e-02, - -3.06676855e-06, -1.03689024e-01, 1.12463120e-05, 2.12421035e-02, - 1.49527284e-01, -8.43693804e-06, -9.19966034e-02, 7.29687036e-06, - 7.06149531e-02, -2.34979071e-06, -5.99502179e-02, 1.69600700e-05, - -5.44013904e-02}, - {3.87989462e-02, -5.09371835e-02, 1.38065503e-05, 9.82846073e-02, - -1.18841209e-01, -1.18545403e-05, -8.15298483e-02, 3.00875608e-05, - 8.35900770e-02, -1.59559966e-01, -2.15179589e-05, 5.52453175e-02, - -3.31812027e-05, -1.03662600e-01, 2.31400408e-05, 2.12263201e-02, - -1.49498091e-01, -1.21731754e-05, 9.19816474e-02, 2.09883141e-05, - 7.05842505e-02, -4.00747946e-05, -5.99102578e-02, 7.99720300e-06, - -5.44127519e-02}, - {1.36317882e-01, -9.04136302e-06, -1.74440126e-01, -2.43620345e-01, - 8.16593556e-06, 3.29764038e-06, 1.65464768e-02, 1.46579245e-01, - 2.69381618e-01, -5.52748380e-06, 1.44914533e-05, -1.20161122e-05, - -2.75083516e-02, 7.27263534e-02, -1.46113209e-01, -2.34896645e-01, - 6.02172970e-06, -2.29001104e-05, 7.28897115e-06, 3.00428431e-05, - 6.96966457e-02, -1.73045962e-02, -2.40968942e-02, 1.18047760e-01, - 1.62973005e-01}, - {1.24509620e-01, 2.12479747e-01, -1.78022497e-01, -1.35611030e-02, - -3.36257085e-02, -1.55858406e-01, 4.11696436e-02, -2.69569716e-03, - -2.38249817e-01, -2.17512974e-01, -7.51277789e-03, -4.03065038e-02, - -1.73740996e-02, 1.46035118e-02, 1.57917954e-01, 5.04659441e-02, - 5.67815576e-02, 1.29668937e-01, 2.58965596e-02, 3.41589399e-02, - 4.90472601e-02, 4.91272081e-03, 1.87407840e-03, 1.34201043e-02, - 1.67870765e-01}, - {1.24512803e-01, -2.12496593e-01, -1.78013473e-01, -1.35597446e-02, - 3.36120287e-02, 1.55851978e-01, 4.11495853e-02, -2.68674001e-03, - -2.38260935e-01, 2.17527428e-01, 7.50656672e-03, 4.03304074e-02, - -1.73830243e-02, 1.45857658e-02, 1.57906644e-01, 5.04428625e-02, - -5.67442075e-02, -1.29686290e-01, -2.58883407e-02, -3.41409129e-02, - 4.90499955e-02, 4.94002746e-03, 1.90091291e-03, 1.33941358e-02, - 1.67870371e-01}, - {5.16090105e-02, 8.11115768e-02, 8.78858176e-02, 8.11206751e-02, - 1.18724070e-01, 1.21467562e-01, 1.39216101e-02, 1.21475323e-01, - 1.59277001e-05, 7.35405859e-02, 1.76442192e-01, 6.50334181e-02, - -7.15913899e-02, 6.50299667e-02, 1.30104810e-05, -7.35047998e-02, - 3.14641648e-05, 1.07722328e-01, 1.18258404e-01, -2.16465253e-02, - -7.11004676e-02, -2.16513603e-02, -3.99763698e-06, -1.07693275e-01, - -8.12806125e-02}, - {5.15954383e-02, -8.11056410e-02, 8.78618512e-02, 8.10958470e-02, - -1.18709487e-01, -1.21448106e-01, 1.39086452e-02, 1.21461099e-01, - -2.73630093e-05, -7.34815651e-02, -1.76441754e-01, -6.49994867e-02, - -7.15988931e-02, 6.50551219e-02, -6.44534596e-08, -7.35523907e-02, - 6.50806234e-05, -1.07712815e-01, -1.18280568e-01, 2.16783826e-02, - -7.11155806e-02, -2.16199654e-02, 5.84172164e-05, -1.07737544e-01, - -8.12704244e-02}, - {5.77651247e-02, 1.12042418e-05, 9.27085980e-02, 1.30884240e-01, - 1.90465474e-05, 1.84104889e-05, 2.24122363e-03, 1.83767448e-01, - 1.35225514e-01, 1.95031777e-05, 2.83733193e-05, 1.55108987e-05, - -8.55747228e-02, 7.79212862e-02, 1.89235119e-01, 1.14029810e-01, - 1.77207410e-05, 1.85900281e-05, 2.81453730e-05, 5.63326772e-06, - -6.47957885e-02, -5.30259183e-02, 1.08943346e-01, 1.60080560e-01, - 8.01485478e-02}, - {1.26802457e-01, 1.45267930e-05, 3.21410131e-01, -5.90823011e-06, - 5.38099907e-06, 2.59566065e-05, 3.73377293e-01, -7.05027194e-06, - 1.78552892e-06, -1.02890176e-05, 8.92230150e-06, 2.19062369e-05, - 2.79591473e-01, 3.54580731e-06, 5.21107482e-06, -9.37427526e-06, - 3.41120091e-06, -1.85503434e-05, 6.40272467e-06, 6.64356443e-06, - 1.11984181e-01, 2.06768214e-05, 9.71400418e-06, -1.73194843e-05, - 2.59368878e-05}, - {5.62810309e-02, 8.91827425e-02, 9.18472607e-02, -8.91939589e-02, - -1.27252483e-01, 1.27976004e-01, 5.44041494e-03, -1.27980345e-01, - 1.88803780e-05, 7.26669215e-02, -1.83811158e-01, 5.86634229e-02, - -8.28493644e-02, -5.86456327e-02, 1.09146690e-05, 7.26348633e-02, - -1.70594628e-05, 1.06991185e-01, -1.14392981e-01, -3.34985311e-02, - -6.75856225e-02, 3.35239010e-02, -1.25879051e-05, 1.06976128e-01, - -6.70244087e-02}, - {5.62709164e-02, -8.91748526e-02, 9.18217555e-02, -8.91886470e-02, - 1.27252192e-01, -1.27947441e-01, 5.41062198e-03, -1.27980955e-01, - 1.13213048e-05, -7.26556144e-02, 1.83811463e-01, -5.86209840e-02, - -8.28746180e-02, -5.86557911e-02, 3.78885093e-05, 7.26558104e-02, - -1.82191029e-05, -1.07015771e-01, 1.14396997e-01, 3.35249536e-02, - -6.76075716e-02, 3.35203897e-02, 4.85232390e-05, 1.06975459e-01, - -6.70334762e-02}, - {5.70179168e-02, 1.28501110e-01, 9.22719512e-02, -6.64414612e-05, - 2.84125178e-04, 1.82381784e-01, 3.83930059e-03, -1.64179167e-04, - -1.31235381e-01, -1.08395613e-01, -9.03622064e-05, 8.04595773e-02, - -8.42306140e-02, -6.53447158e-05, -1.86523042e-01, -1.64507336e-03, - -4.17052265e-03, -1.55688264e-01, -5.11820041e-04, -5.01917408e-02, - -6.62447786e-02, 2.72918775e-04, -1.11677241e-01, -8.62674524e-04, - 7.36126841e-02}, - {5.70189315e-02, -1.28501600e-01, 9.22715684e-02, -7.05903971e-05, - -2.72972567e-04, -1.82370581e-01, 3.83956318e-03, -1.62370239e-04, - -1.31241339e-01, 1.08397548e-01, 8.62424375e-05, -8.04274796e-02, - -8.42046823e-02, -5.70870404e-05, -1.86534199e-01, -1.62643337e-03, - 4.14582586e-03, 1.55716451e-01, 4.93576463e-04, 5.02159049e-02, - -6.61641202e-02, 2.71808973e-04, -1.11681689e-01, -8.67651922e-04, - 7.36016215e-02}, - {5.62744446e-02, 7.28427902e-06, 9.18309686e-02, -1.26124984e-01, - -1.31301496e-05, 1.25114362e-05, 5.42568705e-03, -1.80972497e-01, - 1.27256044e-01, 1.76798141e-05, -1.74934738e-05, 1.60561331e-05, - -8.28517398e-02, -8.29354519e-02, 1.83811494e-01, -1.02757794e-01, - -2.46097062e-05, 9.87132340e-06, -2.71811878e-05, 1.62803425e-05, - -6.75825473e-02, 4.73864575e-02, 1.14393215e-01, -1.51316286e-01, - 6.70429267e-02}, - {9.34555143e-02, -5.02650917e-06, -1.83914046e-01, 1.25193006e-01, - -6.38371547e-06, 6.99915594e-06, 1.10511624e-01, -1.71508190e-01, - 1.30775990e-01, 2.50191289e-06, 1.37592807e-05, 3.41170762e-06, - -1.50075275e-04, 6.30355489e-02, -1.79083417e-01, 1.11280816e-01, - 9.31619340e-06, 8.29871083e-06, -3.28287137e-06, -2.04731456e-05, - -2.24300239e-02, 6.40734627e-02, 9.46008583e-02, -1.53383889e-01, - 7.88285640e-02}, - {8.72925662e-02, 7.70830368e-02, -1.79062090e-01, 7.71011634e-02, - 1.14263743e-01, -1.12786540e-01, 1.22125405e-01, -1.12807231e-01, - 2.00651459e-05, 7.15732289e-02, -1.66281524e-01, 5.44777639e-02, - -1.40342040e-02, 5.44778859e-02, -1.76307527e-05, -7.15258509e-02, - 3.02940321e-05, -1.02964514e-01, 1.03913545e-01, 2.95127131e-02, - -2.88304795e-02, 2.95270889e-02, -6.33624725e-06, 1.02917323e-01, - -7.98784002e-02}, - {8.72838192e-02, -7.70668888e-02, -1.79074270e-01, 7.70683483e-02, - -1.14218819e-01, 1.12792751e-01, 1.22189551e-01, -1.12799052e-01, - 4.73634009e-07, -7.15113604e-02, 1.66270106e-01, -5.45274303e-02, - -1.40945092e-02, 5.45285046e-02, -1.25257036e-05, -7.15218102e-02, - 2.05361409e-05, 1.02936000e-01, -1.03967955e-01, -2.94674475e-02, - -2.88180803e-02, 2.94891113e-02, 1.20546481e-05, 1.02916662e-01, - -7.98576607e-02}}; -float h4a_bs070[][25] = { - {2.10236756e-01, 2.11273734e-01, 2.89839970e-05, 2.51965609e-01, - 3.39957783e-01, 1.88412934e-06, 1.50726225e-01, 1.82729267e-05, - 5.06015345e-02, 2.51397091e-01, 1.27281572e-05, 1.40548374e-02, - 8.41984307e-05, 3.04224356e-02, 1.55806461e-05, -1.37642479e-01, - 8.22125750e-02, 2.31739334e-05, 9.00750827e-02, 4.24182200e-05, - 4.65059985e-02, 5.54143147e-05, 1.19632242e-03, -8.87199534e-06, - -1.76787076e-01}, - {2.10239237e-01, -2.11271141e-01, -7.70557182e-06, 2.51973734e-01, - -3.39954494e-01, 2.17547284e-05, 1.50746354e-01, 8.24286482e-06, - 5.06200740e-02, -2.51411742e-01, 4.36094453e-06, -1.40505690e-02, - 2.58466598e-05, 3.04424340e-02, 3.73159207e-05, -1.37638642e-01, - -8.21905047e-02, -2.23063389e-05, -9.00735302e-02, 1.45526786e-05, - 4.65445440e-02, 9.07463144e-06, 1.23181728e-03, -1.25158476e-06, - -1.76800503e-01}, - {1.63742395e-01, 1.09550793e-05, -3.61019834e-05, 2.26865128e-01, - 3.26100016e-05, -2.17397701e-05, 1.74500337e-01, -1.84214512e-05, - 2.56292194e-01, 3.82453022e-05, -1.66040860e-05, 7.22194145e-06, - -5.01031434e-05, 2.51677218e-02, -4.68584470e-06, 2.70115222e-01, - 4.74904316e-05, -7.82607979e-06, 3.17661678e-05, -3.64450380e-05, - 6.12149026e-02, -3.60528160e-05, 5.28887125e-02, -6.73887024e-06, - 2.41959169e-01}, - {2.33093699e-01, 3.69324171e-01, -1.53988931e-05, 4.18108172e-02, - 6.71645633e-02, -7.52134292e-06, 1.38364936e-01, -1.22078139e-05, - -3.67890195e-01, -2.65976721e-01, -5.72979945e-07, 2.40290834e-02, - -1.37211148e-05, 1.89447868e-02, -2.48525526e-06, -6.20140911e-02, - -3.52726463e-02, -3.54090082e-06, 1.98378074e-02, -1.33000302e-05, - 3.96818412e-02, -3.69638721e-05, -1.07740134e-01, -1.13466773e-05, - 1.37446439e-01}, - {2.33088040e-01, -3.69320035e-01, -2.51119163e-07, 4.17942129e-02, - -6.71333339e-02, -9.21258842e-06, 1.38373462e-01, 1.32688257e-05, - -3.67898626e-01, 2.66000046e-01, -3.27934718e-06, -2.40182721e-02, - 1.10503978e-05, 1.89419022e-02, -8.02480084e-07, -6.20042125e-02, - 3.53143285e-02, 1.50317005e-05, -1.98303750e-02, -7.27418655e-06, - 3.97396753e-02, 3.78969034e-05, -1.07748854e-01, -2.62739391e-06, - 1.37449686e-01}, - {2.84197044e-01, 2.17807457e-01, -6.76757535e-06, -3.99063838e-01, - -3.21658635e-01, -1.17011554e-06, 1.20972985e-01, 6.66428820e-06, - 1.90690226e-01, 1.74923728e-01, -1.64844288e-06, 1.58565945e-02, - 1.99406204e-05, -2.95827986e-02, 1.43955441e-05, 3.69790118e-02, - 3.29192098e-02, 2.85415684e-05, -8.96653241e-02, 3.62580919e-05, - 2.10568049e-02, 2.30923134e-05, 5.80350891e-02, -2.64394996e-06, - -6.15591555e-02}, - {2.84184926e-01, -2.17798818e-01, -1.42478985e-05, -3.99061475e-01, - 3.21663759e-01, 2.43799900e-05, 1.20940103e-01, -4.99426790e-06, - 1.90701196e-01, -1.74926013e-01, 1.08664305e-05, -1.58287125e-02, - 1.82236938e-05, -2.95844464e-02, 3.48895011e-05, 3.69788715e-02, - -3.28961397e-02, -2.52511183e-05, 8.96519572e-02, 2.46833052e-05, - 2.10032112e-02, -1.56377078e-05, 5.80609348e-02, -4.39551986e-06, - -6.15645518e-02}}; -float h4a_bs470[][25] = { - {1.22739252e-01, 1.38684558e-01, -1.77701244e-01, 1.63117293e-01, - 2.32809588e-01, -1.05437280e-01, 3.64507083e-02, -1.29816545e-01, - 3.28686711e-02, 1.80373847e-01, -1.60296824e-01, -3.26494425e-02, - -9.85109660e-03, -2.95588545e-02, -2.26850859e-02, -1.05791055e-01, - 5.73726477e-02, -1.12404684e-01, -1.18516035e-02, 3.29088924e-02, - 6.57779291e-02, 3.56008882e-02, -6.77852779e-03, 5.38567750e-02, - -1.45516073e-01}, - {1.22746819e-01, -1.38692886e-01, -1.77726215e-01, 1.63117720e-01, - -2.32814723e-01, 1.05441845e-01, 3.64883207e-02, -1.29839986e-01, - 3.28539405e-02, -1.80364440e-01, 1.60301791e-01, 3.26328684e-02, - -9.88987857e-03, -2.95328316e-02, -2.27200023e-02, -1.05819849e-01, - -5.73227387e-02, 1.12444156e-01, 1.18390020e-02, -3.28720381e-02, - 6.58187265e-02, 3.55909818e-02, -6.77067453e-03, 5.38162708e-02, - -1.45532492e-01}, - {1.12474118e-01, 4.90333722e-06, -1.31474566e-01, 1.97157599e-01, - 7.34688560e-06, -2.06865029e-05, 3.07059594e-02, -7.19260545e-02, - 2.29968402e-01, 4.90119427e-06, -3.80958429e-05, 2.51917473e-05, - -8.33406694e-02, -5.97773238e-02, -6.58055177e-02, 2.35136411e-01, - 1.16341330e-05, -4.01771473e-05, 4.15276903e-05, -1.65406245e-05, - 6.43782602e-02, -3.98222259e-02, -3.11685003e-02, -7.91528107e-02, - 2.03807554e-01}, - {1.56080056e-01, 2.90133390e-01, -1.73819088e-01, 2.64248792e-02, - 4.53640302e-02, -1.41174721e-01, -7.43788043e-03, -2.46635854e-02, - -3.00019578e-01, -2.25903207e-01, -3.24089046e-02, -8.66320225e-02, - -4.35717327e-02, 2.95947272e-03, 1.27379897e-01, -4.38241265e-02, - -2.40794792e-02, 7.93500475e-02, -7.24756591e-04, -1.21771662e-02, - 7.50665628e-02, 1.28847316e-04, 1.73643288e-02, 2.53893209e-02, - 1.19977950e-01}, - {1.56081388e-01, -2.90142342e-01, -1.73806411e-01, 2.64040528e-02, - -4.53303760e-02, 1.41158437e-01, -7.46281884e-03, -2.46591819e-02, - -3.00024731e-01, 2.25892440e-01, 3.24258412e-02, 8.66707202e-02, - -4.35855936e-02, 2.92531252e-03, 1.27385583e-01, -4.37911773e-02, - 2.40622597e-02, -7.93699699e-02, 7.68049761e-04, 1.21807878e-02, - 7.50996314e-02, 1.95013469e-04, 1.73594912e-02, 2.54274273e-02, - 1.19963012e-01}, - {1.83065090e-01, 1.47586679e-01, -2.11341519e-01, -2.98213313e-01, - -2.32979087e-01, -1.04579094e-01, -2.21949033e-02, 1.66909719e-01, - 1.69955026e-01, 1.47801974e-01, 1.40290361e-01, -3.56148347e-02, - -5.95942095e-03, 8.25765184e-02, -5.31391097e-02, -2.82705837e-03, - 6.35230996e-04, -5.80640372e-02, 1.25889507e-02, 2.58690027e-02, - 7.90131706e-02, -5.99962373e-03, -1.28191649e-02, -4.90019908e-02, - -4.10979098e-02}, - {1.83052194e-01, -1.47568495e-01, -2.11337080e-01, -2.98200838e-01, - 2.32962387e-01, 1.04588667e-01, -2.21922323e-02, 1.66911106e-01, - 1.69979279e-01, -1.47825311e-01, -1.40293730e-01, 3.55876004e-02, - -5.92309428e-03, 8.25810202e-02, -5.31256947e-02, -2.86198300e-03, - -5.93719100e-04, 5.80507451e-02, -1.25780970e-02, -2.58614684e-02, - 7.89813566e-02, -6.03804596e-03, -1.28365836e-02, -4.90411833e-02, - -4.10970410e-02}, - {1.42271202e-01, 1.39089710e-01, 2.74256138e-01, 1.39362454e-01, - 1.28400175e-01, 1.98255222e-01, 1.47856321e-01, 1.98374406e-01, - 4.97522103e-04, 2.87005783e-02, 1.68187741e-01, 8.84849247e-02, - -3.15743685e-02, 8.81423255e-02, 2.62621909e-04, -2.76523063e-02, - 7.84145063e-04, 2.56447309e-02, 7.53308964e-02, -5.49795787e-02, - -5.86126012e-02, -5.52691148e-02, -4.30314205e-04, -2.50175088e-02, - 5.53856280e-03}, - {1.42262927e-01, -1.39062580e-01, 2.74256286e-01, 1.39362017e-01, - -1.28366747e-01, -1.98235163e-01, 1.47877025e-01, 1.98404592e-01, - 4.88233102e-04, -2.86474638e-02, -1.68172607e-01, -8.84984965e-02, - -3.15706436e-02, 8.81823463e-02, 2.73294397e-04, -2.76835904e-02, - -7.06490201e-04, -2.56185713e-02, -7.53452203e-02, 5.49600813e-02, - -5.86251804e-02, -5.52848870e-02, -4.13735317e-04, -2.50437466e-02, - 5.53328018e-03}, - {1.42508178e-01, 1.33105485e-01, 2.74900389e-01, -1.39702754e-01, - -1.13432523e-01, 1.93357099e-01, 1.48081035e-01, -1.99774528e-01, - 2.93406422e-04, 5.79483200e-03, -1.55312283e-01, 9.29746815e-02, - -3.29324324e-02, -8.94869664e-02, 1.31321185e-03, 2.80059027e-02, - 2.53100394e-02, 4.91828834e-03, -8.17555304e-02, -4.64130316e-02, - -6.05443065e-02, 5.67050819e-02, 1.43278015e-03, 2.47201219e-02, - 6.01920969e-03}, - {1.42511273e-01, -1.33119655e-01, 2.74898944e-01, -1.39700821e-01, - 1.13426441e-01, -1.93359471e-01, 1.48068352e-01, -1.99777865e-01, - 2.66972307e-04, -5.76553939e-03, 1.55298135e-01, -9.29506625e-02, - -3.29404197e-02, -8.95054504e-02, 1.30533051e-03, 2.80200165e-02, - -2.53575170e-02, -4.91733092e-03, 8.17424524e-02, 4.64315598e-02, - -6.05424179e-02, 5.66776314e-02, 1.45607652e-03, 2.47061363e-02, - 6.01792158e-03}}; -float h4a_iamf312[][25] = { - {4.558499e-01, 5.076812e-01, -1.716342e-01, -8.600138e-02, 2.091418e-01, - -1.229081e-01, 5.976601e-02, -1.459250e-01, -9.457349e-02, 9.539187e-03, - -1.462084e-01, -2.151111e-02, -1.741245e-02, -3.428085e-02, 5.920217e-03, - -1.724706e-01, 1.119056e-02, -7.434503e-02, -4.970648e-02, 4.479662e-03, - 1.033368e-01, -1.581036e-02, -1.758424e-02, 4.278258e-02, -9.528297e-02}, - {4.558533e-01, -5.076720e-01, -1.716348e-01, -8.598989e-02, -2.091472e-01, - 1.229305e-01, 5.975441e-02, -1.459281e-01, -9.455434e-02, -9.553267e-03, - 1.461986e-01, 2.149967e-02, -1.742868e-02, -3.429070e-02, 5.920595e-03, - -1.724353e-01, -1.118839e-02, 7.432147e-02, 4.973585e-02, -4.500646e-03, - 1.033662e-01, -1.582446e-02, -1.759805e-02, 4.280697e-02, -9.524688e-02}, - {9.837171e-02, 1.125260e-05, -1.279454e-01, 1.846977e-01, 3.108510e-05, - -9.055990e-06, 3.464868e-02, -1.149500e-01, 2.057304e-01, 3.910086e-05, - -2.853236e-05, 4.141368e-06, -6.519038e-02, -1.774718e-02, -8.288739e-02, - 2.196930e-01, 3.659741e-05, -2.565492e-05, 2.560260e-05, -1.224583e-05, - 8.233149e-02, -4.031561e-02, -3.900216e-02, -9.329631e-02, 2.033576e-01}, - {1.107400e-01, 9.484073e-02, 2.157565e-01, 1.399193e-01, 1.206742e-01, - 1.370418e-01, 1.230440e-01, 2.117027e-01, 3.602117e-02, 6.724259e-02, - 1.716764e-01, 6.426968e-02, -1.119380e-02, 1.225081e-01, 4.323087e-02, - -5.829274e-03, 2.993874e-02, 8.941864e-02, 1.018459e-01, -3.543550e-02, - -2.958143e-02, -1.396867e-02, 7.491534e-03, -9.422211e-03, 2.873839e-03}, - {1.107278e-01, -9.483192e-02, 2.157578e-01, 1.398899e-01, -1.206490e-01, - -1.370472e-01, 1.230795e-01, 2.117065e-01, 3.598788e-02, -6.720546e-02, - -1.716713e-01, -6.429218e-02, -1.118488e-02, 1.225523e-01, 4.323569e-02, - -5.879003e-03, -2.988874e-02, -8.941340e-02, -1.018616e-01, 3.543133e-02, - -2.961214e-02, -1.398253e-02, 7.537813e-03, -9.446865e-03, 2.838434e-03}}; -float h4a_iamf712[][25] = { - {1.22739252e-01, 1.38684558e-01, -1.77701244e-01, 1.63117293e-01, - 2.32809588e-01, -1.05437280e-01, 3.64507083e-02, -1.29816545e-01, - 3.28686711e-02, 1.80373847e-01, -1.60296824e-01, -3.26494425e-02, - -9.85109660e-03, -2.95588545e-02, -2.26850859e-02, -1.05791055e-01, - 5.73726477e-02, -1.12404684e-01, -1.18516035e-02, 3.29088924e-02, - 6.57779291e-02, 3.56008882e-02, -6.77852779e-03, 5.38567750e-02, - -1.45516073e-01}, - {1.22746819e-01, -1.38692886e-01, -1.77726215e-01, 1.63117720e-01, - -2.32814723e-01, 1.05441845e-01, 3.64883207e-02, -1.29839986e-01, - 3.28539405e-02, -1.80364440e-01, 1.60301791e-01, 3.26328684e-02, - -9.88987857e-03, -2.95328316e-02, -2.27200023e-02, -1.05819849e-01, - -5.73227387e-02, 1.12444156e-01, 1.18390020e-02, -3.28720381e-02, - 6.58187265e-02, 3.55909818e-02, -6.77067453e-03, 5.38162708e-02, - -1.45532492e-01}, - {1.12474118e-01, 4.90333722e-06, -1.31474566e-01, 1.97157599e-01, - 7.34688560e-06, -2.06865029e-05, 3.07059594e-02, -7.19260545e-02, - 2.29968402e-01, 4.90119427e-06, -3.80958429e-05, 2.51917473e-05, - -8.33406694e-02, -5.97773238e-02, -6.58055177e-02, 2.35136411e-01, - 1.16341330e-05, -4.01771473e-05, 4.15276903e-05, -1.65406245e-05, - 6.43782602e-02, -3.98222259e-02, -3.11685003e-02, -7.91528107e-02, - 2.03807554e-01}, - {1.56080056e-01, 2.90133390e-01, -1.73819088e-01, 2.64248792e-02, - 4.53640302e-02, -1.41174721e-01, -7.43788043e-03, -2.46635854e-02, - -3.00019578e-01, -2.25903207e-01, -3.24089046e-02, -8.66320225e-02, - -4.35717327e-02, 2.95947272e-03, 1.27379897e-01, -4.38241265e-02, - -2.40794792e-02, 7.93500475e-02, -7.24756591e-04, -1.21771662e-02, - 7.50665628e-02, 1.28847316e-04, 1.73643288e-02, 2.53893209e-02, - 1.19977950e-01}, - {1.56081388e-01, -2.90142342e-01, -1.73806411e-01, 2.64040528e-02, - -4.53303760e-02, 1.41158437e-01, -7.46281884e-03, -2.46591819e-02, - -3.00024731e-01, 2.25892440e-01, 3.24258412e-02, 8.66707202e-02, - -4.35855936e-02, 2.92531252e-03, 1.27385583e-01, -4.37911773e-02, - 2.40622597e-02, -7.93699699e-02, 7.68049761e-04, 1.21807878e-02, - 7.50996314e-02, 1.95013469e-04, 1.73594912e-02, 2.54274273e-02, - 1.19963012e-01}, - {1.83065090e-01, 1.47586679e-01, -2.11341519e-01, -2.98213313e-01, - -2.32979087e-01, -1.04579094e-01, -2.21949033e-02, 1.66909719e-01, - 1.69955026e-01, 1.47801974e-01, 1.40290361e-01, -3.56148347e-02, - -5.95942095e-03, 8.25765184e-02, -5.31391097e-02, -2.82705837e-03, - 6.35230996e-04, -5.80640372e-02, 1.25889507e-02, 2.58690027e-02, - 7.90131706e-02, -5.99962373e-03, -1.28191649e-02, -4.90019908e-02, - -4.10979098e-02}, - {1.83052194e-01, -1.47568495e-01, -2.11337080e-01, -2.98200838e-01, - 2.32962387e-01, 1.04588667e-01, -2.21922323e-02, 1.66911106e-01, - 1.69979279e-01, -1.47825311e-01, -1.40293730e-01, 3.55876004e-02, - -5.92309428e-03, 8.25810202e-02, -5.31256947e-02, -2.86198300e-03, - -5.93719100e-04, 5.80507451e-02, -1.25780970e-02, -2.58614684e-02, - 7.89813566e-02, -6.03804596e-03, -1.28365836e-02, -4.90411833e-02, - -4.10970410e-02}, - {2.43039701e-01, 2.33209501e-01, 4.68640067e-01, 4.05776893e-02, - 4.81912688e-02, 3.34979338e-01, 2.52565425e-01, 5.71124825e-02, - 7.04991774e-04, 3.27981433e-02, 5.83653725e-02, 1.54227952e-01, - -5.48611148e-02, 2.48654847e-02, 1.19120291e-03, -7.84914259e-03, - 1.86810456e-02, 2.91224859e-02, 1.75210065e-02, -8.77985481e-02, - -1.01423891e-01, -1.51725669e-02, 5.82814355e-04, -7.53774297e-03, - 9.79478679e-03}, - {2.43033615e-01, -2.33192391e-01, 4.68639193e-01, 4.05786191e-02, - -4.81621414e-02, -3.34960956e-01, 2.52577161e-01, 5.71403089e-02, - 6.77011031e-04, -3.27243158e-02, -5.83602426e-02, -1.54224540e-01, - -5.48630377e-02, 2.48924354e-02, 1.19630245e-03, -7.87044672e-03, - -1.86369624e-02, -2.90956493e-02, -1.75445779e-02, 8.77921521e-02, - -1.01435135e-01, -1.52077495e-02, 6.15866264e-04, -7.57387009e-03, - 9.78859334e-03}}; -float h4a_iamf916[][25] = { // h4a_bs9A3 -> 9+10+3 -> 9.1.6 - {3.82321028e-02, 9.66507715e-02, 2.98905726e-04, 5.06237055e-02, - 1.17973115e-01, 8.21751547e-04, -8.02650713e-02, 1.47043388e-04, - -8.14257793e-02, -1.88160790e-02, 4.34297719e-04, -1.01749217e-01, - -9.50512105e-04, -5.48496241e-02, -1.17663297e-03, -1.57998227e-01, - -1.47199965e-01, -1.43526017e-03, -9.11501540e-02, -1.76945522e-03, - 6.93101449e-02, -3.24381488e-04, 5.80536065e-02, -8.37557917e-04, - -5.67856759e-02}, - {3.82347782e-02, -9.66536547e-02, 2.88004895e-04, 5.06341339e-02, - -1.17989152e-01, -8.00828971e-04, -8.02779962e-02, 1.31361939e-04, - -8.14108611e-02, 1.87805278e-02, -4.00524824e-04, 1.01765150e-01, - -9.32604336e-04, -5.48763231e-02, -1.16783479e-03, -1.57997109e-01, - 1.47165507e-01, 1.45147492e-03, 9.11947851e-02, 1.76013301e-03, - 6.93410995e-02, -3.07404235e-04, 5.80388390e-02, -7.98274280e-04, - -5.68189565e-02}, - {1.16380397e-01, 7.04666813e-06, -1.83935073e-01, 1.91973189e-01, - 2.49135016e-05, 6.30998499e-06, 5.80751644e-02, -1.71562583e-01, - 2.21605553e-01, 5.30364267e-05, 1.17894932e-05, -9.95720968e-06, - -9.90298245e-05, -1.90818318e-02, -1.79158504e-01, 2.17309295e-01, - 7.24511024e-05, 5.35900400e-06, -2.79724155e-05, -1.73237836e-05, - 3.48697512e-02, 6.41503136e-02, 9.60562030e-03, -1.53474158e-01, - 1.91531992e-01}, - {2.32710843e-01, 1.72253943e-01, -2.97806993e-01, -3.44527700e-01, - -2.69366164e-01, -1.03665642e-01, 2.82569946e-02, 2.07306285e-01, - 1.90480467e-01, 1.66083175e-01, 1.46152584e-01, -5.14363100e-02, - -4.69480743e-02, 1.02857263e-01, -1.03297176e-01, -1.82402788e-05, - -4.87278742e-07, -8.34914637e-02, 2.41056752e-02, 1.22884264e-02, - 1.18999115e-01, -2.44913731e-02, -1.70502757e-02, -1.92002402e-05, - -4.76969822e-02}, - {2.32709254e-01, -1.72272129e-01, -2.97793762e-01, -3.44531728e-01, - 2.69381107e-01, 1.03670769e-01, 2.82422029e-02, 2.07293479e-01, - 1.90489038e-01, -1.66097264e-01, -1.46112698e-01, 5.14148231e-02, - -4.69403591e-02, 1.02867719e-01, -1.03295966e-01, -1.83112788e-05, - 1.64282743e-05, 8.34355627e-02, -2.41047131e-02, -1.22367300e-02, - 1.18973405e-01, -2.45007803e-02, -1.70497664e-02, -1.47391402e-05, - -4.77083002e-02}, - {1.66936004e-01, 1.28025506e-01, -1.13504640e-01, 2.67934832e-01, - 2.33118008e-01, -1.12776127e-01, 4.21726727e-02, 1.71425986e-02, - 1.79237735e-01, 2.31158911e-01, -1.66267877e-01, -7.59685238e-04, - -7.45477375e-02, 5.88753168e-03, 1.33803051e-01, 3.03475044e-02, - 1.49570108e-01, -1.02959806e-01, 1.19368434e-02, 2.95239933e-02, - -4.03306776e-03, -7.97024724e-03, 1.70780244e-02, 2.16128332e-01, - -7.76062090e-02}, - {1.66928877e-01, -1.27996150e-01, -1.13505585e-01, 2.67902089e-01, - -2.33046560e-01, 1.12793915e-01, 4.22444871e-02, 1.71742440e-02, - 1.79209428e-01, -2.31057536e-01, 1.66268651e-01, 7.28855062e-04, - -7.46381571e-02, 5.96457438e-03, 1.33820050e-01, 3.03357617e-02, - -1.49465024e-01, 1.02936972e-01, -1.19664058e-02, -2.94424759e-02, - -4.05137116e-03, -8.04594984e-03, 1.71363754e-02, 2.16118709e-01, - -7.75968310e-02}, - {1.24509620e-01, 2.12479747e-01, -1.78022497e-01, -1.35611030e-02, - -3.36257085e-02, -1.55858406e-01, 4.11696436e-02, -2.69569716e-03, - -2.38249817e-01, -2.17512974e-01, -7.51277789e-03, -4.03065038e-02, - -1.73740996e-02, 1.46035118e-02, 1.57917954e-01, 5.04659441e-02, - 5.67815576e-02, 1.29668937e-01, 2.58965596e-02, 3.41589399e-02, - 4.90472601e-02, 4.91272081e-03, 1.87407840e-03, 1.34201043e-02, - 1.67870765e-01}, - {1.24512803e-01, -2.12496593e-01, -1.78013473e-01, -1.35597446e-02, - 3.36120287e-02, 1.55851978e-01, 4.11495853e-02, -2.68674001e-03, - -2.38260935e-01, 2.17527428e-01, 7.50656672e-03, 4.03304074e-02, - -1.73830243e-02, 1.45857658e-02, 1.57906644e-01, 5.04428625e-02, - -5.67442075e-02, -1.29686290e-01, -2.58883407e-02, -3.41409129e-02, - 4.90499955e-02, 4.94002746e-03, 1.90091291e-03, 1.33941358e-02, - 1.67870371e-01}, - {1.15010239e-01, 8.11188402e-02, 2.48590883e-01, 8.11177210e-02, - 1.18726760e-01, 1.21480540e-01, 2.00610257e-01, 1.21471798e-01, - 1.68204646e-05, 7.35354414e-02, 1.76446653e-01, 6.50443712e-02, - 6.82043466e-02, 6.50317396e-02, 1.56160184e-05, -7.35094869e-02, - 3.31697653e-05, 1.07713053e-01, 1.18261605e-01, -2.16432035e-02, - -1.51083771e-02, -2.16410219e-02, 8.59365110e-07, -1.07701935e-01, - -8.12676441e-02}, - {1.14996667e-01, -8.10983776e-02, 2.48566917e-01, 8.10928929e-02, - -1.18706797e-01, -1.21435128e-01, 2.00597292e-01, 1.21457574e-01, - -2.64702448e-05, -7.34867096e-02, -1.76437293e-01, -6.49885336e-02, - 6.81968434e-02, 6.50568948e-02, 2.54108395e-06, -7.35570778e-02, - 6.67862239e-05, -1.07722090e-01, -1.18277367e-01, 2.16817044e-02, - -1.51234901e-02, -2.16096270e-02, 6.32742185e-05, -1.07746204e-01, - -8.12574560e-02}, - {1.59474301e-01, 8.91951567e-02, 3.17486627e-01, -1.78380744e-01, - -1.27259077e-01, 1.27997829e-01, 1.95965602e-01, -2.55950750e-01, - 9.00033847e-02, 7.26742785e-02, -1.83819067e-01, 5.86857294e-02, - -1.63865485e-03, -1.17288080e-01, 1.29987874e-01, -3.05566729e-05, - -3.27555525e-05, 1.06988890e-01, -1.14409000e-01, -3.34836974e-02, - -5.93816094e-02, 6.70415248e-02, 8.08804870e-02, -2.93034972e-05, - -1.96049322e-02}, - {1.59464186e-01, -8.91624384e-02, 3.17461122e-01, -1.78375432e-01, - 1.27245598e-01, -1.27925616e-01, 1.95935809e-01, -2.55951360e-01, - 8.99958256e-02, -7.26482574e-02, 1.83803554e-01, -5.85986775e-02, - -1.66390845e-03, -1.17298239e-01, 1.30014848e-01, -9.60957287e-06, - -3.39151926e-05, -1.07018066e-01, 1.14380978e-01, 3.35397873e-02, - -5.94035585e-02, 6.70380135e-02, 8.09415982e-02, -2.99724972e-05, - -1.96139997e-02}, - {5.70179168e-02, 1.28501110e-01, 9.22719512e-02, -6.64414612e-05, - 2.84125178e-04, 1.82381784e-01, 3.83930059e-03, -1.64179167e-04, - -1.31235381e-01, -1.08395613e-01, -9.03622064e-05, 8.04595773e-02, - -8.42306140e-02, -6.53447158e-05, -1.86523042e-01, -1.64507336e-03, - -4.17052265e-03, -1.55688264e-01, -5.11820041e-04, -5.01917408e-02, - -6.62447786e-02, 2.72918775e-04, -1.11677241e-01, -8.62674524e-04, - 7.36126841e-02}, - {5.70189315e-02, -1.28501600e-01, 9.22715684e-02, -7.05903971e-05, - -2.72972567e-04, -1.82370581e-01, 3.83956318e-03, -1.62370239e-04, - -1.31241339e-01, 1.08397548e-01, 8.62424375e-05, -8.04274796e-02, - -8.42046823e-02, -5.70870404e-05, -1.86534199e-01, -1.62643337e-03, - 4.14582586e-03, 1.55716451e-01, 4.93576463e-04, 5.02159049e-02, - -6.61641202e-02, 2.71808973e-04, -1.11681689e-01, -8.67651922e-04, - 7.36016215e-02}}; -/////////////////////////////// -struct h2m_rdr_t h2m_rdr_tab[] = { - {IAMF_ZOA, BS2051_A, 2, -1, -1, (float *)zoa_bs020, 1, 2}, - {IAMF_ZOA, BS2051_B, 6, 3, -1, (float *)zoa_bs050, 1, 5}, - {IAMF_ZOA, BS2051_C, 8, 3, -1, (float *)zoa_bs250, 1, 7}, - {IAMF_ZOA, BS2051_D, 10, 3, -1, (float *)zoa_bs450, 1, 9}, - {IAMF_ZOA, BS2051_E, 11, 3, -1, (float *)zoa_bs451, 1, 10}, - {IAMF_ZOA, BS2051_F, 12, 10, 11, (float *)zoa_bs370, 1, 10}, - {IAMF_ZOA, BS2051_G, 14, 3, -1, (float *)zoa_bs490, 1, 13}, - {IAMF_ZOA, BS2051_H, 24, 3, 9, (float *)zoa_bs9A3, 1, 22}, - {IAMF_ZOA, BS2051_I, 8, 3, -1, (float *)zoa_bs070, 1, 7}, - {IAMF_ZOA, BS2051_J, 12, 3, -1, (float *)zoa_bs470, 1, 11}, - {IAMF_ZOA, IAMF_312, 6, 3, -1, (float *)zoa_iamf312, 1, 5}, - {IAMF_ZOA, IAMF_712, 10, 3, -1, (float *)zoa_iamf712, 1, 9}, - {IAMF_ZOA, IAMF_BINAURAL, 2, -1, -1, (float *)zoa_bs020, 1, 2}, - {IAMF_ZOA, IAMF_MONO, 1, -1, -1, (float *)zoa_mono, 1, 1}, - {IAMF_ZOA, IAMF_916, 16, 3, -1, (float *)zoa_iamf916, 1, 15}, - - {IAMF_FOA, BS2051_A, 2, -1, -1, (float *)foa_bs020, 4, 2}, - {IAMF_FOA, BS2051_B, 6, 3, -1, (float *)foa_bs050, 4, 5}, - {IAMF_FOA, BS2051_C, 8, 3, -1, (float *)foa_bs250, 4, 7}, - {IAMF_FOA, BS2051_D, 10, 3, -1, (float *)foa_bs450, 4, 9}, - {IAMF_FOA, BS2051_E, 11, 3, -1, (float *)foa_bs451, 4, 10}, - {IAMF_FOA, BS2051_F, 12, 10, 11, (float *)foa_bs370, 4, 10}, - {IAMF_FOA, BS2051_G, 14, 3, -1, (float *)foa_bs490, 4, 13}, - {IAMF_FOA, BS2051_H, 24, 3, 9, (float *)foa_bs9A3, 4, 22}, - {IAMF_FOA, BS2051_I, 8, 3, -1, (float *)foa_bs070, 4, 7}, - {IAMF_FOA, BS2051_J, 12, 3, -1, (float *)foa_bs470, 4, 11}, - {IAMF_FOA, IAMF_312, 6, 3, -1, (float *)foa_iamf312, 4, 5}, - {IAMF_FOA, IAMF_712, 10, 3, -1, (float *)foa_iamf712, 4, 9}, - {IAMF_FOA, IAMF_BINAURAL, 2, -1, -1, (float *)foa_bs020, 4, 2}, - {IAMF_FOA, IAMF_MONO, 1, -1, -1, (float *)foa_mono, 4, 1}, - {IAMF_FOA, IAMF_916, 16, 3, -1, (float *)foa_iamf916, 4, 15}, - - {IAMF_SOA, BS2051_A, 2, -1, -1, (float *)soa_bs020, 9, 2}, - {IAMF_SOA, BS2051_B, 6, 3, -1, (float *)soa_bs050, 9, 5}, - {IAMF_SOA, BS2051_C, 8, 3, -1, (float *)soa_bs250, 9, 7}, - {IAMF_SOA, BS2051_D, 10, 3, -1, (float *)soa_bs450, 9, 9}, - {IAMF_SOA, BS2051_E, 11, 3, -1, (float *)soa_bs451, 9, 10}, - {IAMF_SOA, BS2051_F, 12, 10, 11, (float *)soa_bs370, 9, 10}, - {IAMF_SOA, BS2051_G, 14, 3, -1, (float *)soa_bs490, 9, 13}, - {IAMF_SOA, BS2051_H, 24, 3, 9, (float *)soa_bs9A3, 9, 22}, - {IAMF_SOA, BS2051_I, 8, 3, -1, (float *)soa_bs070, 9, 7}, - {IAMF_SOA, BS2051_J, 12, 3, -1, (float *)soa_bs470, 9, 11}, - {IAMF_SOA, IAMF_312, 6, 3, -1, (float *)soa_iamf312, 9, 5}, - {IAMF_SOA, IAMF_712, 10, 3, -1, (float *)soa_iamf712, 9, 9}, - {IAMF_SOA, IAMF_BINAURAL, 2, -1, -1, (float *)soa_bs020, 9, 2}, - {IAMF_SOA, IAMF_MONO, 1, -1, -1, (float *)soa_mono, 9, 1}, - {IAMF_SOA, IAMF_916, 16, 3, -1, (float *)soa_iamf916, 9, 15}, - - {IAMF_TOA, BS2051_A, 2, -1, -1, (float *)toa_bs020, 16, 2}, - {IAMF_TOA, BS2051_B, 6, 3, -1, (float *)toa_bs050, 16, 5}, - {IAMF_TOA, BS2051_C, 8, 3, -1, (float *)toa_bs250, 16, 7}, - {IAMF_TOA, BS2051_D, 10, 3, -1, (float *)toa_bs450, 16, 9}, - {IAMF_TOA, BS2051_E, 11, 3, -1, (float *)toa_bs451, 16, 10}, - {IAMF_TOA, BS2051_F, 12, 10, 11, (float *)toa_bs370, 16, 10}, - {IAMF_TOA, BS2051_G, 14, 3, -1, (float *)toa_bs490, 16, 13}, - {IAMF_TOA, BS2051_H, 24, 3, 9, (float *)toa_bs9A3, 16, 22}, - {IAMF_TOA, BS2051_I, 8, 3, -1, (float *)toa_bs070, 16, 7}, - {IAMF_TOA, BS2051_J, 12, 3, -1, (float *)toa_bs470, 16, 11}, - {IAMF_TOA, IAMF_312, 6, 3, -1, (float *)toa_iamf312, 16, 5}, - {IAMF_TOA, IAMF_712, 10, 3, -1, (float *)toa_iamf712, 16, 9}, - {IAMF_TOA, IAMF_BINAURAL, 2, -1, -1, (float *)toa_bs020, 16, 2}, - {IAMF_TOA, IAMF_MONO, 1, -1, -1, (float *)toa_mono, 16, 1}, - {IAMF_TOA, IAMF_916, 16, 3, -1, (float *)toa_iamf916, 16, 15}, - - {IAMF_H4A, BS2051_A, 2, -1, -1, (float *)h4a_bs020, 25, 2}, - {IAMF_H4A, BS2051_B, 6, 3, -1, (float *)h4a_bs050, 25, 5}, - {IAMF_H4A, BS2051_C, 8, 3, -1, (float *)h4a_bs250, 25, 7}, - {IAMF_H4A, BS2051_D, 10, 3, -1, (float *)h4a_bs450, 25, 9}, - {IAMF_H4A, BS2051_E, 11, 3, -1, (float *)h4a_bs451, 25, 10}, - {IAMF_H4A, BS2051_F, 12, 10, 11, (float *)h4a_bs370, 25, 10}, - {IAMF_H4A, BS2051_G, 14, 3, -1, (float *)h4a_bs490, 25, 13}, - {IAMF_H4A, BS2051_H, 24, 3, 9, (float *)h4a_bs9A3, 25, 22}, - {IAMF_H4A, BS2051_I, 8, 3, -1, (float *)h4a_bs070, 25, 7}, - {IAMF_H4A, BS2051_J, 12, 3, -1, (float *)h4a_bs470, 25, 11}, - {IAMF_H4A, IAMF_312, 6, 3, -1, (float *)h4a_iamf312, 25, 5}, - {IAMF_H4A, IAMF_712, 10, 3, -1, (float *)h4a_iamf712, 25, 9}, - {IAMF_H4A, IAMF_BINAURAL, 2, -1, -1, (float *)h4a_bs020, 25, 2}, - {IAMF_H4A, IAMF_MONO, 1, -1, -1, (float *)h4a_mono, 25, 1}, - {IAMF_H4A, IAMF_916, 16, 3, -1, (float *)h4a_iamf916, 25, 15}}; - -/* -Layout in: HOA channel layout -Layout out: Direct speaker output channel layout -float *outMatrix: Conversion Matrix (MatrixSize = number of out channels x -number of in channels) -*/ -int IAMF_element_renderer_get_H2M_matrix(IAMF_HOA_LAYOUT *in, - IAMF_PREDEFINED_SP_LAYOUT *out, - struct h2m_rdr_t *outMatrix) { - int i; - for (i = 0; i < sizeof(h2m_rdr_tab) / sizeof(struct h2m_rdr_t); i++) { - if (h2m_rdr_tab[i].in == in->order && h2m_rdr_tab[i].out == out->system) { - *outMatrix = h2m_rdr_tab[i]; - return (0); - } - } - return (-1); -} - -#if DISABLE_LFE_HOA == 0 -static float lfefilter_update(lfe_filter_t *lfe_f, float input); -#endif - -// HOA to Multichannel Renderer -int IAMF_element_renderer_render_H2M(const Arch *arch, - struct h2m_rdr_t *h2mMatrix, float *in[], - float *out[], int nsamples, - lfe_filter_t *lfe) { - int i, j, n; - int n_size = h2mMatrix->n; - - // lfe generator turns on - int lfe1 = h2mMatrix->lfe1; - int lfe2 = h2mMatrix->lfe2; - int map[BS2051_MAX_CHANNELS] = { - // BS2051_H has max channel number(24) - 0, - }; - - /// convert HOA to channel by using the predefined matrix - (*arch->rendering.multiply_channels_by_matrix)( - h2mMatrix->mat, h2mMatrix->m, 1, 0, h2mMatrix->n, h2mMatrix->m, in, out, - nsamples); - - n = 0; - if (lfe1 >= 0 || lfe2 >= 0) { - // find a channel place to move - for (i = 0; i < n_size; i++) { - if (lfe1 == i) { - n++; - } - if (lfe2 == i) { - n++; - } - map[i] = n; - n++; - } - - // move a channel to a new channel place - for (i = n_size - 1; i >= 0; i--) { - if (map[i] != i) { - for (j = 0; j < nsamples; j++) { - out[map[i]][j] = out[i][j]; - } - } - } - -#if DISABLE_LFE_HOA == 1 - ////////////// - // generate lfe signal to lfe channel place - if (lfe1 >= 0) { - for (j = 0; j < nsamples; j++) { - out[lfe1][j] = 0; - } - } - ////////////// - if (lfe2 >= 0) { - for (j = 0; j < nsamples; j++) { - out[lfe2][j] = 0; - } - } -#else - ////////////// - // generate lfe signal to lfe channel place - if (lfe1 >= 0) { - for (j = 0; j < nsamples; j++) { - if (lfe) { // compute lfe - float output; - output = lfefilter_update(lfe, in[0][j]); // use W - if (n_size <= 2) - out[lfe1][j] = output * 0.5; - else - out[lfe1][j] = output / sqrt(n_size); - } else { // lfe off - out[lfe1][j] = 0; - } - } - } - ////////////// - if (lfe2 >= 0) { - for (j = 0; j < nsamples; j++) { - if (lfe) { // lfe on - if (lfe1 >= 0) { // already compute lfe - out[lfe2][j] = out[lfe1][j]; - } else { // compute lfe - float output; - output = lfefilter_update(lfe, in[0][j]); // use W - if (n_size <= 2) - out[lfe2][j] = output * 0.5; - else - out[lfe2][j] = output / sqrt(n_size); - } - } else { // lfe off - out[lfe2][j] = 0; - } - } - } -#endif - } - - return (0); -} - -#if DISABLE_LFE_HOA == 0 -void lfefilter_init(lfe_filter_t *lfe_f, float cutoff_freq, float sample_rate) { - lfe_f->init = 1; - float delta_time = 1 / sample_rate + 1.0e-10; - if (cutoff_freq <= 0) { - // Warning: A LowPassFilter instance has been configured with 0 Hz as - // cut-off frequency. - lfe_f->c = lfe_f->a1 = lfe_f->a2 = lfe_f->a3 = lfe_f->b1 = lfe_f->b2 = 0; - memset(lfe_f->input_history, 0, sizeof(lfe_f->input_history)); - memset(lfe_f->output_history, 0, sizeof(lfe_f->output_history)); - return; - } - lfe_f->c = 1.0f / (float)tanf(M_PI * cutoff_freq * delta_time); - lfe_f->a1 = 1.0f / (1.0f + lfe_f->c + lfe_f->c * lfe_f->c); - lfe_f->a2 = 2.0f * lfe_f->a1; - lfe_f->a3 = lfe_f->a1; - lfe_f->b1 = 2.0f * (1.0f - lfe_f->c * lfe_f->c) * lfe_f->a1; - lfe_f->b2 = (1.0f - lfe_f->c + lfe_f->c * lfe_f->c) * lfe_f->a1; - memset(lfe_f->input_history, 0, sizeof(lfe_f->input_history)); - memset(lfe_f->output_history, 0, sizeof(lfe_f->output_history)); -} - -#define DEFAULT_SAMPLERATE 48000.0f -static float lfefilter_update(lfe_filter_t *lfe_f, float input) { - float output; - - if (lfe_f->init != 1) { - lfefilter_init(lfe_f, 120, DEFAULT_SAMPLERATE); - } - output = lfe_f->a1 * input + lfe_f->a2 * lfe_f->input_history[0] + - lfe_f->a3 * lfe_f->input_history[1] - - lfe_f->b1 * lfe_f->output_history[0] - - lfe_f->b2 * lfe_f->output_history[1]; - - lfe_f->input_history[1] = lfe_f->input_history[0]; - lfe_f->input_history[0] = input; - - lfe_f->output_history[1] = lfe_f->output_history[0]; - lfe_f->output_history[0] = output; - - return (output); -} -#endif diff --git a/code/src/iamf_dec/iamf_audio_block.c b/code/src/iamf_dec/iamf_audio_block.c new file mode 100755 index 00000000..2388f506 --- /dev/null +++ b/code/src/iamf_dec/iamf_audio_block.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_audio_block.c + * @brief IAMF audio block implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "iamf_audio_block.h" + +#include +#include +#include + +#include "iamf_private_definitions.h" + +static int16_t _f32_to_i16(float x) { + x = x * 32768.f; + x = def_max(x, -32768.f); + x = def_min(x, 32767.f); + return (int16_t)lrintf(x); +} + +static int32_t _f32_to_i24(float x) { + x = x * 8388608.f; + x = def_max(x, -8388608.f); + x = def_min(x, 8388607.f); + return (int32_t)lrintf(x); +} + +static int32_t _f32_to_i32(float x) { + x = x * 2147483648.f; + if (x > -2147483648.f && x < 2147483647.f) + return (int32_t)lrintf(x); + else + return (x > 0.0f ? 2147483647 : (-2147483647 - 1)); +} + +iamf_audio_block_t* iamf_audio_block_default_new(uint32_t id) { + iamf_audio_block_t* block = def_mallocz(iamf_audio_block_t, 1); + if (block) block->id = id; + return block; +} + +iamf_audio_block_t* iamf_audio_block_new(uint32_t id, + uint32_t capacity_per_channel, + uint32_t num_channels) { + if (!num_channels || !capacity_per_channel) return 0; + + iamf_audio_block_t* block = iamf_audio_block_default_new(id); + if (!block) return 0; + + block->data = def_mallocz(float, (num_channels * capacity_per_channel)); + if (!block->data) { + iamf_audio_block_delete(block); + return 0; + } + + block->num_channels = num_channels; + block->capacity_per_channel = capacity_per_channel; + + return block; +} + +int iamf_audio_block_resize(iamf_audio_block_t* block, + uint32_t capacity_per_channel, + uint32_t num_channels) { + if (!block) return IAMF_ERR_BAD_ARG; + + if (block->num_samples_per_channel > 0) return IAMF_ERR_INVALID_STATE; + + if (!num_channels || !capacity_per_channel) return IAMF_ERR_BAD_ARG; + + if (block->capacity_per_channel * block->num_samples_per_channel > + capacity_per_channel * num_channels) + return IAMF_OK; + + float* new_data = def_mallocz(float, (num_channels * capacity_per_channel)); + if (!new_data) return -12; + + if (block->data) { + memcpy(new_data, block->data, + sizeof(float) * block->num_channels * block->capacity_per_channel); + def_free(block->data); + } + + block->data = new_data; + block->num_channels = num_channels; + block->capacity_per_channel = capacity_per_channel; + + return IAMF_OK; +} + +void iamf_audio_block_delete(iamf_audio_block_t* block) { + if (block) { + def_free(block->data); + def_free(block); + } +} + +int iamf_audio_block_samples_info_copy(iamf_audio_block_t* dst, + iamf_audio_block_t* src) { + if (!dst || !src) return -22; + + dst->skip = src->skip; + dst->padding = src->padding; + dst->second_skip = src->second_skip; + dst->second_padding = src->second_padding; + dst->num_samples_per_channel = src->num_samples_per_channel; + + return 0; +} + +int iamf_audio_block_padding(iamf_audio_block_t* block, uint32_t padding) { + if (!block) return -22; + + if (block->num_samples_per_channel + padding > block->capacity_per_channel) { + padding = block->capacity_per_channel - block->num_samples_per_channel; + } + + // if (block->interleaved) return -38; + + for (int ch = block->num_channels - 1; ch >= 0; --ch) { + float* channel_data = block->data + ch * block->num_samples_per_channel; + float* new_channel_data = + block->data + ch * (block->num_samples_per_channel + padding); + + memmove(new_channel_data, channel_data, + sizeof(float) * block->num_samples_per_channel); + memset(new_channel_data + block->num_samples_per_channel, 0, + sizeof(float) * padding); + } + + block->num_samples_per_channel += padding; + block->padding += padding; + return padding; +} + +int iamf_audio_block_reorder(iamf_audio_block_t* block, const uint8_t order[], + uint32_t num) { + float* tmp; + if (!block || !order || num > block->num_channels || !block->data) return -22; + + tmp = def_mallocz(float, (block->num_channels * block->capacity_per_channel)); + if (!tmp) return -12; + + for (int i = 0; i < num; ++i) + memcpy(tmp + order[i] * block->num_samples_per_channel, + block->data + i * block->num_samples_per_channel, + sizeof(float) * block->num_samples_per_channel); + def_free(block->data); + block->data = tmp; + + return 0; +} + +int iamf_audio_block_channels_concat(iamf_audio_block_t* dst, + iamf_audio_block_t* src[], uint32_t n) { + int num_channels = 0; + int num_samples = 0; + + if (!dst || !src || n <= 0) return -22; + + // if (dst->interleaved) return -38; + + num_samples = src[0]->num_samples_per_channel; + for (int i = 0; i < n; ++i) { + if (!src[i] || num_samples > dst->capacity_per_channel || + src[i]->num_samples_per_channel != num_samples + // || dst->interleaved != src[i]->interleaved + ) { + warning("iamf_audio_block_channels_concat error!"); + return -22; + } + } + + for (int i = 0; i < n; ++i) num_channels += src[i]->num_channels; + if (dst->num_channels != num_channels) { + error("channel number %d vs %d not match!", dst->num_channels, + num_channels); + return -22; + } + + iamf_audio_block_samples_info_copy(dst, src[0]); + + num_channels = 0; + for (int i = 0; i < n; ++i) { + memcpy(dst->data + num_channels * num_samples, src[i]->data, + sizeof(float) * num_samples * src[i]->num_channels); + num_channels += src[i]->num_channels; + } + + return 0; +} + +int iamf_audio_block_copy(iamf_audio_block_t* dst, iamf_audio_block_t* src, + sample_format_t format) { + uint32_t count = 0; + if (!dst || !src) return -22; + + // Check if destination has enough capacity + count = dst->capacity_per_channel * dst->num_channels; + if (count < src->num_samples_per_channel * src->num_channels) return -22; + + dst->capacity_per_channel = count / src->num_channels; + dst->num_channels = src->num_channels; + dst->num_samples_per_channel = src->num_samples_per_channel; + dst->skip = src->skip; + dst->padding = src->padding; + dst->second_skip = src->second_skip; + dst->second_padding = src->second_padding; + + switch (format) { + case ck_sample_format_none: + // Direct copy - data is already in planar format + memcpy(dst->data, src->data, + sizeof(float) * src->num_channels * src->num_samples_per_channel); + break; + + case ck_sample_format_f32_interleaved: + // Convert from planar to interleaved + for (uint32_t ch = 0; ch < src->num_channels; ++ch) { + for (uint32_t i = 0; i < src->num_samples_per_channel; ++i) { + dst->data[i * src->num_channels + ch] = + src->data[ch * src->num_samples_per_channel + i]; + } + } + break; + + case ck_sample_format_f32_planar: + // Convert from interleaved to planar + for (uint32_t ch = 0; ch < src->num_channels; ++ch) { + for (uint32_t i = 0; i < src->num_samples_per_channel; ++i) { + dst->data[ch * src->num_samples_per_channel + i] = + src->data[i * src->num_channels + ch]; + } + } + break; + + default: + return -38; // Unsupported format + } + + return 0; +} + +int iamf_audio_block_copy_data(iamf_audio_block_t* src, uint8_t* data, + sample_format_t format) { + if (!src || !data || !src->num_channels || !src->num_samples_per_channel) + return -22; + + if (format == ck_sample_format_i16_interleaved) { + int16_t* int16_dst = (int16_t*)data; + for (int c = 0; c < src->num_channels; ++c) { + for (int i = 0; i < src->num_samples_per_channel; i++) { + int16_dst[i * src->num_channels + c] = + _f32_to_i16(src->data[src->num_samples_per_channel * c + i]); + } + } + } else if (format == ck_sample_format_i24_interleaved) { + uint8_t* int24_dst = (uint8_t*)data; + for (int c = 0; c < src->num_channels; ++c) { + for (int i = 0; i < src->num_samples_per_channel; i++) { + int32_t tmp = + _f32_to_i24(src->data[src->num_samples_per_channel * c + i]); + int24_dst[(i * src->num_channels + c) * 3] = tmp & 0xff; + int24_dst[(i * src->num_channels + c) * 3 + 1] = (tmp >> 8) & 0xff; + int24_dst[(i * src->num_channels + c) * 3 + 2] = + ((tmp >> 16) & 0x7f) | ((tmp >> 24) & 0x80); + } + } + } else if (format == ck_sample_format_i32_interleaved) { + int32_t* int32_dst = (int32_t*)data; + for (int c = 0; c < src->num_channels; ++c) { + for (int i = 0; i < src->num_samples_per_channel; i++) { + int32_dst[i * src->num_channels + c] = + _f32_to_i32(src->data[src->num_samples_per_channel * c + i]); + } + } + } + + return 0; +} + +iamf_audio_block_t* iamf_audio_block_samples_concat( + iamf_audio_block_t* blocks[], uint32_t n) { + int num_channels = 0; + int num_samples = 0; + iamf_audio_block_t* ablock = 0; + + if (!blocks || n <= 0) return 0; + + num_channels = blocks[0]->num_channels; + for (int i = 0; i < n; ++i) { + if (blocks[i]->num_channels != num_channels) return 0; + } + + for (int i = 0; i < n; ++i) { + ablock = blocks[i]; + num_samples += + (ablock->num_samples_per_channel - ablock->skip - ablock->padding); + } + + ablock = iamf_audio_block_new(0, num_samples, num_channels); + if (ablock) { + for (int c = 0; c < num_channels; ++c) { + uint32_t off = 0; + for (int i = 0; i < n; ++i) { + uint32_t samples = blocks[i]->num_samples_per_channel - + blocks[i]->skip - blocks[i]->padding; + memcpy(ablock->data + c * num_samples + off, + blocks[i]->data + c * blocks[i]->num_samples_per_channel + + blocks[i]->skip, + sizeof(float) * samples); + off += samples; + } + } + ablock->num_samples_per_channel = num_samples; + } + return ablock; +} + +int iamf_audio_block_trim(iamf_audio_block_t* block) { + uint32_t padding = 0; + if (!block) return -22; + + padding = + block->padding + block->skip + block->second_skip + block->second_padding; + if (block->num_samples_per_channel < padding) { + block->num_samples_per_channel = 0; + return 0; + } + + uint32_t num_samples = block->num_samples_per_channel; + block->num_samples_per_channel -= padding; + + if (num_samples != block->num_samples_per_channel) { + for (int i = 0; i < block->num_channels; ++i) { + float* dst = block->data + i * block->num_samples_per_channel; + float* src = + block->data + i * num_samples + block->skip + block->second_skip; + memmove(dst, src, sizeof(float) * block->num_samples_per_channel); + } + block->skip = block->padding = block->second_skip = block->second_padding = + 0; + } + return 0; +} + +int iamf_audio_block_gain(iamf_audio_block_t* block, float gain) { + if (!block) return -22; + if (gain == def_default_loudness_gain) return 0; + int num_samples = block->num_channels * block->num_samples_per_channel; + + for (int i = 0; i < num_samples; ++i) block->data[i] *= gain; + return 0; +} + +uint32_t iamf_audio_block_available_samples(iamf_audio_block_t* block) { + if (!block) return 0; + return block->num_samples_per_channel - block->skip - block->padding - + block->second_skip - block->second_padding; +} + +int iamf_audio_block_partial_copy_data(iamf_audio_block_t* dst, + uint32_t dst_offset, + iamf_audio_block_t* src, + uint32_t src_offset, uint32_t size) { + if (!dst || !src) return -22; + if (src_offset + size > src->num_samples_per_channel) return -22; + if (dst_offset + size > dst->capacity_per_channel) return -22; + if (dst->num_channels != src->num_channels) return -22; + + for (uint32_t ch = 0; ch < src->num_channels; ++ch) + memcpy(&dst->data[dst_offset + ch * dst->num_samples_per_channel], + &src->data[src_offset + ch * src->num_samples_per_channel], + size * sizeof(float)); + + return 0; +} diff --git a/code/src/iamf_dec/iamf_audio_block.h b/code/src/iamf_dec/iamf_audio_block.h new file mode 100755 index 00000000..658baccc --- /dev/null +++ b/code/src/iamf_dec/iamf_audio_block.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_audio_block.h + * @brief IAMF audio block APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_AUDIO_BLOCK_H__ +#define __IAMF_AUDIO_BLOCK_H__ + +#include + +typedef enum ESampleFormat { + ck_sample_format_none = 0, + ck_sample_format_i16_interleaved, + ck_sample_format_i24_interleaved, + ck_sample_format_i32_interleaved, + ck_sample_format_f32_interleaved, + ck_sample_format_f32_planar = 0x20, +} sample_format_t; + +typedef struct IamfAudioBlock { + uint32_t id; + + float* data; + uint32_t num_channels; + uint32_t num_samples_per_channel; + uint32_t capacity_per_channel; // in samples + + uint32_t skip; // in samples + uint32_t padding; // in samples + uint32_t second_skip; // in samples + uint32_t second_padding; // in samples +} iamf_audio_block_t; + +iamf_audio_block_t* iamf_audio_block_default_new(uint32_t id); +iamf_audio_block_t* iamf_audio_block_new(uint32_t id, + uint32_t capacity_per_channel, + uint32_t num_channels); +int iamf_audio_block_resize(iamf_audio_block_t* block, + uint32_t capacity_per_channel, + uint32_t num_channels); +void iamf_audio_block_delete(iamf_audio_block_t* block); +int iamf_audio_block_samples_info_copy(iamf_audio_block_t* dst, + iamf_audio_block_t* src); +int iamf_audio_block_padding(iamf_audio_block_t* block, uint32_t padding); +int iamf_audio_block_reorder(iamf_audio_block_t* block, const uint8_t order[], + uint32_t num); +int iamf_audio_block_channels_concat(iamf_audio_block_t* dst, + iamf_audio_block_t* src[], uint32_t n); +int iamf_audio_block_copy(iamf_audio_block_t* dst, iamf_audio_block_t* src, + sample_format_t format); +int iamf_audio_block_copy_data(iamf_audio_block_t* src, uint8_t* data, + sample_format_t format); +int iamf_audio_block_partial_copy_data(iamf_audio_block_t* dst, + uint32_t dst_offset, + iamf_audio_block_t* src, + uint32_t src_offset, uint32_t size); +iamf_audio_block_t* iamf_audio_block_samples_concat( + iamf_audio_block_t* blocks[], uint32_t n); +int iamf_audio_block_trim(iamf_audio_block_t* block); +int iamf_audio_block_gain(iamf_audio_block_t* block, float gain); +uint32_t iamf_audio_block_available_samples(iamf_audio_block_t* block); + +#endif //__IAMF_AUDIO_BLOCK_H__ diff --git a/code/src/iamf_dec/IAMF_core_decoder.c b/code/src/iamf_dec/iamf_core_decoder.c similarity index 57% rename from code/src/iamf_dec/IAMF_core_decoder.c rename to code/src/iamf_dec/iamf_core_decoder.c index 8d88216e..65613011 100755 --- a/code/src/iamf_dec/IAMF_core_decoder.c +++ b/code/src/iamf_dec/iamf_core_decoder.c @@ -11,9 +11,9 @@ */ /** - * @file IAMF_core_decoder.c + * @file iamf_core_decoder.c * @brief Core decoder. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ @@ -24,37 +24,38 @@ #include #include -#include "IAMF_core_decoder.h" -#include "IAMF_debug.h" -#include "IAMF_types.h" -#include "IAMF_utils.h" -#include "bitstream.h" -#include "fixedp11_5.h" +#include "clog.h" +#include "iamf_core_decoder.h" +#include "iamf_private_definitions.h" +#include "iamf_string.h" +#include "iamf_types.h" +#include "iamf_utils.h" +#include "iorw.h" -#ifdef IA_TAG -#undef IA_TAG +#ifdef def_log_tag +#undef def_log_tag #endif -#define IA_TAG "IAMF_CORE" +#define def_log_tag "IAMF_CORE" #ifdef CONFIG_OPUS_CODEC -extern const IAMF_Codec iamf_opus_decoder; +extern const iamf_codec_t iamf_opus_decoder; #endif #ifdef CONFIG_AAC_CODEC -extern const IAMF_Codec iamf_aac_decoder; +extern const iamf_codec_t iamf_aac_decoder; #endif #ifdef CONFIG_FLAC_CODEC -extern const IAMF_Codec iamf_flac_decoder; +extern const iamf_codec_t iamf_flac_decoder; #endif -extern const IAMF_Codec iamf_pcm_decoder; +extern const iamf_codec_t iamf_pcm_decoder; -struct IAMF_CoreDecoder { - IAMF_CodecID cid; - const IAMF_Codec *cdec; - IAMF_CodecContext *ctx; +struct IamfCoreDecoder { + iamf_codec_id_t cid; + const iamf_codec_t *cdec; + iamf_codec_context_t *ctx; int ambisonics; void *matrix; @@ -67,27 +68,27 @@ typedef struct FloatMatrix { int column; } FloatMatrix; -static const IAMF_Codec *gCodecs[] = {0, +static const iamf_codec_t *_g_codecs[] = {0, #ifdef CONFIG_OPUS_CODEC - &iamf_opus_decoder, + &iamf_opus_decoder, #else - 0, + 0, #endif #ifdef CONFIG_AAC_CODEC - &iamf_aac_decoder, + &iamf_aac_decoder, #else - 0, + 0, #endif #ifdef CONFIG_FLAC_CODEC - &iamf_flac_decoder, + &iamf_flac_decoder, #else - 0, + 0, #endif - &iamf_pcm_decoder + &iamf_pcm_decoder }; -static int iamf_core_decoder_convert_mono(IAMF_CoreDecoder *ths, float *out, +static int iamf_core_decoder_convert_mono(iamf_core_decoder_t *ths, float *out, float *in, uint32_t frame_size) { uint8_t *map = ths->matrix; @@ -101,7 +102,7 @@ static int iamf_core_decoder_convert_mono(IAMF_CoreDecoder *ths, float *out, } return IAMF_OK; } -static int iamf_core_decoder_convert_projection(IAMF_CoreDecoder *ths, +static int iamf_core_decoder_convert_projection(iamf_core_decoder_t *ths, float *out, float *in, uint32_t frame_size) { FloatMatrix *matrix = ths->matrix; @@ -117,43 +118,45 @@ static int iamf_core_decoder_convert_projection(IAMF_CoreDecoder *ths, return IAMF_OK; } -IAMF_CoreDecoder *iamf_core_decoder_open(IAMF_CodecID cid) { - IAMF_CoreDecoder *ths = 0; - IAMF_CodecContext *ctx = 0; +iamf_core_decoder_t *iamf_core_decoder_open(iamf_codec_id_t cid) { + iamf_core_decoder_t *ths = 0; + iamf_codec_context_t *ctx = 0; + iamf_codec_type_t type = ck_iamf_codec_type_none; int ec = IAMF_OK; - if (!iamf_codec_check(cid)) { - ia_loge("Invlid codec id %u", cid); + if (!iamf_codec_id_check(cid)) { + error("Invalid codec id %u", cid); return 0; } - if (!gCodecs[cid]) { - ia_loge("Unimplment %s decoder.", iamf_codec_name(cid)); + type = iamf_codec_type_get(cid); + if (!_g_codecs[type]) { + error("Unimplemented %s decoder.", iamf_codec_type_string(type)); return 0; } - ths = IAMF_MALLOCZ(IAMF_CoreDecoder, 1); + ths = def_mallocz(iamf_core_decoder_t, 1); if (!ths) { - ia_loge("%s : IAMF_CoreDecoder handle.", - ia_error_code_string(IAMF_ERR_ALLOC_FAIL)); + error("%s : iamf_core_decoder_t handle.", + iamf_error_code_string(IAMF_ERR_ALLOC_FAIL)); return 0; } ths->cid = cid; - ths->cdec = gCodecs[cid]; + ths->cdec = _g_codecs[type]; - ctx = IAMF_MALLOCZ(IAMF_CodecContext, 1); + ctx = def_mallocz(iamf_codec_context_t, 1); if (!ctx) { ec = IAMF_ERR_ALLOC_FAIL; - ia_loge("%s : IAMF_CodecContext handle.", ia_error_code_string(ec)); + error("%s : iamf_codec_context_t handle.", iamf_error_code_string(ec)); goto termination; } ths->ctx = ctx; - ctx->priv = IAMF_MALLOCZ(char, ths->cdec->priv_size); + ctx->priv = def_mallocz(char, ths->cdec->priv_size); if (!ctx->priv) { ec = IAMF_ERR_ALLOC_FAIL; - ia_loge("%s : private data.", ia_error_code_string(ec)); + error("%s : private data.", iamf_error_code_string(ec)); goto termination; } @@ -165,18 +168,16 @@ IAMF_CoreDecoder *iamf_core_decoder_open(IAMF_CodecID cid) { return ths; } -void iamf_core_decoder_close(IAMF_CoreDecoder *ths) { +void iamf_core_decoder_close(iamf_core_decoder_t *ths) { if (ths) { if (ths->ctx) { if (ths->cdec) ths->cdec->close(ths->ctx); - if (ths->ctx->priv) { - free(ths->ctx->priv); - } + if (ths->ctx->priv) free(ths->ctx->priv); free(ths->ctx); } if (ths->matrix) { - if (ths->ambisonics == STREAM_MODE_AMBISONICS_PROJECTION) { + if (ths->ambisonics == ck_stream_mode_ambisonics_projection) { FloatMatrix *fm = ths->matrix; if (fm->matrix) free(fm->matrix); } @@ -189,44 +190,45 @@ void iamf_core_decoder_close(IAMF_CoreDecoder *ths) { } } -int iamf_core_decoder_init(IAMF_CoreDecoder *ths) { - IAMF_CodecContext *ctx = ths->ctx; +int iamf_core_decoder_init(iamf_core_decoder_t *ths) { + iamf_codec_context_t *ctx = ths->ctx; return ths->cdec->init(ctx); } -int iamf_core_decoder_set_codec_conf(IAMF_CoreDecoder *ths, uint8_t *spec, +int iamf_core_decoder_set_codec_conf(iamf_core_decoder_t *ths, uint8_t *spec, uint32_t len) { - IAMF_CodecContext *ctx = ths->ctx; + iamf_codec_context_t *ctx = ths->ctx; ctx->cspec = spec; ctx->clen = len; return IAMF_OK; } -int iamf_core_decoder_set_streams_info(IAMF_CoreDecoder *ths, uint32_t mode, +int iamf_core_decoder_set_streams_info(iamf_core_decoder_t *ths, uint32_t mode, uint8_t channels, uint8_t streams, uint8_t coupled_streams, uint8_t mapping[], uint32_t mapping_size) { - IAMF_CodecContext *ctx = ths->ctx; + iamf_codec_context_t *ctx = ths->ctx; ths->ambisonics = mode; ctx->channels = channels; ctx->streams = streams; ctx->coupled_streams = coupled_streams; if (mapping && mapping_size > 0) { - if (ths->ambisonics == STREAM_MODE_AMBISONICS_PROJECTION) { - FloatMatrix *matrix = IAMF_MALLOCZ(FloatMatrix, 1); + if (ths->ambisonics == ck_stream_mode_ambisonics_projection) { + FloatMatrix *matrix = def_mallocz(FloatMatrix, 1); int count; - BitStream b; + io_context_t ioc, *r; float *factors; if (!matrix) return IAMF_ERR_ALLOC_FAIL; - bs(&b, mapping, mapping_size); + r = &ioc; + ioc_init(r, mapping, mapping_size); matrix->row = ctx->channels; matrix->column = ctx->streams + ctx->coupled_streams; count = matrix->row * matrix->column; - factors = IAMF_MALLOCZ(float, count); + factors = def_mallocz(float, count); if (!factors) { free(matrix); return IAMF_ERR_ALLOC_FAIL; @@ -234,17 +236,17 @@ int iamf_core_decoder_set_streams_info(IAMF_CoreDecoder *ths, uint32_t mode, matrix->matrix = factors; for (int i = 0; i < count; ++i) { - factors[i] = q_to_float(bs_getA16b(&b), 15); - ia_logi("factor %d : %f", i, factors[i]); + factors[i] = iamf_q15_to_float(def_lsb_16bits(ior_b16(r))); + info("factor %d : %f", i, factors[i]); } ths->matrix = matrix; - } else if (ths->ambisonics == STREAM_MODE_AMBISONICS_MONO) { - uint8_t *matrix = IAMF_MALLOCZ(uint8_t, mapping_size); + } else if (ths->ambisonics == ck_stream_mode_ambisonics_mono) { + uint8_t *matrix = def_mallocz(uint8_t, mapping_size); if (!matrix) return IAMF_ERR_ALLOC_FAIL; if (channels != mapping_size) { free(matrix); - ia_loge("Invalid ambisonics mono info."); + error("Invalid ambisonics mono info."); return IAMF_ERR_BAD_ARG; } memcpy(matrix, mapping, mapping_size); @@ -254,25 +256,25 @@ int iamf_core_decoder_set_streams_info(IAMF_CoreDecoder *ths, uint32_t mode, return IAMF_OK; } -int iamf_core_decoder_decode(IAMF_CoreDecoder *ths, uint8_t *buffer[], +int iamf_core_decoder_decode(iamf_core_decoder_t *ths, uint8_t *buffer[], uint32_t size[], uint32_t count, float *out, uint32_t frame_size) { int ret = IAMF_OK; - IAMF_CodecContext *ctx = ths->ctx; + iamf_codec_context_t *ctx = ths->ctx; if (ctx->streams != count) return IAMF_ERR_BUFFER_TOO_SMALL; - if (ths->ambisonics == STREAM_MODE_AMBISONICS_NONE) + if (ths->ambisonics == ck_stream_mode_ambisonics_none) return ths->cdec->decode(ctx, buffer, size, count, out, frame_size); if (!ths->buffer) { float *block = 0; - block = IAMF_MALLOC(float, ctx->channels *frame_size); + block = def_mallocz(float, (ctx->channels * frame_size)); if (!block) return IAMF_ERR_ALLOC_FAIL; ths->buffer = block; } ret = ths->cdec->decode(ctx, buffer, size, count, ths->buffer, frame_size); if (ret > 0) { - if (ths->ambisonics == STREAM_MODE_AMBISONICS_PROJECTION) + if (ths->ambisonics == ck_stream_mode_ambisonics_projection) iamf_core_decoder_convert_projection(ths, out, ths->buffer, ret); else iamf_core_decoder_convert_mono(ths, out, ths->buffer, ret); @@ -280,10 +282,10 @@ int iamf_core_decoder_decode(IAMF_CoreDecoder *ths, uint8_t *buffer[], return ret; } -int iamf_core_decoder_get_delay(IAMF_CoreDecoder *ths) { - if (ths->cdec->info) ths->cdec->info(ths->ctx); - if (ths && ths->ctx) { - return ths->ctx->delay; +uint32_t iamf_core_decoder_get_delay(iamf_core_decoder_t *ths) { + if (ths) { + if (ths->cdec && ths->cdec->info) (ths->cdec->info)(ths->ctx); + if (ths->ctx) return ths->ctx->delay; } return 0; } diff --git a/code/src/iamf_dec/IAMF_core_decoder.h b/code/src/iamf_dec/iamf_core_decoder.h similarity index 80% rename from code/src/iamf_dec/IAMF_core_decoder.h rename to code/src/iamf_dec/iamf_core_decoder.h index b68f65b0..bbc01246 100755 --- a/code/src/iamf_dec/IAMF_core_decoder.h +++ b/code/src/iamf_dec/iamf_core_decoder.h @@ -11,41 +11,41 @@ */ /** - * @file IAMF_core_decoder.h + * @file iamf_core_decoder.h * @brief Core decoder APIs. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ -#ifndef IAMF_CORE_DECODER_H_ -#define IAMF_CORE_DECODER_H_ +#ifndef __IAMF_CORE_DECODER_H__ +#define __IAMF_CORE_DECODER_H__ #include -#include "IAMF_codec.h" #include "IAMF_defines.h" +#include "iamf_codec.h" -typedef struct IAMF_CoreDecoder IAMF_CoreDecoder; +typedef struct IamfCoreDecoder iamf_core_decoder_t; /** * @brief Open an iamf core decoder. * @param [in] cid : the codec id. * @return return an iamf core decoder handle. */ -IAMF_CoreDecoder *iamf_core_decoder_open(IAMF_CodecID cid); +iamf_core_decoder_t *iamf_core_decoder_open(iamf_codec_id_t cid); /** * @brief Close the iamf core decoder. * @param [in] ths : the core decoder handle. */ -void iamf_core_decoder_close(IAMF_CoreDecoder *ths); +void iamf_core_decoder_close(iamf_core_decoder_t *ths); /** * @brief Initialize the iamf core decoder. * @param [in] ths : the core decoder handle. * @return @ref IAErrCode. */ -int iamf_core_decoder_init(IAMF_CoreDecoder *ths); +int iamf_core_decoder_init(iamf_core_decoder_t *ths); /** * @brief Set the codec specific data to iamf core decoder. @@ -54,7 +54,7 @@ int iamf_core_decoder_init(IAMF_CoreDecoder *ths); * @param [in] len : the length of codec specific data. * @return @ref IAErrCode. */ -int iamf_core_decoder_set_codec_conf(IAMF_CoreDecoder *ths, uint8_t *spec, +int iamf_core_decoder_set_codec_conf(iamf_core_decoder_t *ths, uint8_t *spec, uint32_t len); /** @@ -69,7 +69,7 @@ int iamf_core_decoder_set_codec_conf(IAMF_CoreDecoder *ths, uint8_t *spec, * @param [in] mapping_size : the length of mapping matrix. * @return @ref IAErrCode. */ -int iamf_core_decoder_set_streams_info(IAMF_CoreDecoder *ths, uint32_t mode, +int iamf_core_decoder_set_streams_info(iamf_core_decoder_t *ths, uint32_t mode, uint8_t channels, uint8_t streams, uint8_t coupled_streams, uint8_t mapping[], @@ -85,7 +85,7 @@ int iamf_core_decoder_set_streams_info(IAMF_CoreDecoder *ths, uint32_t mode, * @param [in] frame_size : the size of one audio frame. * @return @ref IAErrCode. */ -int iamf_core_decoder_decode(IAMF_CoreDecoder *ths, uint8_t *buffers[], +int iamf_core_decoder_decode(iamf_core_decoder_t *ths, uint8_t *buffers[], uint32_t *sizes, uint32_t count, float *out, uint32_t frame_size); @@ -93,6 +93,6 @@ int iamf_core_decoder_decode(IAMF_CoreDecoder *ths, uint8_t *buffers[], * @brief Get the delay of iamf decoding. * @return return the decoder delay. */ -int iamf_core_decoder_get_delay(IAMF_CoreDecoder *ths); +uint32_t iamf_core_decoder_get_delay(iamf_core_decoder_t *ths); -#endif /* IAMF_CORE_DECODER_H_ */ +#endif /* __IAMF_CORE_DECODER_H__ */ diff --git a/code/src/iamf_dec/iamf_database.c b/code/src/iamf_dec/iamf_database.c new file mode 100755 index 00000000..f9033f78 --- /dev/null +++ b/code/src/iamf_dec/iamf_database.c @@ -0,0 +1,1290 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_database.c + * @brief IAMF database implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "iamf_database.h" + +#include +#include + +#include "clog.h" +#include "iamf_layout.h" +#include "iamf_obu_parser.h" +#include "iamf_private_definitions.h" +#include "iamf_string.h" +#include "iamf_utils.h" +#include "obu/iamf_obu_all.h" + +#undef def_log_tag +#define def_log_tag "IAMF_DB" + +static int _iadb_polar_copy(polar_t *dst, polar_t *src) { + if (!dst || !src) return IAMF_ERR_BAD_ARG; + + dst->azimuth = src->azimuth; + dst->elevation = src->elevation; + dst->distance = src->distance; + + return IAMF_OK; +} + +static void _iadb_parameter_block_free(parameter_block_t *block) { + if (block->subblocks) + deque_free(block->subblocks, + def_default_free_ptr(iamf_parameter_subblock_free)); + free(block); +} + +static parameter_block_t *_iadb_parameter_block_new(parameter_base_t *base) { + parameter_block_t *block = 0; + if (base->type == ck_iamf_parameter_type_mix_gain) { + mix_gain_parameter_block_t *pbk = + def_mallocz(mix_gain_parameter_block_t, 1); + mix_gain_parameter_base_t *mgpbs = (mix_gain_parameter_base_t *)base; + if (pbk) { + block = def_parameter_block_ptr(pbk); + pbk->end_gain = mgpbs->default_mix_gain_db; + } + } else if (base->type == ck_iamf_parameter_type_polar || + base->type == ck_iamf_parameter_type_dual_polar) { + polars_parameter_block_t *pbk = def_mallocz(polars_parameter_block_t, 1); + polars_parameter_base_t *pbs = def_polars_parameter_base_ptr(base); + if (pbk) { + block = def_parameter_block_ptr(pbk); + pbk->num_polars = pbs->num_polars; + for (int i = 0; i < pbk->num_polars; ++i) { + _iadb_polar_copy(&pbk->end_polars[i], &pbs->default_polars[i]); + } + } + } else if (iamf_parameter_type_is_cartesian(base->type)) { + cartesians_parameter_block_t *pbk = + def_mallocz(cartesians_parameter_block_t, 1); + cartesians_parameter_base_t *cbs = (cartesians_parameter_base_t *)base; + if (pbk) { + block = def_parameter_block_ptr(pbk); + pbk->num_cartesians = cbs->num_cartesians; + for (int i = 0; i < pbk->num_cartesians; ++i) { + pbk->end_cartesians[i].x = cbs->default_cartesians[i].x; + pbk->end_cartesians[i].y = cbs->default_cartesians[i].y; + pbk->end_cartesians[i].z = cbs->default_cartesians[i].z; + } + } + } else { + block = def_mallocz(parameter_block_t, 1); + } + + if (block) { + block->base = base; + block->subblocks = deque_new(); + } + return block; +} + +static int _iadb_parameter_block_find(value_wrap_t item, value_wrap_t key) { + return def_value_wrap_type_ptr(parameter_block_t, &item) + ->base->parameter_id == key.u32; +} + +static int _iadb_parameter_block_manager_add(parameter_block_manager_t *manager, + parameter_base_t *base) { + value_wrap_t v; + + if (vector_find(manager->parameter_blocks, + def_value_wrap_instance_u32(base->parameter_id), + _iadb_parameter_block_find, &v) < 0) { + parameter_block_t *block = _iadb_parameter_block_new(base); + + if (base->type == ck_iamf_parameter_type_demixing) { + vector_push(manager->demixing_infos, def_value_wrap_instance_ptr(block)); + } else if (base->type == ck_iamf_parameter_type_recon_gain) { + vector_push(manager->recon_gains, def_value_wrap_instance_ptr(block)); + } else if (base->type == ck_iamf_parameter_type_mix_gain) { + vector_push(manager->mix_gains, def_value_wrap_instance_ptr(block)); + } else if (base->type == ck_iamf_parameter_type_momentary_loudness) { + vector_push(manager->coordinates, def_value_wrap_instance_ptr(block)); + } else if (iamf_parameter_type_is_coordinate(base->type)) { + vector_push(manager->coordinates, def_value_wrap_instance_ptr(block)); + } else { + _iadb_parameter_block_free(block); + return IAMF_ERR_BAD_ARG; + } + vector_push(manager->parameter_blocks, def_value_wrap_instance_ptr(block)); + } + + return IAMF_OK; +} + +static int _iadb_parameter_block_manager_add_obu( + parameter_block_manager_t *manager, iamf_parameter_block_obu_t *obu) { + value_wrap_t v; + + if (vector_find(manager->parameter_blocks, + def_value_wrap_instance_u32(obu->base->parameter_id), + _iadb_parameter_block_find, &v) >= 0) { + parameter_block_t *block = def_value_wrap_type_ptr(parameter_block_t, &v); + int n = array_size(obu->subblocks); + if (n <= 0) return IAMF_ERR_BAD_ARG; + + if (obu->obu.obu_flags & ck_iamf_obu_flag_redundant && + deque_length(block->subblocks) > 0) { + debug("Ignore redundant parameter obu with id %u.", + obu->base->parameter_id); + } else { + int idx = deque_length(block->subblocks); + if (block->reset_start_time || block->elapsed < 0 || + block->elapsed > block->duration) { + if (block->base->type == ck_iamf_parameter_type_mix_gain) { + mix_gain_parameter_block_t *pblock = + def_mix_gain_parameter_block_ptr(block); + mix_gain_parameter_base_t *pbase = + def_mix_gain_parameter_base_ptr(block->base); + pblock->end_gain = pbase->default_mix_gain_db; + debug("Use default mix gain (%d dB) as starting value for pid %u.", + pblock->end_gain, block->base->parameter_id); + } else if (iamf_parameter_type_is_polar(block->base->type)) { + polars_parameter_block_t *pblock = + def_polars_parameter_block_ptr(block); + polars_parameter_base_t *pbase = + def_polars_parameter_base_ptr(block->base); + for (int i = 0; i < pblock->num_polars; ++i) { + pblock->end_polars[i].azimuth = pbase->default_polars[i].azimuth; + pblock->end_polars[i].elevation = + pbase->default_polars[i].elevation; + pblock->end_polars[i].distance = pbase->default_polars[i].distance; + debug( + "Use default polar coordinates (%f, %f, %f) as starting values " + "for pid %u - %d.", + pblock->end_polars[i].azimuth, pblock->end_polars[i].elevation, + pblock->end_polars[i].distance, block->base->parameter_id, i); + } + } else if (iamf_parameter_type_is_cartesian(block->base->type)) { + cartesians_parameter_block_t *pblock = + def_cartesians_parameter_block_ptr(block); + cartesians_parameter_base_t *pbase = + def_cartesians_parameter_base_ptr(block->base); + for (int i = 0; i < pblock->num_cartesians; ++i) { + pblock->end_cartesians[i].x = pbase->default_cartesians[i].x; + pblock->end_cartesians[i].y = pbase->default_cartesians[i].y; + pblock->end_cartesians[i].z = pbase->default_cartesians[i].z; + debug( + "Use default cartesian coordinates (%f, %f, %f) as starting " + "values for pid %u - %d.", + pblock->end_cartesians[i].x, pblock->end_cartesians[i].y, + pblock->end_cartesians[i].z, block->base->parameter_id, i); + } + } + block->reset_start_time = 0; + } + + for (int i = 0; i < n; ++i) { + value_wrap_t *pv = array_at(obu->subblocks, i); + parameter_subblock_t *psb = def_parameter_subblock_ptr(pv->ptr); + block->duration += psb->subblock_duration; + deque_push_back(block->subblocks, *pv); + pv->ptr = 0; + + if (psb->type == ck_iamf_parameter_type_mix_gain) { + mix_gain_parameter_block_t *pblock = + def_mix_gain_parameter_block_ptr(block); + mix_gain_parameter_subblock_t *sub = + def_mix_gain_parameter_subblock_ptr(psb); + + if (sub->gain.animation_type == ck_iamf_animation_type_inter_linear || + sub->gain.animation_type == ck_iamf_animation_type_inter_bezier) { + sub->gain_db.data.start = pblock->end_gain; + if (sub->gain.animation_type == ck_iamf_animation_type_inter_linear) + sub->gain_db.animation_type = ck_iamf_animation_type_linear; + else + sub->gain_db.animation_type = ck_iamf_animation_type_bezier; + } + + if (sub->gain.animation_type == ck_iamf_animation_type_step) + pblock->end_gain = sub->gain_db.data.start; + else + pblock->end_gain = sub->gain_db.data.end; + + } else if (iamf_parameter_type_is_polar(psb->type)) { + polars_parameter_block_t *pblock = + def_polars_parameter_block_ptr(block); + polars_parameter_subblock_t *sub = + def_polars_parameter_subblock_ptr(psb); + + for (int j = 0; j < pblock->num_polars; ++j) { + if (sub->animation_type == ck_iamf_animation_type_inter_linear || + sub->animation_type == ck_iamf_animation_type_inter_bezier) { + sub->polars[j].azimuth.start = pblock->end_polars[j].azimuth; + sub->polars[j].elevation.start = pblock->end_polars[j].elevation; + sub->polars[j].distance.start = pblock->end_polars[j].distance; + if (sub->animation_type == ck_iamf_animation_type_inter_linear) { + sub->polars[j].animation_type = ck_iamf_animation_type_linear; + } else { + sub->polars[j].animation_type = ck_iamf_animation_type_bezier; + } + } + + if (sub->animation_type == ck_iamf_animation_type_step) { + pblock->end_polars[j].azimuth = sub->polars[j].azimuth.start; + pblock->end_polars[j].elevation = sub->polars[j].elevation.start; + pblock->end_polars[j].distance = sub->polars[j].distance.start; + } else { + pblock->end_polars[j].azimuth = sub->polars[j].azimuth.end; + pblock->end_polars[j].elevation = sub->polars[j].elevation.end; + pblock->end_polars[j].distance = sub->polars[j].distance.end; + } + } + } else if (iamf_parameter_type_is_cartesian(psb->type)) { + cartesians_parameter_block_t *pblock = + def_cartesians_parameter_block_ptr(block); + cartesians_parameter_subblock_t *sub = + def_cartesians_parameter_subblock_ptr(psb); + + for (int j = 0; j < pblock->num_cartesians; ++j) { + if (sub->animation_type == ck_iamf_animation_type_inter_linear || + sub->animation_type == ck_iamf_animation_type_inter_bezier) { + sub->cartesians[j].x.start = pblock->end_cartesians[j].x; + sub->cartesians[j].y.start = pblock->end_cartesians[j].y; + sub->cartesians[j].z.start = pblock->end_cartesians[j].z; + if (sub->animation_type == ck_iamf_animation_type_inter_linear) { + sub->cartesians[j].animation_type = + ck_iamf_animation_type_linear; + } else { + sub->cartesians[j].animation_type = + ck_iamf_animation_type_bezier; + } + } + + if (sub->animation_type == ck_iamf_animation_type_step) { + pblock->end_cartesians[j].x = sub->cartesians[j].x.start; + pblock->end_cartesians[j].y = sub->cartesians[j].y.start; + pblock->end_cartesians[j].z = sub->cartesians[j].z.start; + } else { + pblock->end_cartesians[j].x = sub->cartesians[j].x.end; + pblock->end_cartesians[j].y = sub->cartesians[j].y.end; + pblock->end_cartesians[j].z = sub->cartesians[j].z.end; + } + } + } + } + + if (!block->next_block_index) { + block->next_block_index = -1; + } else if (idx > 0) { + block->next_block_index = idx; + } + debug( + "Add parameter block obu with id %u. subblocks %u->%u, " + "next_block_index %d", + obu->base->parameter_id, idx, deque_length(block->subblocks), + block->next_block_index); + } + + return IAMF_OK; + } + + return IAMF_ERR_BAD_ARG; +} + +static int _iadb_parameter_block_manager_init( + parameter_block_manager_t *manager) { + manager->parameter_blocks = vector_new(); + manager->demixing_infos = vector_new(); + manager->recon_gains = vector_new(); + manager->mix_gains = vector_new(); + manager->coordinates = vector_new(); + if (!manager->parameter_blocks || !manager->demixing_infos || + !manager->recon_gains || !manager->mix_gains || !manager->coordinates) { + error("Failed to allocate memory for parameter blocks."); + return IAMF_ERR_ALLOC_FAIL; + } + return IAMF_OK; +} + +static void _iadb_parameter_block_manager_uninit( + parameter_block_manager_t *manager) { + if (manager->parameter_blocks) + vector_free(manager->parameter_blocks, + def_default_free_ptr(_iadb_parameter_block_free)); + if (manager->demixing_infos) vector_free(manager->demixing_infos, 0); + if (manager->recon_gains) vector_free(manager->recon_gains, 0); + if (manager->mix_gains) vector_free(manager->mix_gains, 0); + if (manager->coordinates) vector_free(manager->coordinates, 0); + memset(manager, 0, sizeof(parameter_block_manager_t)); +} + +static int _iadb_parameter_block_manager_time_elapse( + parameter_block_manager_t *pbm, fraction_t time) { + parameter_subblock_t *psb = 0; + int n = vector_size(pbm->parameter_blocks); + + for (int i = 0; i < n; ++i) { + parameter_block_t *block = def_value_wrap_type_ptr( + parameter_block_t, vector_at(pbm->parameter_blocks, i)); + + debug("S: pid %u, duration %u, elapsed %d, rate %u, elapse %u/%u", + block->base->parameter_id, block->duration, block->elapsed, + block->base->parameter_rate, time.numerator, time.denominator); + + if (deque_length(block->subblocks) > 0) { + if (block->elapsed < 0) { + // the elapsed time returns to the normal value + block->elapsed = 0 - block->elapsed; + } else { + block->elapsed += + iamf_fraction_transform(time, block->base->parameter_rate); + + // Calculate the number of subblocks covered by elapsed + int elapsed_duration = block->elapsed; + int elapsed_subblock_count = 0; + + for (int j = 0; j < deque_length(block->subblocks); ++j) { + psb = def_parameter_subblock_ptr( + def_value_wrap_optional_ptr(deque_at(block->subblocks, j))); + if (psb && elapsed_duration > 0 && + elapsed_duration >= psb->subblock_duration) { + elapsed_duration -= psb->subblock_duration; + elapsed_subblock_count++; + } else { + break; + } + } + + // Check if subblocks before next_block_index need to be deleted + if (block->next_block_index > 0 && + elapsed_subblock_count >= block->next_block_index) { + // Delete subblocks before next_block_index + for (int k = 0; k < block->next_block_index; ++k) { + value_wrap_t v; + psb = def_parameter_subblock_ptr( + def_value_wrap_optional_ptr(deque_at(block->subblocks, 0))); + if (psb) { + block->duration -= psb->subblock_duration; + deque_pop_front(block->subblocks, &v); + iamf_parameter_subblock_free(psb); + } + } + block->elapsed = elapsed_duration; + // Set next_block_index to -1 + block->next_block_index = -1; + } else if (block->next_block_index == -1 && block->elapsed > 0 && + block->elapsed >= block->duration) { + // Delete all remaining subblocks + while (deque_length(block->subblocks) > 0) { + value_wrap_t v; + psb = def_parameter_subblock_ptr( + def_value_wrap_optional_ptr(deque_at(block->subblocks, 0))); + if (psb) { + deque_pop_front(block->subblocks, &v); + iamf_parameter_subblock_free(psb); + } + } + + // The elapsed time is a negative value, which means that there is a + // gaps in the parameters. When new parameters are added, the elapsed + // time will return to the normal value. + // By default, the elapsed time is constant in the process of 1~n-1 + // times. + block->elapsed = block->duration - block->elapsed; + block->duration = 0; + } + } + } else { + block->reset_start_time = 1; + } + + debug("E: pid %u, duration %u, elapsed %d", block->base->parameter_id, + block->duration, block->elapsed, + block->elapsed < 0 || block->elapsed > block->duration + ? "." + : ", in gaps."); + } + return IAMF_OK; +} + +static int _iadb_mix_presentation_obu_find(value_wrap_t item, + value_wrap_t key) { + return def_value_wrap_type_ptr(iamf_mix_presentation_obu_t, &item) + ->mix_presentation_id == key.u32; +} +static int _iadb_audio_element_obu_find(value_wrap_t item, value_wrap_t key) { + return def_value_wrap_type_ptr(iamf_audio_element_obu_t, &item) + ->audio_element_id == key.u32; +} + +static int _iadb_descriptor_init(iamf_database_t *database) { + database->descriptors.codec_config_obus = vector_new(); + database->descriptors.audio_element_obus = vector_new(); + database->descriptors.mix_presentation_obus = vector_new(); + + database->codec_configs = vector_new(); + database->audio_elements = vector_new(); + + if (!database->descriptors.codec_config_obus || + !database->descriptors.audio_element_obus || + !database->descriptors.mix_presentation_obus || + !database->codec_configs || !database->audio_elements) { + def_err_msg_enomem("descriptors", "Database"); + return IAMF_ERR_ALLOC_FAIL; + } + return IAMF_OK; +} + +static void _iadb_descriptor_uninit(iamf_database_t *database) { + if (database->descriptors.ia_sequence_header_obu) + iamf_sequence_header_obu_free(database->descriptors.ia_sequence_header_obu); + if (database->descriptors.codec_config_obus) + vector_free(database->descriptors.codec_config_obus, + def_default_free_ptr(iamf_codec_config_obu_free)); + if (database->descriptors.audio_element_obus) + vector_free(database->descriptors.audio_element_obus, + def_default_free_ptr(iamf_audio_element_obu_free)); + if (database->descriptors.mix_presentation_obus) + vector_free(database->descriptors.mix_presentation_obus, + def_default_free_ptr(iamf_mix_presentation_obu_free)); + memset(&database->descriptors, 0, sizeof(database->descriptors)); + + if (database->codec_configs) + vector_free(database->codec_configs, def_default_free_ptr(free)); + if (database->audio_elements) + vector_free(database->audio_elements, def_default_free_ptr(free)); + debug("uninit descriptors obus."); +} + +static int _iadb_descriptors_codec_config_obu_check_profile( + iamf_descriptors_t *descriptors, iamf_codec_config_obu_t *cco, + iamf_profile_t profile) { + int ret = def_pass; + switch (profile) { + case ck_iamf_profile_base_advanced: + case ck_iamf_profile_advanced_1: + case ck_iamf_profile_advanced_2: { + int n = vector_size(descriptors->codec_config_obus); + trace( + "Codec config count %d, profile %s, lpcm codec count %d, codec type " + "%s(0x%08x)", + n, iamf_profile_type_string(profile), descriptors->num_lpcm_codec, + iamf_codec_type_string(iamf_codec_type_get(cco->codec_id)), + cco->codec_id); + if ((n > def_max_codec_configs) || + (n && !descriptors->num_lpcm_codec && + cco->codec_id != ck_iamf_codec_id_lpcm)) { + warning("Too many codec configs or no LPCM codec config."); + ret = def_error; + } + + // TODO: The frame sizes and the sample rates identified (implicitly or + // explicitly) by the two Codec Config OBUs SHALL be the same. + } break; + default: + break; + } + return ret; +} + +static int _iadb_descriptors_mix_presentation_obu_check_profile( + iamf_descriptors_t *descriptors, iamf_mix_presentation_obu_t *mpo, + iamf_profile_t profile) { + int ret = def_pass; + + // TODO: If num_sub_mixes = 1 in all Mix Presentation OBUs, there SHALL be + // only one unique Codec Config OBU. + // TODO: Every Audio Substreams used in the first sub-mix of all Mix + // Presentation OBUs SHALL be coded using the same Codec Config OBU. + + switch (profile) { + case ck_iamf_profile_base_advanced: { + uint32_t element_flags = 0; + uint32_t k = array_size(mpo->sub_mixes); + uint32_t m = vector_size(descriptors->mix_presentation_obus); + + for (int s = 0; s < k; ++s) { + obu_sub_mix_t *sub = + def_value_wrap_type_ptr(obu_sub_mix_t, array_at(mpo->sub_mixes, s)); + int n = array_size(sub->audio_element_configs); + + for (int i = 0; i < n; ++i) { + value_wrap_t v; + obu_audio_element_config_t *aec = + def_value_wrap_type_ptr(obu_audio_element_config_t, + array_at(sub->audio_element_configs, i)); + + int idx = vector_find(descriptors->audio_element_obus, + def_value_wrap_instance_u32(aec->element_id), + _iadb_audio_element_obu_find, &v); + iamf_audio_element_obu_t *aeo = def_value_wrap_type_ptr( + iamf_audio_element_obu_t, + vector_at(descriptors->audio_element_obus, idx)); + if (aeo->audio_element_type == ck_audio_element_type_object_based) + element_flags |= 1; + else + element_flags |= 2; + } + } + + if (!m && element_flags == 3) { + error( + "Object-based can't with channel-based or secen-based elements in " + "Mix Presentation OBU %u.", + mpo->mix_presentation_id); + ret = def_error; + } else if (m && element_flags & 1) { + error("Mix Presentation OBU %u with object-based must be first.", + mpo->mix_presentation_id); + ret = def_error; + } + + if (ret != def_pass) + warning( + "Mix Presentation OBU %u, element flags 0x%x(b01-obj, b10-chn), " + "mix count %u", + mpo->mix_presentation_id, element_flags, m); + + } break; + default: + break; + } + return ret; +} + +static int _iadb_descriptor_obu_check_profile(iamf_descriptors_t *descriptors, + iamf_obu_t *obu, + iamf_profile_t profile) { + int ret = def_pass; + switch (obu->obu_type) { + case ck_iamf_obu_codec_config: { + iamf_codec_config_obu_t *cco = def_codec_config_obu_ptr(obu); + ret = _iadb_descriptors_codec_config_obu_check_profile(descriptors, cco, + profile); + } break; + case ck_iamf_obu_audio_element: { + iamf_audio_element_obu_t *aeo = def_audio_element_obu_ptr(obu); + ret = iamf_audio_element_obu_check_profile(aeo, profile); + } break; + + case ck_iamf_obu_mix_presentation: { + iamf_mix_presentation_obu_t *mpo = def_mix_presentation_obu_ptr(obu); + ret = iamf_mix_presentation_obu_check_profile( + mpo, descriptors->audio_element_obus, profile); + if (ret == def_pass) + ret = _iadb_descriptors_mix_presentation_obu_check_profile( + descriptors, mpo, profile); + + } break; + + default: + break; + } + + return ret; +} + +static codec_config_t *_iadb_codec_config_new(iamf_codec_config_obu_t *obu) { + codec_config_t *cc = def_mallocz(codec_config_t, 1); + if (!cc) return 0; + + cc->id = obu->codec_config_id; + cc->codec_config_obu = obu; + iamf_codec_config_obu_get_parameter(obu, &cc->codec_param); + return cc; +} + +#define _iadb_codec_config_free free + +static int _iadb_codec_config_obu_add(iamf_database_t *database, + iamf_codec_config_obu_t *obu) { + int ret = IAMF_OK; + codec_config_t *cc = _iadb_codec_config_new(obu); + if (!cc) return IAMF_ERR_ALLOC_FAIL; + + vector_push(database->codec_configs, def_value_wrap_instance_ptr(cc)); + if (vector_push(database->descriptors.codec_config_obus, + def_value_wrap_instance_ptr(obu)) < 0) { + ret = IAMF_ERR_ALLOC_FAIL; + } + + if (obu->codec_id == ck_iamf_codec_id_lpcm) + ++database->descriptors.num_lpcm_codec; + + return ret; +} + +int _iadb_codec_config_find(value_wrap_t item, value_wrap_t key) { + return def_value_wrap_type_ptr(codec_config_t, &item)->id == key.u32; +} + +int _iadb_audio_element_find(value_wrap_t item, value_wrap_t key) { + return def_value_wrap_type_ptr(audio_element_t, &item)->id == key.u32; +} + +static int _iadb_audio_element_obu_add(iamf_database_t *database, + iamf_audio_element_obu_t *obu) { + int ret = IAMF_OK; + audio_element_t *ae = 0; + codec_config_t *cc = 0; + parameter_base_t *pb = 0; + value_wrap_t v; + + if (vector_find(database->codec_configs, + def_value_wrap_instance_u32(obu->codec_config_id), + _iadb_codec_config_find, &v) < 0) { + warning("Can not find codec config with id %u for audio element %u", + obu->codec_config_id, obu->audio_element_id); + return IAMF_ERR_BAD_ARG; + } + cc = v.ptr; + + if (vector_find(database->audio_elements, + def_value_wrap_instance_u32(obu->audio_element_id), + _iadb_audio_element_find, &v) >= 0) { + debug("audio element %u is already in database.", obu->audio_element_id); + return IAMF_OK; + } + + ae = def_mallocz(audio_element_t, 1); + if (!ae) return IAMF_ERR_ALLOC_FAIL; + + ae->id = obu->audio_element_id; + ae->codec_config = cc; + ae->audio_element_obu = obu; + pb = iamf_audio_element_obu_get_parameter(obu, + ck_iamf_parameter_type_demixing); + ae->demixing_info_id = pb ? pb->parameter_id : def_i32_id_none; + if (pb) + _iadb_parameter_block_manager_add(&database->parameter_block_manager, pb); + pb = iamf_audio_element_obu_get_parameter(obu, + ck_iamf_parameter_type_recon_gain); + ae->recon_gain_id = pb ? pb->parameter_id : def_i32_id_none; + if (pb) + _iadb_parameter_block_manager_add(&database->parameter_block_manager, pb); + + vector_push(database->descriptors.audio_element_obus, + def_value_wrap_instance_ptr(obu)); + vector_push(database->audio_elements, def_value_wrap_instance_ptr(ae)); + + if (obu->audio_element_type == ck_audio_element_type_object_based) + ++database->descriptors.num_object_elements; + + return ret; +} + +static int _iadb_mix_presentation_obu_add(iamf_database_t *database, + iamf_mix_presentation_obu_t *obu) { + parameter_block_manager_t *pm = &database->parameter_block_manager; + uint32_t k = array_size(obu->sub_mixes); + for (int s = 0; s < k; ++s) { + obu_sub_mix_t *sub = + def_value_wrap_type_ptr(obu_sub_mix_t, array_at(obu->sub_mixes, s)); + int n = array_size(sub->audio_element_configs); + + for (int i = 0; i < n; ++i) { + obu_audio_element_config_t *aec = def_value_wrap_type_ptr( + obu_audio_element_config_t, array_at(sub->audio_element_configs, i)); + int m = array_size(aec->rendering_config.parameters); + for (int j = 0; j < m; ++j) { + parameter_base_t *pb = def_param_base_ptr( + def_value_wrap_ptr(array_at(aec->rendering_config.parameters, j))); + if (pb) _iadb_parameter_block_manager_add(pm, pb); + } + _iadb_parameter_block_manager_add( + pm, def_param_base_ptr(&aec->element_mix_gain)); + } + _iadb_parameter_block_manager_add( + pm, def_param_base_ptr(&sub->output_mix_gain)); + + int loudness_count = array_size(sub->loudness); + for (int i = 0; i < loudness_count; ++i) { + obu_loudness_info_t *loudness_info = def_value_wrap_type_ptr( + obu_loudness_info_t, array_at(sub->loudness, i)); + + if (loudness_info->info_type & def_loudness_info_type_momentary) { + _iadb_parameter_block_manager_add( + pm, + def_param_base_ptr( + &loudness_info->momentary_loudness.momentary_loudness_param)); + } + } + } + + vector_push(database->descriptors.mix_presentation_obus, + def_value_wrap_instance_ptr(obu)); + + return IAMF_OK; +} + +static int _iadb_parameter_block_obu_add(iamf_database_t *database, + iamf_parameter_block_obu_t *obu) { + parameter_block_manager_t *pm = &database->parameter_block_manager; + return _iadb_parameter_block_manager_add_obu(pm, obu); +} + +static int _iadb_audio_element_find_with_pid(value_wrap_t item, + value_wrap_t key) { + audio_element_t *ae = def_value_wrap_type_ptr(audio_element_t, &item); + return ae->demixing_info_id == key.u32 || ae->recon_gain_id == key.u32; +} + +static int _iadb_audio_element_config_find(value_wrap_t item, + value_wrap_t key) { + return def_value_wrap_type_ptr(obu_audio_element_config_t, &item) + ->element_id == key.u32; +} + +static parameter_subblock_t *_iadb_parameter_block_get_subblock( + iamf_database_t *database, uint32_t pid, uint32_t offset) { + parameter_block_t *pbk = iamf_database_get_parameter_block(database, pid); + parameter_subblock_t *subblock = 0, *s = 0; + uint32_t start; + int count; + + if (!pbk) return 0; + + start = pbk->elapsed + offset; + count = deque_length(pbk->subblocks); + + for (int i = 0; i < count; ++i) { + s = def_parameter_subblock_ptr( + def_value_wrap_optional_ptr(deque_at(pbk->subblocks, i))); + if (start < s->subblock_duration) { + subblock = s; + break; + } else { + start -= s->subblock_duration; + } + } + return subblock; +} + +int iamf_database_init(iamf_database_t *database) { + memset(database, 0, sizeof(iamf_database_t)); + + if (_iadb_descriptor_init(database) != IAMF_OK || + _iadb_parameter_block_manager_init(&database->parameter_block_manager) != + IAMF_OK) { + iamf_database_uninit(database); + return IAMF_ERR_ALLOC_FAIL; + } + + return IAMF_OK; +} + +void iamf_database_uninit(iamf_database_t *database) { + trace("uninit database..."); + if (!database) return; + + _iadb_descriptor_uninit(database); + _iadb_parameter_block_manager_uninit(&database->parameter_block_manager); + memset(database, 0, sizeof(iamf_database_t)); +} + +int iamf_database_reset_descriptors(iamf_database_t *database) { + iamf_profile_t profile = database->profile; + iamf_database_uninit(database); + iamf_database_init(database); + database->profile = profile; + return IAMF_OK; +} + +int iamf_database_set_profile(iamf_database_t *database, + iamf_profile_t profile) { + if (profile == ck_iamf_profile_none || def_iamf_profile_count <= profile) + return IAMF_ERR_BAD_ARG; + database->profile = profile; + return IAMF_OK; +} + +iamf_profile_t iamf_database_get_profile(iamf_database_t *database) { + if (!database) return ck_iamf_profile_none; + return database->profile; +} + +int iamf_database_add_obu(iamf_database_t *database, iamf_obu_t *obu) { + int ret; + + if (!obu) return IAMF_ERR_BAD_ARG; + + if (database->descriptors.state == ck_descriptors_state_none) { + debug("Processing OBU type: %s", iamf_obu_type_string(obu->obu_type)); + if (obu->obu_type != ck_iamf_obu_sequence_header) { + iamf_obu_free(obu); + return IAMF_ERR_INVALID_STATE; + } else { + info("Get IA Sequence Header OBU."); + } + } + + ret = _iadb_descriptor_obu_check_profile(&database->descriptors, obu, + database->profile); + + if (ret < def_pass) { + debug("Profile check failed for OBU type: %s", + iamf_obu_type_string(obu->obu_type)); + iamf_obu_free(obu); + return ret == def_error ? IAMF_ERR_INTERNAL : IAMF_ERR_INVALID_PACKET; + } + + ret = IAMF_ERR_INTERNAL; + + switch (obu->obu_type) { + case ck_iamf_obu_sequence_header: { + iamf_sequence_header_obu_t *sho = def_iamf_sequence_header_obu_ptr(obu); + + if (sho->primary_profile > database->profile) { + error("Not support profile %u ia sequence.", sho->primary_profile); + ret = IAMF_ERR_UNIMPLEMENTED; + break; + } + + if (database->profile > sho->additional_profile) + database->profile = sho->additional_profile; + + if (database->descriptors.ia_sequence_header_obu) { + warning("WARNING : Receive IAMF Sequence Header OBU again !!!"); + iamf_sequence_header_obu_free( + database->descriptors.ia_sequence_header_obu); + } + + database->descriptors.ia_sequence_header_obu = sho; + database->descriptors.state = ck_descriptors_state_processing; + ret = IAMF_OK; + break; + } + case ck_iamf_obu_codec_config: + ret = _iadb_codec_config_obu_add(database, def_codec_config_obu_ptr(obu)); + break; + case ck_iamf_obu_audio_element: + ret = + _iadb_audio_element_obu_add(database, def_audio_element_obu_ptr(obu)); + break; + case ck_iamf_obu_mix_presentation: + ret = _iadb_mix_presentation_obu_add(database, + def_mix_presentation_obu_ptr(obu)); + break; + case ck_iamf_obu_parameter_block: + ret = _iadb_parameter_block_obu_add(database, + def_parameter_block_obu_ptr(obu)); + iamf_obu_free(obu); + obu = 0; + break; + default: + debug("Iamf %s Obu(%d) is not needed in database.", + iamf_obu_type_string(obu->obu_type), obu->obu_type); + ret = IAMF_ERR_UNIMPLEMENTED; + } + + if (ret < 0 && obu) iamf_obu_free(obu); + return ret; +} + +audio_element_t *iamf_database_get_audio_element(iamf_database_t *database, + uint32_t id) { + value_wrap_t v; + if (vector_find(database->audio_elements, def_value_wrap_instance_u32(id), + _iadb_audio_element_find, &v) >= 0) + return def_value_wrap_type_ptr(audio_element_t, &v); + return 0; +} + +iamf_codec_config_obu_t *iamf_database_get_codec_config_obu( + iamf_database_t *database, uint32_t id) { + value_wrap_t v; + if (vector_find(database->codec_configs, def_value_wrap_instance_u32(id), + _iadb_codec_config_find, &v) >= 0) { + codec_config_t *cc = def_value_wrap_type_ptr(codec_config_t, &v); + return cc ? cc->codec_config_obu : 0; + } + return 0; +} + +audio_element_t *iamf_database_get_audio_element_with_pid( + iamf_database_t *database, uint32_t pid) { + value_wrap_t v; + if (vector_find(database->audio_elements, def_value_wrap_instance_u32(pid), + _iadb_audio_element_find_with_pid, &v) >= 0) { + return def_value_wrap_type_ptr(audio_element_t, &v); + } + return 0; +} + +iamf_audio_element_obu_t *iamf_database_get_audio_element_obu( + iamf_database_t *database, uint32_t eid) { + audio_element_t *ae = iamf_database_get_audio_element(database, eid); + return ae ? ae->audio_element_obu : 0; +} + +iamf_mix_presentation_obu_t *iamf_database_get_mix_presentation_obu( + iamf_database_t *database, uint32_t id) { + value_wrap_t v; + + return vector_find(database->descriptors.mix_presentation_obus, + def_value_wrap_instance_u32(id), + _iadb_mix_presentation_obu_find, &v) < 0 + ? 0 + : def_value_wrap_type_ptr(iamf_mix_presentation_obu_t, &v); +} + +iamf_mix_presentation_obu_t *iamf_database_get_mix_presentation_obu_default( + iamf_database_t *database) { + if (!database) return 0; + + int n = vector_size(database->descriptors.mix_presentation_obus); + if (n <= 0) return 0; + + // Return the first mix presentation OBU in the database + return def_value_wrap_type_ptr( + iamf_mix_presentation_obu_t, + vector_at(database->descriptors.mix_presentation_obus, 0)); +} + +iamf_mix_presentation_obu_t *iamf_database_find_mix_presentation_obu( + iamf_database_t *database, func_mix_presentation_obu_check_t check_func, + iamf_layout_t target_layout) { + if (!database || !check_func) return 0; + + int n = vector_size(database->descriptors.mix_presentation_obus); + + for (int i = 0; i < n; ++i) { + iamf_mix_presentation_obu_t *obu = def_value_wrap_type_ptr( + iamf_mix_presentation_obu_t, + vector_at(database->descriptors.mix_presentation_obus, i)); + + if (obu && check_func(obu, target_layout, database)) return obu; + } + return 0; +} + +iamf_mix_presentation_obu_t * +iamf_database_find_mix_presentation_obu_with_highest_layout( + iamf_database_t *database, iamf_layout_t reference_layout) { + iamf_mix_presentation_obu_t *selected_mpo = 0; + iamf_layout_t highest_layout = + def_sound_system_layout_instance(SOUND_SYSTEM_NONE); + + int n = vector_size(database->descriptors.mix_presentation_obus); + + for (int i = 0; i < n; ++i) { + iamf_mix_presentation_obu_t *obu = def_value_wrap_type_ptr( + iamf_mix_presentation_obu_t, + vector_at(database->descriptors.mix_presentation_obus, i)); + + if (obu && array_size(obu->sub_mixes) > 0) { + // Traverse all sub_mixes in the mix presentation + int m = array_size(obu->sub_mixes); + for (int j = 0; j < m; ++j) { + obu_sub_mix_t *sub = + def_value_wrap_optional_ptr(array_at(obu->sub_mixes, j)); + + if (sub && array_size(sub->loudness_layouts) > 0) { + int layout_count = array_size(sub->loudness_layouts); + for (int k = 0; k < layout_count; ++k) { + iamf_layout_t *layout = + def_value_wrap_optional_ptr(array_at(sub->loudness_layouts, k)); + if (!layout) continue; + + if ((iamf_layout_higher_check(*layout, reference_layout, 0) || + (iamf_layout_is_equal( + highest_layout, + def_sound_system_layout_instance(SOUND_SYSTEM_NONE)) && + iamf_layout_higher_check(*layout, reference_layout, 1))) && + iamf_layout_higher_check(*layout, highest_layout, 0)) { + highest_layout = *layout; + selected_mpo = obu; + debug("Selected MPO: %u, Layout: %s", obu->mix_presentation_id, + iamf_layout_string(highest_layout)); + } + } + } + } + } + } + + return selected_mpo; +} + +iamf_audio_element_obu_t *iamf_database_get_audio_element_obu_with_pid( + iamf_database_t *database, uint32_t pid) { + audio_element_t *ae = iamf_database_get_audio_element_with_pid(database, pid); + return ae ? ae->audio_element_obu : 0; +} + +parameter_base_t *iamf_database_get_parameter_base(iamf_database_t *database, + uint32_t pid) { + parameter_block_t *pbk = iamf_database_get_parameter_block(database, pid); + return pbk ? pbk->base : 0; +} + +parameter_block_t *iamf_database_get_parameter_block(iamf_database_t *database, + uint32_t parameter_id) { + value_wrap_t v; + return vector_find(database->parameter_block_manager.parameter_blocks, + def_value_wrap_instance_u32(parameter_id), + _iadb_parameter_block_find, &v) >= 0 + ? def_value_wrap_type_ptr(parameter_block_t, &v) + : 0; +} + +int iamf_database_enable_parameter_block(iamf_database_t *database, + uint32_t pid) { + value_wrap_t v; + if (vector_find(database->parameter_block_manager.parameter_blocks, + def_value_wrap_instance_u32(pid), _iadb_parameter_block_find, + &v) >= 0) { + parameter_block_t *pbk = def_value_wrap_type_ptr(parameter_block_t, &v); + pbk->enabled = 1; + debug("enable parameter block with id %u", pid); + return 1; + } + return 0; +} + +int iamf_database_enable_mix_presentation_parameter_blocks( + iamf_database_t *database, uint32_t pid) { + iamf_mix_presentation_obu_t *mpo = + iamf_database_get_mix_presentation_obu(database, pid); + int num_sub_mixes = 0; + if (!mpo) return IAMF_ERR_BAD_ARG; + + num_sub_mixes = array_size(mpo->sub_mixes); + + for (int i = 0; i < num_sub_mixes; i++) { + obu_sub_mix_t *sub = + def_value_wrap_optional_ptr(array_at(mpo->sub_mixes, i)); + int num_configs = 0; + if (!sub) continue; + + num_configs = array_size(sub->audio_element_configs); + for (int j = 0; j < num_configs; j++) { + obu_audio_element_config_t *config = + def_value_wrap_optional_ptr(array_at(sub->audio_element_configs, j)); + audio_element_t *ae = 0; + if (!config) continue; + + ae = iamf_database_get_audio_element(database, config->element_id); + if (ae->demixing_info_id != def_i32_id_none) + iamf_database_enable_parameter_block(database, ae->demixing_info_id); + if (ae->recon_gain_id != def_i32_id_none) + iamf_database_enable_parameter_block(database, ae->recon_gain_id); + + iamf_database_enable_parameter_block( + database, config->element_mix_gain.base.parameter_id); + } + iamf_database_enable_parameter_block( + database, sub->output_mix_gain.base.parameter_id); + } + + return IAMF_OK; +} + +int iamf_database_disable_parameter_blocks(iamf_database_t *database) { + int n = vector_size(database->parameter_block_manager.parameter_blocks); + for (int i = 0; i < n; ++i) { + parameter_block_t *pbk = def_value_wrap_type_ptr( + parameter_block_t, + vector_at(database->parameter_block_manager.parameter_blocks, i)); + if (pbk) pbk->enabled = 0; + } + return IAMF_OK; +} + +int iamf_database_disabled_parameter_blocks_clear(iamf_database_t *database) { + int n = vector_size(database->parameter_block_manager.parameter_blocks); + for (int i = 0; i < n; ++i) { + parameter_block_t *pbk = def_value_wrap_type_ptr( + parameter_block_t, + vector_at(database->parameter_block_manager.parameter_blocks, i)); + + if (pbk && !pbk->enabled && pbk->subblocks) { + deque_free(pbk->subblocks, + def_default_free_ptr(iamf_parameter_subblock_free)); + pbk->subblocks = deque_new(); + pbk->duration = 0; + pbk->elapsed = 0; + } + } + return IAMF_OK; +} + +int iamf_database_get_demix_mode(iamf_database_t *database, uint32_t pid, + uint32_t offset) { + demixing_info_parameter_subblock_t *subblock = + (demixing_info_parameter_subblock_t *)_iadb_parameter_block_get_subblock( + database, pid, offset); + return subblock ? subblock->demixing_mode : def_dmx_mode_none; +} + +array_t *iamf_database_get_recon_gain_present_flags(iamf_database_t *database, + uint32_t pid) { + array_t *flags = 0; + audio_element_t *ae = iamf_database_get_audio_element_with_pid(database, pid); + if (!ae) return 0; + + if (ae->audio_element_obu->audio_element_type == + ck_audio_element_type_channel_based) { + channel_based_audio_element_obu_t *cae = + def_channel_based_audio_element_obu_ptr(ae->audio_element_obu); + int n = array_size(cae->channel_audio_layer_configs); + flags = array_new(n); + if (!flags) return 0; + for (int i = 0; i < n; ++i) { + value_wrap_t *v; + obu_channel_layer_config_t *clc = def_value_wrap_optional_ptr( + array_at(cae->channel_audio_layer_configs, i)); + v = array_at(flags, i); + if (v) { + v->u32 = clc->recon_gain_is_present_flag; + } else { + continue; + } + } + } + + return flags; +} + +int iamf_database_get_subblocks(iamf_database_t *database, uint32_t pid, + fraction_t number, + parameter_subblock_t ***subblocks) { + parameter_block_t *pbk = iamf_database_get_parameter_block(database, pid); + uint32_t requested_count = number.numerator; + uint32_t requested_rate = number.denominator; + parameter_subblock_t *subblock = 0; + int count = 0; + + if (!pbk || !subblocks || !deque_length(pbk->subblocks)) + return IAMF_ERR_BAD_ARG; + + uint32_t converted_count; + if (requested_rate == pbk->base->parameter_rate) { + converted_count = requested_count; + } else { + converted_count = + iamf_fraction_transform(number, pbk->base->parameter_rate); + } + + debug( + "pid %u, converted_count %u, elapsed %d, duration %u, next_block_index " + "%d", + pid, converted_count, pbk->elapsed, pbk->duration, pbk->next_block_index); + + // for gaps in delay case. + if (pbk->elapsed > 0 && pbk->elapsed + converted_count > pbk->duration) { + warning("required subblocks exceed the duration of parameter block %u.", + pid); + return IAMF_ERR_BUFFER_TOO_SMALL; + } + + if (pbk->elapsed <= 0) { + if (!pbk->next_block_index) + return IAMF_ERR_BAD_ARG; + else if (pbk->next_block_index == -1) { + count = deque_length(pbk->subblocks); + *subblocks = def_mallocz(parameter_subblock_t *, count); + if (!*subblocks) return IAMF_ERR_ALLOC_FAIL; + for (int i = 0; i < count; ++i) { + subblock = (parameter_subblock_t *)def_value_wrap_optional_ptr( + deque_at(pbk->subblocks, i)); + if (subblock) (*subblocks)[i] = subblock; + } + return count; + } + } else { + uint32_t next_block_duration = 0; + if (pbk->next_block_index > 0) { + for (int i = 0; + i < pbk->next_block_index && i < deque_length(pbk->subblocks); ++i) { + subblock = (parameter_subblock_t *)def_value_wrap_optional_ptr( + deque_at(pbk->subblocks, i)); + next_block_duration += subblock->subblock_duration; + } + } + + if (pbk->elapsed + converted_count > next_block_duration && + pbk->next_block_index > 0) { + count = deque_length(pbk->subblocks) - pbk->next_block_index; + if (count > 0) { + *subblocks = def_mallocz(parameter_subblock_t *, count); + if (!*subblocks) return IAMF_ERR_ALLOC_FAIL; + for (int i = pbk->next_block_index; i < deque_length(pbk->subblocks); + ++i) { + subblock = (parameter_subblock_t *)def_value_wrap_optional_ptr( + deque_at(pbk->subblocks, i)); + if (subblock) (*subblocks)[i - pbk->next_block_index] = subblock; + } + return count; + } + } + } + + *subblocks = 0; + debug("No subblocks found for pid %u", pid); + return 0; +} + +uint32_t iamf_database_get_parameter_rate(iamf_database_t *database, + uint32_t pid) { + parameter_block_t *pbk = iamf_database_get_parameter_block(database, pid); + return pbk ? pbk->base->parameter_rate : 0; +} + +int iamf_database_time_elapse(iamf_database_t *database, fraction_t time) { + return _iadb_parameter_block_manager_time_elapse( + &database->parameter_block_manager, time); +} + +int iamf_database_get_audio_element_default_demixing_info( + iamf_database_t *database, uint32_t eid, int *mode, int *weight_index) { + audio_element_t *ae = iamf_database_get_audio_element(database, eid); + if (!ae || ae->demixing_info_id == def_i32_id_none) return IAMF_ERR_BAD_ARG; + parameter_base_t *base = + iamf_database_get_parameter_base(database, ae->demixing_info_id); + if (!base) return IAMF_ERR_BAD_ARG; + demixing_info_parameter_base_t *dmx = def_demixing_info_param_base_ptr(base); + *mode = dmx->dmixp_mode; + *weight_index = dmx->default_w; + + return IAMF_OK; +} + +int iamf_database_get_audio_element_demix_mode(iamf_database_t *database, + uint32_t eid, + fraction_t offset) { + audio_element_t *ae = iamf_database_get_audio_element(database, eid); + if (!ae || ae->demixing_info_id == def_i32_id_none) { + return def_dmx_mode_none; + } + + // Convert fraction_t offset to uint32_t for the existing function + uint32_t offset_samples = iamf_fraction_transform(offset, 1); + + return iamf_database_get_demix_mode(database, ae->demixing_info_id, + offset_samples); +} + +descriptors_state_t iamf_database_descriptors_get_state( + iamf_database_t *database) { + return database->descriptors.state; +} + +int iamf_database_descriptors_complete(iamf_database_t *database) { + if (database->descriptors.state == ck_descriptors_state_processing && + (vector_size(database->descriptors.codec_config_obus) && + vector_size(database->descriptors.audio_element_obus) && + vector_size(database->descriptors.mix_presentation_obus))) { + database->descriptors.state = ck_descriptors_state_completed; + } + + return database->descriptors.state == ck_descriptors_state_completed; +} diff --git a/code/src/iamf_dec/iamf_database.h b/code/src/iamf_dec/iamf_database.h new file mode 100755 index 00000000..1e382409 --- /dev/null +++ b/code/src/iamf_dec/iamf_database.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_database.h + * @brief IAMF database APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_DATABASE_H__ +#define __IAMF_DATABASE_H__ + +#include "cdeque.h" +#include "cvector.h" +#include "iamf_obu_all.h" +#include "iamf_obu_parser.h" +#include "iamf_utils.h" + +#define def_parameter_block_ptr(a) def_ptr(parameter_block, a) +#define def_mix_gain_parameter_block_ptr(a) def_ptr(mix_gain_parameter_block, a) +#define def_polars_parameter_block_ptr(a) def_ptr(polars_parameter_block, a) +#define def_cartesians_parameter_block_ptr(a) \ + def_ptr(cartesians_parameter_block, a) + +typedef int (*func_mix_presentation_obu_check_t)(iamf_mix_presentation_obu_t *, + iamf_layout_t, void *); + +typedef enum EDBDescriptorsState { + ck_descriptors_state_none = 0, + ck_descriptors_state_processing, + ck_descriptors_state_completed, +} descriptors_state_t; + +typedef struct DBCodecConfig { + uint32_t id; + iamf_codec_config_obu_t *codec_config_obu; + + audio_codec_parameter_t codec_param; +} codec_config_t; + +/*** + * Audio Element Info + */ + +typedef struct DBAudioElement { + uint32_t id; + iamf_audio_element_obu_t *audio_element_obu; + + codec_config_t *codec_config; + + uint32_t demixing_info_id; + uint32_t recon_gain_id; +} audio_element_t; + +/*** + * Parameter Block Info + * */ + +typedef struct DBParameterBlock { + parameter_base_t *base; + deque_t *subblocks; + uint32_t duration; + int elapsed; + int enabled; + // Default start of first block is 0, this variable records the start position + // of second block, If 0, it means there is no second block. + int next_block_index; + int reset_start_time; +} parameter_block_t; + +typedef struct DBMixGainParameterBlock { + parameter_block_t parameter_block; + float end_gain; +} mix_gain_parameter_block_t; + +typedef struct DBPolarsParameterBlock { + parameter_block_t parameter_block; + uint32_t num_polars; + polar_t end_polars[2]; +} polars_parameter_block_t; + +typedef struct DBCartesiansParameterBlock { + parameter_block_t parameter_block; + uint32_t num_cartesians; + cartesian_t end_cartesians[2]; +} cartesians_parameter_block_t; + +typedef struct DBParameterBlockManager { + vector_t *parameter_blocks; // vector + + vector_t *demixing_infos; // vector + vector_t *recon_gains; // vector + vector_t *mix_gains; // vector + vector_t *coordinates; // vector +} parameter_block_manager_t; + +typedef struct IamfDescriptors { + iamf_sequence_header_obu_t *ia_sequence_header_obu; + + vector_t *codec_config_obus; + vector_t *audio_element_obus; + vector_t *mix_presentation_obus; + + int num_lpcm_codec; + int num_object_elements; + descriptors_state_t state; +} iamf_descriptors_t; + +/*** + * OBU Database Info + * */ + +typedef struct Iamf_Database { + iamf_descriptors_t descriptors; + + vector_t *codec_configs; // vector + vector_t *audio_elements; // vector + + parameter_block_manager_t parameter_block_manager; + + iamf_profile_t profile; +} iamf_database_t; + +// WARNING: it well be removed in the future. +typedef struct MixGainUnit { + int count; + float constant_gain; + float *gains; +} mix_gain_unit_t; + +/*** + * IAMF OBU Database APIs. + * */ + +int iamf_database_init(iamf_database_t *database); +void iamf_database_uninit(iamf_database_t *database); +int iamf_database_reset_descriptors(iamf_database_t *database); +int iamf_database_set_profile(iamf_database_t *database, + iamf_profile_t profile); +iamf_profile_t iamf_database_get_profile(iamf_database_t *database); + +int iamf_database_add_obu(iamf_database_t *database, iamf_obu_t *obu); +iamf_codec_config_obu_t *iamf_database_get_codec_config_obu( + iamf_database_t *database, uint32_t id); +audio_element_t *iamf_database_get_audio_element(iamf_database_t *database, + uint32_t id); +audio_element_t *iamf_database_get_audio_element_with_pid( + iamf_database_t *database, uint32_t pid); +iamf_audio_element_obu_t *iamf_database_get_audio_element_obu( + iamf_database_t *database, uint32_t eid); +iamf_audio_element_obu_t *iamf_database_get_audio_element_obu_with_pid( + iamf_database_t *database, uint32_t pid); +iamf_mix_presentation_obu_t *iamf_database_get_mix_presentation_obu( + iamf_database_t *database, uint32_t id); +iamf_mix_presentation_obu_t *iamf_database_get_mix_presentation_obu_default( + iamf_database_t *database); +iamf_mix_presentation_obu_t *iamf_database_find_mix_presentation_obu( + iamf_database_t *database, func_mix_presentation_obu_check_t check_func, + iamf_layout_t target_layout); +iamf_mix_presentation_obu_t * +iamf_database_find_mix_presentation_obu_with_highest_layout( + iamf_database_t *database, iamf_layout_t reference_layout); +parameter_base_t *iamf_database_get_parameter_base(iamf_database_t *database, + uint32_t pid); +parameter_block_t *iamf_database_get_parameter_block(iamf_database_t *database, + uint32_t pid); +int iamf_database_enable_parameter_block(iamf_database_t *database, + uint32_t pid); +int iamf_database_enable_mix_presentation_parameter_blocks( + iamf_database_t *database, uint32_t pid); +int iamf_database_disable_parameter_blocks(iamf_database_t *database); +int iamf_database_disabled_parameter_blocks_clear(iamf_database_t *database); +int iamf_database_get_demix_mode(iamf_database_t *database, uint32_t pid, + uint32_t offset); +array_t *iamf_database_get_recon_gain_present_flags(iamf_database_t *database, + uint32_t pid); +int iamf_database_get_subblocks(iamf_database_t *database, uint32_t pid, + fraction_t number, + parameter_subblock_t ***subblocks); +uint32_t iamf_database_get_parameter_rate(iamf_database_t *database, + uint32_t pid); +int iamf_database_time_elapse(iamf_database_t *database, fraction_t time); +int iamf_database_get_audio_element_default_demixing_info( + iamf_database_t *database, uint32_t eid, int *mode, int *weight_index); +int iamf_database_get_audio_element_demix_mode(iamf_database_t *database, + uint32_t eid, fraction_t offset); + +descriptors_state_t iamf_database_descriptors_get_state( + iamf_database_t *database); +int iamf_database_descriptors_complete(iamf_database_t *database); + +#endif // __IAMF_DATABASE_H__ diff --git a/code/src/iamf_dec/iamf_decoder.c b/code/src/iamf_dec/iamf_decoder.c new file mode 100755 index 00000000..dd55f081 --- /dev/null +++ b/code/src/iamf_dec/iamf_decoder.c @@ -0,0 +1,1430 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file IAMF_decoder.c + * @brief IAMF decoder. + * @version 2.0.0 + * @date Created 03/03/2023 + **/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "IAMF_decoder.h" +#include "clog.h" +#include "cvector.h" +#include "demixer.h" +#include "iamf_decoder_private.h" +#include "iamf_layout.h" +#include "iamf_obu_all.h" +#include "iamf_post_processor.h" +#include "iamf_private_definitions.h" +#include "iamf_renderer.h" +#include "iamf_string.h" +#include "iamf_utils.h" + +#undef def_log_tag +#define def_log_tag "IAMF_DEC" + +#define SR 0 +#if SR +extern void iamf_rec_stream_log(int eid, int chs, float *in, int size); +extern void iamf_mix_stream_log(int chs, float *out, int size); +extern void iamf_stream_log_free(); +#endif + +static int _matching_loudess_layout_check(iamf_mix_presentation_obu_t *mpo, + iamf_layout_t target_layout, + void *data) { + int m = array_size(mpo->sub_mixes); + for (int j = 0; j < m; ++j) { + obu_sub_mix_t *sub = + def_value_wrap_optional_ptr(array_at(mpo->sub_mixes, j)); + int n = array_size(sub->loudness_layouts); + + for (int i = 0; i < n; ++i) { + iamf_layout_t *check_layout = + def_value_wrap_optional_ptr(array_at(sub->loudness_layouts, i)); + if (!check_layout) continue; + if (iamf_layout_is_equal(target_layout, *check_layout)) return def_true; + } + } + + return def_false; +} + +static int _stereo_layout_and_headphones_check_internal( + iamf_mix_presentation_obu_t *mpo, void *data, int headphones) { + iamf_database_t *database = (iamf_database_t *)data; + if (array_size(mpo->sub_mixes) != 1) return def_false; + + obu_sub_mix_t *sub_mix = + def_value_wrap_optional_ptr(array_at(mpo->sub_mixes, 0)); + + if (array_size(sub_mix->audio_element_configs) != 1 || + array_size(sub_mix->loudness_layouts) != 1 || + !_matching_loudess_layout_check( + mpo, def_sound_system_layout_instance(SOUND_SYSTEM_A), data)) + return def_false; + + obu_audio_element_config_t *aec = + def_value_wrap_optional_ptr(array_at(sub_mix->audio_element_configs, 0)); + iamf_audio_element_obu_t *e = + iamf_database_get_audio_element_obu(database, aec->element_id); + + if (e && e->audio_element_type == ck_audio_element_type_channel_based) { + channel_based_audio_element_obu_t *cae = + def_channel_based_audio_element_obu_ptr(e); + if (array_size(cae->channel_audio_layer_configs) == 1) { + obu_channel_layer_config_t *clc = def_value_wrap_optional_ptr( + array_at(cae->channel_audio_layer_configs, 0)); + if (clc->loudspeaker_layout == ck_iamf_loudspeaker_layout_stereo && + (!headphones || !aec->rendering_config.headphones_rendering_mode)) + return def_true; + } + } + return def_false; +} + +static int _stereo_layout_and_headphones_check(iamf_mix_presentation_obu_t *mpo, + iamf_layout_t unused, + void *data) { + return _stereo_layout_and_headphones_check_internal(mpo, data, 1); +} + +static int _stereo_layout_check(iamf_mix_presentation_obu_t *mpo, + iamf_layout_t unused, void *data) { + return _stereo_layout_and_headphones_check_internal(mpo, data, 0); +} + +static int _binaural_layout_check(iamf_mix_presentation_obu_t *mpo, + iamf_layout_t unused, void *data) { + iamf_database_t *database = (iamf_database_t *)data; + if (array_size(mpo->sub_mixes) != 1) return def_false; + + obu_sub_mix_t *sub_mix = + def_value_wrap_optional_ptr(array_at(mpo->sub_mixes, 0)); + + if (array_size(sub_mix->audio_element_configs) != 1) return def_false; + + obu_audio_element_config_t *aec = + def_value_wrap_optional_ptr(array_at(sub_mix->audio_element_configs, 0)); + iamf_audio_element_obu_t *e = + iamf_database_get_audio_element_obu(database, aec->element_id); + + if (e && e->audio_element_type == ck_audio_element_type_channel_based) { + channel_based_audio_element_obu_t *cae = + def_channel_based_audio_element_obu_ptr(e); + if (array_size(cae->channel_audio_layer_configs) == 1) { + obu_channel_layer_config_t *clc = def_value_wrap_optional_ptr( + array_at(cae->channel_audio_layer_configs, 0)); + if (clc->loudspeaker_layout == ck_iamf_loudspeaker_layout_binaural) + return def_true; + } + } + + return def_false; +} + +static sample_format_t _get_sample_format(uint32_t bit_depth, int interleaved) { + if (bit_depth == 16) return ck_sample_format_i16_interleaved; + if (bit_depth == 24) return ck_sample_format_i24_interleaved; + if (bit_depth == 32) return ck_sample_format_i32_interleaved; + return ck_sample_format_i16_interleaved; +} + +static float iamf_mix_presentation_get_best_loudness( + iamf_mix_presentation_obu_t *obj, iamf_layout_t *layout) { + obu_sub_mix_t *sub; + float loudness_lkfs = def_default_loudness_lkfs; + iamf_layout_t highest_layout = + def_sound_system_layout_instance(SOUND_SYSTEM_NONE); + + int num_sub_mixes = array_size(obj->sub_mixes); + + for (int sub_idx = 0; sub_idx < num_sub_mixes; ++sub_idx) { + sub = def_value_wrap_optional_ptr(array_at(obj->sub_mixes, sub_idx)); + if (!sub) continue; + + int n = array_size(sub->loudness_layouts); + if (n <= 0) continue; + + for (int i = 0; i < n; ++i) { + iamf_layout_t *loudness_layout = + def_value_wrap_optional_ptr(array_at(sub->loudness_layouts, i)); + if (!loudness_layout) continue; + + if (iamf_layout_is_equal(*layout, *loudness_layout)) { + obu_loudness_info_t *li = + def_value_wrap_optional_ptr(array_at(sub->loudness, i)); + if (li) { + loudness_lkfs = + iamf_gain_q78_to_db(def_lsb_16bits(li->integrated_loudness)); + info( + "selected loudness %f db from exact match layout in sub_mix[%d] " + "<- 0x%x", + loudness_lkfs, sub_idx, def_lsb_16bits(li->integrated_loudness)); + return loudness_lkfs; + } + } + + if (iamf_layout_is_equal(highest_layout, def_sound_system_layout_instance( + SOUND_SYSTEM_NONE)) || + iamf_layout_higher_check(*loudness_layout, highest_layout, 1)) { + obu_loudness_info_t *li = + def_value_wrap_optional_ptr(array_at(sub->loudness, i)); + if (li) { + highest_layout = *loudness_layout; + loudness_lkfs = + iamf_gain_q78_to_db(def_lsb_16bits(li->integrated_loudness)); + debug( + "selected loudness %f db from highest layout in sub_mix[%d] <- " + "0x%x", + loudness_lkfs, sub_idx, def_lsb_16bits(li->integrated_loudness)); + } + } + } + } + + debug("selected loudness %f db from highest layout %s", loudness_lkfs, + iamf_layout_string(highest_layout)); + + return loudness_lkfs; +} + +static int iamf_decoder_priv_decode(iamf_decoder_t *self, const uint8_t *data, + int32_t size, uint32_t *rsize, void *pcm) { + iamf_decoder_context_t *ctx = &self->ctx; + iamf_presentation_t *pst = self->presentation; + iamf_audio_block_t *audio_block = 0; + iamf_audio_block_t *out = 0; + fraction_t frame_duration = self->ctx.frame_duration; + int ret = 0; + + if (data && size) { + *rsize = iamf_obu_parser_parse(self->parser, data, size); + + iamf_parser_state_t state = iamf_obu_parser_get_state(self->parser); + if (state == ck_iamf_parser_state_run) return 0; + if (state == ck_iamf_parser_state_switch) { + ctx->status = ck_iamf_decoder_status_reconfigure; + return IAMF_ERR_INVALID_STATE; + } + + ctx->status = ck_iamf_decoder_status_process; + audio_block = iamf_presentation_process(pst); + } else if (ctx->cache.decoder) { + ctx->status = ck_iamf_decoder_status_process; + while (1) { + audio_block = iamf_element_reconstructor_flush(self->reconstructor, + def_i32_id_none); + if (audio_block) { + ret = 1; + frame_duration.numerator = audio_block->num_samples_per_channel; + iamf_presentation_add_audio_block(pst, audio_block); +#if SR + iamf_rec_stream_log(audio_block->id, audio_block->num_channels, + audio_block->data, + audio_block->capacity_per_channel); +#endif + } else + break; + } + + if (ret) { + ctx->cache.decoder = 0; + audio_block = iamf_presentation_process(pst); + } + } + + if (audio_block) { + uint32_t _2nd_skip = audio_block->second_skip; + frame_duration.numerator -= _2nd_skip; + frame_duration.numerator -= audio_block->second_padding; + iamf_database_time_elapse(&self->ctx.database, frame_duration); + + if (_2nd_skip > 0) ctx->cache.decoder = _2nd_skip; + + audio_block->padding += audio_block->second_padding; + audio_block->second_padding = 0; + + if (audio_block->padding > 0) { + ctx->cache.padding += audio_block->padding; + audio_block->padding = 0; + if (ctx->cache.decoder && ctx->cache.padding > ctx->cache.decoder) { + audio_block->padding = ctx->cache.padding - ctx->cache.decoder; + ctx->cache.padding = ctx->cache.decoder = 0; + } else if (!ctx->cache.decoder) { + audio_block->padding = ctx->cache.padding; + ctx->cache.padding = 0; + } + debug("cache info: decoder %d, padding %d", ctx->cache.decoder, + ctx->cache.padding); + } + iamf_audio_block_trim(audio_block); + + if (!audio_block->num_samples_per_channel) { + iamf_audio_block_delete(audio_block); + ctx->status = ck_iamf_decoder_status_parse_2; + return 0; + } + + iamf_post_processor_process(self->post_processor, audio_block, &out); + iamf_audio_block_delete(audio_block); + } + + if (!data || !size) { + iamf_audio_block_t *ablocks[2] = {0}; + ablocks[0] = out; + iamf_post_processor_process(self->post_processor, 0, &ablocks[1]); + + if (ablocks[0] && ablocks[1]) { + out = iamf_audio_block_samples_concat(ablocks, 2); + iamf_audio_block_delete(ablocks[0]); + iamf_audio_block_delete(ablocks[1]); + } else if (ablocks[0]) + out = ablocks[0]; + else if (ablocks[1]) + out = ablocks[1]; + } + + if (out) { +#if SR + iamf_mix_stream_log(out->num_channels, out->data, + out->capacity_per_channel); +#endif + sample_format_t format = _get_sample_format(ctx->bit_depth, 1); + iamf_audio_block_copy_data(out, pcm, format); + ret = out->num_samples_per_channel; + iamf_audio_block_delete(out); + } + + ctx->status = ck_iamf_decoder_status_parse_2; + + return ret; +} + +static int iamf_decoder_priv_parse_descriptor_obus(iamf_decoder_t *self, + const uint8_t *data, + uint32_t size, + uint32_t *rsize) { + int ret = IAMF_OK; + uint32_t n = 0; + iamf_decoder_context_t *ctx = &self->ctx; + + n = iamf_obu_parser_parse(self->parser, data, size); + + if (iamf_database_descriptors_get_state(&ctx->database) == + ck_descriptors_state_completed) + self->ctx.status = ck_iamf_decoder_status_configure; + else + ret = IAMF_ERR_BUFFER_TOO_SMALL; + + if (rsize) *rsize = n; + return ret; +} + +static iamf_mix_presentation_obu_t *iamf_decoder_priv_get_best_mix_presentation( + iamf_decoder_t *self) { + iamf_decoder_context_t *ctx = &self->ctx; + iamf_database_t *database = &ctx->database; + iamf_layout_t target_layout = ctx->layout; + iamf_mix_presentation_obu_t *obu = 0; + + if (ctx->layout.type == ck_iamf_layout_type_binaural) { + obu = iamf_database_find_mix_presentation_obu( + database, _binaural_layout_check, target_layout); + if (obu) return obu; + + obu = iamf_database_find_mix_presentation_obu( + database, _matching_loudess_layout_check, target_layout); + if (obu) return obu; + } else if (ctx->layout.type == + ck_iamf_layout_type_loudspeakers_ss_convention) { + if (ctx->layout.sound_system == SOUND_SYSTEM_A) { + obu = iamf_database_find_mix_presentation_obu( + database, _stereo_layout_and_headphones_check, target_layout); + if (obu) return obu; + + obu = iamf_database_find_mix_presentation_obu( + database, _stereo_layout_check, target_layout); + if (obu) return obu; + } else { + obu = iamf_database_find_mix_presentation_obu( + database, _matching_loudess_layout_check, target_layout); + if (obu) return obu; + } + } + + obu = iamf_database_find_mix_presentation_obu_with_highest_layout( + database, target_layout); + return obu ? obu : iamf_database_get_mix_presentation_obu_default(database); +} + +static int iamf_decoder_priv_enable_mix_presentation( + iamf_decoder_t *self, iamf_mix_presentation_obu_t *mpo) { + iamf_decoder_context_t *ctx = &self->ctx; + iamf_database_t *database = &ctx->database; + iamf_presentation_t *old = self->presentation; + iamf_presentation_t *pst; + + pst = iamf_presentation_create(mpo->mix_presentation_id, database, + self->reconstructor, ctx->layout); + if (!pst) return IAMF_ERR_ALLOC_FAIL; + + debug("enable mix presentation id %u, %p", mpo->mix_presentation_id, mpo); + + iamf_database_disable_parameter_blocks(database); + iamf_database_enable_mix_presentation_parameter_blocks( + database, mpo->mix_presentation_id); + iamf_database_disabled_parameter_blocks_clear(database); + self->presentation = pst; + + if (old) iamf_presentation_destroy(old); + + return IAMF_OK; +} + +int iamf_decoder_priv_update_frame_info(iamf_decoder_t *self) { + iamf_decoder_context_t *ctx = &self->ctx; + iamf_database_t *database = &ctx->database; + iamf_mix_presentation_obu_t *mix_presentation_obu = 0; + obu_sub_mix_t *sub_mix = 0; + obu_audio_element_config_t *audio_element_config = 0; + audio_element_t *audio_element = 0; + codec_config_t *codec_config = 0; + uint32_t id = iamf_presentation_get_id(self->presentation); + + int ret = IAMF_ERR_INTERNAL; + + uint32_t sample_rate = 0; + uint32_t num_samples_per_frame = 0; + + mix_presentation_obu = iamf_database_get_mix_presentation_obu(database, id); + int num_sub_mixes = array_size(mix_presentation_obu->sub_mixes); + + for (int i = 0; i < num_sub_mixes; ++i) { + sub_mix = def_value_wrap_optional_ptr( + array_at(mix_presentation_obu->sub_mixes, i)); + + int n = array_size(sub_mix->audio_element_configs); + for (int j = 0; j < n; ++j) { + audio_element_config = def_value_wrap_optional_ptr( + array_at(sub_mix->audio_element_configs, j)); + audio_element = iamf_database_get_audio_element( + database, audio_element_config->element_id); + codec_config = audio_element->codec_config; + if (!sample_rate) { + sample_rate = codec_config->codec_param.sample_rate; + num_samples_per_frame = codec_config->codec_param.frame_size; + ret = IAMF_OK; + } else if (sample_rate != codec_config->codec_param.sample_rate || + num_samples_per_frame != + codec_config->codec_param.frame_size) { + warning("Different sample rate or frame size found."); + ret = IAMF_ERR_UNIMPLEMENTED; + } + } + } + + if (ret == IAMF_OK) { + ctx->frame_duration.numerator = num_samples_per_frame; + ctx->frame_duration.denominator = sample_rate; + info("Frame duration updated for presentation %u: %u/%u.", id, + ctx->frame_duration.numerator, ctx->frame_duration.denominator); + } + + return ret; +} + +int iamf_decoder_priv_configure(iamf_decoder_t *self, const uint8_t *data, + uint32_t size, uint32_t *rsize) { + int ret = IAMF_OK; + iamf_decoder_context_t *ctx; + iamf_database_t *database; + + trace("self %p, data %p, size %d", self, data, size); + + if (!self) return IAMF_ERR_BAD_ARG; + + ctx = &self->ctx; + database = &ctx->database; + + if (self->post_processor && + (ctx->configure_flags & def_iamf_decoder_config_output_layout)) { + info("Initialize post processor."); + iamf_post_processor_init(self->post_processor, self->ctx.sampling_rate, + iamf_layout_channels_count(&self->ctx.layout)); + if (ctx->enable_limiter) + iamf_post_processor_enable_limiter(self->post_processor, + self->ctx.limiter_threshold_db); + ctx->configure_flags &= ~def_iamf_decoder_config_output_layout; + } + + if (data && size > 0) { + if (ctx->status == ck_iamf_decoder_status_init) + ctx->status = ck_iamf_decoder_status_parse_1; + else if (ctx->status == ck_iamf_decoder_status_parse_2) + ctx->status = ck_iamf_decoder_status_reconfigure; + + if (ctx->status == ck_iamf_decoder_status_reconfigure) { + info("Reconfigure decoder."); + iamf_database_reset_descriptors(database); + ctx->status = ck_iamf_decoder_status_parse_1; + } + + ret = iamf_decoder_priv_parse_descriptor_obus(self, data, size, rsize); + } else if (ctx->configure_flags) { + info("configure flags 0x%x", ctx->configure_flags); + if (ctx->status < ck_iamf_decoder_status_configure) { + error("Decoder need configure with descriptor obus. status %d", + ctx->status); + return IAMF_ERR_BAD_ARG; + } + + if (ctx->configure_flags & def_iamf_decoder_config_mix_presentation) { + if (!iamf_database_get_mix_presentation_obu(database, + ctx->mix_presentation_id)) { + warning("Invalid mix presentation id %" PRId64 ".", + ctx->mix_presentation_id); + return IAMF_ERR_INTERNAL; + } + } + + } else { + error("Decoder need configure with descriptor obus."); + return IAMF_ERR_BAD_ARG; + } + + ctx->configure_flags = 0; + + if (ret == IAMF_OK) { + iamf_mix_presentation_obu_t *mpo = 0; + + if (ctx->mix_presentation_id != def_i64_id_none) + mpo = iamf_database_get_mix_presentation_obu(database, + ctx->mix_presentation_id); + else { + mpo = iamf_decoder_priv_get_best_mix_presentation(self); + ctx->mix_presentation_id = mpo->mix_presentation_id; + } + + if (mpo) { + info("get mix presentation id %u", + mpo ? mpo->mix_presentation_id : def_i32_id_none); + ret = iamf_decoder_priv_enable_mix_presentation(self, mpo); + if (ret != IAMF_OK) { + error("Fail to enable mix presentation %u.", mpo->mix_presentation_id); + } else { + if (ctx->layout.type == ck_iamf_layout_type_binaural) { + iamf_presentation_set_head_rotation(self->presentation, + &ctx->head_rotation); + iamf_presentation_enable_head_tracking(self->presentation, + ctx->head_tracking_enabled); + } + + // Set element gain offset to presentation. + if (ctx->element_gains && hash_map_size(ctx->element_gains) > 0) { + hash_map_iterator_t *iter = hash_map_iterator_new(ctx->element_gains); + if (iter) { + do { + uint32_t element_id = hash_map_iterator_get_key(iter); + value_wrap_t *value = hash_map_iterator_get_value(iter); + if (value) { + float gain_offset = def_value_wrap_f32(value); + int ret = iamf_presentation_set_element_gain_offset( + self->presentation, element_id, gain_offset); + if (ret == IAMF_OK) { + info( + "Applied gain offset %f to element %u in presentation %u", + gain_offset, element_id, mpo->mix_presentation_id); + } else { + warning( + "Failed to apply gain offset %f to element %u in " + "presentation %u: %d", + gain_offset, element_id, mpo->mix_presentation_id, ret); + } + } + } while (!hash_map_iterator_next(iter)); + hash_map_iterator_delete(iter); + } + // Clear element gains after applying to presentation + hash_map_delete(ctx->element_gains, 0); + ctx->element_gains = 0; + info("Cleared element gains after applying to presentation %u", + mpo->mix_presentation_id); + } + + // Check if the sampling rate of the stream in presentation matches the + // configured sampling rate + int in_sampling_rate = + iamf_presentation_get_sampling_rate(self->presentation); + if (in_sampling_rate == ctx->sampling_rate) { + iamf_post_processor_disable_resampler(self->post_processor); + } else { + ret = iamf_post_processor_enable_resampler(self->post_processor, + in_sampling_rate); + if (ret != IAMF_OK) { + error("Fail to enable resampler for presentation %u.", + mpo->mix_presentation_id); + return ret; + } + } + + ret = iamf_decoder_priv_update_frame_info(self); + if (ret == IAMF_OK) { + self->ctx.status = ck_iamf_decoder_status_parse_2; + self->ctx.loudness_lkfs = + iamf_mix_presentation_get_best_loudness(mpo, &self->ctx.layout); + if (self->ctx.normalized_loudness_lkfs != def_default_loudness_lkfs) { + iamf_presentation_set_loudness_gain( + self->presentation, + f32_db_to_linear(self->ctx.normalized_loudness_lkfs - + self->ctx.loudness_lkfs)); + } + } + } + } else { + ret = IAMF_ERR_INTERNAL; + if (ctx->mix_presentation_id != def_i64_id_none) + warning("Fail to find the mix presentation %u obu.", + ctx->mix_presentation_id); + else + warning("Fail to find the valid mix presentation obu, try again."); + } + } + + return ret; +} + +static iamf_parser_state_t iamf_decoder_priv_process_descriptor_obus( + iamf_decoder_t *self, iamf_obu_t *obu) { + iamf_database_t *database = &self->ctx.database; + + if (obu) + debug("Processing OBU type: %s", iamf_obu_type_string(obu->obu_type)); + + if ((!obu || !iamf_obu_is_descriptor(obu)) && + iamf_database_descriptors_complete(database)) { + if (obu) iamf_obu_free(obu); + info("All descriptor OBUs are received."); + return ck_iamf_parser_state_switch; + } + + iamf_database_add_obu(database, obu); + return ck_iamf_parser_state_run; +} + +static iamf_parser_state_t iamf_decoder_priv_process_data_obus( + iamf_decoder_t *self, iamf_obu_t *obu) { + iamf_decoder_context_t *ctx = &self->ctx; + iamf_presentation_t *presentation = self->presentation; + iamf_database_t *database = &self->ctx.database; + iamf_parser_state_t state = ck_iamf_parser_state_run; + + if (!obu) return ck_iamf_parser_state_run; + + debug("Processing OBU type: %s", iamf_obu_type_string(obu->obu_type)); + + if ((!ctx->key_frame && ctx->delimiter && + obu->obu_type != ck_iamf_obu_temporal_delimiter) || + iamf_obu_is_redundant_copy(obu)) { + iamf_obu_free(obu); + return ck_iamf_parser_state_run; + } + + if (!ctx->key_frame && !ctx->delimiter && + obu->obu_type != ck_iamf_obu_temporal_delimiter) + ctx->key_frame = 1; + + switch (obu->obu_type) { + case ck_iamf_obu_parameter_block: { + info("Processing parameter block OBU"); + + iamf_parameter_block_obu_t *pbo = def_parameter_block_obu_ptr(obu); + + if (pbo->base->type == ck_iamf_parameter_type_demixing || + pbo->base->type == ck_iamf_parameter_type_recon_gain) { + iamf_audio_element_obu_t *aeo = + iamf_database_get_audio_element_obu_with_pid( + database, pbo->base->parameter_id); + parameter_subblock_t *subblock = def_value_wrap_type_ptr( + parameter_subblock_t, array_at(pbo->subblocks, 0)); + if (subblock) { + if (subblock->type == ck_iamf_parameter_type_demixing) { + demixing_info_parameter_subblock_t *demixing_info = + def_demixing_info_parameter_subblock_ptr(subblock); + iamf_element_reconstructor_update_demixing_mode( + self->reconstructor, aeo->audio_element_id, + demixing_info->demixing_mode); + trace("update demix mode %d", demixing_info->demixing_mode); + } else { + recon_gain_parameter_subblock_t *recon_gain = + def_recon_gain_parameter_subblock_ptr(subblock); + int index = + iamf_element_reconstructor_get_channel_based_reconstructed_layout_index( + self->reconstructor, aeo->audio_element_id); + + int n = array_size(recon_gain->recon_gains); + for (int i = 0; i < n; ++i) { + recon_gain_t *recon_info = def_value_wrap_type_ptr( + recon_gain_t, array_at(recon_gain->recon_gains, i)); + if (recon_info && recon_info->layer == index) { + iamf_element_reconstructor_update_recon_gain( + self->reconstructor, aeo->audio_element_id, recon_info); + break; + } + } + } + } + } + + // Provide parameter block OBU to iamf_database for processing + int ret = iamf_database_add_obu(database, obu); + if (ret != IAMF_OK) { + error("Failed to add parameter block OBU to database"); + iamf_obu_free(obu); + } + } break; + + case ck_iamf_obu_temporal_delimiter: { + if (!ctx->delimiter) ctx->delimiter = 1; + if (!ctx->key_frame) { + iamf_temporal_delimiter_obu_t *tdo = + def_temporal_delimiter_obu_ptr(obu); + if (tdo->key_frame) ctx->key_frame = 1; + } + iamf_obu_free(obu); + } break; + + case ck_iamf_obu_audio_frame: + case ck_iamf_obu_audio_frame_id0: + case ck_iamf_obu_audio_frame_id1: + case ck_iamf_obu_audio_frame_id2: + case ck_iamf_obu_audio_frame_id3: + case ck_iamf_obu_audio_frame_id4: + case ck_iamf_obu_audio_frame_id5: + case ck_iamf_obu_audio_frame_id6: + case ck_iamf_obu_audio_frame_id7: + case ck_iamf_obu_audio_frame_id8: + case ck_iamf_obu_audio_frame_id9: + case ck_iamf_obu_audio_frame_id10: + case ck_iamf_obu_audio_frame_id11: + case ck_iamf_obu_audio_frame_id12: + case ck_iamf_obu_audio_frame_id13: + case ck_iamf_obu_audio_frame_id14: + case ck_iamf_obu_audio_frame_id15: + case ck_iamf_obu_audio_frame_id16: + case ck_iamf_obu_audio_frame_id17: { + iamf_audio_frame_obu_t *afo = def_audio_frame_obu_ptr(obu); + int ret = iamf_element_reconstructor_add_audio_frame_obu( + self->reconstructor, afo); + if (ret == IAMF_ERR_INVALID_PACKET) { + iamf_database_time_elapse(&self->ctx.database, + self->ctx.frame_duration); + } else if (ret > 0) { + iamf_audio_block_t *audio_block = + iamf_element_reconstructor_process(self->reconstructor); + if (audio_block) { + uint32_t _2nd_skip = audio_block->second_skip; + fraction_t frame_duration = self->ctx.frame_duration; +#if SR + iamf_rec_stream_log(audio_block->id, audio_block->num_channels, + audio_block->data, + audio_block->capacity_per_channel); +#endif + frame_duration.numerator -= _2nd_skip; + ret = iamf_presentation_add_audio_block(presentation, audio_block); + if (ret > 0) { + state = ck_iamf_parser_state_stop; + } else if (ret == IAMF_ERR_INVALID_PACKET) { + iamf_database_time_elapse(&self->ctx.database, frame_duration); + } + } else { + warning("No audio block available."); + } + } + } break; + + case ck_iamf_obu_sequence_header: { + info("*********** FOUND NEW MAGIC CODE **********"); + state = ck_iamf_parser_state_switch; + } + + default: { + iamf_obu_free(obu); + } break; + } + + return state; +} + +static iamf_parser_state_t iamf_decoder_priv_process_obus(iamf_obu_t *obu, + void *user_data) { + iamf_decoder_t *self = (iamf_decoder_t *)user_data; + iamf_decoder_context_t *ctx = &self->ctx; + + if (ctx->status == ck_iamf_decoder_status_parse_1) + return iamf_decoder_priv_process_descriptor_obus(self, obu); + else if (ctx->status == ck_iamf_decoder_status_parse_2) + return iamf_decoder_priv_process_data_obus(self, obu); + + warning("Unexpected state %d of decoder.", ctx->status); + return ck_iamf_parser_state_stop; +} + +static int iamf_decoder_priv_create_parser(iamf_decoder_t *self) { + iamf_database_t *database = &self->ctx.database; + iamf_obu_extra_parameters_t eparam; + + memset(&eparam, 0, sizeof(iamf_obu_extra_parameters_t)); + eparam.pbo_interfaces.this = database; + eparam.pbo_interfaces.get_parameter_base = + (fun_get_parameter_base_t)iamf_database_get_parameter_base; + eparam.pbo_interfaces.get_recon_gain_present_flags = + (fun_get_recon_gain_present_flags_t) + iamf_database_get_recon_gain_present_flags; + + self->parser = + iamf_obu_parser_create(iamf_decoder_priv_process_obus, self, &eparam); + return self->parser ? IAMF_OK : IAMF_ERR_ALLOC_FAIL; +} + +/* ----------------------------- APIs ----------------------------- */ + +IAMF_DecoderHandle IAMF_decoder_open(void) { + iamf_decoder_t *self = 0; + info("open iamf decoder."); + self = def_mallocz(iamf_decoder_t, 1); + if (self) { + iamf_decoder_context_t *ctx = &self->ctx; + + ctx->status = ck_iamf_decoder_status_init; + + ctx->sampling_rate = def_default_sampling_rate; + ctx->mix_presentation_id = def_i64_id_none; + ctx->loudness_lkfs = def_default_loudness_lkfs; + ctx->normalized_loudness_lkfs = def_default_loudness_lkfs; + ctx->limiter_threshold_db = def_limiter_max_true_peak; + ctx->enable_limiter = 1; + + ctx->head_rotation = def_quaternion_instance(1.0, 0.0, 0.0, 0.0); + + self->reconstructor = iamf_element_reconstructor_create(); + self->post_processor = iamf_post_processor_create(); + + if (iamf_decoder_priv_create_parser(self) != IAMF_OK || + !self->reconstructor || !self->post_processor || + iamf_database_init(&ctx->database) != IAMF_OK) { + IAMF_decoder_close(self); + return 0; + } + iamf_database_set_profile(&ctx->database, def_iamf_profile_default); + } + return self; +} + +int IAMF_decoder_close(IAMF_DecoderHandle handle) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + info("close iamf decoder."); +#if SR + iamf_stream_log_free(); +#endif + if (self) { + iamf_decoder_context_t *ctx = &self->ctx; + iamf_database_uninit(&ctx->database); + if (ctx->element_gains) hash_map_delete(ctx->element_gains, 0); + + if (self->parser) iamf_obu_parser_destroy(self->parser); + if (self->reconstructor) + iamf_element_reconstructor_destroy(self->reconstructor); + if (self->presentation) iamf_presentation_destroy(self->presentation); + if (self->post_processor) iamf_post_processor_destroy(self->post_processor); + } + def_free(self); + return 0; +} + +int IAMF_decoder_set_profile(IAMF_DecoderHandle handle, IA_Profile profile) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + iamf_profile_t _profile = def_iamf_profile_cast(profile); + if (!self) return IAMF_ERR_BAD_ARG; + + if (_profile < ck_iamf_profile_none || + _profile > ck_iamf_profile_advanced_2) { + return IAMF_ERR_BAD_ARG; + } + + info("set profile %s (%d)", iamf_profile_type_string(_profile), _profile); + + return iamf_database_set_profile(&self->ctx.database, _profile); +} + +IA_Profile IAMF_decoder_get_profile(IAMF_DecoderHandle handle) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + if (!self) return def_ia_profile_cast(ck_iamf_profile_none); + + return def_ia_profile_cast(iamf_database_get_profile(&self->ctx.database)); +} + +int IAMF_decoder_configure(IAMF_DecoderHandle handle, const uint8_t *data, + uint32_t size, uint32_t *rsize) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + uint32_t read = 0; + int ret = iamf_decoder_priv_configure(self, data, size, &read); + + if (rsize) { + *rsize = read; + if ((ret != IAMF_OK && ret != IAMF_ERR_BUFFER_TOO_SMALL) || + (ret == IAMF_ERR_BUFFER_TOO_SMALL && + self->ctx.status != ck_iamf_decoder_status_parse_2)) + error("fail to configure decoder with errno %d (%s).", ret, + iamf_error_code_string(ret)); + return ret; + } + + if (ret == IAMF_ERR_BUFFER_TOO_SMALL && + iamf_database_descriptors_complete(&self->ctx.database)) { + self->ctx.configure_flags |= def_iamf_decoder_config_presentation; + self->ctx.status = ck_iamf_decoder_status_parse_2; + info("configure with complete descriptor OBUs."); + ret = iamf_decoder_priv_configure(self, 0, 0, 0); + } + + if (ret != IAMF_OK) + error("fail to configure decoder with errno %d (%s).", ret, + iamf_error_code_string(ret)); + + return ret; +} + +int IAMF_decoder_decode(IAMF_DecoderHandle handle, const uint8_t *data, + int32_t size, uint32_t *rsize, void *pcm) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + uint32_t read = 0; + int ret = IAMF_OK; + + if (!self) return IAMF_ERR_BAD_ARG; + trace("decode iamf decoder. data %p, size %d, statue %d", data, size, + self->ctx.status); + if (self->ctx.status != ck_iamf_decoder_status_parse_2) + return IAMF_ERR_INVALID_STATE; + ret = iamf_decoder_priv_decode(self, data, size, &read, pcm); + if (rsize) *rsize = read; + return ret; +} + +int IAMF_decoder_output_layout_set_sound_system(IAMF_DecoderHandle handle, + IAMF_SoundSystem ss) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + iamf_decoder_context_t *ctx; + if (!self) return IAMF_ERR_BAD_ARG; + if (!iamf_sound_system_check(ss)) return IAMF_ERR_BAD_ARG; + + ctx = &self->ctx; + if (ctx->layout.type == ck_iamf_layout_type_loudspeakers_ss_convention && + ctx->layout.sound_system == ss) + return IAMF_OK; + + info("sound system %d, channels %d", ss, + IAMF_layout_sound_system_channels_count(ss)); + + ctx->layout.type = ck_iamf_layout_type_loudspeakers_ss_convention; + ctx->layout.sound_system = ss; + ctx->configure_flags |= def_iamf_decoder_config_output_layout; + return IAMF_OK; +} + +int IAMF_decoder_output_layout_set_binaural(IAMF_DecoderHandle handle) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + iamf_decoder_context_t *ctx; + + if (!self) return IAMF_ERR_BAD_ARG; + + ctx = &self->ctx; + if (ctx->layout.type == ck_iamf_layout_type_binaural) return IAMF_OK; + + info("binaural channels %d", IAMF_layout_binaural_channels_count()); + ctx->layout.type = ck_iamf_layout_type_binaural; + ctx->configure_flags |= def_iamf_decoder_config_output_layout; + return IAMF_OK; +} + +int IAMF_decoder_set_mix_presentation_id(IAMF_DecoderHandle handle, + uint64_t id64) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + iamf_decoder_context_t *ctx; + uint32_t id = def_lsb_32bits(id64); + + if (!self || id64 > UINT32_MAX) return IAMF_ERR_BAD_ARG; + + ctx = &self->ctx; + + if (ctx->mix_presentation_id == id) { + debug("mix presentation id %u is same as current setting. skip it. ", + ctx->mix_presentation_id); + return IAMF_OK; + } + + ctx->mix_presentation_id = id; + if (!self->presentation || + ctx->mix_presentation_id != iamf_presentation_get_id(self->presentation)) + ctx->configure_flags |= def_iamf_decoder_config_mix_presentation; + info("set new mix presentation id %" PRId64 ".", ctx->mix_presentation_id); + + if (ctx->status > ck_iamf_decoder_status_configure) + iamf_decoder_priv_configure(self, 0, 0, 0); + + return IAMF_OK; +} + +int64_t IAMF_decoder_get_mix_presentation_id(IAMF_DecoderHandle handle) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + return self ? self->ctx.mix_presentation_id : def_i64_id_none; +} + +int IAMF_layout_sound_system_channels_count(IAMF_SoundSystem ss) { + const iamf_layout_info_t *info = + iamf_layout_get_info(def_sound_system_layout_instance(ss)); + if (!info) { + error("invalid sound system %x", ss); + return IAMF_ERR_BAD_ARG; + } + debug("sound system %x, channels %d", ss, info->channels); + return info->channels; +} + +int IAMF_layout_binaural_channels_count() { return 2; } + +char *IAMF_decoder_get_codec_capability() { + char *ccs_str = def_mallocz(char, def_ccs_str_size); + char cc_str[def_cc_str_size]; + + if (!ccs_str) return 0; + + snprintf(cc_str, def_cc_str_size, "iamf.%.03d.%.03d.ipcm", + def_iamf_profile_default, def_iamf_profile_default); + strncat(ccs_str, cc_str, def_cc_str_size); + +#ifdef CONFIG_OPUS_CODEC + snprintf(cc_str, def_cc_str_size, ";iamf.%.03d.%.03d.Opus", + def_iamf_profile_default, def_iamf_profile_default); + strncat(ccs_str, cc_str, def_cc_str_size); +#endif + +#ifdef CONFIG_AAC_CODEC + snprintf(cc_str, def_cc_str_size, ";iamf.%.03d.%.03d.mp4a.40.2", + def_iamf_profile_default, def_iamf_profile_default); + strncat(ccs_str, cc_str, def_cc_str_size); +#endif + +#ifdef CONFIG_FLAC_CODEC + snprintf(cc_str, def_cc_str_size, ";iamf.%.03d.%.03d.fLaC", + def_iamf_profile_default, def_iamf_profile_default); + strncat(ccs_str, cc_str, def_cc_str_size); +#endif + + return ccs_str; +} + +int IAMF_decoder_set_normalization_loudness(IAMF_DecoderHandle handle, + float loudness) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + if (!self) return IAMF_ERR_BAD_ARG; + if (self->ctx.normalized_loudness_lkfs != loudness) { + self->ctx.normalized_loudness_lkfs = loudness; + if (self->ctx.status > ck_iamf_decoder_status_configure) { + iamf_presentation_set_loudness_gain( + self->presentation, + f32_db_to_linear(self->ctx.normalized_loudness_lkfs - + self->ctx.loudness_lkfs)); + } + } + return IAMF_OK; +} + +int IAMF_decoder_set_bit_depth(IAMF_DecoderHandle handle, uint32_t bit_depth) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + iamf_sample_bit_depth_t valid_bit_depths[] = { + SAMPLE_BIT_DEPTH_16, SAMPLE_BIT_DEPTH_24, SAMPLE_BIT_DEPTH_32}; + int ret = IAMF_ERR_BAD_ARG; + + if (!self) return IAMF_ERR_BAD_ARG; + + for (int i = 0; + i < sizeof(valid_bit_depths) / sizeof(iamf_sample_bit_depth_t); ++i) { + if (bit_depth == valid_bit_depths[i]) { + self->ctx.bit_depth = bit_depth; + ret = IAMF_OK; + break; + } + } + return ret; +} + +int IAMF_decoder_peak_limiter_enable(IAMF_DecoderHandle handle, + uint32_t enable) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + if (!self) return IAMF_ERR_BAD_ARG; + self->ctx.enable_limiter = enable; + return IAMF_OK; +} + +int IAMF_decoder_peak_limiter_set_threshold(IAMF_DecoderHandle handle, + float db) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + if (!self) return IAMF_ERR_BAD_ARG; + self->ctx.limiter_threshold_db = db; + return IAMF_OK; +} + +float IAMF_decoder_peak_limiter_get_threshold(IAMF_DecoderHandle handle) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + if (!self) return def_limiter_max_true_peak; + return self->ctx.limiter_threshold_db; +} + +int IAMF_decoder_set_sampling_rate(IAMF_DecoderHandle handle, uint32_t rate) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + IAMF_SampleBitDepth valid_sampling_rates[] = { + SAMPLING_RATE_8000, SAMPLING_RATE_11025, SAMPLING_RATE_16000, + SAMPLING_RATE_22050, SAMPLING_RATE_24000, SAMPLING_RATE_32000, + SAMPLING_RATE_44100, SAMPLING_RATE_48000, SAMPLING_RATE_64000, + SAMPLING_RATE_88200, SAMPLING_RATE_96000, SAMPLING_RATE_176400, + SAMPLING_RATE_192000}; + int ret = IAMF_ERR_BAD_ARG; + + if (!self) return IAMF_ERR_BAD_ARG; + + for (int i = 0; + i < sizeof(valid_sampling_rates) / sizeof(IAMF_SampleBitDepth); ++i) { + if (rate == valid_sampling_rates[i]) { + if (rate != self->ctx.sampling_rate) self->ctx.sampling_rate = rate; + ret = IAMF_OK; + break; + } + } + return ret; +} + +int IAMF_decoder_set_audio_element_gain_offset(IAMF_DecoderHandle handle, + uint32_t id, float gain) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + iamf_decoder_context_t *ctx; + + if (!self) return IAMF_ERR_BAD_ARG; + if (self->presentation) + return iamf_presentation_set_element_gain_offset(self->presentation, id, + gain); + + ctx = &self->ctx; + if (!ctx->element_gains) + ctx->element_gains = hash_map_new(def_hash_map_capacity_elements); + if (!ctx->element_gains) return IAMF_ERR_ALLOC_FAIL; + + return hash_map_put(ctx->element_gains, id, + def_value_wrap_instance_f32(gain)) < 0 + ? IAMF_ERR_INTERNAL + : IAMF_ERR_PENDING; +} + +int IAMF_decoder_get_audio_element_gain_offset(IAMF_DecoderHandle handle, + uint32_t id, float *gain) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + iamf_decoder_context_t *ctx; + value_wrap_t *value; + + if (!self || !gain) return IAMF_ERR_BAD_ARG; + if (self->presentation) + return iamf_presentation_get_element_gain_offset(self->presentation, id, + gain); + + ctx = &self->ctx; + if (!ctx->element_gains) return IAMF_ERR_INVALID_STATE; + + value = hash_map_get(ctx->element_gains, id); + if (!value) return IAMF_ERR_BAD_ARG; + + *gain = def_value_wrap_f32(value); + return IAMF_OK; +} + +int IAMF_decoder_set_head_rotation(IAMF_DecoderHandle handle, float w, float x, + float y, float z) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + iamf_decoder_context_t *ctx; + int ret = IAMF_OK; + + if (!self) return IAMF_ERR_BAD_ARG; + + ctx = &self->ctx; + + // Validate quaternion (should be approximately unit length) + float quaternion_length = sqrtf(w * w + x * x + y * y + z * z); + if (quaternion_length < 0.001f) { + warning("Head rotation quaternion is too close to zero, ignoring"); + return IAMF_ERR_BAD_ARG; + } + + // Normalize quaternion to ensure it's unit length + if (fabsf(quaternion_length - 1.0f) > 0.001f) { + w /= quaternion_length; + x /= quaternion_length; + y /= quaternion_length; + z /= quaternion_length; + debug("Normalized head rotation quaternion: w=%f, x=%f, y=%f, z=%f", w, x, + y, z); + } + + ctx->head_rotation.w = w; + ctx->head_rotation.x = x; + ctx->head_rotation.y = y; + ctx->head_rotation.z = z; + + debug("Set head rotation: w=%f, x=%f, y=%f, z=%f", w, x, y, z); + + if (self->presentation) { + ret = iamf_presentation_set_head_rotation(self->presentation, + &ctx->head_rotation); + } else { + debug( + "Presentation not active, head rotation stored for later application"); + ret = IAMF_ERR_PENDING; + } + + return ret; +} + +int IAMF_decoder_enable_head_tracking(IAMF_DecoderHandle handle, + uint32_t enable) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + iamf_decoder_context_t *ctx; + int ret = IAMF_OK; + + if (!self) return IAMF_ERR_BAD_ARG; + + ctx = &self->ctx; + + if (ctx->head_tracking_enabled == enable) return IAMF_OK; + + ctx->head_tracking_enabled = enable; + + debug("Head tracking %s in decoder", enable ? "enabled" : "disabled"); + + if (self->presentation) { + ret = iamf_presentation_enable_head_tracking(self->presentation, enable); + } else { + debug( + "Presentation not active, head tracking setting stored for later " + "application"); + ret = IAMF_ERR_PENDING; + } + + return ret; +} + +IAMF_StreamInfo *IAMF_decoder_get_stream_info(IAMF_DecoderHandle handle) { + iamf_decoder_t *self = (iamf_decoder_t *)handle; + if (!self) return 0; + + iamf_decoder_context_t *ctx = &self->ctx; + + if (ctx->status <= ck_iamf_decoder_status_parse_1) return 0; + + IAMF_StreamInfo *info = def_mallocz(IAMF_StreamInfo, 1); + if (!info) { + error("Failed to allocate memory for IAMF_StreamInfo"); + return 0; + } + + iamf_database_t *database = &ctx->database; + obu_audio_element_config_t *audio_element_config = 0; + + info->max_frame_size = + iamf_fraction_transform(ctx->frame_duration, ctx->sampling_rate); + info->max_frame_size += iamf_post_processor_get_delay(self->post_processor); + + if (database->descriptors.ia_sequence_header_obu) { + info->iamf_stream_info.primary_profile = def_ia_profile_cast( + database->descriptors.ia_sequence_header_obu->primary_profile); + info->iamf_stream_info.additional_profile = def_ia_profile_cast( + database->descriptors.ia_sequence_header_obu->additional_profile); + } else { + info->iamf_stream_info.primary_profile = + info->iamf_stream_info.additional_profile = + def_ia_profile_cast(iamf_database_get_profile(database)); + } + + codec_config_t *db_codec_config = def_value_wrap_type_ptr( + codec_config_t, vector_at(database->codec_configs, 0)); + + info->iamf_stream_info.codec_ids[0] = + def_iamf_codec_id_cast(db_codec_config->codec_param.type); + info->iamf_stream_info.codec_ids[1] = + def_iamf_codec_id_cast(ck_iamf_codec_type_none); + info->iamf_stream_info.sampling_rate = + db_codec_config->codec_param.sample_rate; + info->iamf_stream_info.samples_per_channel_in_frame = + db_codec_config->codec_param.frame_size; + + int num_codec_configs = vector_size(database->codec_configs); + if (num_codec_configs > 1) { + db_codec_config = def_value_wrap_type_ptr( + codec_config_t, vector_at(database->codec_configs, 1)); + info->iamf_stream_info.codec_ids[1] = db_codec_config->codec_param.type; + } + + if (info->iamf_stream_info.codec_ids[0] == + def_iamf_codec_id_cast(ck_iamf_codec_type_opus) || + info->iamf_stream_info.codec_ids[1] == + def_iamf_codec_id_cast(ck_iamf_codec_type_opus)) + info->iamf_stream_info.sampling_rate = SAMPLING_RATE_48000; + + info->iamf_stream_info.mix_presentation_count = + vector_size(database->descriptors.mix_presentation_obus); + + if (info->iamf_stream_info.mix_presentation_count > 0) { + info->iamf_stream_info.mix_presentations = + def_mallocz(iamf_mix_presentation_info_t, + info->iamf_stream_info.mix_presentation_count); + if (info->iamf_stream_info.mix_presentations) { + for (int i = 0; i < info->iamf_stream_info.mix_presentation_count; ++i) { + iamf_mix_presentation_obu_t *mpo = def_value_wrap_type_ptr( + iamf_mix_presentation_obu_t, + vector_at(database->descriptors.mix_presentation_obus, i)); + + if (mpo) { + info->iamf_stream_info.mix_presentations[i].id = + mpo->mix_presentation_id; + int num_sub_mixes = array_size(mpo->sub_mixes); + + // Count total audio elements across all sub-mixes + uint32_t total_audio_elements = 0; + for (int sub_idx = 0; sub_idx < num_sub_mixes; ++sub_idx) { + obu_sub_mix_t *sub = + def_value_wrap_optional_ptr(array_at(mpo->sub_mixes, sub_idx)); + if (sub) { + total_audio_elements += array_size(sub->audio_element_configs); + } + } + + // Allocate elements array + if (total_audio_elements > 0) { + info->iamf_stream_info.mix_presentations[i].elements = def_mallocz( + iamf_element_presentation_info_t, total_audio_elements); + info->iamf_stream_info.mix_presentations[i].num_audio_elements = + total_audio_elements; + + uint32_t element_idx = 0; + for (int sub_idx = 0; sub_idx < num_sub_mixes; ++sub_idx) { + obu_sub_mix_t *sub = def_value_wrap_optional_ptr( + array_at(mpo->sub_mixes, sub_idx)); + + if (sub) { + int num_audio_elements = array_size(sub->audio_element_configs); + + for (int elem_idx = 0; elem_idx < num_audio_elements; + ++elem_idx) { + audio_element_config = def_value_wrap_optional_ptr( + array_at(sub->audio_element_configs, elem_idx)); + + if (audio_element_config && + element_idx < total_audio_elements) { + // Set element ID + info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .eid = audio_element_config->element_id; + + info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .mode = audio_element_config->rendering_config + .headphones_rendering_mode; + info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .profile = audio_element_config->rendering_config + .binaural_filter_profile; + + // Check for gain offset range + if ((audio_element_config->rendering_config.flags & + def_rendering_config_flag_element_gain_offset) && + (audio_element_config->rendering_config + .element_gain_offset_type == + ck_element_gain_offset_type_range)) { + info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .gain_offset_range = + def_mallocz(iamf_element_gain_offset_range_t, 1); + if (info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .gain_offset_range) { + info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .gain_offset_range->min = + audio_element_config->rendering_config + .element_gain_offset_db.min; + info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .gain_offset_range->max = + audio_element_config->rendering_config + .element_gain_offset_db.max; + } + } else { + info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .gain_offset_range = 0; + } + + element_idx++; + } + } + } + } + } else { + info->iamf_stream_info.mix_presentations[i].elements = 0; + info->iamf_stream_info.mix_presentations[i].num_audio_elements = 0; + } + } + } + } + } + + return info; +} + +void IAMF_decoder_free_stream_info(iamf_stream_info_t *info) { + if (!info) return; + + if (info->iamf_stream_info.mix_presentations) { + for (uint32_t i = 0; i < info->iamf_stream_info.mix_presentation_count; + ++i) { + if (info->iamf_stream_info.mix_presentations[i].elements) { + for (uint32_t j = 0; + j < info->iamf_stream_info.mix_presentations[i].num_audio_elements; + ++j) { + def_free(info->iamf_stream_info.mix_presentations[i] + .elements[j] + .gain_offset_range); + } + def_free(info->iamf_stream_info.mix_presentations[i].elements); + } + } + def_free(info->iamf_stream_info.mix_presentations); + } + + def_free(info); +} diff --git a/code/src/iamf_dec/iamf_decoder_private.h b/code/src/iamf_dec/iamf_decoder_private.h new file mode 100755 index 00000000..27075bbc --- /dev/null +++ b/code/src/iamf_dec/iamf_decoder_private.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_decoder_private.h + * @brief IAMF decoder internal APIs. + * @version 2.0.0 + * @date Created 03/03/2023 + **/ + +#ifndef IAMF_DECODER_PRIVATE_H +#define IAMF_DECODER_PRIVATE_H + +#include + +#include "iamf_database.h" +#include "iamf_element_reconstructor.h" +#include "iamf_post_processor.h" +#include "iamf_presentation.h" + +typedef enum EIamfDecoderStatus { + ck_iamf_decoder_status_init, + ck_iamf_decoder_status_parse_1, + ck_iamf_decoder_status_configure, + ck_iamf_decoder_status_reconfigure, + ck_iamf_decoder_status_parse_2, + ck_iamf_decoder_status_process, +} iamf_decoder_status_t; + +struct IAMF_DecoderContext { + uint32_t flags; + iamf_decoder_status_t status; + uint32_t configure_flags; + + uint32_t bit_depth; + uint32_t sampling_rate; + + fraction_t frame_duration; + + iamf_layout_t layout; + int64_t mix_presentation_id; + + hash_map_t *element_gains; + + float loudness_lkfs; + float normalized_loudness_lkfs; + float limiter_threshold_db; + int enable_limiter; + + quaternion_t head_rotation; + uint32_t head_tracking_enabled; + + int key_frame; + int delimiter; + + struct { + uint32_t decoder; // delay for decoder + uint32_t padding; // number samples of trimming at end + } cache; + + iamf_database_t database; +}; + +typedef struct IAMF_DecoderContext iamf_decoder_context_t; + +struct IAMF_Decoder { + iamf_decoder_context_t ctx; + + iamf_obu_parser_t *parser; + iamf_element_reconstructor_t *reconstructor; + iamf_presentation_t *presentation; + iamf_post_processor_t *post_processor; +}; + +typedef struct IAMF_Decoder iamf_decoder_t; + +#endif /* IAMF_DECODER_PRIVATE_H */ diff --git a/code/src/iamf_dec/iamf_element_reconstructor.c b/code/src/iamf_dec/iamf_element_reconstructor.c new file mode 100755 index 00000000..7f0f452a --- /dev/null +++ b/code/src/iamf_dec/iamf_element_reconstructor.c @@ -0,0 +1,1339 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_element_reconstructor.c + * @brief IAMF element reconstructor implementation. + * @version 0.1 + * @date Created 12/11/2025 + **/ + +#include "iamf_element_reconstructor.h" + +#include +#include + +#include "chashmap.h" +#include "clog.h" +#include "demixer.h" +#include "iamf_core_decoder.h" +#include "iamf_layout.h" +#include "iamf_private_definitions.h" +#include "iamf_string.h" +#include "iamf_types.h" + +#undef def_log_tag +#define def_log_tag "IAMF_REC" + +#define SRDBG 0 +#if SRDBG +extern void iamf_rec_stream_log(int eid, int chs, float* in, int size); +extern void iamf_stream_log_free(); +#endif + +// ============================================================================= +// Private Structure Definitions +// ============================================================================= + +typedef struct BaseReconstructor base_reconstructor_t; +typedef void (*fun_reconstructor_destroy_t)(base_reconstructor_t* self); +typedef iamf_audio_block_t* (*fun_reconstructor_process_frame_t)( + base_reconstructor_t* self, int flush); + +struct BaseReconstructor { + const iamf_audio_element_obu_t* audio_element_obu; + iamf_audio_element_type_t type; + + uint32_t num_samples_per_frame; + + uint32_t num_audio_streams; + uint32_t num_audio_channels; + uint32_t num_audio_frames; + uint32_t delay; + + uint32_t audio_frame_ids[def_max_audio_streams]; + iamf_audio_frame_obu_t* audio_frame_obus[def_max_audio_streams]; + + hash_map_t* audio_frames_map; // substream_id(uint32_t) : audio_frame_obu_t* + + fun_reconstructor_destroy_t destroy; + fun_reconstructor_process_frame_t process_frame; +}; + +typedef struct SceneBasedReconstructor { + base_reconstructor_t base; + iamf_core_decoder_t* core_decoder; +} scene_based_reconstructor_t; + +typedef struct ChannelBasedReconstructor { + base_reconstructor_t base; + + iamf_core_decoder_t* core_decoders[def_max_channel_groups]; + uint8_t num_groups; + struct { + iamf_loudspeaker_layout_t layout; + int stream_start_index; + int num_streams; + int num_channels; + } group_infos[def_max_channel_groups]; + + int target_layout_index; + Demixer* demixer; +} channel_based_reconstructor_t; + +typedef struct ObjectBasedReconstructor { + base_reconstructor_t base; + iamf_core_decoder_t* core_decoder; +} object_based_reconstructor_t; + +// ============================================================================= +// Public Interface Implementation +// ============================================================================= + +// Full definition of the iamf_element_reconstructor_t structure. +typedef struct IamfElementReconstructor { + hash_map_t* reconstructor_map; // element_id(uint32_t) : base_reconstructor_t + hash_map_t* + audio_frame_obus; // substream id(uint32_t) : element_id(uint32_t) +} iamf_element_reconstructor_t; + +// ============================================================================= +// Private Function Definitions +// ============================================================================= + +static iamf_core_decoder_t* _core_decoder_open( + stream_mode_t mode, int channels, int nb_streams, int nb_coupled_streams, + uint8_t* mapping, int mapping_size, const iamf_codec_config_obu_t* conf) { + iamf_core_decoder_t* dec; + int ret = 0; + + dec = iamf_core_decoder_open(conf->codec_id); + + if (dec) { + iamf_core_decoder_set_codec_conf(dec, conf->decoder_config->data, + conf->decoder_config->size); + debug( + "codec %s, mode %d, channels %d, streams %d, coupled streams %d, " + "mapping size %d", + iamf_codec_type_string(iamf_codec_type_get(conf->codec_id)), mode, + channels, nb_streams, nb_coupled_streams, mapping_size); + iamf_core_decoder_set_streams_info(dec, mode, channels, nb_streams, + nb_coupled_streams, mapping, + mapping_size); + ret = iamf_core_decoder_init(dec); + if (ret != IAMF_OK) { + error("Fail to initalize core decoder."); + iamf_core_decoder_close(dec); + dec = 0; + } + } + + return dec; +} + +static int _core_decoder_decode(iamf_core_decoder_t* dec, + iamf_audio_frame_obu_t** audio_frame_obus, + uint32_t num_obus, iamf_audio_block_t* ablock, + int flush) { + int samples = 0; + uint8_t* buffers[def_max_audio_streams] = {0}; + uint32_t sizes[def_max_audio_streams] = {0}; + + if (!dec || !ablock) return IAMF_ERR_BAD_ARG; + + if (!flush) { + for (int i = 0; i < num_obus; ++i) { + buffers[i] = audio_frame_obus[i]->audio_frame->data; + sizes[i] = audio_frame_obus[i]->audio_frame->size; + } + } + + samples = + iamf_core_decoder_decode(dec, buffers, sizes, num_obus, ablock->data, + ablock->capacity_per_channel); + if (samples < 0) { + error("Fail to decode core audio data: %d", samples); + return samples; + } + + ablock->num_samples_per_channel = samples; + if (samples < ablock->capacity_per_channel) { + iamf_audio_block_padding(ablock, ablock->capacity_per_channel - samples); + samples = ablock->capacity_per_channel; + } + + return samples; +} + +static int _reconstructor_init(base_reconstructor_t* self, + const iamf_audio_element_obu_t* aeo, + const iamf_codec_config_obu_t* cco) { + self->audio_element_obu = (iamf_audio_element_obu_t*)aeo; + self->type = aeo->audio_element_type; + self->num_samples_per_frame = cco->num_samples_per_frame; + self->num_audio_frames = 0; + self->num_audio_streams = array_size(aeo->audio_substream_ids); + self->audio_frames_map = hash_map_new(def_hash_map_capacity_audio_frames); + if (!self->audio_frames_map) return IAMF_ERR_ALLOC_FAIL; + for (int i = 0; i < self->num_audio_streams; ++i) { + self->audio_frame_ids[i] = + def_value_wrap_u32(array_at(aeo->audio_substream_ids, i)); + hash_map_put(self->audio_frames_map, self->audio_frame_ids[i], + def_value_wrap_instance_ptr(&self->audio_frame_obus[i])); + } + + if (aeo->audio_element_type == ck_audio_element_type_channel_based) { + const channel_based_audio_element_obu_t* cbo = + (const channel_based_audio_element_obu_t*)aeo; + uint32_t channels = 0; + for (int i = 0; i < cbo->max_valid_layers; ++i) { + const obu_channel_layer_config_t* ctx = + def_value_wrap_ptr(array_at(cbo->channel_audio_layer_configs, i)); + channels += (ctx->coupled_substream_count + ctx->substream_count); + } + self->num_audio_channels = channels; + } else if (aeo->audio_element_type == ck_audio_element_type_scene_based) { + const scene_based_audio_element_obu_t* sbo = + (const scene_based_audio_element_obu_t*)aeo; + self->num_audio_channels = sbo->output_channel_count; + } else if (aeo->audio_element_type == ck_audio_element_type_object_based) { + self->num_audio_channels = self->num_audio_streams; + } + + return IAMF_OK; +} + +static void _reconstructor_uninit(base_reconstructor_t* self) { + if (self->audio_frames_map) hash_map_delete(self->audio_frames_map, 0); +} + +static void _reconstructor_and_audio_block_update_delay( + base_reconstructor_t* self, iamf_audio_block_t* block, uint32_t delay) { + debug("update delay: delay %u <- %u, audio block skip %u, padding %u", delay, + self->delay, block->skip, block->padding); + if (delay > 0 && delay != self->delay && + block->skip + block->padding + delay < block->num_samples_per_channel) { + block->second_skip = delay; + self->delay = delay; + } +} + +static void _reconstructor_delete_all_audio_frame_obus( + base_reconstructor_t* self) { + if (!self) return; + int n = hash_map_size(self->audio_frames_map); + for (int i = 0; i < n; ++i) + if (self->audio_frame_obus[i]) + iamf_audio_frame_obu_free(self->audio_frame_obus[i]); + memset(self->audio_frame_obus, 0, sizeof(self->audio_frame_obus)); + self->num_audio_frames = 0; +} + +static int _get_new_channels(iamf_loudspeaker_layout_t last, + iamf_loudspeaker_layout_t cur, + iamf_channel_t* new_chs, uint32_t count) { + uint32_t chs = 0; + + /** + * In ChannelGroup for Channel audio: The order conforms to following rules: + * + * @ Coupled Substream(s) comes first and followed by non-coupled + * Substream(s). + * @ Coupled Substream(s) for surround channels comes first and followed by + * one(s) for top channels. + * @ Coupled Substream(s) for front channels comes first and followed by + * one(s) for side, rear and back channels. + * @ Coupled Substream(s) for side channels comes first and followed by one(s) + * for rear channels. + * @ Center channel comes first and followed by LFE and followed by the other + * one. + * */ + + if (last == ck_iamf_loudspeaker_layout_none) { + chs = iamf_loudspeaker_layout_get_decoding_channels(cur, new_chs, count); + } else if (iamf_audio_layer_base_layout_check(last) && + iamf_audio_layer_base_layout_check(cur)) { + const iamf_layout_info_t* info1 = iamf_loudspeaker_layout_get_info(last); + const iamf_layout_info_t* info2 = iamf_loudspeaker_layout_get_info(cur); + uint32_t s1 = info1->surround; + uint32_t s2 = info2->surround; + uint32_t t1 = info1->height; + uint32_t t2 = info2->height; + + if (s1 < 5 && 5 <= s2) { + new_chs[chs++] = ck_iamf_channel_l5; + new_chs[chs++] = ck_iamf_channel_r5; + debug("new channels : l5/r5(l7/r7)"); + } + if (s1 < 7 && 7 <= s2) { + new_chs[chs++] = ck_iamf_channel_sl7; + new_chs[chs++] = ck_iamf_channel_sr7; + debug("new channels : sl7/sr7"); + } + if (t2 != t1 && t2 == 4) { + new_chs[chs++] = ck_iamf_channel_hfl; + new_chs[chs++] = ck_iamf_channel_hfr; + debug("new channels : hfl/hfr"); + } + if (t2 - t1 == 4) { + new_chs[chs++] = ck_iamf_channel_hbl; + new_chs[chs++] = ck_iamf_channel_hbr; + debug("new channels : hbl/hbr"); + } else if (!t1 && t2 - t1 == 2) { + if (s2 < 5) { + new_chs[chs++] = ck_iamf_channel_tl; + new_chs[chs++] = ck_iamf_channel_tr; + debug("new channels : tl/tr"); + } else { + new_chs[chs++] = ck_iamf_channel_hl; + new_chs[chs++] = ck_iamf_channel_hr; + debug("new channels : hl/hr"); + } + } + + if (s1 < 3 && 3 <= s2) { + new_chs[chs++] = ck_iamf_channel_c; + new_chs[chs++] = ck_iamf_channel_lfe; + debug("new channels : c/lfe"); + } + if (s1 < 2 && 2 <= s2) { + new_chs[chs++] = ck_iamf_channel_l2; + debug("new channel : l2"); + } + } + + if (chs > count) { + error("too much new channels %d, we only need less than %d channels", chs, + count); + chs = IAMF_ERR_BUFFER_TOO_SMALL; + } + return chs; +} + +static int _get_target_layout_channels_order(channel_based_reconstructor_t* cbr, + iamf_channel_t* order, int max) { + int chs = 0; + iamf_loudspeaker_layout_t type = ck_iamf_loudspeaker_layout_none; + + for (int i = 0; i <= cbr->target_layout_index; ++i) { + if (i) type = cbr->group_infos[i - 1].layout; + chs += _get_new_channels(type, cbr->group_infos[i].layout, &order[chs], + max - chs); + } + return chs; +} + +static iamf_channel_t _get_output_gain_channel(iamf_loudspeaker_layout_t type, + iamf_output_gain_channel_t gch) { + iamf_channel_t ch = ck_iamf_channel_none; + const iamf_layout_info_t* info = iamf_loudspeaker_layout_get_info(type); + switch (gch) { + case ck_iamf_channel_gain_l: { + switch (type) { + case ck_iamf_loudspeaker_layout_mono: + ch = ck_iamf_channel_mono; + break; + case ck_iamf_loudspeaker_layout_stereo: + ch = ck_iamf_channel_l2; + break; + case ck_iamf_loudspeaker_layout_312: + ch = ck_iamf_channel_l3; + break; + default: + break; + } + } break; + + case ck_iamf_channel_gain_r: { + switch (type) { + case ck_iamf_loudspeaker_layout_stereo: + ch = ck_iamf_channel_r2; + break; + case ck_iamf_loudspeaker_layout_312: + ch = ck_iamf_channel_r3; + break; + default: + break; + } + } break; + + case ck_iamf_channel_gain_ls: + if (info->surround == 5) ch = ck_iamf_channel_sl5; + break; + + case ck_iamf_channel_gain_rs: + if (info->surround == 5) ch = ck_iamf_channel_sr5; + break; + + case ck_iamf_channel_gain_ltf: + ch = info->surround < 5 ? ck_iamf_channel_tl : ck_iamf_channel_hl; + break; + + case ck_iamf_channel_gain_rtf: + ch = info->surround < 5 ? ck_iamf_channel_tr : ck_iamf_channel_hr; + break; + + default: + break; + } + + return ch; +} + +static int _get_all_channels_output_gains(channel_based_reconstructor_t* cbr, + int channels_map[], float gains[], + int max) { + const channel_based_audio_element_obu_t* cbo = + (const channel_based_audio_element_obu_t*)cbr->base.audio_element_obu; + int count = 0; + for (int l = 0; l < cbr->num_groups; ++l) { + obu_channel_layer_config_t* config = + def_value_wrap_ptr(array_at(cbo->channel_audio_layer_configs, l)); + if (config->output_gain_is_present_flag) { + uint32_t flags = config->output_gain_info.output_gain_flag; + for (int c = 0; c < ck_iamf_channel_gain_count; ++c) { + if (flags & def_rshift(c)) { + channels_map[count] = + _get_output_gain_channel(config->loudspeaker_layout, c); + if (channels_map[count] != ck_iamf_channel_none) { + gains[count++] = config->output_gain_info.output_gain_linear; + } + } + } + } + } + + return count; +} + +static int _set_default_demixing_info(channel_based_reconstructor_t* cbr) { + const iamf_audio_element_obu_t* aeo = cbr->base.audio_element_obu; + int mode, weight_idx; + int n = array_size(aeo->parameters); + int i = 0; + for (; i < n; ++i) { + parameter_subblock_t* pb = + def_value_wrap_optional_ptr(array_at(aeo->parameters, i)); + if (pb && pb->type == ck_iamf_parameter_type_demixing) { + demixing_info_parameter_base_t* dp = (demixing_info_parameter_base_t*)pb; + mode = dp->dmixp_mode; + weight_idx = dp->default_w; + break; + } + } + return i < n ? demixer_set_demixing_info(cbr->demixer, mode, weight_idx) + : IAMF_ERR_INTERNAL; +} + +static uint32_t _get_recon_channels_flags(iamf_loudspeaker_layout_t l1, + iamf_loudspeaker_layout_t l2) { + uint32_t s1, s2, t1, t2, flags; + const iamf_layout_info_t *info1, *info2; + + if (l1 == l2) return 0; + + info1 = iamf_loudspeaker_layout_get_info(l1); + info2 = iamf_loudspeaker_layout_get_info(l2); + + s1 = info1->surround; + s2 = info2->surround; + t1 = info1->height; + t2 = info2->height; + flags = 0; + + if (s1 != s2) { + if (s2 <= 3) { + flags |= def_rshift(ck_iamf_channel_recon_l); + flags |= def_rshift(ck_iamf_channel_recon_r); + } else if (s2 == 5) { + flags |= def_rshift(ck_iamf_channel_recon_ls); + flags |= def_rshift(ck_iamf_channel_recon_rs); + } else if (s2 == 7) { + flags |= def_rshift(ck_iamf_channel_recon_lb); + flags |= def_rshift(ck_iamf_channel_recon_rb); + } + } + + if (t2 != t1 && t2 == 4) { + flags |= def_rshift(ck_iamf_channel_recon_ltb); + flags |= def_rshift(ck_iamf_channel_recon_rtb); + } + + if (s2 == 5 && t1 && t2 == t1) { + flags |= def_rshift(ck_iamf_channel_recon_ltf); + flags |= def_rshift(ck_iamf_channel_recon_rtf); + } + + return flags; +} + +static int _get_recon_channels_order(iamf_loudspeaker_layout_t layout, + uint32_t flags, iamf_channel_t* order, + int channels) { + int chs = 0; + static iamf_recon_channel_t recon_channel_order[] = { + ck_iamf_channel_recon_l, ck_iamf_channel_recon_c, + ck_iamf_channel_recon_r, ck_iamf_channel_recon_ls, + ck_iamf_channel_recon_rs, ck_iamf_channel_recon_ltf, + ck_iamf_channel_recon_rtf, ck_iamf_channel_recon_lb, + ck_iamf_channel_recon_rb, ck_iamf_channel_recon_ltb, + ck_iamf_channel_recon_rtb, ck_iamf_channel_recon_lfe}; + + static iamf_channel_t channel_layout_map + [ck_iamf_loudspeaker_layout_count][ck_iamf_channel_recon_count] = { + {ck_iamf_channel_mono, ck_iamf_channel_none, ck_iamf_channel_none, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_none, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_none, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_none}, + {ck_iamf_channel_l2, ck_iamf_channel_none, ck_iamf_channel_r2, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_none, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_none, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_none}, + {ck_iamf_channel_l5, ck_iamf_channel_c, ck_iamf_channel_r5, + ck_iamf_channel_sl5, ck_iamf_channel_sr5, ck_iamf_channel_none, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_none, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_lfe}, + {ck_iamf_channel_l5, ck_iamf_channel_c, ck_iamf_channel_r5, + ck_iamf_channel_sl5, ck_iamf_channel_sr5, ck_iamf_channel_hl, + ck_iamf_channel_hr, ck_iamf_channel_none, ck_iamf_channel_none, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_lfe}, + {ck_iamf_channel_l5, ck_iamf_channel_c, ck_iamf_channel_r5, + ck_iamf_channel_sl5, ck_iamf_channel_sr5, ck_iamf_channel_hfl, + ck_iamf_channel_hfr, ck_iamf_channel_none, ck_iamf_channel_none, + ck_iamf_channel_hbl, ck_iamf_channel_hbr, ck_iamf_channel_lfe}, + {ck_iamf_channel_l7, ck_iamf_channel_c, ck_iamf_channel_r7, + ck_iamf_channel_sl7, ck_iamf_channel_sr7, ck_iamf_channel_none, + ck_iamf_channel_none, ck_iamf_channel_bl7, ck_iamf_channel_br7, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_lfe}, + {ck_iamf_channel_l7, ck_iamf_channel_c, ck_iamf_channel_r7, + ck_iamf_channel_sl7, ck_iamf_channel_sr7, ck_iamf_channel_hl, + ck_iamf_channel_hr, ck_iamf_channel_bl7, ck_iamf_channel_br7, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_lfe}, + {ck_iamf_channel_l7, ck_iamf_channel_c, ck_iamf_channel_r7, + ck_iamf_channel_sl7, ck_iamf_channel_sr7, ck_iamf_channel_hfl, + ck_iamf_channel_hfr, ck_iamf_channel_bl7, ck_iamf_channel_br7, + ck_iamf_channel_hbl, ck_iamf_channel_hbr, ck_iamf_channel_lfe}, + {ck_iamf_channel_l3, ck_iamf_channel_c, ck_iamf_channel_r3, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_tl, + ck_iamf_channel_tr, ck_iamf_channel_none, ck_iamf_channel_none, + ck_iamf_channel_none, ck_iamf_channel_none, ck_iamf_channel_lfe}}; + +#define def_recon_channel_flag(c) def_rshift(c) + + for (int c = 0; c < ck_iamf_channel_recon_count; ++c) { + if (flags & def_recon_channel_flag(recon_channel_order[c])) { + order[chs++] = channel_layout_map[layout][recon_channel_order[c]]; + if (chs >= channels) break; + } + } + + return IAMF_OK; +} + +static int _set_default_recon_gain(channel_based_reconstructor_t* cbr) { + if (cbr->target_layout_index > 0) { + iamf_loudspeaker_layout_t layout = cbr->group_infos[0].layout; + iamf_loudspeaker_layout_t target_layout = + cbr->group_infos[cbr->target_layout_index].layout; + uint32_t flags = _get_recon_channels_flags(layout, target_layout); + debug("first layer %d, target layout %d", layout, target_layout); + debug("default recon gain flags 0x%04x", flags); + int nb_channels = bit1_count(flags); + debug("default channel count %d", nb_channels); + iamf_channel_t order[ck_iamf_channel_recon_count]; + float recon_gain[ck_iamf_channel_recon_count]; + _get_recon_channels_order(target_layout, flags, order, + ck_iamf_channel_recon_count); + for (int i = 0; i < nb_channels; ++i) { + recon_gain[i] = def_default_recon_gain; + debug("channel %s(%d) : default recon gain is 1.", + iamf_channel_name(order[i]), order[i]); + } + demixer_set_recon_gain(cbr->demixer, nb_channels, order, recon_gain, flags); + } + + return IAMF_OK; +} + +static int _set_channel_based_target_layout(channel_based_reconstructor_t* cbr, + iamf_loudspeaker_layout_t layout) { + iamf_channel_t channels_map[def_max_audio_channels]; + int channels = 0; + + // Only configure demixer if it exists (num_groups > 1) + if (cbr->demixer) { + demixer_set_channel_layout( + cbr->demixer, cbr->group_infos[cbr->target_layout_index].layout); + channels = _get_target_layout_channels_order(cbr, channels_map, + def_max_audio_channels); + demixer_set_channels_order(cbr->demixer, channels_map, channels); + + _set_default_recon_gain(cbr); + } + + return IAMF_OK; +} + +static void _iamf_audio_block_trimming_info_update( + iamf_audio_block_t* ablock, iamf_audio_frame_obu_t* afo) { + if (!ablock || !afo) return; + ablock->skip += afo->num_samples_to_trim_at_start; + ablock->padding += afo->num_samples_to_trim_at_end; +} + +static int _demixer_config(Demixer* demixer, + channel_based_reconstructor_t* cbr) { + iamf_channel_t channels_map[def_max_audio_channels]; + int channels = 0; + float gains[def_max_audio_channels]; + + demixer_set_frame_offset(demixer, 0); + + channels = _get_all_channels_output_gains(cbr, (int*)channels_map, gains, + def_max_audio_channels); + demixer_set_output_gain(demixer, channels_map, gains, channels); + + _set_default_demixing_info(cbr); + return IAMF_OK; +} + +static iamf_audio_block_t* _demixer_reconstruct_stream( + Demixer* demixer, iamf_audio_block_t* ablock) { + iamf_audio_block_t* abk = iamf_audio_block_new( + ablock->id, ablock->capacity_per_channel, ablock->num_channels); + if (!abk) return 0; + demixer_demixing(demixer, abk->data, ablock->data, + ablock->num_samples_per_channel); + iamf_audio_block_samples_info_copy(abk, ablock); + return abk; +} + +static iamf_audio_block_t* +_channel_based_reconstructor_reconstruct_element_stream( + channel_based_reconstructor_t* self, int flush) { + const iamf_layout_info_t* info = iamf_loudspeaker_layout_get_info( + self->group_infos[self->target_layout_index].layout); + uint32_t channels = info->channels; + iamf_audio_block_t* ablock = 0; + int num_obus = 0; + + if (info->flags & ck_iamf_layout_flag_subset) { + const iamf_layout_info_t* reference_info = + iamf_loudspeaker_layout_get_info(info->reference_layout); + channels = reference_info->channels; + } + + num_obus = 1 == self->num_groups ? self->group_infos[0].num_streams + : self->group_infos[1].stream_start_index; + + ablock = iamf_audio_block_new(self->base.audio_element_obu->audio_element_id, + self->base.num_samples_per_frame, channels); + if (!ablock) { + error("Failed to allocate audio block in channel-based reconstructor %u.", + self->base.audio_element_obu->audio_element_id); + return 0; + } + + if (_core_decoder_decode(self->core_decoders[0], self->base.audio_frame_obus, + num_obus, ablock, flush) < 0) { + error("Failed to decode audio data in channel-based reconstructor %u.", + self->base.audio_element_obu->audio_element_id); + iamf_audio_block_delete(ablock); + ablock = 0; + } else { + _iamf_audio_block_trimming_info_update(ablock, + self->base.audio_frame_obus[0]); + _reconstructor_and_audio_block_update_delay( + &self->base, ablock, + iamf_core_decoder_get_delay(self->core_decoders[0])); + iamf_audio_block_reorder(ablock, info->decoding_map, info->channels); + } + + return ablock; +} + +static iamf_audio_block_t* +_channel_based_reconstructor_reconstruct_element_scalable_stream( + channel_based_reconstructor_t* self, int flush) { + const iamf_layout_info_t* info = iamf_loudspeaker_layout_get_info( + self->group_infos[self->target_layout_index].layout); + uint32_t channels = info->channels; + iamf_audio_block_t* ablock = 0; + iamf_audio_block_t* ablocks[def_max_audio_streams] = {0}; + int ret = IAMF_OK; + int start_index = 0, end_next_index = 0; + + ablock = iamf_audio_block_new(self->base.audio_element_obu->audio_element_id, + self->base.num_samples_per_frame, channels); + if (!ablock) { + error("Failed to allocate audio block in channel-based reconstructor %u.", + self->base.audio_element_obu->audio_element_id); + return 0; + } + + for (int i = 0; i <= self->target_layout_index; ++i) { + start_index = end_next_index; + end_next_index = i == (self->num_groups - 1) + ? self->base.num_audio_streams + : self->group_infos[i + 1].stream_start_index; + + ablocks[i] = iamf_audio_block_new( + self->base.audio_element_obu->audio_element_id, + self->base.num_samples_per_frame, self->group_infos[i].num_channels); + if (!ablocks[i]) { + error("Failed to allocate audio block in channel-based reconstructor %u.", + self->base.audio_element_obu->audio_element_id); + ret = IAMF_ERR_ALLOC_FAIL; + break; + } + + ret = _core_decoder_decode(self->core_decoders[i], + &self->base.audio_frame_obus[start_index], + end_next_index - start_index, ablocks[i], flush); + + if (ret < 0) { + error("Failed to decode audio data in channel-based reconstructor %u.", + self->base.audio_element_obu->audio_element_id); + break; + } + } + + if (ret > 0) { + iamf_audio_block_t* tmp = ablock; + + iamf_audio_block_channels_concat(tmp, ablocks, + self->target_layout_index + 1); +#if SRDBG + // iamf_rec_stream_log(tmp->id, tmp->num_channels, tmp->data, + // tmp->capacity_per_channel); +#endif + + _iamf_audio_block_trimming_info_update(ablock, + self->base.audio_frame_obus[0]); + _reconstructor_and_audio_block_update_delay( + &self->base, ablock, + iamf_core_decoder_get_delay(self->core_decoders[0])); + + if (ablock->second_skip) + demixer_set_frame_offset(self->demixer, ablock->second_skip); + ablock = _demixer_reconstruct_stream(self->demixer, tmp); + iamf_audio_block_delete(tmp); + +#if SRDBG + iamf_rec_stream_log(ablock->id, ablock->num_channels, ablock->data, + ablock->capacity_per_channel); +#endif + + } else { + if (ablock) iamf_audio_block_delete(ablock); + ablock = 0; + } + + for (int i = 0; i <= self->target_layout_index; ++i) + iamf_audio_block_delete(ablocks[i]); + + return ablock; +} + +static void _channel_based_reconstructor_delete( + channel_based_reconstructor_t* self) { + if (!self) return; + + _reconstructor_uninit(&self->base); + + for (int i = 0; i < self->num_groups; ++i) { + if (self->core_decoders[i]) iamf_core_decoder_close(self->core_decoders[i]); + } + if (self->demixer) demixer_close(self->demixer); + + def_free(self); +} + +static iamf_audio_block_t* _channel_based_reconstructor_process_frame( + channel_based_reconstructor_t* self, int flush) { + return self->num_groups == 1 + ? _channel_based_reconstructor_reconstruct_element_stream(self, + flush) + : _channel_based_reconstructor_reconstruct_element_scalable_stream( + self, flush); +} + +static channel_based_reconstructor_t* _channel_based_reconstructor_new( + const iamf_audio_element_obu_t* aeo, const iamf_codec_config_obu_t* cco) { + const channel_based_audio_element_obu_t* cbo = + (const channel_based_audio_element_obu_t*)aeo; + int stream_start_index = 0; + channel_based_reconstructor_t* cbr = + def_mallocz(channel_based_reconstructor_t, 1); + if (!cbr) { + def_err_msg_enomem("Channel Based Reconstructor", "Reconstructor"); + return 0; + } + + if (_reconstructor_init(&cbr->base, aeo, cco) != IAMF_OK) { + _channel_based_reconstructor_delete(cbr); + return 0; + } + + cbr->base.destroy = + (fun_reconstructor_destroy_t)_channel_based_reconstructor_delete; + cbr->base.process_frame = (fun_reconstructor_process_frame_t) + _channel_based_reconstructor_process_frame; + + cbr->num_groups = cbo->max_valid_layers; + cbr->target_layout_index = cbo->max_valid_layers - 1; + + for (int i = 0; i < cbr->num_groups; ++i) { + obu_channel_layer_config_t* ctx = + def_value_wrap_ptr(array_at(cbo->channel_audio_layer_configs, i)); + cbr->group_infos[i].layout = iamf_audio_layer_layout_get( + ctx->loudspeaker_layout, ctx->expanded_loudspeaker_layout); + cbr->group_infos[i].stream_start_index = stream_start_index; + cbr->group_infos[i].num_streams = ctx->substream_count; + cbr->group_infos[i].num_channels = + ctx->substream_count + ctx->coupled_substream_count; + + stream_start_index += ctx->substream_count; + + cbr->core_decoders[i] = _core_decoder_open( + ck_stream_mode_ambisonics_none, + ctx->coupled_substream_count + ctx->substream_count, + ctx->substream_count, ctx->coupled_substream_count, 0, 0, cco); + if (!cbr->core_decoders[i]) { + _channel_based_reconstructor_delete(cbr); + return 0; + } + } + + if (cbr->num_groups > 1) { + cbr->demixer = demixer_open(cco->num_samples_per_frame); + if (!cbr->demixer) { + def_err_msg_enomem("Demixer", "Reconstructor"); + _channel_based_reconstructor_delete(cbr); + return 0; + } + + info("open demixer."); + _demixer_config(cbr->demixer, cbr); + } + + info("make channel based reconstructor for element %u", + aeo->audio_element_id); + + return cbr; +} + +stream_mode_t _get_stream_mode_ambisonics( + iamf_ambisonics_mode_t ambisonics_mode) { + if (ambisonics_mode == ck_ambisonics_mode_mono) + return ck_stream_mode_ambisonics_mono; + else if (ambisonics_mode == ck_ambisonics_mode_projection) + return ck_stream_mode_ambisonics_projection; + return ck_stream_mode_ambisonics_none; +} + +static void _scene_based_reconstructor_delete( + scene_based_reconstructor_t* self) { + if (!self) return; + _reconstructor_uninit(&self->base); + if (self->core_decoder) iamf_core_decoder_close(self->core_decoder); + def_free(self); +} + +static iamf_audio_block_t* _scene_based_reconstructor_process_frame( + scene_based_reconstructor_t* self, int flush) { + iamf_audio_block_t* ablock = iamf_audio_block_new( + self->base.audio_element_obu->audio_element_id, + self->base.num_samples_per_frame, self->base.num_audio_channels); + debug("samples %u, channels %u, block %p", self->base.num_samples_per_frame, + self->base.num_audio_channels, ablock); + int ret = + _core_decoder_decode(self->core_decoder, self->base.audio_frame_obus, + self->base.num_audio_streams, ablock, flush); + if (ret < 0) { + error("Failed to decode audio data in scene-based reconstructor %u.", + self->base.audio_element_obu->audio_element_id); + iamf_audio_block_delete(ablock); + ablock = 0; + } else { + _iamf_audio_block_trimming_info_update(ablock, + self->base.audio_frame_obus[0]); + _reconstructor_and_audio_block_update_delay( + &self->base, ablock, iamf_core_decoder_get_delay(self->core_decoder)); + } + + return ablock; +} + +static scene_based_reconstructor_t* _scene_based_reconstructor_new( + const iamf_audio_element_obu_t* aeo, const iamf_codec_config_obu_t* cco) { + const scene_based_audio_element_obu_t* sbo = + (const scene_based_audio_element_obu_t*)aeo; + scene_based_reconstructor_t* sbr = + def_mallocz(scene_based_reconstructor_t, 1); + if (!sbr) { + def_err_msg_enomem("Scene Based Reconstructor", "Reconstructor"); + return 0; + } + + if (_reconstructor_init(&sbr->base, aeo, cco) != IAMF_OK) { + _scene_based_reconstructor_delete(sbr); + return 0; + } + + sbr->base.destroy = + (fun_reconstructor_destroy_t)_scene_based_reconstructor_delete; + sbr->base.process_frame = (fun_reconstructor_process_frame_t) + _scene_based_reconstructor_process_frame; + + if (sbo->ambisonics_mode == ck_ambisonics_mode_mono || + sbo->ambisonics_mode == ck_ambisonics_mode_projection) + sbr->core_decoder = _core_decoder_open( + _get_stream_mode_ambisonics(sbo->ambisonics_mode), + sbo->output_channel_count, sbo->substream_count, + sbo->coupled_substream_count, sbo->channel_mapping, + sbo->mapping_size * (sbo->ambisonics_mode == ck_ambisonics_mode_mono + ? 1 + : sizeof(short)), + cco); + + if (!sbr->core_decoder) { + _scene_based_reconstructor_delete(sbr); + return 0; + } + + info("make scene based reconstructor for element %u", aeo->audio_element_id); + return sbr; +} + +static void _object_based_reconstructor_delete( + object_based_reconstructor_t* self) { + if (!self) return; + _reconstructor_uninit(&self->base); + if (self->core_decoder) iamf_core_decoder_close(self->core_decoder); + def_free(self); +} + +static iamf_audio_block_t* _object_based_reconstructor_process_frame( + object_based_reconstructor_t* self, int flush) { + iamf_audio_block_t* ablock = iamf_audio_block_new( + self->base.audio_element_obu->audio_element_id, + self->base.num_samples_per_frame, self->base.num_audio_channels); + debug("samples %u, channels %u, block %p", self->base.num_samples_per_frame, + self->base.num_audio_channels, ablock); + int ret = + _core_decoder_decode(self->core_decoder, self->base.audio_frame_obus, + self->base.num_audio_streams, ablock, flush); + if (ret < 0) { + error("Failed to decode audio data in object-based reconstructor %u.", + self->base.audio_element_obu->audio_element_id); + iamf_audio_block_delete(ablock); + ablock = 0; + } else { + _iamf_audio_block_trimming_info_update(ablock, + self->base.audio_frame_obus[0]); + _reconstructor_and_audio_block_update_delay( + &self->base, ablock, iamf_core_decoder_get_delay(self->core_decoder)); + } + + return ablock; +} + +static object_based_reconstructor_t* _object_based_reconstructor_new( + const iamf_audio_element_obu_t* aeo, const iamf_codec_config_obu_t* cco) { + const object_based_audio_element_obu_t* obo = + (const object_based_audio_element_obu_t*)aeo; + object_based_reconstructor_t* obr = + def_mallocz(object_based_reconstructor_t, 1); + if (!obr) { + def_err_msg_enomem("Object Based Reconstructor", "Reconstructor"); + return 0; + } + + if (_reconstructor_init(&obr->base, aeo, cco) != IAMF_OK) { + _object_based_reconstructor_delete(obr); + return 0; + } + + obr->base.destroy = + (fun_reconstructor_destroy_t)_object_based_reconstructor_delete; + obr->base.process_frame = (fun_reconstructor_process_frame_t) + _object_based_reconstructor_process_frame; + + obr->base.num_audio_channels = obo->num_objects; + + obr->core_decoder = _core_decoder_open( + ck_stream_mode_ambisonics_none, obr->base.num_audio_channels, + obr->base.num_audio_streams, + obr->base.num_audio_channels != obr->base.num_audio_streams, 0, 0, cco); + + if (!obr->core_decoder) { + _object_based_reconstructor_delete(obr); + return 0; + } + + info("make object based reconstructor for element %u with %u objects", + aeo->audio_element_id, obo->num_objects); + return obr; +} + +static void _reconstructor_delete(base_reconstructor_t* self) { + if (!self) return; + if (self->destroy) self->destroy(self); +} + +static void iamf_element_reconstructor_priv_delete_all_audio_frame_obus( + iamf_element_reconstructor_t* self) { + if (!self || !hash_map_size(self->reconstructor_map)) return; + + hash_map_iterator_t* iter = hash_map_iterator_new(self->reconstructor_map); + if (iter) { + do { + _reconstructor_delete_all_audio_frame_obus(def_value_wrap_type_ptr( + base_reconstructor_t, hash_map_iterator_get_value(iter))); + } while (!hash_map_iterator_next(iter)); + hash_map_iterator_delete(iter); + } +} + +// ============================================================================= +// Public Interface Implementation +// ============================================================================= + +iamf_element_reconstructor_t* iamf_element_reconstructor_create() { + iamf_element_reconstructor_t* reconstructor = + def_mallocz(iamf_element_reconstructor_t, 1); + if (!reconstructor) { + def_err_msg_enomem("instance", "Reconstructor"); + return 0; + } + + reconstructor->reconstructor_map = + hash_map_new(def_hash_map_capacity_elements); + if (!reconstructor->reconstructor_map) { + def_err_msg_enomem("reconstructors map", "Reconstructor"); + iamf_element_reconstructor_destroy(reconstructor); + return 0; + } + + reconstructor->audio_frame_obus = + hash_map_new(def_hash_map_capacity_audio_frames); + if (!reconstructor->audio_frame_obus) { + def_err_msg_enomem("audio frames map", "Reconstructor"); + iamf_element_reconstructor_destroy(reconstructor); + return 0; + } + + return reconstructor; +} + +void iamf_element_reconstructor_destroy( + iamf_element_reconstructor_t* reconstructor) { + if (!reconstructor) return; + + if (reconstructor->reconstructor_map) + hash_map_delete(reconstructor->reconstructor_map, + def_default_free_ptr(_reconstructor_delete)); + + if (reconstructor->audio_frame_obus) + hash_map_delete(reconstructor->audio_frame_obus, 0); + + def_free(reconstructor); +} + +int iamf_element_reconstructor_add_element( + iamf_element_reconstructor_t* reconstructor, + const iamf_audio_element_obu_t* aeo, const iamf_codec_config_obu_t* cco) { + base_reconstructor_t* br = 0; + if (!reconstructor || !aeo || !cco) return IAMF_ERR_BAD_ARG; + + switch (aeo->audio_element_type) { + case ck_audio_element_type_channel_based: { + channel_based_reconstructor_t* cbr = + _channel_based_reconstructor_new(aeo, cco); + if (!cbr) { + error("Failed to create channel-based reconstructor."); + return IAMF_ERR_ALLOC_FAIL; + } + br = (base_reconstructor_t*)cbr; + } break; + case ck_audio_element_type_scene_based: { + scene_based_reconstructor_t* sbr = + _scene_based_reconstructor_new(aeo, cco); + if (!sbr) { + error("Failed to create scene-based reconstructor."); + return IAMF_ERR_ALLOC_FAIL; + } + br = (base_reconstructor_t*)sbr; + } break; + case ck_audio_element_type_object_based: { + object_based_reconstructor_t* obr = + _object_based_reconstructor_new(aeo, cco); + if (!obr) { + error("Failed to create object-based reconstructor."); + return IAMF_ERR_ALLOC_FAIL; + } + br = (base_reconstructor_t*)obr; + break; + } + default: { + warning("Unsupported audio element type %d.", aeo->audio_element_type); + return IAMF_ERR_UNIMPLEMENTED; + } + } + + if (br) { + int n = array_size(aeo->audio_substream_ids); + trace("add element %u, substream ids %d to reconstructor.", + aeo->audio_element_id, n); + hash_map_put(reconstructor->reconstructor_map, aeo->audio_element_id, + def_value_wrap_instance_ptr(br)); + for (int i = 0; i < n; ++i) { + hash_map_put(reconstructor->audio_frame_obus, + def_value_wrap_u32(array_at(aeo->audio_substream_ids, i)), + def_value_wrap_instance_u32(aeo->audio_element_id)); + } + } + + return IAMF_OK; // Success +} + +int iamf_element_reconstructor_add_audio_frame_obu( + iamf_element_reconstructor_t* self, iamf_audio_frame_obu_t* obu) { + value_wrap_t* val = 0; + uint32_t eid = 0; + base_reconstructor_t* recon = 0; + iamf_audio_frame_obu_t** afo = 0; + int ret = IAMF_OK; + + if (!self || !obu) { + error("Invalid arguments: self or obu is NULL."); + return IAMF_ERR_BAD_ARG; + } + + val = hash_map_get(self->audio_frame_obus, obu->audio_substream_id); + if (!val) { + debug("Audio element ID not found for substream ID %u.", + obu->audio_substream_id); + iamf_audio_frame_obu_free(obu); + return IAMF_ERR_BAD_ARG; + } + eid = def_value_wrap_u32(val); + + val = hash_map_get(self->reconstructor_map, eid); + if (!val) { + warning("Reconstructor not found for audio element ID %u.", eid); + iamf_audio_frame_obu_free(obu); + return IAMF_ERR_INTERNAL; + } + recon = def_value_wrap_ptr(val); + + val = hash_map_get(recon->audio_frames_map, obu->audio_substream_id); + if (!val) { + warning("Audio frame node not found for substream ID %u in self.", + obu->audio_substream_id); + iamf_audio_frame_obu_free(obu); + return IAMF_ERR_INTERNAL; + } + afo = def_value_wrap_ptr(val); + + if (*afo) { + warning("Substream ID %u already has an audio frame OBU.", + obu->audio_substream_id); + iamf_element_reconstructor_priv_delete_all_audio_frame_obus(self); + ret = IAMF_ERR_INVALID_PACKET; + } + + *afo = obu; + recon->num_audio_frames++; + + if (recon->num_audio_frames != recon->num_audio_streams) return ret; + debug("element %u all audio frames %d are ready.", eid, + recon->num_audio_frames); + + return 1; +} + +iamf_audio_block_t* iamf_element_reconstructor_process( + iamf_element_reconstructor_t* self) { + iamf_audio_block_t* ablock = 0; + if (!self || !hash_map_size(self->reconstructor_map)) { + debug( + "iamf_element_reconstructor_process: self is NULL or reconstructor_map " + "is empty"); + return 0; + } + + debug("iamf_element_reconstructor_process: reconstructor_map size = %d", + hash_map_size(self->reconstructor_map)); + + hash_map_iterator_t* iter = hash_map_iterator_new(self->reconstructor_map); + if (iter) { + do { + base_reconstructor_t* br = def_value_wrap_type_ptr( + base_reconstructor_t, hash_map_iterator_get_value(iter)); + if (br) { + if (br->num_audio_streams == br->num_audio_frames) { + if (br->process_frame) ablock = br->process_frame(br, 0); + _reconstructor_delete_all_audio_frame_obus(br); + break; + } else { + debug( + "audio element %u: Waiting for more audio " + "frames (%d/%d)", + hash_map_iterator_get_key(iter), br->num_audio_frames, + br->num_audio_streams); + } + } + } while (!hash_map_iterator_next(iter)); + hash_map_iterator_delete(iter); + } + return ablock; +} + +iamf_audio_block_t* iamf_element_reconstructor_flush( + iamf_element_reconstructor_t* self, uint32_t id) { + iamf_audio_block_t* ablock = 0; + if (!self) return 0; + + if (id == def_i32_id_none) { + hash_map_iterator_t* iter = hash_map_iterator_new(self->reconstructor_map); + if (iter) { + do { + base_reconstructor_t* br = def_value_wrap_type_ptr( + base_reconstructor_t, hash_map_iterator_get_value(iter)); + if (br->delay) { + ablock = br->process_frame(br, 1); + ablock->second_padding = ablock->num_samples_per_channel - br->delay; + br->delay = 0; + break; + } + } while (!hash_map_iterator_next(iter)); + hash_map_iterator_delete(iter); + } + } else { + base_reconstructor_t* br = + def_value_wrap_optional_ptr(hash_map_get(self->reconstructor_map, id)); + if (br && br->delay > 0) { + ablock = br->process_frame(br, 1); + ablock->second_padding = ablock->num_samples_per_channel - br->delay; + br->delay = 0; + } + } + + return ablock; +} + +int iamf_element_reconstructor_update_demixing_mode( + iamf_element_reconstructor_t* reconstructor, int audio_element_id, + int demixing_mode) { + if (!reconstructor) return IAMF_ERR_BAD_ARG; + base_reconstructor_t* br = def_value_wrap_optional_ptr( + hash_map_get(reconstructor->reconstructor_map, audio_element_id)); + + if (!br) return IAMF_ERR_BAD_ARG; + if (br->type == ck_audio_element_type_channel_based) { + channel_based_reconstructor_t* cbr = (channel_based_reconstructor_t*)br; + if (cbr->demixer) + return demixer_set_demixing_info(cbr->demixer, demixing_mode, + def_dmx_weight_index_none); + } + return IAMF_ERR_BAD_ARG; +} + +int iamf_element_reconstructor_update_recon_gain( + iamf_element_reconstructor_t* reconstructor, int audio_element_id, + const recon_gain_t* recon_gain) { + if (!reconstructor || !recon_gain) return IAMF_ERR_BAD_ARG; + base_reconstructor_t* br = def_value_wrap_optional_ptr( + hash_map_get(reconstructor->reconstructor_map, audio_element_id)); + if (!br) return IAMF_ERR_BAD_ARG; + if (br->type == ck_audio_element_type_channel_based) { + channel_based_reconstructor_t* cbr = (channel_based_reconstructor_t*)br; + if (cbr->target_layout_index == recon_gain->layer) { + int channels = array_size(recon_gain->recon_gain_linear); + iamf_channel_t order[ck_iamf_channel_recon_count] = {0}; + float recon_gain_linear[ck_iamf_channel_recon_count] = {0}; + for (int i = 0; i < channels; ++i) + recon_gain_linear[i] = + def_value_wrap_f32(array_at(recon_gain->recon_gain_linear, i)); + _get_recon_channels_order( + cbr->group_infos[cbr->target_layout_index].layout, + recon_gain->recon_gain_flags, order, ck_iamf_channel_recon_count); + return demixer_set_recon_gain(cbr->demixer, channels, order, + recon_gain_linear, + recon_gain->recon_gain_flags); + } + } + return IAMF_ERR_BAD_ARG; +} + +int iamf_element_reconstructor_set_channel_based_target_layout( + iamf_element_reconstructor_t* reconstructor, int audio_element_id, + iamf_loudspeaker_layout_t target_layout) { + base_reconstructor_t* br = 0; + if (!reconstructor) { + error("Invalid reconstructor instance."); + return IAMF_ERR_BAD_ARG; + } + + if (!iamf_audio_layer_base_layout_check(target_layout)) { + debug("Invalid target layout (%d) specified.", target_layout); + return IAMF_ERR_BAD_ARG; + } + + br = def_value_wrap_optional_ptr( + hash_map_get(reconstructor->reconstructor_map, audio_element_id)); + if (!br) { + error("Audio element with ID %d not found.", audio_element_id); + return IAMF_ERR_INTERNAL; + } + + if (br->type == ck_audio_element_type_channel_based) { + channel_based_reconstructor_t* cbr = (channel_based_reconstructor_t*)br; + int i = 0; + for (; i < cbr->num_groups; ++i) { + if (cbr->group_infos[i].layout == target_layout) { + cbr->target_layout_index = i; + break; + } + } + + if (i < cbr->num_groups) + return _set_channel_based_target_layout(cbr, target_layout); + } + + return IAMF_ERR_BAD_ARG; +} + +int iamf_element_reconstructor_get_channel_based_reconstructed_layout_index( + iamf_element_reconstructor_t* self, int audio_element_id) { + if (!self) return IAMF_ERR_BAD_ARG; + base_reconstructor_t* br = def_value_wrap_optional_ptr( + hash_map_get(self->reconstructor_map, audio_element_id)); + if (!br) return IAMF_ERR_BAD_ARG; + if (br->type == ck_audio_element_type_channel_based) { + channel_based_reconstructor_t* cbr = (channel_based_reconstructor_t*)br; + // Add bounds checking for target_layout_index + if (cbr->target_layout_index >= 0 && + cbr->target_layout_index < cbr->num_groups) { + return cbr->target_layout_index; + } + } + + return IAMF_ERR_BAD_ARG; +} + +int iamf_element_reconstructor_activate_element( + iamf_element_reconstructor_t* reconstructor, int audio_element_id) { + return IAMF_OK; // Success +} diff --git a/code/src/iamf_dec/iamf_element_reconstructor.h b/code/src/iamf_dec/iamf_element_reconstructor.h new file mode 100755 index 00000000..dba02463 --- /dev/null +++ b/code/src/iamf_dec/iamf_element_reconstructor.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_element_reconstructor.h + * @brief IAMF element reconstructor APIs. + * @version 0.1 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_ELEMENT_RECONSTRUCTOR_H__ +#define __IAMF_ELEMENT_RECONSTRUCTOR_H__ + +#include +#include + +#include "iamf_audio_block.h" +#include "iamf_obu_all.h" + +typedef struct IamfElementReconstructor iamf_element_reconstructor_t; + +/** + * @brief Create an iamf_element_reconstructor_t instance. + * + * @return iamf_element_reconstructor_t* Success: pointer to the new instance; + * Failure: NULL. + */ +iamf_element_reconstructor_t* iamf_element_reconstructor_create(); + +/** + * @brief Destroy an iamf_element_reconstructor_t instance and release its + * internal resources. + * + * @param reconstructor Pointer to the iamf_element_reconstructor_t instance to + * destroy. + */ +void iamf_element_reconstructor_destroy(iamf_element_reconstructor_t* self); + +/** + * @brief Add an Audio Element to be reconstructed. + * + * This function will create a specific reconstructor (SceneBased, ChannelBased, + * or ObjectBased) based on the iamf_audio_element_obu_t type and store it + * internally. + * + * @param reconstructor iamf_element_reconstructor_t instance. + * @param audio_element_obu Pointer to the Audio Element OBU. + * @param codec_config_obu Pointer to the associated Codec Config OBU. + * @return int Success: 0; Failure: error code. + */ +int iamf_element_reconstructor_add_element( + iamf_element_reconstructor_t* self, + const iamf_audio_element_obu_t* audio_element_obu, + const iamf_codec_config_obu_t* codec_config_obu); + +/** + * @brief Receive and process a raw OBU stream. + * + * This function uses the internal IamfObuParser to parse the OBU stream and + * then dispatches it to the appropriate specific reconstructor based on the OBU + * type (e.g., Audio Frame, Parameter Block). + * + * @param reconstructor iamf_element_reconstructor_t instance. + * @return int Success: 0; Failure: error code. + */ +int iamf_element_reconstructor_add_audio_frame_obu( + iamf_element_reconstructor_t* self, iamf_audio_frame_obu_t* obu); + +iamf_audio_block_t* iamf_element_reconstructor_process( + iamf_element_reconstructor_t* self); + +iamf_audio_block_t* iamf_element_reconstructor_flush( + iamf_element_reconstructor_t* self, uint32_t id); + +/** + * @brief Update demixing info for a Channel-based Element. + * + * @param reconstructor iamf_element_reconstructor_t instance. + * @param audio_element_id The ID of the Audio Element to update. + * @param demixing_info Pointer to the new Demixing Info. + * @return int Success: 0; Failure: error code (e.g., element not found or not + * channel-based). + */ +int iamf_element_reconstructor_update_demixing_mode( + iamf_element_reconstructor_t* self, int audio_element_id, + int demixing_mode); + +/** + * @brief Update recon gain for a Channel-based Element. + * + * @param reconstructor iamf_element_reconstructor_t instance. + * @param audio_element_id The ID of the Audio Element to update. + * @param recon_gain Pointer to the new Recon Gain. + * @return int Success: 0; Failure: error code (e.g., element not found or not + * channel-based). + */ +int iamf_element_reconstructor_update_recon_gain( + iamf_element_reconstructor_t* self, int audio_element_id, + const recon_gain_t* recon_gain); + +/** + * @brief Set the target layout for a Channel-based Element. + * + * @param reconstructor iamf_element_reconstructor_t instance. + * @param audio_element_id The ID of the Audio Element to update. + * @param target_layout The target loudspeaker layout to set. + * @return int Success: 0; Failure: error code (e.g., element not found or not + * channel-based). + */ +int iamf_element_reconstructor_set_channel_based_target_layout( + iamf_element_reconstructor_t* self, int audio_element_id, + iamf_loudspeaker_layout_t target_layout); + +int iamf_element_reconstructor_get_channel_based_reconstructed_layout_index( + iamf_element_reconstructor_t* self, int audio_element_id); +/** + * @brief Activate a ReconstructorEntry for an Audio Element. + * + * This function activates the ReconstructorEntry associated with the given + * audio_element_id, making it ready for processing audio frames. + * + * @param reconstructor iamf_element_reconstructor_t instance. + * @param audio_element_id The ID of the Audio Element to activate. + * @return int Success: 0; Failure: error code (e.g., element not found). + */ +int iamf_element_reconstructor_activate_element( + iamf_element_reconstructor_t* self, int audio_element_id); + +#endif // __IAMF_ELEMENT_RECONSTRUCTOR_H__ diff --git a/code/src/iamf_dec/iamf_layout.c b/code/src/iamf_dec/iamf_layout.c new file mode 100755 index 00000000..7bcb549d --- /dev/null +++ b/code/src/iamf_dec/iamf_layout.c @@ -0,0 +1,571 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file IAMF_layout.c + * @brief Channel layout. + * @version 2.0.0 + * @date Created 08/05/2024 + **/ + +#include "iamf_layout.h" + +static const iamf_layout_info_t iamf_layouts[] = { + { + .id = ck_iamf_layout_id_mono, + .name = "Mono", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_scalable, + .channels = 1, + .surround = 1, + .lfe1 = def_lfe_none, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_MONO, + .layout = ck_iamf_loudspeaker_layout_mono, + .decoding_map = {0}, + .channel_layout = {ck_iamf_channel_mono}, + }, + { + .id = ck_iamf_layout_id_stereo, + .name = "Stereo", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_scalable, + .channels = 2, + .surround = 2, + .lfe1 = def_lfe_none, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_A, + .layout = ck_iamf_loudspeaker_layout_stereo, + .decoding_map = {0, 1}, + .channel_layout = {ck_iamf_channel_l2, ck_iamf_channel_r2}, + }, + { + .id = ck_iamf_layout_id_5_1, + .name = "5.1", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_scalable, + .channels = 6, + .surround = 5, + .lfe1 = 3, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_B, + .layout = ck_iamf_loudspeaker_layout_510, + .decoding_map = {0, 1, 4, 5, 2, 3}, + .channel_layout = {ck_iamf_channel_l5, ck_iamf_channel_r5, + ck_iamf_channel_c, ck_iamf_channel_lfe, + ck_iamf_channel_sl5, ck_iamf_channel_sr5}, + }, + { + .id = ck_iamf_layout_id_5_1_2, + .name = "5.1.2", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_scalable, + .channels = 8, + .height = 2, + .surround = 5, + .lfe1 = 3, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_C, + .layout = ck_iamf_loudspeaker_layout_512, + .decoding_map = {0, 1, 4, 5, 6, 7, 2, 3}, + .channel_layout = {ck_iamf_channel_l5, ck_iamf_channel_r5, + ck_iamf_channel_c, ck_iamf_channel_lfe, + ck_iamf_channel_sl5, ck_iamf_channel_sr5, + ck_iamf_channel_hl, ck_iamf_channel_hr}, + }, + { + .id = ck_iamf_layout_id_5_1_4, + .name = "5.1.4", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_scalable, + .channels = 10, + .height = 4, + .surround = 5, + .lfe1 = 3, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_D, + .layout = ck_iamf_loudspeaker_layout_514, + .decoding_map = {0, 1, 4, 5, 6, 7, 8, 9, 2, 3}, + .channel_layout = {ck_iamf_channel_l5, ck_iamf_channel_r5, + ck_iamf_channel_c, ck_iamf_channel_lfe, + ck_iamf_channel_sl5, ck_iamf_channel_sr5, + ck_iamf_channel_hfl, ck_iamf_channel_hfr, + ck_iamf_channel_hbl, ck_iamf_channel_hbr}, + }, + { + .id = ck_iamf_layout_id_7_1, + .name = "7.1", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_scalable, + .channels = 8, + .surround = 7, + .lfe1 = 3, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_I, + .layout = ck_iamf_loudspeaker_layout_710, + .decoding_map = {0, 1, 4, 5, 6, 7, 2, 3}, + .channel_layout = {ck_iamf_channel_l7, ck_iamf_channel_r7, + ck_iamf_channel_c, ck_iamf_channel_lfe, + ck_iamf_channel_sl7, ck_iamf_channel_sr7, + ck_iamf_channel_bl7, ck_iamf_channel_br7}, + }, + { + .id = ck_iamf_layout_id_7_1_2, + .name = "7.1.2", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_scalable, + .channels = 10, + .height = 2, + .surround = 7, + .lfe1 = 3, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_EXT_712, + .layout = ck_iamf_loudspeaker_layout_712, + .decoding_map = {0, 1, 4, 5, 6, 7, 8, 9, 2, 3}, + .channel_layout = {ck_iamf_channel_l7, ck_iamf_channel_r7, + ck_iamf_channel_c, ck_iamf_channel_lfe, + ck_iamf_channel_sl7, ck_iamf_channel_sr7, + ck_iamf_channel_bl7, ck_iamf_channel_br7, + ck_iamf_channel_hl, ck_iamf_channel_hr}, + }, + { + .id = ck_iamf_layout_id_7_1_4, + .name = "7.1.4", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_scalable, + .channels = 12, + .height = 4, + .surround = 7, + .sound_system = SOUND_SYSTEM_J, + .layout = ck_iamf_loudspeaker_layout_714, + .lfe1 = 3, + .lfe2 = def_lfe_none, + .decoding_map = {0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 2, 3}, + .channel_layout = {ck_iamf_channel_l7, ck_iamf_channel_r7, + ck_iamf_channel_c, ck_iamf_channel_lfe, + ck_iamf_channel_sl7, ck_iamf_channel_sr7, + ck_iamf_channel_bl7, ck_iamf_channel_br7, + ck_iamf_channel_hfl, ck_iamf_channel_hfr, + ck_iamf_channel_hbl, ck_iamf_channel_hbr}, + }, + { + .id = ck_iamf_layout_id_3_1_2, + .name = "3.1.2", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_scalable, + .channels = 6, + .height = 2, + .surround = 3, + .lfe1 = 3, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_EXT_312, + .layout = ck_iamf_loudspeaker_layout_312, + .decoding_map = {0, 1, 4, 5, 2, 3}, + .channel_layout = {ck_iamf_channel_l3, ck_iamf_channel_r3, + ck_iamf_channel_c, ck_iamf_channel_lfe, + ck_iamf_channel_tl, ck_iamf_channel_tr}, + }, + { + .id = ck_iamf_layout_id_binaural, + .name = "binaural", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out, + .channels = 2, + .surround = 2, + .lfe1 = def_lfe_none, + .lfe2 = def_lfe_none, + .layout = ck_iamf_loudspeaker_layout_binaural, + }, + { + .id = ck_iamf_layout_id_sound_system_e, + .name = "Sound System E", + .flags = ck_iamf_layout_flag_out, + .channels = 11, + .surround = 5, + .height = 4, + .bottom = 1, + .lfe1 = 3, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_E, + .layout = ck_iamf_loudspeaker_layout_none, + }, + { + .id = ck_iamf_layout_id_sound_system_f, + .name = "Sound System F", + .flags = ck_iamf_layout_flag_out, + .channels = 12, + .surround = 7, + .height = 3, + .lfe1 = 10, + .lfe2 = 11, + .sound_system = SOUND_SYSTEM_F, + .layout = ck_iamf_loudspeaker_layout_none, + }, + { + .id = ck_iamf_layout_id_sound_system_g, + .name = "Sound System G", + .flags = ck_iamf_layout_flag_out, + .channels = 14, + .surround = 9, + .height = 4, + .lfe1 = 3, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_G, + .layout = ck_iamf_loudspeaker_layout_none, + }, + { + .id = ck_iamf_layout_id_expanded_lfe, + .name = "LFE", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 1, + .layout = ck_iamf_loudspeaker_layout_expanded_lfe, + .reference_layout = ck_iamf_loudspeaker_layout_714, + // .decoding_map = {3}, + .decoding_map = {0}, + }, + { + .id = ck_iamf_layout_id_expanded_stereo_s, + .name = "Stereo-S", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 2, + .layout = ck_iamf_loudspeaker_layout_expanded_stereo_s, + .reference_layout = ck_iamf_loudspeaker_layout_514, + // .decoding_map = {4, 5}, + .decoding_map = {0, 1}, + }, + { + .id = ck_iamf_layout_id_expanded_stereo_ss, + .name = "STEREO-SS", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 2, + .layout = ck_iamf_loudspeaker_layout_expanded_stereo_ss, + .reference_layout = ck_iamf_loudspeaker_layout_714, + // .decoding_map = {4, 5}, + .decoding_map = {0, 1}, + }, + { + .id = ck_iamf_layout_id_expanded_stereo_rs, + .name = "STEREO-RS", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 2, + .layout = ck_iamf_loudspeaker_layout_expanded_stereo_rs, + .reference_layout = ck_iamf_loudspeaker_layout_714, + // .decoding_map = {6, 7}, + .decoding_map = {0, 1}, + }, + { + .id = ck_iamf_layout_id_expanded_stereo_tf, + .name = "STEREO-TF", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 2, + .layout = ck_iamf_loudspeaker_layout_expanded_stereo_tf, + .reference_layout = ck_iamf_loudspeaker_layout_714, + // .decoding_map = {8, 9}, + .decoding_map = {0, 1}, + }, + { + .id = ck_iamf_layout_id_expanded_stereo_tb, + .name = "STEREO-TB", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 2, + .layout = ck_iamf_loudspeaker_layout_expanded_stereo_tb, + .reference_layout = ck_iamf_loudspeaker_layout_714, + // .decoding_map = {10, 11}, + .decoding_map = {0, 1}, + }, + { + .id = ck_iamf_layout_id_expanded_top_4ch, + .name = "Top-4ch", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 4, + .layout = ck_iamf_loudspeaker_layout_expanded_top_4ch, + .reference_layout = ck_iamf_loudspeaker_layout_714, + // .decoding_map = {8, 9, 10, 11}, + .decoding_map = {0, 1, 2, 3}, + }, + { + .id = ck_iamf_layout_id_expanded_3ch, + .name = "3.0ch", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 3, + .layout = ck_iamf_loudspeaker_layout_expanded_3ch, + .reference_layout = ck_iamf_loudspeaker_layout_714, + .decoding_map = {0, 1, 2}, + }, + { + .id = ck_iamf_layout_id_expanded_9_1_6, + .name = "9.1.6ch", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_expanded, + // .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + // ck_iamf_layout_flag_expanded | ck_iamf_layout_flag_subset, + .channels = 16, + .surround = 9, + .height = 6, + .lfe1 = 3, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_EXT_916, + .layout = ck_iamf_loudspeaker_layout_expanded_916, + // .reference_layout = ck_iamf_loudspeaker_layout_expanded_a293, + .decoding_map = {6, 7, 0, 1, 8, 9, 4, 5, 10, 11, 14, 15, 12, 13, 2, 3}, + // .decoding_map = {6, 7, 0, 1, 10, 11, 4, 5, 12, 13, 18, 19, 16, 17, 2, + // 3}, // LFE1->LFE2 (9) + }, + { + .id = ck_iamf_layout_id_expanded_stereo_f, + .name = "Stereo-F", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 2, + .layout = ck_iamf_loudspeaker_layout_expanded_stereo_f, + .reference_layout = ck_iamf_loudspeaker_layout_expanded_916, + .decoding_map = {0, 1}, + }, + { + .id = ck_iamf_layout_id_expanded_stereo_si, + .name = "Stereo-Si", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 2, + .layout = ck_iamf_loudspeaker_layout_expanded_stereo_si, + .reference_layout = ck_iamf_loudspeaker_layout_expanded_916, + // .decoding_map = {8, 9}, // 9.1.6 + // .decoding_map = {10, 11}, // 22.2 + .decoding_map = {0, 1}, + }, + { + .id = ck_iamf_layout_id_expanded_stereo_tpsi, + .name = "Stereo-TpSi", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 2, + .layout = ck_iamf_loudspeaker_layout_expanded_stereo_tpsi, + .reference_layout = ck_iamf_loudspeaker_layout_expanded_916, + // .decoding_map = {14, 15}, // 9.1.6 + // .decoding_map = {18, 19}, // 22.2 + .decoding_map = {0, 1}, + }, + { + .id = ck_iamf_layout_id_expanded_top_6ch, + .name = "Top-6ch", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 6, + .layout = ck_iamf_loudspeaker_layout_expanded_top_6ch, + .reference_layout = ck_iamf_loudspeaker_layout_expanded_916, + // .decoding_map = {10, 11, 14, 15, 12, 13}, // 9.1.6 + // .decoding_map = {12, 13, 18, 19, 16, 17}, // 22.2 + .decoding_map = {0, 1, 4, 5, 2, 3}, + }, + { + .id = ck_iamf_layout_id_expanded_a_2_9_3, + .name = "10.2.9.3ch (Sound System H)", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_expanded, + .channels = 24, + .surround = 10, + .height = 9, + .bottom = 3, + .lfe1 = 3, + .lfe2 = 9, + .sound_system = SOUND_SYSTEM_H, + .layout = ck_iamf_loudspeaker_layout_expanded_a293, + .decoding_map = {6, 7, 0, 1, 10, 11, 4, 5, 12, 13, 18, 19, + 16, 17, 22, 23, 2, 8, 14, 15, 20, 21, 3, 9}, + }, + { + .id = ck_iamf_layout_id_expanded_lfe_pair, + .name = "LFE-Pair", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 2, + .layout = ck_iamf_loudspeaker_layout_expanded_lfe_pair, + .reference_layout = ck_iamf_loudspeaker_layout_expanded_a293, + // .decoding_map = {3, 9}, + .decoding_map = {0, 1}, + }, + { + .id = ck_iamf_layout_id_expanded_bottom_3ch, + .name = "Bottom-3ch", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 3, + .bottom = 3, + .layout = ck_iamf_loudspeaker_layout_expanded_bottom_3ch, + .reference_layout = ck_iamf_loudspeaker_layout_expanded_a293, + // .decoding_map = {22, 23, 21}, + .decoding_map = {1, 2, 0}, + }, + { + .id = ck_iamf_layout_id_expanded_7_1_5_4, + .name = "7.1.5.4ch", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_out | + ck_iamf_layout_flag_expanded, + .channels = 17, + .surround = 7, + .height = 9, + .bottom = 4, + .lfe1 = 3, + .lfe2 = def_lfe_none, + .sound_system = SOUND_SYSTEM_EXT_7154, + .layout = ck_iamf_loudspeaker_layout_expanded_7154, + .decoding_map = {0, 1, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 2, 10, + 3}, + }, + + { + .id = ck_iamf_layout_id_expanded_bottom_4ch, + .name = "Bottom-4ch", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 4, + .layout = ck_iamf_loudspeaker_layout_expanded_bottom_4ch, + .reference_layout = ck_iamf_loudspeaker_layout_expanded_7154, + // .decoding_map = {13, 14, 15, 16}, + .decoding_map = {0, 1, 2, 3}, + }, + { + .id = ck_iamf_layout_id_expanded_top_1ch, + .name = "Top-1ch", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 1, + .layout = ck_iamf_loudspeaker_layout_expanded_top_1ch, + .reference_layout = ck_iamf_loudspeaker_layout_expanded_7154, + // .decoding_map = {10}, + .decoding_map = {0}, + }, + { + .id = ck_iamf_layout_id_expanded_top_5ch, + .name = "Top-5ch", + .flags = ck_iamf_layout_flag_in | ck_iamf_layout_flag_expanded | + ck_iamf_layout_flag_subset, + .channels = 5, + .layout = ck_iamf_loudspeaker_layout_expanded_top_5ch, + .reference_layout = ck_iamf_loudspeaker_layout_expanded_7154, + // .decoding_map = {8, 9, 11, 12, 10}, + .decoding_map = {0, 1, 3, 4, 2}, + }, +}; + +const iamf_layout_info_t *iamf_layout_get_info(iamf_layout_t layout) { + const iamf_layout_info_t *info = 0; + + if (layout.type == ck_iamf_layout_type_loudspeakers_ss_convention) { + iamf_sound_system_t ss = layout.sound_system; + for (uint32_t i = 0; i < sizeof(iamf_layouts) / sizeof(iamf_layouts[0]); + ++i) { + if (iamf_layouts[i].sound_system == ss && + (iamf_layouts[i].flags & ck_iamf_layout_flag_out)) { + info = &iamf_layouts[i]; + break; + } + } + } else if (layout.type == ck_iamf_layout_type_binaural) + info = + iamf_loudspeaker_layout_get_info(ck_iamf_loudspeaker_layout_binaural); + return info; +} + +const iamf_layout_info_t *iamf_loudspeaker_layout_get_info( + iamf_loudspeaker_layout_t type) { + const iamf_layout_info_t *info = 0; + for (uint32_t i = 0; i < sizeof(iamf_layouts) / sizeof(iamf_layouts[0]); + ++i) { + if (iamf_layouts[i].layout == type && + (iamf_layouts[i].flags & ck_iamf_layout_flag_in)) { + info = &iamf_layouts[i]; + break; + } + } + return info; +} + +int iamf_loudspeaker_layout_get_decoding_channels( + iamf_loudspeaker_layout_t type, iamf_channel_t *channels, uint32_t count) { + const iamf_layout_info_t *info = iamf_loudspeaker_layout_get_info(type); + for (uint32_t i = 0; i < info->channels; ++i) + channels[i] = info->channel_layout[info->decoding_map[i]]; + return info->channels; +} + +int iamf_loudspeaker_layout_get_rendering_channels( + iamf_loudspeaker_layout_t type, iamf_channel_t *channels, uint32_t count) { + const iamf_layout_info_t *info = iamf_loudspeaker_layout_get_info(type); + if (count < info->channels) return IAMF_ERR_BUFFER_TOO_SMALL; + for (uint32_t i = 0; i < info->channels; ++i) + channels[i] = info->channel_layout[i]; + return info->channels; +} + +int iamf_layout_channels_count(iamf_layout_t *layout) { + int ret = 0; + if (layout->type == ck_iamf_layout_type_loudspeakers_ss_convention) { + const iamf_layout_info_t *info = iamf_layout_get_info(*layout); + if (info) ret = info->channels; + } else if (layout->type == ck_iamf_layout_type_binaural) { + ret = 2; + } + + return ret; +} + +int iamf_layout_is_equal(iamf_layout_t a, iamf_layout_t b) { + if (a.type != b.type) return def_false; + + switch (a.type) { + case ck_iamf_layout_type_loudspeakers_ss_convention: + return a.sound_system == b.sound_system; + + case ck_iamf_layout_type_binaural: + return def_true; + + case ck_iamf_layout_type_not_defined: + default: + break; + } + return def_false; +} + +static iamf_layout_t _get_sound_system_layout_instance(iamf_layout_t layout) { + if (layout.type == ck_iamf_layout_type_binaural) + return def_sound_system_layout_instance(SOUND_SYSTEM_A); + else if (layout.type == ck_iamf_layout_type_loudspeakers_ss_convention) + return layout; + else + return def_sound_system_layout_instance(SOUND_SYSTEM_NONE); +} + +int iamf_layout_higher_check(iamf_layout_t layout1, iamf_layout_t layout2, + int equal) { + iamf_layout_t ss_layout1 = _get_sound_system_layout_instance(layout1); + iamf_layout_t ss_layout2 = _get_sound_system_layout_instance(layout2); + const iamf_layout_info_t *info1 = iamf_layout_get_info(ss_layout1); + const iamf_layout_info_t *info2 = iamf_layout_get_info(ss_layout2); + + if (!info1) return def_false; + if (!info2) return def_true; + if (!equal && iamf_layout_is_equal(ss_layout1, ss_layout2)) return def_false; + + // A higher layout x'.y'.z' means that x', y', and z' are greater than or + // equal to x, y, and z + return (info1->surround >= info2->surround) && + (info1->height >= info2->height) && (info1->bottom >= info2->bottom) && + (info1->channels >= info2->channels); +} diff --git a/code/src/iamf_dec/iamf_layout.h b/code/src/iamf_dec/iamf_layout.h new file mode 100755 index 00000000..f9f5f797 --- /dev/null +++ b/code/src/iamf_dec/iamf_layout.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_layout.h + * @brief Channel Layout APIs. + * @version 0.1 + * @date Created 08/05/2024 + **/ + +#ifndef __IAMF_LAYOUT_H__ +#define __IAMF_LAYOUT_H__ + +#include + +#include "iamf_private_definitions.h" +#include "iamf_utils.h" + +#define def_lfe_none -1 + +typedef struct IamfLayoutInfo iamf_layout_info_t; + +typedef enum EIamfLayoutID { + /// @brief No layout. + ck_iamf_layout_id_none, + + /// @brief output channel layout in version 1.0 + ck_iamf_layout_id_sound_system_e = 0x01002000, + ck_iamf_layout_id_sound_system_f, + ck_iamf_layout_id_sound_system_g, + + /// @brief input/output channel layout in version 1.0 + ck_iamf_layout_id_mono = 0x01003000, + ck_iamf_layout_id_stereo, // SOUND_SYSTEM_A + ck_iamf_layout_id_5_1, // SOUND_SYSTEM_B + ck_iamf_layout_id_5_1_2, // SOUND_SYSTEM_C + ck_iamf_layout_id_5_1_4, // SOUND_SYSTEM_D + ck_iamf_layout_id_7_1, // SOUND_SYSTEM_I + ck_iamf_layout_id_7_1_2, + ck_iamf_layout_id_7_1_4, // SOUND_SYSTEM_J + ck_iamf_layout_id_3_1_2, + ck_iamf_layout_id_binaural, + + /// @brief input channel layout in version 1.1 + ck_iamf_layout_id_expanded_lfe = 0x01011000, + ck_iamf_layout_id_expanded_stereo_s, + ck_iamf_layout_id_expanded_stereo_ss, + ck_iamf_layout_id_expanded_stereo_rs, + ck_iamf_layout_id_expanded_stereo_tf, + ck_iamf_layout_id_expanded_stereo_tb, + ck_iamf_layout_id_expanded_top_4ch, + ck_iamf_layout_id_expanded_3ch, + ck_iamf_layout_id_expanded_stereo_f, + ck_iamf_layout_id_expanded_stereo_si, + ck_iamf_layout_id_expanded_stereo_tpsi, + ck_iamf_layout_id_expanded_top_6ch, + ck_iamf_layout_id_expanded_lfe_pair, + ck_iamf_layout_id_expanded_bottom_3ch, + ck_iamf_layout_id_expanded_bottom_4ch, + ck_iamf_layout_id_expanded_top_1ch, + ck_iamf_layout_id_expanded_top_5ch, + + /// @brief input/output channel layout in version 1.1 + ck_iamf_layout_id_expanded_9_1_6 = 0x01013000, + ck_iamf_layout_id_expanded_a_2_9_3, + ck_iamf_layout_id_expanded_7_1_5_4, + +} iamf_layout_id_t; + +typedef enum EIamfLayoutFlag { + ck_iamf_layout_flag_in = 0x00000001, + ck_iamf_layout_flag_out = 0x00000002, + ck_iamf_layout_flag_scalable = 0x00000004, + ck_iamf_layout_flag_expanded = 0x00000008, + // ck_iamf_layout_flag_subset = 0x00000010, + ck_iamf_layout_flag_subset = 0x00000000, // disable subset flag. +} iamf_layout_flag_t; + +struct IamfLayoutInfo { + iamf_layout_id_t id; + const char *name; + uint32_t flags; + + struct { + uint32_t channels; + + uint32_t surround; + uint32_t height; + uint32_t bottom; + + int lfe1; + int lfe2; + }; + + iamf_sound_system_t sound_system; + iamf_loudspeaker_layout_t layout; + iamf_loudspeaker_layout_t reference_layout; + + uint8_t decoding_map[def_max_audio_channels]; + iamf_channel_t channel_layout[def_max_audio_channels]; +}; + +const iamf_layout_info_t *iamf_layout_get_info(iamf_layout_t); +const iamf_layout_info_t *iamf_loudspeaker_layout_get_info( + iamf_loudspeaker_layout_t); + +int iamf_loudspeaker_layout_get_decoding_channels(iamf_loudspeaker_layout_t, + iamf_channel_t *, uint32_t); +int iamf_loudspeaker_layout_get_rendering_channels(iamf_loudspeaker_layout_t, + iamf_channel_t *, uint32_t); + +int iamf_layout_channels_count(iamf_layout_t *layout); +int iamf_layout_is_equal(iamf_layout_t a, iamf_layout_t b); +int iamf_layout_higher_check(iamf_layout_t layout1, iamf_layout_t layout2, + int equal); + +#endif // __IAMF_LAYOUT_H__ diff --git a/code/src/iamf_dec/iamf_obu_parser.c b/code/src/iamf_dec/iamf_obu_parser.c new file mode 100755 index 00000000..2f4f07ee --- /dev/null +++ b/code/src/iamf_dec/iamf_obu_parser.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_obu_parser.c + * @brief IAMF OBU Parser module implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "iamf_obu_parser.h" + +#include +#include + +#include "clog.h" +#include "iamf_private_definitions.h" +#include "obu/iamf_obu_all.h" + +#undef def_log_tag +#define def_log_tag "IAMF_PRS" + +typedef struct IamfObuParser { + iamf_profile_t profile; + fun_obu_process_t obu_process; + iamf_parser_state_t state; + void *user_data; + iamf_obu_extra_parameters_t extra_params; +} iamf_obu_parser_t; + +// --- Forward declarations --- +static iamf_parser_state_t iamf_obu_parser_process_single_obu( + iamf_obu_parser_t *parser, iamf_obu_raw_t *raw_obu); + +// --- API Implementations --- + +iamf_obu_parser_t *iamf_obu_parser_create( + fun_obu_process_t obu_process, void *user_data, + const iamf_obu_extra_parameters_t *extra_params) { + iamf_obu_parser_t *parser = def_mallocz(iamf_obu_parser_t, 1); + if (!parser) { + error("iamf_obu_parser_create: Failed to allocate memory for parser"); + return 0; + } + + parser->obu_process = obu_process; + parser->state = ck_iamf_parser_state_idle; + parser->user_data = user_data; + + // Initialize and copy extra parameters if provided + if (extra_params) + memcpy(&parser->extra_params, extra_params, + sizeof(iamf_obu_extra_parameters_t)); + + parser->profile = def_iamf_profile_default; + return parser; +} + +void iamf_obu_parser_destroy(iamf_obu_parser_t *parser) { def_free(parser); } + +uint32_t iamf_obu_parser_parse(iamf_obu_parser_t *parser, const uint8_t *data, + uint32_t size) { + uint8_t *current_ptr = (uint8_t *)data; + uint32_t remaining_bytes = size; + iamf_parser_state_t state = ck_iamf_parser_state_run; + + if (!parser || !data || !size) { + error( + "iamf_obu_parser_parse: Invalid arguments (parser=%p, data=%p, " + "size=%u)", + parser, data, size); + return 0; + } + + while (remaining_bytes > 0) { + iamf_obu_raw_t raw_obu; + uint32_t obu_size = + iamf_obu_raw_split(current_ptr, remaining_bytes, &raw_obu); + if (!obu_size) break; + + state = iamf_obu_parser_process_single_obu(parser, &raw_obu); + if (state == ck_iamf_parser_state_switch) { + debug("parsed OBU to the next step."); + break; + } + + current_ptr += obu_size; + remaining_bytes -= obu_size; + + if (state == ck_iamf_parser_state_stop) break; + } + + if (state != parser->state) parser->state = state; + + return current_ptr - data; +} + +iamf_parser_state_t iamf_obu_parser_get_state(iamf_obu_parser_t *parser) { + return parser ? parser->state : ck_iamf_parser_state_idle; +} + +// Internal function: process a single OBU +static iamf_parser_state_t iamf_obu_parser_process_single_obu( + iamf_obu_parser_t *parser, iamf_obu_raw_t *raw_obu) { + iamf_obu_t *obu = 0; + + if (iamf_obu_raw_is_reserved_obu(raw_obu, parser->profile)) + return ck_iamf_parser_state_run; + + obu = iamf_obu_new(raw_obu, &parser->extra_params); + + if (!obu) { + debug("iamf_obu_parser_process_single_obu: iamf_obu_new failed"); + return ck_iamf_parser_state_run; + } else if (obu->obu_type == ck_iamf_obu_sequence_header) { + iamf_sequence_header_obu_t *sho = def_iamf_sequence_header_obu_ptr(obu); + if (parser->profile > sho->additional_profile || + (parser->profile < sho->additional_profile && + sho->additional_profile <= def_iamf_profile_default)) { + info("iamf_obu_parser_process_single_obu: Profile changed from %u to %u", + parser->profile, sho->additional_profile); + parser->profile = sho->additional_profile; + } + } + + return parser->obu_process(obu, parser->user_data); +} diff --git a/code/src/iamf_dec/iamf_obu_parser.h b/code/src/iamf_dec/iamf_obu_parser.h new file mode 100755 index 00000000..5b5272ef --- /dev/null +++ b/code/src/iamf_dec/iamf_obu_parser.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_obu_parser.h + * @brief IAMF OBU Parser module. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_OBU_PARSER_H__ +#define __IAMF_OBU_PARSER_H__ + +#include "obu/iamf_obu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Enumeration of IAMF OBU parser states. + * + * This enumeration defines the possible states of the IAMF OBU parser during + * the parsing process. The parser transitions between these states based on + * the processing results of individual OBUs and the callback function return + * values. + */ +typedef enum EIamfParserState { + /** Parser is idle - not initialized or ready for new parsing session. */ + ck_iamf_parser_state_idle, + + /** Parser is running and actively processing OBUs. */ + ck_iamf_parser_state_run, + + /** Parser has stopped processing due to error or completion. */ + ck_iamf_parser_state_stop, + + /** Parser detected new stream and requires calling module to handle + * switching. + */ + ck_iamf_parser_state_switch, +} iamf_parser_state_t; + +/** + * @brief Callback function type for processing a parsed IAMF OBU. + * + * This function pointer defines the signature for a callback that will be + * invoked by the parser for each successfully parsed OBU (excluding reserved + * and temporal delimiter OBUs). + * + * @param obu Pointer to the parsed IAMF OBU structure. The callback function + * is responsible for managing the lifecycle of this OBU, including + * freeing its memory if necessary, using the appropriate + * `iamf_obu_free` function. + * @param user_data A pointer to user-provided data that was passed to + * `iamf_obu_parser_create`. This allows the callback to access + * custom context. + * @return int An integer status code. Return IAMF_OK (0) for success, + * or an appropriate IAMF error code on failure. If an error + * is returned, the parsing process may be affected or halted + * depending on the implementation. + */ +typedef iamf_parser_state_t (*fun_obu_process_t)(iamf_obu_t *obu, + void *user_data); + +/** + * @brief Opaque structure for the IAMF OBU parser instance. + * + * This structure holds the internal state of the OBU parser, including the + * profile, callback function, user data, and any extra parameters. + */ +typedef struct IamfObuParser iamf_obu_parser_t; + +/** + * @brief Creates and initializes an IAMF OBU parser instance. + * + * This function allocates memory for a new parser and initializes it with + * the provided OBU processing callback, user data, and any extra parameters. + * The parser is initially set to the default IAMF profile. + * + * @param obu_process A function pointer of type `fun_obu_process_t` that + * will be called for each valid OBU parsed. This callback + * is responsible for handling the parsed OBU data. + * @param user_data A void pointer to arbitrary user data. This pointer will + * be passed to the `obu_process` callback function, allowing + * it to access external context or state. + * @param extra_params A pointer to an `iamf_obu_extra_parameters_t` structure + * containing additional configuration for OBU parsing. + * This can be NULL if no extra parameters are needed. + * The content of this structure is copied internally, so + * the original structure can be freed or modified after + * this call without affecting the parser. + * @return iamf_obu_parser_t* On success, returns a pointer to the newly + * created parser instance. On failure (e.g., + * memory allocation error), returns NULL. + */ +iamf_obu_parser_t *iamf_obu_parser_create( + fun_obu_process_t obu_process, void *user_data, + const iamf_obu_extra_parameters_t *extra_params); + +/** + * @brief Destroys an IAMF OBU parser instance and frees its resources. + * + * This function deallocates the memory associated with the parser instance + * that was created by `iamf_obu_parser_create`. After calling this function, + * the parser pointer should no longer be used. + * + * @param parser Pointer to the IAMF OBU parser instance to be destroyed. + * If NULL is passed, the function does nothing. + */ +void iamf_obu_parser_destroy(iamf_obu_parser_t *parser); + +/** + * @brief Parses a buffer containing IAMF OBU stream data. + * + * This function iteratively processes a buffer of raw IAMF bitstream data. + * It identifies and parses individual OBUs within the buffer. For each + * successfully parsed OBU (excluding reserved and temporal delimiter OBUs), + * the registered `obu_process` callback is invoked. The function continues + * to parse OBUs until the input buffer is exhausted or an incomplete OBU + * is encountered at the end of the buffer. + * + * If an error occurs during the processing of a specific OBU (e.g., the + * `obu_process` callback returns an error), an error message is logged, + * but the parsing attempt continues with the next OBU in the buffer. + * Invalid arguments to this function will result in 0 bytes being processed. + * + * @param parser Pointer to the IAMF OBU parser instance. + * @param data Pointer to the buffer containing the IAMF OBU stream data. + * @param size The size of the data buffer in bytes. + * @return uint32_t The actual number of bytes consumed from the input `data` + * buffer. This value represents the total size of all fully + * processed OBUs. It can be less than `size` if the buffer + * ends with a partial OBU. Returns 0 if `parser`, `data`, or + * `size` are invalid, or if no OBUs could be processed. + */ +uint32_t iamf_obu_parser_parse(iamf_obu_parser_t *parser, const uint8_t *data, + uint32_t size); + +/** + * @brief Retrieves the current state of the IAMF OBU parser. + * + * This function returns the current parsing state of the IAMF OBU parser + * instance. The state reflects the result of the most recent parsing operation + * and indicates the current operational status of the parser. This can be used + * to monitor the parsing progress, determine if the parser encountered errors, + * or check if more data is needed to continue processing. + * + * The parser state is updated after each call to `iamf_obu_parser_parse` and + * reflects the final state returned by the OBU processing callback function. + * The state transitions are managed by the parser based on the processing + * results of individual OBUs and the callback return values. + * + * @param parser Pointer to the IAMF OBU parser instance. + * @return iamf_parser_state_t The current state of the parser. + */ +iamf_parser_state_t iamf_obu_parser_get_state(iamf_obu_parser_t *parser); + +#ifdef __cplusplus +} +#endif + +#endif // __IAMF_OBU_PARSER_H__ diff --git a/code/src/iamf_dec/iamf_post_processor.c b/code/src/iamf_dec/iamf_post_processor.c new file mode 100755 index 00000000..802530a8 --- /dev/null +++ b/code/src/iamf_dec/iamf_post_processor.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_post_processor.c + * @brief IAMF post processor implementation. + * @version 0.1 + * @date Created 12/11/2025 + **/ + +#include "iamf_post_processor.h" + +#include "IAMF_defines.h" +#include "audio_effect_peak_limiter.h" +#include "clog.h" +#include "cvalue.h" +#include "iamf_private_definitions.h" +#include "iamf_utils.h" +#include "speex_resampler.h" + +#define def_default_speex_resampler_quality 4 + +#define def_limiter_maximum_true_peak -1.0f +#define def_limiter_attack_sec 0.001f +#define def_limiter_release_sec 0.200f +#define def_limiter_look_ahead_sec 0.005f +#define def_limiter_look_ahead 240 + +typedef enum EStatus { + ck_status_none, + ck_status_init, + ck_status_process, + ck_status_flush, +} status_t; + +typedef struct IamfResampler { + iamf_audio_block_t *buffer[2]; + uint32_t in_sample_rate; + SpeexResamplerState *speex_resampler; +} iamf_resampler_t; + +struct IamfPostProcessor { + status_t status; + uint32_t sample_rate; + uint32_t channels; + + uint32_t delay_resampler; + uint32_t delay_limiter; + + iamf_resampler_t *resampler; + AudioEffectPeakLimiter *limiter; +}; + +static iamf_audio_block_t *iamf_post_processor_priv_resample( + iamf_post_processor_t *self, iamf_audio_block_t *audio_block) { + iamf_audio_block_t *out = 0; + iamf_resampler_t *resampler = self->resampler; + SpeexResamplerState *speex_resampler = resampler->speex_resampler; + uint32_t input_size = 0, resample_size = 0; + float *data = 0; + + if (audio_block) { + input_size = audio_block->num_samples_per_channel; + + if (!resampler->buffer[0] || + resampler->buffer[0]->capacity_per_channel < input_size) { + if (resampler->buffer[0]) { + iamf_audio_block_delete(resampler->buffer[0]); + resampler->buffer[0] = 0; + } + resampler->buffer[0] = + iamf_audio_block_new(0, input_size, self->channels); + if (!resampler->buffer[0]) return 0; + } + + resampler->buffer[0]->num_samples_per_channel = input_size; + iamf_audio_block_copy(resampler->buffer[0], audio_block, + ck_sample_format_f32_interleaved); + + resample_size = iamf_fraction_transform( + (fraction_t){.numerator = input_size, + .denominator = resampler->in_sample_rate}, + self->sample_rate); + data = resampler->buffer[0]->data; + } else { + resample_size = speex_resampler_get_output_latency(speex_resampler); + input_size = speex_resampler_get_input_latency(speex_resampler); + } + + if (resample_size > 0) { + out = iamf_audio_block_new(0, resample_size, self->channels); + if (!out) return 0; + + if (!resampler->buffer[1] || + resampler->buffer[1]->capacity_per_channel < resample_size) { + if (resampler->buffer[1]) { + iamf_audio_block_delete(resampler->buffer[1]); + resampler->buffer[1] = 0; + } + resampler->buffer[1] = + iamf_audio_block_new(0, resample_size, self->channels); + if (!resampler->buffer[1]) { + iamf_audio_block_delete(out); + return 0; + } + } + + speex_resampler_process_interleaved_float( + speex_resampler, data, &input_size, resampler->buffer[1]->data, + &resample_size); + resampler->buffer[1]->num_samples_per_channel = resample_size; + + iamf_audio_block_copy(out, resampler->buffer[1], + ck_sample_format_f32_planar); + } else { + warning("no samples to resample."); + } + + return out; +} + +static iamf_audio_block_t *iamf_post_processor_priv_limit( + iamf_post_processor_t *self, iamf_audio_block_t *audio_block) { + iamf_audio_block_t *out = 0; + int num_samples = 0; + if (audio_block) { + out = iamf_audio_block_new( + audio_block->id, audio_block->num_samples_per_channel, self->channels); + if (!out) return 0; + + num_samples = audio_effect_peak_limiter_process_block( + self->limiter, audio_block->data, out->data, + audio_block->num_samples_per_channel); + } else { + float *in = def_mallocz(float, self->delay_limiter * self->channels); + if (!in) return 0; + out = iamf_audio_block_new(0, self->delay_limiter, self->channels); + if (!out) { + def_free(in); + return 0; + } + + num_samples = audio_effect_peak_limiter_process_block( + self->limiter, in, out->data, self->delay_limiter); + def_free(in); + } + + out->num_samples_per_channel = num_samples; + + return out; +} + +iamf_post_processor_t *iamf_post_processor_create() { + iamf_post_processor_t *self = def_mallocz(iamf_post_processor_t, 1); + if (!self) return 0; + self->status = ck_status_none; + return self; +} + +void iamf_post_processor_destroy(iamf_post_processor_t *self) { + if (!self) return; + iamf_post_processor_disable_resampler(self); + iamf_post_processor_disable_limiter(self); + def_free(self); +} + +int iamf_post_processor_init(iamf_post_processor_t *self, uint32_t sample_rate, + uint32_t channels) { + if (!self) return IAMF_ERR_BAD_ARG; + + self->status = ck_status_init; + + if (self->sample_rate != sample_rate) self->sample_rate = sample_rate; + if (self->channels != channels) self->channels = channels; + + self->status = ck_status_process; + + return IAMF_OK; +} + +int iamf_post_processor_enable_resampler(iamf_post_processor_t *self, + uint32_t in_sample_rate) { + int err; + iamf_resampler_t *resampler = def_mallocz(iamf_resampler_t, 1); + if (!resampler) return IAMF_ERR_ALLOC_FAIL; + SpeexResamplerState *speex_resampler = + speex_resampler_init(self->channels, in_sample_rate, self->sample_rate, + def_default_speex_resampler_quality, &err); + info("resample: in %u, out %u", in_sample_rate, self->sample_rate); + if (!speex_resampler) { + def_free(resampler); + return IAMF_ERR_ALLOC_FAIL; + } + resampler->speex_resampler = speex_resampler; + resampler->in_sample_rate = in_sample_rate; + speex_resampler_skip_zeros(speex_resampler); + + self->resampler = resampler; + self->delay_resampler = speex_resampler_get_output_latency(speex_resampler); + + return IAMF_OK; +} + +int iamf_post_processor_disable_resampler(iamf_post_processor_t *self) { + if (!self->resampler) return IAMF_OK; + if (self->resampler->buffer[0]) + iamf_audio_block_delete(self->resampler->buffer[0]); + if (self->resampler->buffer[1]) + iamf_audio_block_delete(self->resampler->buffer[1]); + if (self->resampler->speex_resampler) { + speex_resampler_destroy(self->resampler->speex_resampler); + } + def_free(self->resampler); + self->resampler = 0; + return IAMF_OK; +} + +int iamf_post_processor_enable_limiter(iamf_post_processor_t *self, + float threshold) { + self->limiter = audio_effect_peak_limiter_create(); + if (!self->limiter) return IAMF_ERR_ALLOC_FAIL; + self->delay_limiter = def_limiter_look_ahead_sec * self->sample_rate; + audio_effect_peak_limiter_init(self->limiter, threshold, self->sample_rate, + self->channels, def_limiter_attack_sec, + def_limiter_release_sec, self->delay_limiter); + return IAMF_OK; +} + +int iamf_post_processor_disable_limiter(iamf_post_processor_t *self) { + if (!self->limiter) return IAMF_OK; + audio_effect_peak_limiter_destroy(self->limiter); + self->limiter = 0; + return IAMF_OK; +} + +int iamf_post_processor_process(iamf_post_processor_t *self, + iamf_audio_block_t *in, + iamf_audio_block_t **out) { + iamf_audio_block_t *last = in; + + if (self->status != ck_status_process) return 0; + + if (self->resampler) { + iamf_audio_block_t *next = iamf_post_processor_priv_resample(self, last); + if (!next) return IAMF_ERR_ALLOC_FAIL; + last = next; + } + + if (self->limiter) { + iamf_audio_block_t *next = 0; + iamf_audio_block_t *blocks[2] = {0}; + + if (last) blocks[0] = iamf_post_processor_priv_limit(self, last); + if (!in) blocks[1] = iamf_post_processor_priv_limit(self, 0); + + if (blocks[0] && blocks[1]) { + next = iamf_audio_block_samples_concat(blocks, 2); + iamf_audio_block_delete(blocks[0]); + iamf_audio_block_delete(blocks[1]); + } else if (blocks[0]) { + next = blocks[0]; + } else if (blocks[1]) { + next = blocks[1]; + } + + if (last != in) iamf_audio_block_delete(last); + + if (!next) return IAMF_ERR_ALLOC_FAIL; + last = next; + } + + if (in && last == in) { + last = iamf_audio_block_new(in->id, in->num_samples_per_channel, + self->channels); + + if (!last) return IAMF_ERR_ALLOC_FAIL; + iamf_audio_block_channels_concat(last, &in, 1); + } + + *out = last; + + if (!in) self->status = ck_status_flush; + return IAMF_OK; +} + +uint32_t iamf_post_processor_get_delay(iamf_post_processor_t *self) { + return self->delay_limiter + self->delay_resampler; +} diff --git a/code/src/iamf_dec/iamf_post_processor.h b/code/src/iamf_dec/iamf_post_processor.h new file mode 100755 index 00000000..cae1a51a --- /dev/null +++ b/code/src/iamf_dec/iamf_post_processor.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_post_processor.h + * @brief IAMF post processor APIs. + * @version 0.1 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_POST_PROCESSOR_H__ +#define __IAMF_POST_PROCESSOR_H__ + +#include "iamf_audio_block.h" + +typedef struct IamfPostProcessor iamf_post_processor_t; + +iamf_post_processor_t *iamf_post_processor_create(); +void iamf_post_processor_destroy(iamf_post_processor_t *self); +int iamf_post_processor_init(iamf_post_processor_t *self, uint32_t sample_rate, + uint32_t channels); +int iamf_post_processor_enable_resampler(iamf_post_processor_t *self, + uint32_t in_sample_rate); +int iamf_post_processor_disable_resampler(iamf_post_processor_t *self); +int iamf_post_processor_enable_limiter(iamf_post_processor_t *self, + float threshold); +int iamf_post_processor_disable_limiter(iamf_post_processor_t *self); +int iamf_post_processor_process(iamf_post_processor_t *self, + iamf_audio_block_t *in, + iamf_audio_block_t **out); +uint32_t iamf_post_processor_get_delay(iamf_post_processor_t *self); + +#endif // __IAMF_POST_PROCESSOR_H__ diff --git a/code/src/iamf_dec/iamf_presentation.c b/code/src/iamf_dec/iamf_presentation.c new file mode 100755 index 00000000..12eb8ca0 --- /dev/null +++ b/code/src/iamf_dec/iamf_presentation.c @@ -0,0 +1,1519 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_presentation.c + * @brief IAMF presentation implementation. + * @version 2.0.0 + * @date Created 05/09/2025 + **/ + +#include "iamf_presentation.h" + +#include +#include +#include + +#include "chashmap.h" +#include "clog.h" +#include "iamf_element_reconstructor.h" +#include "iamf_layout.h" +#include "iamf_private_definitions.h" +#include "iamf_renderer.h" +#include "iamf_string.h" +#include "iamf_synchronizer.h" +#include "iamf_types.h" +#include "obu/iamf_obu_all.h" + +#undef def_log_tag +#define def_log_tag "IAMF_PST" + +#define def_pst_str "IAMF Presentation" + +/** + * @brief IAMF element presentation structure + */ +typedef struct IamfPresentationElement { + uint32_t element_id; + uint32_t sub_mix_index; + + int sampling_rate; + uint32_t number_samples_per_frame; + int num_channels; + + uint32_t scheme; + + iamf_rendering_param_t rendering_config; + iamf_layout_t out_layout; + + union { + iamf_loudspeaker_layout_t layout; + uint32_t position_id; + } in; + + uint32_t mix_gain_id; + + int enable_gain_offset; + struct { + float offset; + float min; + float max; + } gain_offset; + uint32_t gain_offset_pid; // Unique gain offset parameter ID generated to + // avoid conflicts + + iamf_audio_block_t* block; +} iamf_presentation_element_t; + +/** + * @brief IAMF presentation structure + */ +typedef struct IamfPresentation { + uint32_t id; + + iamf_layout_t layout; + + vector_t* output_mix_gain_ids; + uint32_t num_audio_blocks; + + iamf_database_t* database; + iamf_element_reconstructor_t* reconstructor; + hash_map_t* elements; // iamf_presentation_element_t + iamf_synchronizer_t* synchronizer; + iamf_renderer_t renderer; + + float loudness_gain; + int out_sampling_rate; +} iamf_presentation_t; + +/** + * @brief Check if a parameter ID conflicts with existing parameter IDs + * + * This function checks if the given pid conflicts with any existing + * parameter IDs in the presentation, including mix_gain_id and + * position_param_id. It prevents parameter ID conflicts when generating + * unique gain offset parameter IDs. + * + * @param self Pointer to the presentation instance + * @param element_id The element ID being checked + * @param pid The parameter ID to test for conflicts + * @return 1 if there is a conflict, 0 otherwise + */ +static int iamf_presentation_pid_conflicts(iamf_presentation_t* self, + uint32_t element_id, uint32_t pid) { + // Check conflict with mix_gain_id for the same element + value_wrap_t* val = hash_map_get(self->elements, element_id); + if (val) { + iamf_presentation_element_t* element = + def_value_wrap_type_ptr(iamf_presentation_element_t, val); + if (element->mix_gain_id == pid) { + debug("Parameter ID %u conflicts with mix_gain_id for element %u", pid, + element_id); + return 1; + } + } + + // Check conflict with position_param_id across all elements + if (self->elements) { + hash_map_iterator_t* it = hash_map_iterator_new(self->elements); + if (it) { + do { + val = hash_map_iterator_get_value(it); + iamf_presentation_element_t* elem = + def_value_wrap_type_ptr(iamf_presentation_element_t, val); + if (elem->in.position_id == pid) { + debug( + "Parameter ID %u conflicts with position_param_id for element %u", + pid, elem->element_id); + hash_map_iterator_delete(it); + return 1; + } + } while (!hash_map_iterator_next(it)); + hash_map_iterator_delete(it); + } + } + + return 0; +} + +/** + * @brief Generate a unique gain offset parameter ID + * + * This function generates a unique parameter ID for gain offset that doesn't + * conflict with any existing parameter IDs. It uses two strategies: + * 1. Try direct pid + * 2. Try linear offset (pid + offset) + * + * @param self Pointer to the presentation instance + * @param element_id The element ID + * @return A unique parameter ID for gain offset + */ +static uint32_t iamf_presentation_generate_unique_gain_offset_id( + iamf_presentation_t* self, uint32_t element_id) { + // First, try using pid directly + uint32_t candidate_id = self->id; + if (!iamf_presentation_pid_conflicts(self, element_id, candidate_id)) { + debug("Using direct id %u as gain offset parameter ID", candidate_id); + return candidate_id; + } + + // If conflict, try different offsets + for (uint32_t offset = 1; offset < 0xFFFF; offset++) { + candidate_id += offset; + if (!iamf_presentation_pid_conflicts(self, element_id, candidate_id)) { + debug( + "Generated unique gain offset ID: original_id=%u, unique_id=%u, " + "offset=%u", + self->id, candidate_id, offset); + return candidate_id; + } + } + + // If all offsets conflict, use id as fallback + warning("All offsets conflict, using pid as fallback: id=%u", self->id); + return self->id; +} + +static animated_float32_t _create_step_animated_gain(float start_value) { + animated_float32_t animated_gain; + + memset(&animated_gain, 0, sizeof(animated_gain)); + animated_gain.animation_type = ck_iamf_animation_type_step; + animated_gain.data.start = start_value; + + return animated_gain; +} + +static animated_polar_t _create_step_animated_polar(float azimuth, + float elevation, + float distance) { + animated_polar_t animated_polar; + memset(&animated_polar, 0, sizeof(animated_polar)); + animated_polar.animation_type = ck_iamf_animation_type_step; + animated_polar.azimuth = + def_animated_data_step_instance(animated_data_float32_t, azimuth); + animated_polar.elevation = + def_animated_data_step_instance(animated_data_float32_t, elevation); + animated_polar.distance = + def_animated_data_step_instance(animated_data_float32_t, distance); + return animated_polar; +} + +static animated_cartesian_t _create_step_animated_cartesian(float x, float y, + float z) { + animated_cartesian_t animated_cartesian; + memset(&animated_cartesian, 0, sizeof(animated_cartesian)); + animated_cartesian.x = + def_animated_data_step_instance(animated_data_float32_t, x); + animated_cartesian.y = + def_animated_data_step_instance(animated_data_float32_t, y); + animated_cartesian.z = + def_animated_data_step_instance(animated_data_float32_t, z); + return animated_cartesian; +} + +// Helper function to free all element presentations in a hash_map_t +static void iamf_presentation_priv_delete_all_elements(hash_map_t* elements) { + if (!elements || !hash_map_size(elements)) return; + + hash_map_iterator_t* iter = hash_map_iterator_new(elements); + if (iter) { + do { + iamf_presentation_element_t* element = def_value_wrap_type_ptr( + iamf_presentation_element_t, hash_map_iterator_get_value(iter)); + if (element && element->block) iamf_audio_block_delete(element->block); + def_free(element); + } while (!hash_map_iterator_next(iter)); + hash_map_iterator_delete(iter); + } +} + +iamf_loudspeaker_layout_t +iamf_presentation_priv_channel_based_element_get_out_layout( + iamf_presentation_t* self, channel_based_audio_element_obu_t* cbo, + obu_audio_element_config_t* audio_config) { + iamf_layout_t* layout = &self->layout; + + if (!cbo) return ck_iamf_loudspeaker_layout_none; + if (cbo->max_valid_layers == 1) { + obu_channel_layer_config_t* config = + def_value_wrap_type_ptr(obu_channel_layer_config_t, + array_at(cbo->channel_audio_layer_configs, 0)); + iamf_loudspeaker_layout_t layout = iamf_audio_layer_layout_get( + config->loudspeaker_layout, config->expanded_loudspeaker_layout); + const iamf_layout_info_t* info = iamf_loudspeaker_layout_get_info(layout); + return info->flags & ck_iamf_layout_flag_subset ? info->reference_layout + : info->layout; + } + + if (layout->type == ck_iamf_layout_type_binaural) { + int headphones_rendering_mode = + audio_config->rendering_config.headphones_rendering_mode; + if (headphones_rendering_mode > 0) { + obu_channel_layer_config_t* config = def_value_wrap_type_ptr( + obu_channel_layer_config_t, array_at(cbo->channel_audio_layer_configs, + cbo->max_valid_layers - 1)); + debug("use the highest layout downmix to binaural."); + return config->loudspeaker_layout; + } + } + + uint8_t out_sound_system = layout->type == ck_iamf_layout_type_binaural + ? SOUND_SYSTEM_A + : layout->sound_system; + + for (int i = 0; i < cbo->max_valid_layers; ++i) { + obu_channel_layer_config_t* config = + def_value_wrap_type_ptr(obu_channel_layer_config_t, + array_at(cbo->channel_audio_layer_configs, i)); + const iamf_layout_info_t* info = + iamf_loudspeaker_layout_get_info(config->loudspeaker_layout); + if ((info->flags & ck_iamf_layout_flag_out) && + info->sound_system == out_sound_system) { + info("scalabel channels layer is %d", config->loudspeaker_layout); + return config->loudspeaker_layout; + } + } + + // select next highest available layout + int playback_channels = iamf_layout_get_info(*layout)->channels; + for (int i = 0; i < cbo->max_valid_layers; ++i) { + obu_channel_layer_config_t* config = + def_value_wrap_type_ptr(obu_channel_layer_config_t, + array_at(cbo->channel_audio_layer_configs, i)); + int channels = + iamf_loudspeaker_layout_get_info(config->loudspeaker_layout)->channels; + if (channels > playback_channels) { + info("scalabel channels layer is %d", config->loudspeaker_layout); + return config->loudspeaker_layout; + } + } + + if (cbo->max_valid_layers) { + obu_channel_layer_config_t* config = def_value_wrap_type_ptr( + obu_channel_layer_config_t, + array_at(cbo->channel_audio_layer_configs, cbo->max_valid_layers - 1)); + return config->loudspeaker_layout; // use the highest layout + } + + return ck_iamf_loudspeaker_layout_none; +} + +static iamf_presentation_element_t* iamf_presentation_priv_make_element( + iamf_presentation_t* self, uint32_t sub_mix_index, + obu_audio_element_config_t* audio_config) { + iamf_presentation_element_t* element = 0; + iamf_audio_element_obu_t* aeo = 0; + iamf_codec_config_obu_t* cco = 0; + uint32_t eid = audio_config->element_id; + audio_codec_parameter_t acparam = {0}; + + debug("make presentation element %u", eid); + aeo = iamf_database_get_audio_element_obu(self->database, eid); + if (!aeo) { + warning("no audio element found for id %u", eid); + return 0; + } + + cco = + iamf_database_get_codec_config_obu(self->database, aeo->codec_config_id); + if (!cco) { + warning("no codec config found for id %u", aeo->codec_config_id); + return 0; + } + + iamf_codec_config_obu_get_parameter(cco, &acparam); + + element = def_mallocz(iamf_presentation_element_t, 1); + if (!element) return 0; + + element->element_id = eid; + element->sub_mix_index = sub_mix_index; + element->scheme = aeo->audio_element_type; + element->sampling_rate = acparam.sample_rate; + element->rendering_config = def_rendering_param_instance( + audio_config->rendering_config.headphones_rendering_mode, + audio_config->rendering_config.binaural_filter_profile); + element->number_samples_per_frame = cco->num_samples_per_frame; + element->mix_gain_id = audio_config->element_mix_gain.base.parameter_id; + + if (audio_config->rendering_config.flags & + def_rendering_config_flag_element_gain_offset) { + element->enable_gain_offset = 1; + // Initialize gain offset PID when gain offset is enabled + element->gain_offset_pid = iamf_presentation_generate_unique_gain_offset_id( + self, element->element_id); + debug( + "Initialized gain offset PID during element creation: element_id=%u, " + "gain_offset_pid=%u", + element->element_id, element->gain_offset_pid); + element->gain_offset.offset = + audio_config->rendering_config.element_gain_offset_db.value; + element->gain_offset.min = + audio_config->rendering_config.element_gain_offset_db.min; + element->gain_offset.max = + audio_config->rendering_config.element_gain_offset_db.max; + } + + debug("codec conf id %u, codec id 0x%x (%s), sampling rate is %u", + cco->codec_config_id, cco->codec_id, + iamf_codec_type_string(iamf_codec_type_get(cco->codec_id)), + element->sampling_rate); + + if (element->scheme == ck_audio_element_type_channel_based) { + channel_based_audio_element_obu_t* cbo = + def_channel_based_audio_element_obu_ptr(aeo); + element->in.layout = + iamf_presentation_priv_channel_based_element_get_out_layout( + self, cbo, audio_config); + info("get decoded channel based layout %d", element->in.layout); + const iamf_layout_info_t* info = + iamf_loudspeaker_layout_get_info(element->in.layout); + element->num_channels = info->channels; + } else if (element->scheme == ck_audio_element_type_scene_based) { + scene_based_audio_element_obu_t* sbo = + def_scene_based_audio_element_obu_ptr(aeo); + element->num_channels = sbo->output_channel_count; + } else if (element->scheme == ck_audio_element_type_object_based) { + object_based_audio_element_obu_t* obo = + def_object_based_audio_element_obu_ptr(aeo); + element->num_channels = obo->num_objects; + + // Get position parameter ID from rendering_config for object-based elements + element->in.position_id = def_i32_id_none; // Initialize to invalid value + if (audio_config->rendering_config.parameters) { + for (int i = 0; i < array_size(audio_config->rendering_config.parameters); + i++) { + parameter_base_t* param_base = def_value_wrap_type_ptr( + parameter_base_t, + array_at(audio_config->rendering_config.parameters, i)); + if (param_base && iamf_parameter_type_is_coordinate(param_base->type)) { + element->in.position_id = param_base->parameter_id; + debug( + "Found position_id %u for object-based element %u from " + "rendering_config", + element->in.position_id, element->element_id); + break; + } + } + } + + if (element->in.position_id == def_i32_id_none) { + warning( + "No position parameter found in rendering_config for object-based " + "element %u", + element->element_id); + } + } else { + warning("unknown scheme %d", element->scheme); + } + + return element; +} + +static int iamf_presentation_priv_make_elements(iamf_presentation_t* self) { + iamf_mix_presentation_obu_t* mix_presentation_obu = + iamf_database_get_mix_presentation_obu(self->database, self->id); + + if (mix_presentation_obu->sub_mixes) { + for (size_t i = 0; i < array_size(mix_presentation_obu->sub_mixes); i++) { + obu_sub_mix_t* sub_mix = def_value_wrap_type_ptr( + obu_sub_mix_t, array_at(mix_presentation_obu->sub_mixes, i)); + if (sub_mix) { + vector_push(self->output_mix_gain_ids, + def_value_wrap_instance_u32( + sub_mix->output_mix_gain.base.parameter_id)); + if (sub_mix && sub_mix->audio_element_configs) { + for (size_t j = 0; j < array_size(sub_mix->audio_element_configs); + j++) { + obu_audio_element_config_t* audio_config = def_value_wrap_type_ptr( + obu_audio_element_config_t, + array_at(sub_mix->audio_element_configs, j)); + if (audio_config) { + iamf_presentation_element_t* element = + iamf_presentation_priv_make_element(self, i, audio_config); + if (!element || + hash_map_put(self->elements, element->element_id, + def_value_wrap_instance_ptr(element)) < 0) { + def_free(element); + warning( + "Failed to insert element presentation for element_id: %u", + audio_config->element_id); + return IAMF_ERR_INTERNAL; + } + } + } + } + } + } + } + + return IAMF_OK; +} + +static int iamf_presentation_priv_add_elements_to_reconstructor( + iamf_presentation_t* self) { + if (!self) return IAMF_ERR_BAD_ARG; + if (!self->elements) return IAMF_ERR_INTERNAL; + + hash_map_iterator_t* iter = hash_map_iterator_new(self->elements); + int ret = IAMF_OK; + + debug("elements size %d", hash_map_size(self->elements)); + if (iter) { + do { + uint32_t eid = hash_map_iterator_get_key(iter); + debug("add element %u to reconstructor", eid); + iamf_presentation_element_t* element = def_value_wrap_type_ptr( + iamf_presentation_element_t, hash_map_iterator_get_value(iter)); + if (!element) { + error("Invalid presentation element for element id: %u", eid); + ret = IAMF_ERR_INTERNAL; + break; + } + + iamf_audio_element_obu_t* audio_element_obu = + iamf_database_get_audio_element_obu(self->database, eid); + if (!audio_element_obu) { + error("Failed to get audio_element_obu for element id: %u", eid); + ret = IAMF_ERR_INTERNAL; + break; + } + + iamf_codec_config_obu_t* codec_config_obu = + iamf_database_get_codec_config_obu( + self->database, audio_element_obu->codec_config_id); + if (!codec_config_obu) { + error( + "Failed to get codec_config_obu for codec config id: %u (element " + "id: %u)", + audio_element_obu->codec_config_id, eid); + ret = IAMF_ERR_INTERNAL; + break; + } + + ret = iamf_element_reconstructor_add_element( + self->reconstructor, audio_element_obu, codec_config_obu); + if (ret != IAMF_OK) { + error("Failed to add reconstructor for element_id: %u", eid); + break; + } + + info("Successfully added reconstructor for element_id: %u", eid); + } while (!hash_map_iterator_next(iter)); + hash_map_iterator_delete(iter); + } + + return ret; +} + +static int iamf_presentation_priv_activate_elements_and_parameters( + iamf_presentation_t* self) { + if (!self || !self->elements) return IAMF_ERR_BAD_ARG; + if (!hash_map_size(self->elements)) return IAMF_ERR_INTERNAL; + + hash_map_iterator_t* iter = hash_map_iterator_new(self->elements); + int ret = IAMF_OK; + + if (iter) { + do { + uint32_t eid = hash_map_iterator_get_key(iter); + iamf_presentation_element_t* element = def_value_wrap_type_ptr( + iamf_presentation_element_t, hash_map_iterator_get_value(iter)); + + if (!element) { + error("Invalid element self for element_id: %u", eid); + ret = IAMF_ERR_INTERNAL; + break; + } + + if (element->scheme == ck_audio_element_type_channel_based) + iamf_element_reconstructor_set_channel_based_target_layout( + self->reconstructor, eid, element->in.layout); + + iamf_element_reconstructor_activate_element(self->reconstructor, eid); + iamf_synchronizer_add_audio_cache(self->synchronizer, eid); + + iamf_audio_element_obu_t* aeo = + iamf_database_get_audio_element_obu(self->database, eid); + if (aeo) { + int n = array_size(aeo->parameters); + for (int i = 0; i < n; i++) { + parameter_base_t* pb = def_value_wrap_type_ptr( + parameter_base_t, array_at(aeo->parameters, i)); + if (pb) + iamf_database_enable_parameter_block(self->database, + pb->parameter_id); + } + } + + if (element->scheme == ck_audio_element_type_object_based) + iamf_database_enable_parameter_block(self->database, + element->in.position_id); + + iamf_database_enable_parameter_block(self->database, + element->mix_gain_id); + } while (!hash_map_iterator_next(iter)); + + hash_map_iterator_delete(iter); + } + + // Enable momentary loudness parameters from mix presentation OBU + iamf_mix_presentation_obu_t* mix_presentation_obu = + iamf_database_get_mix_presentation_obu(self->database, self->id); + if (mix_presentation_obu && mix_presentation_obu->sub_mixes) { + for (size_t i = 0; i < array_size(mix_presentation_obu->sub_mixes); i++) { + obu_sub_mix_t* sub_mix = def_value_wrap_type_ptr( + obu_sub_mix_t, array_at(mix_presentation_obu->sub_mixes, i)); + if (sub_mix && sub_mix->loudness) { + for (size_t j = 0; j < array_size(sub_mix->loudness); j++) { + obu_loudness_info_t* loudness_info = def_value_wrap_type_ptr( + obu_loudness_info_t, array_at(sub_mix->loudness, j)); + if (loudness_info && + (loudness_info->info_type & def_loudness_info_type_momentary)) { + // Enable the momentary loudness parameter block + iamf_database_enable_parameter_block( + self->database, + loudness_info->momentary_loudness.momentary_loudness_param.base + .parameter_id); + } + } + } + } + } + + int n = vector_size(self->output_mix_gain_ids); + for (int i = 0; i < n; i++) + iamf_database_enable_parameter_block( + self->database, + def_value_wrap_u32(vector_at(self->output_mix_gain_ids, i))); + + return ret; +} + +static int iamf_presentation_priv_activate_renderer(iamf_presentation_t* self) { + hash_map_iterator_t* iter = hash_map_iterator_new(self->elements); + if (!iter) return IAMF_ERR_INTERNAL; + + iamf_presentation_element_t* element = def_value_wrap_type_ptr( + iamf_presentation_element_t, hash_map_iterator_get_value(iter)); + hash_map_iterator_delete(iter); + + int ret = iamf_renderer_init(&self->renderer, self->layout, + element->number_samples_per_frame, + element->sampling_rate); + + if (ret != IAMF_OK) return ret; + + iter = hash_map_iterator_new(self->elements); + if (iter) { + do { + iamf_presentation_element_t* element = def_value_wrap_type_ptr( + iamf_presentation_element_t, hash_map_iterator_get_value(iter)); + if (element->scheme == ck_audio_element_type_channel_based) { + int dmx_default_mode = def_dmx_mode_none; + int dmx_default_w_idx = def_dmx_weight_index_none; + iamf_database_get_audio_element_default_demixing_info( + self->database, element->element_id, &dmx_default_mode, + &dmx_default_w_idx); + ret = iamf_renderer_add_channel_based_element( + &self->renderer, element->element_id, element->sub_mix_index, + element->in.layout, element->rendering_config, dmx_default_mode, + dmx_default_w_idx); + if (ret != IAMF_OK) + error( + "Failed to add channel based element to renderer for element_id: " + "%u with layout %d", + element->element_id, element->in.layout); + } else if (element->scheme == ck_audio_element_type_scene_based) { + ret = iamf_renderer_add_scene_based_element( + &self->renderer, element->element_id, element->sub_mix_index, + element->num_channels, element->rendering_config); + if (ret != IAMF_OK) + error( + "" + "Failed to add scene based element to renderer for element_id: " + "%u with scene channels %d", + element->element_id, element->num_channels); + } else if (element->scheme == ck_audio_element_type_object_based) { + ret = iamf_renderer_add_object_based_element( + &self->renderer, element->element_id, element->sub_mix_index, + element->num_channels, element->rendering_config); + if (ret != IAMF_OK) + error( + "Failed to add object based element to renderer for element_id: " + "%u with object channels %d", + element->element_id, element->num_channels); + } + + if (ret != IAMF_OK) break; + } while (!hash_map_iterator_next(iter)); + hash_map_iterator_delete(iter); + } + + if (ret != IAMF_OK) { + error("Failed to initialize renderer for presentation %u", self->id); + iamf_renderer_uninit(&self->renderer); + } + + return ret; +} + +static void iamf_presentation_priv_delete_all_audio_blocks( + iamf_presentation_t* self) { + if (!self) return; + hash_map_iterator_t* iter = hash_map_iterator_new(self->elements); + if (iter) { + do { + iamf_presentation_element_t* element = def_value_wrap_type_ptr( + iamf_presentation_element_t, hash_map_iterator_get_value(iter)); + if (element && element->block) { + iamf_audio_block_delete(element->block); + element->block = 0; + } + } while (!hash_map_iterator_next(iter)); + hash_map_iterator_delete(iter); + } + + self->num_audio_blocks = 0; +} + +static int iamf_presentation_priv_sync_audio_blocks(iamf_presentation_t* self) { + if (!self || !self->elements || !self->synchronizer) { + error("Invalid presentation or synchronizer"); + return IAMF_ERR_BAD_ARG; + } + + iamf_audio_block_t* blocks[def_max_audio_streams]; + int n = 0; + hash_map_iterator_t* iter = hash_map_iterator_new(self->elements); + if (iter) { + do { + iamf_presentation_element_t* element = def_value_wrap_type_ptr( + iamf_presentation_element_t, hash_map_iterator_get_value(iter)); + if (element) { + if (!element->block) { + element->block = iamf_audio_block_default_new(element->element_id); + if (!element->block) + warning( + "Failed to allocate memory for audio block for element (%u) " + "for synchronization.", + element->element_id); + else { + debug("Allocated audio block for element_id: %u", + element->element_id); + element->block->num_channels = element->num_channels; + } + } + if (element->block && n < def_max_audio_streams) + blocks[n++] = element->block; + } + + } while (!hash_map_iterator_next(iter)); + hash_map_iterator_delete(iter); + } + + return n > 0 ? iamf_synchronizer_sync_audio_blocks(self->synchronizer, blocks, + n) + : IAMF_ERR_INTERNAL; +} + +static int iamf_presentation_priv_update_element_downmix_info( + iamf_presentation_t* self, iamf_presentation_element_t* element) { + if (!self || !element) return IAMF_ERR_BAD_ARG; + + // Get downmix mode for the element + int downmix_mode = iamf_database_get_audio_element_demix_mode( + self->database, element->element_id, + (fraction_t){.numerator = 1, .denominator = element->sampling_rate}); + + // Update renderer if downmix mode is not none + if (downmix_mode != def_dmx_mode_none) { + int ret = iamf_renderer_update_element_downmix_mode( + &self->renderer, element->element_id, downmix_mode, + element->block->num_samples_per_channel); + if (ret != IAMF_OK) { + error("Failed to update downmix mode for element_id: %u", + element->element_id); + return ret; + } + debug("Updated downmix mode to %d for element_id: %u", downmix_mode, + element->element_id); + } + + return IAMF_OK; +} + +static int iamf_presentation_priv_update_element_gain_offset( + iamf_presentation_t* self, iamf_presentation_element_t* element) { + if (!self || !element) return IAMF_ERR_BAD_ARG; + + // Apply element gain offset if enabled + if (element->enable_gain_offset) { + animated_float32_t animated_gain = + _create_step_animated_gain(element->gain_offset.offset); + int ret = iamf_renderer_update_element_animated_gain( + &self->renderer, element->element_id, element->gain_offset_pid, + animated_gain, element->block->num_samples_per_channel); + if (ret != IAMF_OK) { + error("Failed to update element gain offset for element_id: %u", + element->element_id); + return ret; + } + debug( + "Successfully updated element gain offset: element_id=%u, " + "gain_offset_pid=%u, offset=%f", + element->element_id, element->gain_offset_pid, + element->gain_offset.offset); + } + + return IAMF_OK; +} + +static int iamf_presentation_priv_update_element_mix_gain( + iamf_presentation_t* self, iamf_presentation_element_t* element) { + fraction_t num_samples_frac; + if (!self || !element) return IAMF_ERR_BAD_ARG; + + // Handle second skip if present + if (element->block->second_skip > 0) { + animated_float32_t animated_gain = _create_step_animated_gain(1.0f); + iamf_renderer_update_element_animated_gain( + &self->renderer, element->element_id, element->mix_gain_id, + animated_gain, element->block->second_skip); + } + + parameter_subblock_t** subblocks = 0; + num_samples_frac.numerator = element->block->num_samples_per_channel - + element->block->second_skip - + element->block->second_padding; + num_samples_frac.denominator = element->sampling_rate; + int n = iamf_database_get_subblocks(self->database, element->mix_gain_id, + num_samples_frac, &subblocks); + + debug("mix gain subblocks count %d", n); + + // Process mix gain subblocks + if (n > 0) { + float durations = 0.0f; + uint32_t rate = + iamf_database_get_parameter_rate(self->database, element->mix_gain_id); + + for (int i = 0; i < n; i++) { + uint32_t approximate_durations = durations + 0.5f; + float duration = iamf_fraction_transform_float( + def_fraction_instance(subblocks[i]->subblock_duration, rate), + element->sampling_rate); + durations += duration; + duration = durations + 0.5f - approximate_durations; + + mix_gain_parameter_subblock_t* subblock = + def_mix_gain_parameter_subblock_ptr(subblocks[i]); + iamf_renderer_update_element_animated_gain( + &self->renderer, element->element_id, element->mix_gain_id, + subblock->gain_db, duration); + + durations += duration; + } + } else if (n < 0) { + // Use default mix gain to build animated gain + parameter_base_t* param_base = + iamf_database_get_parameter_base(self->database, element->mix_gain_id); + if (!param_base) + warning("Parameter base not found for mix gain id %u", + element->mix_gain_id); + if (param_base && param_base->type == ck_iamf_parameter_type_mix_gain) { + mix_gain_parameter_base_t* mix_gain_param = + (mix_gain_parameter_base_t*)param_base; + animated_float32_t animated_gain = + _create_step_animated_gain(mix_gain_param->default_mix_gain_db); + + // Use the entire frame duration + iamf_renderer_update_element_animated_gain( + &self->renderer, element->element_id, element->mix_gain_id, + animated_gain, element->block->num_samples_per_channel); + } + } + + if (element->block->second_padding > 0) { + animated_float32_t animated_gain = _create_step_animated_gain(1.0f); + iamf_renderer_update_element_animated_gain( + &self->renderer, element->element_id, element->mix_gain_id, + animated_gain, element->block->second_padding); + } + + if (subblocks) def_free(subblocks); + + debug("Successfully processed mix gain for element_id: %u", + element->element_id); + return IAMF_OK; +} + +static int iamf_presentation_priv_update_element_positions( + iamf_presentation_t* self, iamf_presentation_element_t* element) { + fraction_t num_samples_frac; + if (!self || !element) return IAMF_ERR_BAD_ARG; + + // Only process positions for object-based elements + if (element->scheme != ck_audio_element_type_object_based) return IAMF_OK; + + if (element->in.position_id == def_i32_id_none) { + debug("No valid position_id for object-based element_id: %u", + element->element_id); + return IAMF_OK; + } + + parameter_base_t* param_base = + iamf_database_get_parameter_base(self->database, element->in.position_id); + + if (!param_base || !iamf_parameter_type_is_coordinate(param_base->type)) { + warning( + "Invalid or non-coordinate position parameter %u for element_id: %u", + element->in.position_id, element->element_id); + return IAMF_OK; + } + + debug( + "Processing positions for object-based element_id: %u using position_id: " + "%u, type: %d", + element->element_id, element->in.position_id, param_base->type); + + uint32_t position_param_id = element->in.position_id; + num_samples_frac.numerator = element->block->num_samples_per_channel - + element->block->second_skip - + element->block->second_padding; + num_samples_frac.denominator = element->sampling_rate; + + // Get position subblocks based on parameter type + if (iamf_parameter_type_is_polar(param_base->type)) { + parameter_subblock_t** subblock = 0; + int n = iamf_database_get_subblocks(self->database, position_param_id, + num_samples_frac, &subblock); + polars_parameter_base_t* polars_param = + def_polars_parameter_base_ptr(param_base); + int num_objects = polars_param->num_polars > def_max_number_of_objects + ? def_max_number_of_objects + : polars_param->num_polars; + + debug("polar position subblocks count %d for element_id: %u", n, + element->element_id); + + if (element->block->second_skip) { + // Handle second skip for polar positions + animated_polar_t animated_polar_positions[def_max_number_of_objects]; + for (uint32_t k = 0; k < num_objects; k++) + animated_polar_positions[k] = + _create_step_animated_polar(0.0f, 0.0f, 1.0f); + + iamf_renderer_update_element_animated_polar_positions( + &self->renderer, element->element_id, position_param_id, + animated_polar_positions, num_objects, element->block->second_skip); + } + + if (n > 0) { + float durations = 0.0f; + uint32_t rate = + iamf_database_get_parameter_rate(self->database, position_param_id); + polars_parameter_subblock_t* polars_subblocks = + def_polars_parameter_subblock_ptr(*subblock); + + for (int j = 0; j < n; j++) { + uint32_t approximate_durations = durations + 0.5f; + float duration = iamf_fraction_transform_float( + def_fraction_instance(polars_subblocks[j].base.subblock_duration, + rate), + element->sampling_rate); + durations += duration; + duration = durations + 0.5f - approximate_durations; + + iamf_renderer_update_element_animated_polar_positions( + &self->renderer, element->element_id, position_param_id, + polars_subblocks->polars, polars_subblocks->num_polars, duration); + + durations += duration; + } + } else if (n < 0) { + // Use default positions from parameter_base_t to create virtual subblock + int num_objects = polars_param->num_polars > def_max_number_of_objects + ? def_max_number_of_objects + : polars_param->num_polars; + + animated_polar_t animated_polar_positions[def_max_number_of_objects]; + for (uint32_t k = 0; k < num_objects; k++) + animated_polar_positions[k] = _create_step_animated_polar( + polars_param->default_polars[k].azimuth, + polars_param->default_polars[k].elevation, + polars_param->default_polars[k].distance); + + iamf_renderer_update_element_animated_polar_positions( + &self->renderer, element->element_id, position_param_id, + animated_polar_positions, num_objects, + element->block->num_samples_per_channel); + } + + if (element->block->second_padding) { + // Handle second padding for polar positions + animated_polar_t animated_polar_positions[def_max_number_of_objects]; + for (uint32_t k = 0; k < num_objects; k++) + animated_polar_positions[k] = + _create_step_animated_polar(0.0f, 0.0f, 1.0f); + + iamf_renderer_update_element_animated_polar_positions( + &self->renderer, element->element_id, position_param_id, + animated_polar_positions, num_objects, + element->block->second_padding); + } + + if (subblock) def_free(subblock); + + } else if (iamf_parameter_type_is_cartesian(param_base->type)) { + parameter_subblock_t** subblock = 0; + int n = iamf_database_get_subblocks(self->database, position_param_id, + num_samples_frac, &subblock); + cartesians_parameter_base_t* cartesians_param = + def_cartesians_parameter_base_ptr(param_base); + int num_objects = + cartesians_param->num_cartesians > def_max_number_of_objects + ? def_max_number_of_objects + : cartesians_param->num_cartesians; + + debug("cartesian position subblocks count %d for element_id: %u", n, + element->element_id); + + if (element->block->second_skip) { + // Handle second skip for cartesian positions + animated_cartesian_t + animated_cartesian_positions[def_max_number_of_objects]; + for (uint32_t k = 0; k < num_objects; k++) + animated_cartesian_positions[k] = + _create_step_animated_cartesian(0.0f, 0.0f, 0.0f); + + iamf_renderer_update_element_animated_cartesian_positions( + &self->renderer, element->element_id, animated_cartesian_positions, + num_objects, element->block->second_skip); + } + + if (n > 0) { + cartesians_parameter_subblock_t* cartesians_subblocks = + def_cartesians_parameter_subblock_ptr(*subblock); + float durations = 0.0f; + uint32_t rate = + iamf_database_get_parameter_rate(self->database, position_param_id); + + for (int j = 0; j < n; j++) { + uint32_t approximate_durations = durations + 0.5f; + float duration = iamf_fraction_transform_float( + def_fraction_instance( + cartesians_subblocks[j].base.subblock_duration, rate), + element->sampling_rate); + durations += duration; + duration = durations + 0.5f - approximate_durations; + + iamf_renderer_update_element_animated_cartesian_positions( + &self->renderer, element->element_id, + cartesians_subblocks->cartesians, + cartesians_subblocks->num_cartesians, duration); + + durations += duration; + } + } else if (n < 0) { + // Use default positions from parameter_base_t + int num_objects = + cartesians_param->num_cartesians > def_max_number_of_objects + ? def_max_number_of_objects + : cartesians_param->num_cartesians; + + animated_cartesian_t + animated_cartesian_positions[def_max_number_of_objects]; + for (uint32_t k = 0; k < num_objects; k++) + animated_cartesian_positions[k] = _create_step_animated_cartesian( + cartesians_param->default_cartesians[k].x, + cartesians_param->default_cartesians[k].y, + cartesians_param->default_cartesians[k].z); + + iamf_renderer_update_element_animated_cartesian_positions( + &self->renderer, element->element_id, animated_cartesian_positions, + num_objects, element->block->num_samples_per_channel); + } + + if (element->block->second_padding) { + // Handle second padding for cartesian positions + animated_cartesian_t + animated_cartesian_positions[def_max_number_of_objects]; + for (uint32_t k = 0; k < num_objects; k++) + animated_cartesian_positions[k] = + _create_step_animated_cartesian(0.0f, 0.0f, 0.0f); + + iamf_renderer_update_element_animated_cartesian_positions( + &self->renderer, element->element_id, animated_cartesian_positions, + num_objects, element->block->second_padding); + } + + if (subblock) def_free(subblock); + } + + debug("Successfully processed positions for object-based element_id: %u", + element->element_id); + return IAMF_OK; +} + +static int iamf_presentation_priv_update_output_mix_gain( + iamf_presentation_t* self, iamf_audio_block_t* block, + fraction_t num_samples_frac) { + int num_gains = vector_size(self->output_mix_gain_ids); + if (!self || !block) return IAMF_ERR_BAD_ARG; + if (num_gains <= 0) return IAMF_ERR_INTERNAL; + + for (int g = 0; g < num_gains; g++) { + // set output mix gain + uint32_t pid = def_value_wrap_u32(vector_at(self->output_mix_gain_ids, g)); + parameter_subblock_t** subblocks = 0; + int n = iamf_database_get_subblocks(self->database, pid, num_samples_frac, + &subblocks); + uint32_t rate = iamf_database_get_parameter_rate(self->database, pid); + + // Handle second skip if present + if (block->second_skip > 0) { + animated_float32_t animated_gain = _create_step_animated_gain(1.0f); + iamf_renderer_update_animated_gain(&self->renderer, pid, g, animated_gain, + block->second_skip); + } + + // Process output mix gain subblocks + if (n > 0) { + float durations = 0.0f; + for (int i = 0; i < n; i++) { + if (!subblocks[i]) continue; + + uint32_t approximate_durations = durations + 0.5f; + float duration = iamf_fraction_transform_float( + def_fraction_instance(subblocks[i]->subblock_duration, rate), + num_samples_frac.denominator); + durations += duration; + duration = durations + 0.5f - approximate_durations; + + mix_gain_parameter_subblock_t* mix_gain_subblock = + def_mix_gain_parameter_subblock_ptr(subblocks[i]); + iamf_renderer_update_animated_gain( + &self->renderer, pid, g, mix_gain_subblock->gain_db, duration); + durations += duration; + } + } else if (n < 0) { + // Use default mix gain to build animated gain + parameter_base_t* param_base = + iamf_database_get_parameter_base(self->database, pid); + if (param_base && param_base->type == ck_iamf_parameter_type_mix_gain) { + mix_gain_parameter_base_t* mix_gain_param = + (mix_gain_parameter_base_t*)param_base; + animated_float32_t animated_gain = + _create_step_animated_gain(mix_gain_param->default_mix_gain_db); + + // Use the entire frame duration + uint32_t frame_duration = block->num_samples_per_channel; + iamf_renderer_update_animated_gain(&self->renderer, pid, g, + animated_gain, frame_duration); + } + } + + if (block->second_padding > 0) { + animated_float32_t animated_gain = _create_step_animated_gain(1.0f); + iamf_renderer_update_animated_gain(&self->renderer, pid, g, animated_gain, + block->second_padding); + } + + if (subblocks) def_free(subblocks); + } + debug("Successfully processed output mix gain for presentation_id: %u", + self->id); + return IAMF_OK; +} + +static int iamf_presentation_priv_loudness_process(iamf_presentation_t* self, + iamf_audio_block_t* block) { + if (self->loudness_gain != def_default_loudness_gain) + iamf_audio_block_gain(block, self->loudness_gain); + return IAMF_OK; +} + +iamf_presentation_t* iamf_presentation_create( + uint32_t id, iamf_database_t* database, + iamf_element_reconstructor_t* reconstructor, iamf_layout_t layout) { + iamf_presentation_t* self = 0; + int ret = IAMF_OK; + + if (!database || !reconstructor) return 0; + + if (!iamf_database_get_mix_presentation_obu(database, id)) { + error("No mix self OBU found for ID: %u", id); + return 0; + } + + self = def_mallocz(iamf_presentation_t, 1); + if (!self) return 0; + + self->id = id; + self->database = database; + self->reconstructor = reconstructor; + self->layout = layout; + self->loudness_gain = def_default_loudness_gain; + + self->elements = hash_map_new(def_hash_map_capacity_elements); + if (!self->elements) { + def_err_msg_enomem("Elements", def_pst_str); + iamf_presentation_destroy(self); + return 0; + } + + self->synchronizer = iamf_synchronizer_create(); + if (!self->synchronizer) { + def_err_msg_enomem("Synchronizer", def_pst_str); + iamf_presentation_destroy(self); + return 0; + } + + self->output_mix_gain_ids = vector_new(); + if (!self->output_mix_gain_ids) { + error("Failed to allocate memory for output mix gain IDs"); + iamf_presentation_destroy(self); + return 0; + } + + if (iamf_presentation_priv_make_elements(self) != IAMF_OK) { + error("Failed to create element presentations"); + iamf_presentation_destroy(self); + return 0; + } + + ret = iamf_presentation_priv_add_elements_to_reconstructor(self); + if (ret != IAMF_OK) { + error("Errno(%d): failed to add elements to reconstructor", ret); + iamf_presentation_destroy(self); + return 0; + } + + ret = iamf_presentation_priv_activate_elements_and_parameters(self); + if (ret != IAMF_OK) { + error("Errno(%d): failed to set layout and activate reconstructor entries", + ret); + iamf_presentation_destroy(self); + return 0; + } + + if (self->elements && hash_map_size(self->elements) > 0) { + hash_map_iterator_t* iter = hash_map_iterator_new(self->elements); + if (iter) { + iamf_presentation_element_t* element = def_value_wrap_type_ptr( + iamf_presentation_element_t, hash_map_iterator_get_value(iter)); + if (element) { + self->out_sampling_rate = element->sampling_rate; + debug("Set presentation out_sampling_rate to %d from element %u", + self->out_sampling_rate, element->element_id); + } + hash_map_iterator_delete(iter); + } + } + + if (iamf_presentation_priv_activate_renderer(self) != IAMF_OK) { + error("Failed to activate renderer"); + iamf_presentation_destroy(self); + return 0; + } + + info("Successfully initialized IAMF OAR"); + + return self; +} + +void iamf_presentation_destroy(iamf_presentation_t* self) { + if (!self) return; + + if (self->output_mix_gain_ids) vector_free(self->output_mix_gain_ids, 0); + if (self->elements) { + iamf_presentation_priv_delete_all_elements(self->elements); + hash_map_delete(self->elements, 0); + self->elements = 0; + } + iamf_renderer_uninit(&self->renderer); + if (self->synchronizer) iamf_synchronizer_destroy(self->synchronizer); + def_free(self); +} + +int iamf_presentation_set_element_gain_offset(iamf_presentation_t* self, + uint32_t eid, float offset) { + if (!self) { + error("Invalid presentation object"); + return IAMF_ERR_BAD_ARG; + } + + if (!self->elements) { + error("Presentation elements not initialized"); + return IAMF_ERR_INTERNAL; + } + + // Find the presentation element by element_id + value_wrap_t* val = hash_map_get(self->elements, eid); + if (!val) { + error("Element with ID %u not found in presentation", eid); + return IAMF_ERR_INTERNAL; + } + + iamf_presentation_element_t* element = + def_value_wrap_type_ptr(iamf_presentation_element_t, val); + if (!element) { + error("Invalid element for element_id: %u", eid); + return IAMF_ERR_INTERNAL; + } + + // Check if gain offset is enabled for this element + if (!element->enable_gain_offset) { + warning("Gain offset is not enabled for element ID %u", eid); + return IAMF_ERR_BAD_ARG; + } + + // Validate offset is within allowed range + if (offset < element->gain_offset.min || offset > element->gain_offset.max) { + error("Gain offset %f is out of range [%f, %f] for element ID %u", offset, + element->gain_offset.min, element->gain_offset.max, eid); + return IAMF_ERR_BAD_ARG; + } + + // Set the gain offset + element->gain_offset.offset = offset; + debug("Successfully set gain offset to %f for element ID %u", offset, eid); + + return IAMF_OK; +} + +int iamf_presentation_get_element_gain_offset(iamf_presentation_t* self, + uint32_t eid, float* offset) { + if (!self || !offset) { + error("Invalid presentation object or offset pointer"); + return IAMF_ERR_BAD_ARG; + } + + if (!self->elements) { + error("Presentation elements not initialized"); + return IAMF_ERR_INTERNAL; + } + + // Find the presentation element by element_id + value_wrap_t* val = hash_map_get(self->elements, eid); + if (!val) { + error("Element with ID %u not found in presentation", eid); + return IAMF_ERR_INTERNAL; + } + + iamf_presentation_element_t* element = + def_value_wrap_type_ptr(iamf_presentation_element_t, val); + if (!element) { + error("Invalid element for element_id: %u", eid); + return IAMF_ERR_INTERNAL; + } + + // Check if gain offset is enabled for this element + if (!element->enable_gain_offset) { + warning("Gain offset is not enabled for element ID %u", eid); + return IAMF_ERR_BAD_ARG; + } + + // Get the gain offset + *offset = element->gain_offset.offset; + debug("Successfully got gain offset %f for element ID %u", *offset, eid); + + return IAMF_OK; +} + +int iamf_presentation_set_loudness_gain(iamf_presentation_t* self, float gain) { + if (!self || !gain) return IAMF_ERR_BAD_ARG; + if (self->loudness_gain != gain) self->loudness_gain = gain; + return IAMF_OK; +} + +uint32_t iamf_presentation_get_id(iamf_presentation_t* self) { + if (!self) return def_i32_id_none; + return self->id; +} + +int iamf_presentation_get_sampling_rate(iamf_presentation_t* self) { + if (!self) return IAMF_ERR_BAD_ARG; + return self->out_sampling_rate; +} + +int iamf_presentation_add_audio_block(iamf_presentation_t* self, + iamf_audio_block_t* audio_block) { + int ret = IAMF_OK; + if (!self || !audio_block) { + error("Invalid arguments: presentation or audio_block is NULL"); + return IAMF_ERR_BAD_ARG; + } + + uint32_t eid = audio_block->id; + iamf_presentation_element_t* element = 0; + value_wrap_t* val = 0; + + // Find the presentation element by element_id + val = hash_map_get(self->elements, eid); + if (!val) { + error("Element with ID %u not found in presentation", eid); + return IAMF_ERR_INTERNAL; + } + + element = def_value_wrap_type_ptr(iamf_presentation_element_t, val); + + if (element->block) { + ret = IAMF_ERR_INVALID_PACKET; + warning("Audio block already exists for element ID %u", eid); + iamf_presentation_priv_delete_all_audio_blocks(self); + } + + element->block = audio_block; + ++self->num_audio_blocks; + debug("Successfully added audio block for element ID %u", eid); + + if (self->num_audio_blocks == hash_map_size(self->elements)) ret = 1; + return ret; +} + +iamf_audio_block_t* iamf_presentation_process(iamf_presentation_t* self) { + fraction_t num_samples_frac; + uint32_t num_output_samples = 0; + iamf_audio_block_t* block = 0; + int ret = IAMF_OK; + + if (!self || !self->elements || !self->database) { + error("Invalid presentation object for processing."); + return 0; + } + + // Check if all audio blocks are present before starting processing. + if (self->num_audio_blocks != hash_map_size(self->elements)) { + warning( + "Not all audio blocks received for presentation %u. Received %u, " + "expected %u.", + self->id, self->num_audio_blocks, hash_map_size(self->elements)); + } + + ret = iamf_presentation_priv_sync_audio_blocks(self); + if (ret != IAMF_OK) + warning("Failed to sync audio blocks for presentation %u", self->id); + + hash_map_iterator_t* iter = hash_map_iterator_new(self->elements); + if (!iter) { + error("Failed to create iterator for presentation elements."); + return 0; + } + + block = def_value_wrap_type_ptr(iamf_presentation_element_t, + hash_map_iterator_get_value(iter)) + ->block; + + do { + iamf_presentation_element_t* element = def_value_wrap_type_ptr( + iamf_presentation_element_t, hash_map_iterator_get_value(iter)); + if (!element || !element->block) { + // This should ideally not be hit if num_audio_blocks check passes. + error("Invalid element or missing audio block for element_id: %u", + hash_map_iterator_get_key(iter)); + ret = IAMF_ERR_INTERNAL; + break; + } + + if (!num_output_samples) { + num_output_samples = element->number_samples_per_frame; + num_samples_frac.numerator = element->block->num_samples_per_channel - + element->block->second_skip - + element->block->second_padding; + num_samples_frac.denominator = element->sampling_rate; + } + + iamf_presentation_priv_update_element_downmix_info(self, element); + + iamf_presentation_priv_update_element_gain_offset(self, element); + + iamf_presentation_priv_update_element_mix_gain(self, element); + + iamf_presentation_priv_update_element_positions(self, element); + + ret = iamf_renderer_add_element_audio_data(&self->renderer, element->block); + if (ret != IAMF_OK) { + error("Failed to add audio data for element_id: %u", element->element_id); + break; + } + + } while (!hash_map_iterator_next(iter)); + hash_map_iterator_delete(iter); + + if (ret != IAMF_OK) return 0; + + iamf_presentation_priv_update_output_mix_gain(self, block, num_samples_frac); + + iamf_audio_block_t* output_block = iamf_audio_block_new( + self->id, num_output_samples, iamf_layout_channels_count(&self->layout)); + if (!output_block) { + error("Failed to allocate memory for output audio block."); + return 0; + } + + iamf_audio_block_samples_info_copy(output_block, block); + + ret = iamf_renderer_render(&self->renderer, output_block); + + iamf_presentation_priv_delete_all_audio_blocks(self); + + if (ret != IAMF_OK) { + error("errno <%d> : renderer failed to produce output audio block.", ret); + iamf_audio_block_delete(output_block); + return 0; + } + + iamf_presentation_priv_loudness_process(self, output_block); + + debug("Successfully processed presentation %u.", self->id); + return output_block; +} + +int iamf_presentation_set_head_rotation(iamf_presentation_t* self, + const quaternion_t* quaternion) { + if (!self || !quaternion) return IAMF_ERR_BAD_ARG; + + if (self->layout.type != ck_iamf_layout_type_binaural) { + warning( + "Head rotation is only effective for binaural output layout. " + "Current layout type: %d. Head rotation will be stored but not " + "applied.", + self->layout.type); + return IAMF_ERR_INVALID_STATE; + } + + debug("Set head rotation in presentation: w=%f, x=%f, y=%f, z=%f", + quaternion->w, quaternion->x, quaternion->y, quaternion->z); + + return iamf_renderer_set_head_rotation(&self->renderer, quaternion); +} + +int iamf_presentation_enable_head_tracking(iamf_presentation_t* self, + uint32_t enable) { + if (!self) return IAMF_ERR_BAD_ARG; + + if (self->layout.type != ck_iamf_layout_type_binaural) { + warning( + "Head tracking is only effective for binaural output layout. " + "Current layout type: %d. Head tracking setting will be stored but not " + "applied.", + self->layout.type); + return IAMF_ERR_INVALID_STATE; + } + + debug("Head tracking %s in presentation", enable ? "enabled" : "disabled"); + + return iamf_renderer_enable_head_tracking(&self->renderer, enable); +} diff --git a/code/src/iamf_dec/iamf_presentation.h b/code/src/iamf_dec/iamf_presentation.h new file mode 100755 index 00000000..3c5148f8 --- /dev/null +++ b/code/src/iamf_dec/iamf_presentation.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_presentation.h + * @brief IAMF presentation API. + * @version 2.0.0 + * @date Created 05/09/2025 + **/ + +#ifndef __IAMF_PRESENTATION_H__ +#define __IAMF_PRESENTATION_H__ + +#include "IAMF_defines.h" +#include "chashmap.h" +#include "iamf_audio_block.h" +#include "iamf_database.h" +#include "iamf_element_reconstructor.h" +#include "iamf_obu_parser.h" +#include "iamf_renderer.h" +#include "iamf_types.h" +#include "obu/mix_presentation_obu.h" + +typedef struct IamfPresentation iamf_presentation_t; + +iamf_presentation_t* iamf_presentation_create( + uint32_t id, iamf_database_t* database, + iamf_element_reconstructor_t* reconstructor, iamf_layout_t layout); + +void iamf_presentation_destroy(iamf_presentation_t* self); + +int iamf_presentation_set_element_gain_offset(iamf_presentation_t* self, + uint32_t eid, float offset); +int iamf_presentation_get_element_gain_offset(iamf_presentation_t* self, + uint32_t eid, float* offset); +int iamf_presentation_set_loudness_gain(iamf_presentation_t* self, float gain); + +uint32_t iamf_presentation_get_id(iamf_presentation_t* self); +int iamf_presentation_get_sampling_rate(iamf_presentation_t* self); + +int iamf_presentation_add_audio_block(iamf_presentation_t* self, + iamf_audio_block_t* audio_block); + +iamf_audio_block_t* iamf_presentation_process(iamf_presentation_t* self); + +/** + * @brief Set head rotation for 3D audio rendering in the presentation. + * + * This function sets the head rotation using quaternion representation to + * counter-rotate the intermediate Ambisonic bed, producing stable sound sources + * in binaural reproduction. The head rotation is essential for immersive 3D + * audio experiences where the listener's head orientation affects audio + * perception. + * + * @param [in] self : Pointer to the presentation instance. + * @param [in] quaternion : Pointer to the quaternion structure containing + * head rotation. + * + * @return 0 on success, non-zero error code on failure. + * + * @note This function should be called regularly during audio playback to + * update the head position based on sensor data from head tracking devices. The + * head rotation data is passed to the renderer for processing during audio + * rendering to create realistic 3D audio spatialization. + * + * @warning Head rotation functionality is only effective for binaural output + * layout. For other output layouts (stereo, multichannel), head rotation + * settings will be stored but will not affect the audio output. + */ +int iamf_presentation_set_head_rotation(iamf_presentation_t* self, + const quaternion_t* quaternion); + +/** + * @brief Enable or disable head tracking for 3D audio rendering in the + * presentation. + * + * This function enables or disables head tracking functionality. When enabled, + * the renderer will use head rotation data to create immersive 3D audio + * experiences. + * + * @param [in] self : Pointer to the presentation instance. + * @param [in] enable : 1 to enable head tracking, 0 to disable. + * + * @return 0 on success, non-zero error code on failure. + * + * @note Head tracking must be enabled before setting head rotation values. + * This function should be called before starting audio playback or when + * dynamically enabling/disabling head tracking during playback. + * + * @warning Head tracking functionality is only effective for binaural output + * layout. For other output layouts (stereo, multichannel), this setting + * will be stored but will not affect the audio output. + */ +int iamf_presentation_enable_head_tracking(iamf_presentation_t* self, + uint32_t enable); + +#endif // __IAMF_PRESENTATION_H__ diff --git a/code/src/iamf_dec/iamf_private_definitions.h b/code/src/iamf_dec/iamf_private_definitions.h new file mode 100755 index 00000000..46e071ef --- /dev/null +++ b/code/src/iamf_dec/iamf_private_definitions.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_private_definitions.h + * @brief IAMF private definitions. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_PRIVATE_DEFINITIONS_H__ +#define __IAMF_PRIVATE_DEFINITIONS_H__ + +#include "IAMF_defines.h" +#include "clog.h" +#include "definitions.h" + +#define def_iamf_ustr "IAMF" + +#define def_pass 1 +#define def_error 0 +#define def_fatal (-1) + +#define def_true 1 +#define def_false 0 + +#define def_iamf_profile_default ck_iamf_profile_advanced_2 +#define def_iamf_profile_count (def_iamf_profile_default + 1) + +#define def_audio_sample_format_default 0x10 +#define def_default_sampling_rate 48000 + +#define def_limiter_max_true_peak -1.0f +#define def_default_loudness_lkfs 0.0f +#define def_default_loudness_gain 1.0f + +#define def_i32_id_none (-1) +#define def_i64_id_none (-1LL) + +#define def_iamf_decoder_config_mix_presentation 0x1 +#define def_iamf_decoder_config_output_layout 0x2 +#define def_iamf_decoder_config_presentation 0x100 + +#define def_err_msg_enomem(obj, tag) \ + error("Fail to allocate memory for " obj " of " tag ".") + +#define def_lsb_16bits(a) ((a) & 0xFFFF) +#define def_lsb_32bits(a) ((a) & 0xFFFFFFFFULL) + +#define def_dmx_mode_none -1 +#define def_dmx_weight_index_none -1 + +#define def_base_enhanced_audio_elements 28 +#define def_base_enhanced_audio_channels def_base_enhanced_audio_elements +#define def_base_enhanced_ambisonic_audio_channels 25 + +#define def_max_audio_streams def_base_enhanced_ambisonic_audio_channels +#define def_max_audio_channels def_base_enhanced_audio_channels +#define def_hash_map_capacity_elements 32 +#define def_hash_map_capacity_audio_frames def_hash_map_capacity_elements +#define def_max_channel_groups 8 +#define def_max_sub_mixes 2 +#define def_max_codec_configs 2 + +#define def_iamf_loudspeaker_layout_expanded 15 +#define def_iamf_loudspeaker_layout_expanded_mask 0x10 + +#define def_default_recon_gain 1.0f + +#define def_ccs_str_size 1024 +#define def_cc_str_size 128 +#define def_q78_num_bits 16 +#define def_azimuth_num_bits 9 +#define def_elevation_num_bits 8 +#define def_distance_num_bits 7 + +// Assumed bit depths for cartesian coordinates +#define def_cartesian_8_num_bits 8 +#define def_cartesian_16_num_bits 16 + +#define def_max_audio_objects 2 + +#define def_max_opus_frame_size 960 * 6 +#define def_max_aac_frame_size 2048 +#define def_max_flac_frame_size 32768 + +#define def_clip3(min, max, val) (val < min ? min : val > max ? max : val) +#define def_azimuth_clip(val) def_clip3(-180, 180, val) +#define def_elevation_clip(val) def_clip3(-90, 90, val) +#define def_distance_clip(val) def_clip3(0.0f, 1.0f, val) +#define def_clip_normalized(val) def_clip3(-1.0f, 1.0f, val) + +#define def_ptr(type, a) ((type##_t *)(a)) +#define def_cast(type, a) ((type)(a)) +#define def_ia_profile_cast(a) def_cast(IA_Profile, (a)) +#define def_iamf_profile_cast(a) def_cast(iamf_profile_t, (a)) +#define def_iamf_codec_id_cast(a) def_cast(IAMF_CodecID, (a)) + +#define def_rshift(a) (1 << (a)) + +#define def_sound_system_layout_instance(layout) \ + (iamf_layout_t) { \ + .type = ck_iamf_layout_type_loudspeakers_ss_convention, \ + .sound_system = layout \ + } +#define def_binaural_layout_instance() \ + (iamf_layout_t) { .type = ck_iamf_layout_type_binaural } + +#endif // __IAMF_PRIVATE_DEFINITIONS_H__ diff --git a/code/src/iamf_dec/iamf_renderer.c b/code/src/iamf_dec/iamf_renderer.c new file mode 100755 index 00000000..2f1d2a91 --- /dev/null +++ b/code/src/iamf_dec/iamf_renderer.c @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_renderer.c + * @brief renderer implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "iamf_renderer.h" + +#include +#include + +#include "iamf_private_definitions.h" + +static const struct { + iamf_sound_system_t sound_system; + oar_layout_t layout; +} _iamf2oar_sound_system_map[] = { + {SOUND_SYSTEM_A, ck_oar_layout_sound_system_a_020}, + {SOUND_SYSTEM_B, ck_oar_layout_sound_system_b_050}, + {SOUND_SYSTEM_C, ck_oar_layout_sound_system_c_250}, + {SOUND_SYSTEM_D, ck_oar_layout_sound_system_d_450}, + {SOUND_SYSTEM_E, ck_oar_layout_sound_system_e_451}, + {SOUND_SYSTEM_F, ck_oar_layout_sound_system_f_370}, + {SOUND_SYSTEM_G, ck_oar_layout_sound_system_g_490}, + {SOUND_SYSTEM_H, ck_oar_layout_sound_system_h_9a3}, + {SOUND_SYSTEM_I, ck_oar_layout_sound_system_i_070}, + {SOUND_SYSTEM_J, ck_oar_layout_sound_system_j_470}, + {SOUND_SYSTEM_EXT_712, ck_oar_layout_712}, + {SOUND_SYSTEM_EXT_312, ck_oar_layout_312}, + {SOUND_SYSTEM_MONO, ck_oar_layout_mono}, + {SOUND_SYSTEM_EXT_916, ck_oar_layout_916}, + {SOUND_SYSTEM_EXT_7154, ck_oar_layout_7154}, +}; + +oar_layout_t _iamf2oar_output_layout_get(iamf_layout_t layout) { + if (layout.type == ck_iamf_layout_type_binaural) + return ck_oar_layout_binaural; + if (layout.type != ck_iamf_layout_type_loudspeakers_ss_convention) + return ck_oar_layout_none; + for (size_t i = 0; i < sizeof(_iamf2oar_sound_system_map) / + sizeof(_iamf2oar_sound_system_map[0]); + i++) + if (layout.sound_system == _iamf2oar_sound_system_map[i].sound_system) + return _iamf2oar_sound_system_map[i].layout; + return ck_oar_layout_none; +} + +static const struct { + iamf_loudspeaker_layout_t iamf_layout; + oar_layout_t oar_layout; +} _iamf2oar_channel_layout_map[] = { + {ck_iamf_loudspeaker_layout_mono, ck_oar_layout_mono}, + {ck_iamf_loudspeaker_layout_stereo, ck_oar_layout_stereo}, + {ck_iamf_loudspeaker_layout_510, ck_oar_layout_51}, + {ck_iamf_loudspeaker_layout_512, ck_oar_layout_512}, + {ck_iamf_loudspeaker_layout_514, ck_oar_layout_514}, + {ck_iamf_loudspeaker_layout_710, ck_oar_layout_71}, + {ck_iamf_loudspeaker_layout_712, ck_oar_layout_712}, + {ck_iamf_loudspeaker_layout_714, ck_oar_layout_714}, + {ck_iamf_loudspeaker_layout_312, ck_oar_layout_312}, + {ck_iamf_loudspeaker_layout_binaural, ck_oar_layout_binaural}, + {ck_iamf_loudspeaker_layout_expanded_lfe, ck_oar_layout_lfe}, + {ck_iamf_loudspeaker_layout_expanded_stereo_s, ck_oar_layout_stereo_s}, + {ck_iamf_loudspeaker_layout_expanded_stereo_ss, ck_oar_layout_stereo_ss}, + {ck_iamf_loudspeaker_layout_expanded_stereo_rs, ck_oar_layout_stereo_rs}, + {ck_iamf_loudspeaker_layout_expanded_stereo_tf, ck_oar_layout_stereo_tf}, + {ck_iamf_loudspeaker_layout_expanded_stereo_tb, ck_oar_layout_stereo_tb}, + {ck_iamf_loudspeaker_layout_expanded_top_4ch, ck_oar_layout_top_4ch}, + {ck_iamf_loudspeaker_layout_expanded_3ch, ck_oar_layout_3ch}, + {ck_iamf_loudspeaker_layout_expanded_916, ck_oar_layout_916}, + {ck_iamf_loudspeaker_layout_expanded_stereo_f, ck_oar_layout_stereo_f}, + {ck_iamf_loudspeaker_layout_expanded_stereo_si, ck_oar_layout_stereo_si}, + {ck_iamf_loudspeaker_layout_expanded_stereo_tpsi, + ck_oar_layout_stereo_tpsi}, + {ck_iamf_loudspeaker_layout_expanded_top_6ch, ck_oar_layout_top_6ch}, + {ck_iamf_loudspeaker_layout_expanded_lfe_pair, ck_oar_layout_lfe_pair}, + {ck_iamf_loudspeaker_layout_expanded_bottom_3ch, ck_oar_layout_bottom_3ch}, + {ck_iamf_loudspeaker_layout_expanded_bottom_4ch, ck_oar_layout_bottom_4ch}, + {ck_iamf_loudspeaker_layout_expanded_top_1ch, ck_oar_layout_top_1ch}, + {ck_iamf_loudspeaker_layout_expanded_top_5ch, ck_oar_layout_top_5ch}, + {ck_iamf_loudspeaker_layout_expanded_a293, ck_oar_layout_a293}, + {ck_iamf_loudspeaker_layout_expanded_7154, ck_oar_layout_7154}, +}; + +static oar_layout_t _iamf2oar_input_layout_get( + iamf_loudspeaker_layout_t layout) { + for (size_t i = 0; i < sizeof(_iamf2oar_channel_layout_map) / + sizeof(_iamf2oar_channel_layout_map[0]); + i++) + if (layout == _iamf2oar_channel_layout_map[i].iamf_layout) + return _iamf2oar_channel_layout_map[i].oar_layout; + return ck_oar_layout_none; +} + +static oar_hoa_t _iamf2oar_hoa_get(uint32_t channels) { + switch (channels) { + case 1: + return ck_oar_zoa; + case 4: + return ck_oar_1oa; + case 9: + return ck_oar_2oa; + case 16: + return ck_oar_3oa; + case 25: + return ck_oar_4oa; + default: + return ck_oar_hoa_none; + } +} + +static oar_audio_block_t _iamf2oar_audio_block_copy(iamf_audio_block_t* block) { + oar_audio_block_t data = {block->data, block->num_channels, + block->num_samples_per_channel}; + return data; +} + +static void _set_rendering_parameters(parameter_set_t* parameters, + iamf_rendering_param_t param) { + parameters->flags |= def_parameter_set_flag_iamf_element_rendering_config; + parameters->element_rendering_config.headphones_rendering_mode = + param.headphones_rendering_mode; + parameters->element_rendering_config.binaural_filter_profile = + param.binaural_filter_profile; +} + +static int iamf_renderer_private_acquire_group_id(iamf_renderer_t* self, + uint32_t index) { + if (index >= def_max_sub_mixes) return IAMF_ERR_BAD_ARG; + + if (self->gids[index] == def_i32_id_none) { + self->gids[index] = oar_add_audio_group(self->oar); + if (self->gids[index] < 0) { + self->gids[index] = def_i32_id_none; + return IAMF_ERR_INTERNAL; + } + } + + return self->gids[index]; +} + +int iamf_renderer_private_add_element( + iamf_renderer_t* self, uint32_t id, uint32_t group_index, + const oar_audio_element_config_t* config) { + int gid = iamf_renderer_private_acquire_group_id(self, group_index); + if (gid < 0) return IAMF_ERR_BAD_ARG; + return oar_add_audio_element(self->oar, gid, id, config) == ck_oar_ok + ? IAMF_OK + : IAMF_ERR_INTERNAL; +} + +int iamf_renderer_init(iamf_renderer_t* self, iamf_layout_t layout, + uint32_t number_samples_per_frame, + uint32_t sampling_rate) { + oar_config_t _config; + _config.target_layout = _iamf2oar_output_layout_get(layout); + if (_config.target_layout == ck_oar_layout_none) return IAMF_ERR_BAD_ARG; + _config.samples_per_channel = number_samples_per_frame; + _config.sampling_rate = sampling_rate; + self->oar = oar_create(&_config); + if (!self->oar) return IAMF_ERR_INTERNAL; + + for (int i = 0; i < def_max_sub_mixes; ++i) self->gids[i] = def_i32_id_none; + self->samples_per_frame = number_samples_per_frame; + + return IAMF_OK; +} + +void iamf_renderer_uninit(iamf_renderer_t* self) { + if (self->oar) oar_destroy(self->oar); + memset(self, 0, sizeof(*self)); +} + +int iamf_renderer_add_channel_based_element(iamf_renderer_t* self, uint32_t id, + uint32_t group_index, + iamf_loudspeaker_layout_t layout, + iamf_rendering_param_t param, + int downmix_mode, + int downmix_weight_index) { + oar_audio_element_config_t config = {0}; + config.type = ck_channel_based; + config.cbc.layout = _iamf2oar_input_layout_get(layout); + if (config.cbc.layout == ck_oar_layout_none) return IAMF_ERR_BAD_ARG; + _set_rendering_parameters(&config.parameters, param); + if (downmix_mode != def_dmx_mode_none) { + config.parameters.flags |= def_parameter_set_flag_iamf_downmix_info; + config.parameters.downmix_info.mode = downmix_mode; + config.parameters.downmix_info.weight_index = downmix_weight_index; + } + + return iamf_renderer_private_add_element(self, id, group_index, &config); +} + +int iamf_renderer_add_scene_based_element(iamf_renderer_t* self, uint32_t id, + uint32_t group_index, + uint32_t number_channels, + iamf_rendering_param_t param) { + oar_audio_element_config_t config = {0}; + config.type = ck_scene_based; + config.sbc.order = _iamf2oar_hoa_get(number_channels); + if (config.sbc.order == ck_oar_hoa_none) return IAMF_ERR_BAD_ARG; + _set_rendering_parameters(&config.parameters, param); + return iamf_renderer_private_add_element(self, id, group_index, &config); +} + +int iamf_renderer_add_object_based_element(iamf_renderer_t* self, uint32_t id, + uint32_t group_index, + uint32_t number_objects, + iamf_rendering_param_t param) { + oar_audio_element_config_t config = {0}; + config.type = ck_object_based; + config.obc.num_objects = number_objects; + _set_rendering_parameters(&config.parameters, param); + + return iamf_renderer_private_add_element(self, id, group_index, &config); +} + +int iamf_renderer_add_element_audio_data(iamf_renderer_t* self, + iamf_audio_block_t* block) { + if (!self || !block) return IAMF_ERR_BAD_ARG; + if (!self->oar) return IAMF_ERR_INTERNAL; + + oar_audio_block_t audio_data = _iamf2oar_audio_block_copy(block); + return oar_update_audio_element_data(self->oar, block->id, &audio_data) == + ck_oar_ok + ? IAMF_OK + : IAMF_ERR_INTERNAL; +} + +int iamf_renderer_update_element_animated_gain(iamf_renderer_t* self, + uint32_t id, uint32_t pid, + animated_float32_t animated_gain, + uint32_t number) { + oar_metadata_t gain; + + if (!self || !self->oar) return IAMF_ERR_BAD_ARG; + + gain.type = ck_metadata_gain; + gain.gain.id = pid; + gain.gain.param_type = ck_param_animated; + + // Assign animated_gains field + gain.gain.animated_gains = animated_gain; + gain.duration = number; + + debug( + "display pid %d: gain %d: animation type %d: start %f, end %f, control " + "%f, control_relative_time %f, duration %d", + pid, pid, animated_gain.animation_type, animated_gain.data.start, + animated_gain.data.end, animated_gain.data.control, + animated_gain.data.control_relative_time, number); + + return oar_update_audio_element_metadata(self->oar, id, &gain) == ck_oar_ok + ? IAMF_OK + : IAMF_ERR_INTERNAL; +} + +int iamf_renderer_update_element_downmix_mode(iamf_renderer_t* self, + uint32_t id, int mode, + int period) { + oar_metadata_t dmx; + dmx.type = ck_metadata_iamf_downmix_mode; + dmx.iamf_downmix_mode.mode = mode; + dmx.duration = period; + return oar_update_audio_element_metadata(self->oar, id, &dmx) == ck_oar_ok + ? IAMF_OK + : IAMF_ERR_INTERNAL; +} + +int iamf_renderer_update_animated_gain(iamf_renderer_t* self, uint32_t pid, + uint32_t group_index, + animated_float32_t animated_gain, + uint32_t number) { + oar_metadata_t gain; + + if (!self || !self->oar || group_index >= def_max_sub_mixes || + self->gids[group_index] == def_i32_id_none) + return IAMF_ERR_BAD_ARG; + + gain.type = ck_metadata_gain; + gain.gain.id = pid; + gain.gain.param_type = ck_param_animated; + + // Assign animated_gains field + gain.gain.animated_gains = animated_gain; + gain.duration = number; + + debug( + "display gid %d: gain %d: animation type %d: start %f, end %f, control " + "%f, control_relative_time %f, duration %d", + self->gids[group_index], pid, animated_gain.animation_type, + animated_gain.data.start, animated_gain.data.end, + animated_gain.data.control, animated_gain.data.control_relative_time, + number); + + return oar_update_metadata(self->oar, self->gids[group_index], &gain) == + ck_oar_ok + ? IAMF_OK + : IAMF_ERR_INTERNAL; +} + +int iamf_renderer_update_element_animated_polar_positions( + iamf_renderer_t* self, uint32_t id, uint32_t pid, + animated_polar_t* positions, uint32_t number, uint32_t duration) { + oar_metadata_t metadata; + + if (!self || !self->oar || !positions) return IAMF_ERR_BAD_ARG; + if (number == 0) return IAMF_ERR_BAD_ARG; + + metadata.type = ck_metadata_object_positions; + metadata.object_positions.param_type = ck_param_animated; + metadata.object_positions.position_type = ck_polar; + + // Count valid positions and copy animated polar positions + uint32_t i = 0; + for (; i < number && i < def_max_number_of_objects; i++) { + metadata.object_positions.animated_polar_positions[i] = positions[i]; + debug( + "Update animated polar positions for element %u-%u: num_objects=%u, " + "duration=%u, index=%u, azimuth=%f, elevation=%f, distance=%f", + id, pid, metadata.object_positions.num_objects, duration, i, + positions[i].azimuth.start, positions[i].elevation.start, + positions[i].distance.start); + } + metadata.object_positions.num_objects = i; + + metadata.duration = duration; + + return oar_update_audio_element_metadata(self->oar, id, &metadata) == + ck_oar_ok + ? IAMF_OK + : IAMF_ERR_INTERNAL; +} + +int iamf_renderer_update_element_animated_cartesian_positions( + iamf_renderer_t* self, uint32_t id, animated_cartesian_t* positions, + uint32_t number, uint32_t duration) { + oar_metadata_t metadata; + + if (!self || !self->oar || !positions) return IAMF_ERR_BAD_ARG; + if (number == 0) return IAMF_ERR_BAD_ARG; + + metadata.type = ck_metadata_object_positions; + metadata.object_positions.param_type = ck_param_animated; + metadata.object_positions.position_type = ck_cartesian; + + // Count valid positions and copy animated cartesian positions + uint32_t i = 0; + for (; i < number && i < def_max_number_of_objects; i++) { + metadata.object_positions.animated_cartesian_positions[i] = positions[i]; + debug( + "Update animated cartesian positions for element %u: index=%u, x=%f," + "y=%f, z=%f", + id, i, positions[i].x.start, positions[i].y.start, + positions[i].z.start); + } + metadata.object_positions.num_objects = i; + + metadata.duration = duration; + + debug( + "Update animated cartesian positions for element %u: num_objects=%u, " + "duration=%u", + id, metadata.object_positions.num_objects, duration); + + return oar_update_audio_element_metadata(self->oar, id, &metadata) == + ck_oar_ok + ? IAMF_OK + : IAMF_ERR_INTERNAL; +} + +int iamf_renderer_render(iamf_renderer_t* self, iamf_audio_block_t* out_block) { + if (!self || !out_block) return IAMF_ERR_BAD_ARG; + if (!self->oar) return IAMF_ERR_INTERNAL; + + uint32_t output_channels = oar_get_number_of_output_channels(self->oar); + uint32_t output_samples = oar_get_samples_per_channel(self->oar); + + if (out_block->capacity_per_channel * out_block->num_channels < + output_samples * output_channels) { + error( + "Output buffer size too small for rendering! Expected %ux%u, got %ux%u", + output_samples, output_channels, out_block->capacity_per_channel, + out_block->num_channels); + return IAMF_ERR_BAD_ARG; + } + + if (out_block->num_channels != output_channels) + out_block->num_channels = output_channels; + + oar_audio_block_t output_data = {out_block->data, output_channels, + output_samples}; + + return oar_render(self->oar, &output_data) == ck_oar_ok ? IAMF_OK + : IAMF_ERR_INTERNAL; +} + +int iamf_renderer_set_head_rotation(iamf_renderer_t* self, + const quaternion_t* quaternion) { + int ret = IAMF_OK; + if (!self || !quaternion) return IAMF_ERR_BAD_ARG; + if (!self->oar) return IAMF_ERR_INTERNAL; + + oar_metadata_t metadata; + metadata.type = ck_metadata_head_rotation; + metadata.head_rotation = *quaternion; + metadata.duration = 0; + + debug("Set head rotation in renderer: w=%f, x=%f, y=%f, z=%f", quaternion->w, + quaternion->x, quaternion->y, quaternion->z); + + for (int i = 0; i < def_max_sub_mixes; i++) { + if (self->gids[i] != def_i32_id_none) { + if (oar_update_metadata(self->oar, self->gids[i], &metadata) != ck_oar_ok) + ret = IAMF_ERR_INTERNAL; + } + } + return ret; +} + +int iamf_renderer_enable_head_tracking(iamf_renderer_t* self, uint32_t enable) { + if (!self) return IAMF_ERR_BAD_ARG; + + debug("Head tracking %s in renderer", enable ? "enabled" : "disabled"); + return oar_enable_head_tracking(self->oar, enable) == ck_oar_ok + ? IAMF_OK + : IAMF_ERR_INTERNAL; +} diff --git a/code/src/iamf_dec/iamf_renderer.h b/code/src/iamf_dec/iamf_renderer.h new file mode 100755 index 00000000..3da7ae37 --- /dev/null +++ b/code/src/iamf_dec/iamf_renderer.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_renderer.h + * @brief renderer API. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_RENDERER_H__ +#define __IAMF_RENDERER_H__ + +#include "IAMF_defines.h" +#include "chashmap.h" +#include "iamf_audio_block.h" +#include "iamf_private_definitions.h" +#include "iamf_types.h" +#include "oar.h" +#include "oar_metadata.h" +#include "parameter_block_obu.h" + +typedef struct IamfOar { + oar_t* oar; + int gids[def_max_sub_mixes]; + int samples_per_frame; +} iamf_renderer_t; + +typedef struct IamfRenderingParam { + uint32_t headphones_rendering_mode; + uint32_t binaural_filter_profile; +} iamf_rendering_param_t; + +#define def_rendering_param_instance(headphone_mode, binaural_profile) \ + (iamf_rendering_param_t) { \ + .headphones_rendering_mode = headphone_mode, \ + .binaural_filter_profile = binaural_profile \ + } + +int iamf_renderer_init(iamf_renderer_t* self, iamf_layout_t layout, + uint32_t number_samples_per_frame, + uint32_t sampling_rate); +void iamf_renderer_uninit(iamf_renderer_t* self); +int iamf_renderer_add_channel_based_element(iamf_renderer_t* self, uint32_t id, + uint32_t group_index, + iamf_loudspeaker_layout_t layout, + iamf_rendering_param_t param, + int downmix_mode, + int downmix_weight_index); +int iamf_renderer_add_scene_based_element(iamf_renderer_t* self, uint32_t id, + uint32_t group_index, + uint32_t number_channels, + iamf_rendering_param_t param); +int iamf_renderer_add_object_based_element(iamf_renderer_t* self, uint32_t id, + uint32_t group_index, + uint32_t number_objects, + iamf_rendering_param_t param); +int iamf_renderer_add_element_audio_data(iamf_renderer_t* self, + iamf_audio_block_t* block); +int iamf_renderer_update_element_animated_gain(iamf_renderer_t* self, + uint32_t id, uint32_t pid, + animated_float32_t animated_gain, + uint32_t number); +int iamf_renderer_update_element_downmix_mode(iamf_renderer_t* self, + uint32_t id, int mode, + int period); +int iamf_renderer_update_animated_gain(iamf_renderer_t* self, uint32_t pid, + uint32_t group_index, + animated_float32_t animated_gain, + uint32_t number); +int iamf_renderer_update_element_animated_polar_positions( + iamf_renderer_t* self, uint32_t id, uint32_t pid, + animated_polar_t* positions, uint32_t number, uint32_t duration); +int iamf_renderer_update_element_animated_cartesian_positions( + iamf_renderer_t* self, uint32_t id, animated_cartesian_t* positions, + uint32_t number, uint32_t duration); + +int iamf_renderer_render(iamf_renderer_t* self, iamf_audio_block_t* out_block); + +/** + * @brief Set head rotation for 3D audio rendering. + * + * This function sets the head rotation using quaternion representation to + * counter-rotate the intermediate Ambisonic bed, producing stable sound sources + * in binaural reproduction. The head rotation is essential for immersive 3D + * audio experiences where the listener's head orientation affects audio + * perception. + * + * @param [in] self : Pointer to the renderer instance. + * @param [in] quaternion : Pointer to the quaternion structure containing + * head rotation. + * + * @return 0 on success, non-zero error code on failure. + * + * @note This function should be called regularly during audio playback to + * update the head position based on sensor data from head tracking devices. The + * head rotation data is used during the rendering process to create realistic + * 3D audio spatialization. + * + * @warning Head rotation functionality is only effective for binaural output + * layout. For other output layouts (stereo, multichannel), head rotation + * settings will be stored but will not affect the audio output. + */ +int iamf_renderer_set_head_rotation(iamf_renderer_t* self, + const quaternion_t* quaternion); + +/** + * @brief Enable or disable head tracking for 3D audio rendering. + * + * This function enables or disables head tracking functionality. When enabled, + * the renderer will use head rotation data to create immersive 3D audio + * experiences. + * + * @param [in] self : Pointer to the renderer instance. + * @param [in] enable : 1 to enable head tracking, 0 to disable. + * + * @return 0 on success, non-zero error code on failure. + * + * @note Head tracking must be enabled before setting head rotation values. + * This function should be called before starting audio playback or when + * dynamically enabling/disabling head tracking during playback. + * + * @warning Head tracking functionality is only effective for binaural output + * layout. For other output layouts (stereo, multichannel), this setting + * will be stored but will not affect the audio output. + */ +int iamf_renderer_enable_head_tracking(iamf_renderer_t* self, uint32_t enable); + +#endif // __IAMF_RENDERER_H__ diff --git a/code/src/iamf_dec/iamf_string.c b/code/src/iamf_dec/iamf_string.c new file mode 100755 index 00000000..d8c96b58 --- /dev/null +++ b/code/src/iamf_dec/iamf_string.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_string.c + * @brief IAMF string implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "iamf_string.h" + +#include "iamf_private_definitions.h" +#include "iamf_utils.h" + +static const char* _g_error_code_strings[] = {"Ok", + "Bad argments", + "Buffer too small", + "Internal error", + "Invalid packet", + "Invalid state", + "Unimplemented", + "Memory allocation failure" + "Pending"}; + +const char* iamf_error_code_string(int errno_) { + int cnt = sizeof(_g_error_code_strings) / sizeof(char*); + int idx = -errno_; + if (idx >= 0 && idx < cnt) { + return _g_error_code_strings[idx]; + } + return "None"; +} + +static const char* _g_profile_type_strings[] = { + "Simple Profile", "Base Profile", "Base Enhanced Profile", + "Base Advanced Profile", "Advanced Profile 1", "Advanced Profile 2"}; + +const char* iamf_profile_type_string(iamf_profile_t profile) { + return profile > ck_iamf_profile_none && profile < def_iamf_profile_count + ? _g_profile_type_strings[profile] + : "None"; +} + +static const char* _g_obu_type_string[] = { + "Codec Config", "Audio Element", "Mix Presentation", + "Parameter Block", "Temporal Delimiter", "Audio Frame", + "Audio Frame ID0", "Audio Frame ID1", "Audio Frame ID2", + "Audio Frame ID3", "Audio Frame ID4", "Audio Frame ID5", + "Audio Frame ID6", "Audio Frame ID7", "Audio Frame ID8", + "Audio Frame ID9", "Audio Frame ID10", "Audio Frame ID11", + "Audio Frame ID12", "Audio Frame ID13", "Audio Frame ID14", + "Audio Frame ID15", "Audio Frame ID16", "Audio Frame ID17", + "Metadata", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", + "Reserved", "IA Sequence Header"}; + +const char* iamf_obu_type_string(iamf_obu_type_t type) { + return type > ck_iamf_obu_none && type < ck_iamf_obu_count + ? _g_obu_type_string[type] + : "None"; +} + +const char* iamf_obu_header_flag2_string(iamf_obu_type_t type) { + if (type == ck_iamf_obu_mix_presentation) { + return "optional_fields_flag"; + } else if (type == ck_iamf_obu_temporal_delimiter) { + return "is_not_key_frame"; + } else if ((type > ck_iamf_obu_temporal_delimiter && + type < ck_iamf_obu_metadata) || + (type >= ck_iamf_obu_audio_frame && + type <= ck_iamf_obu_audio_frame_id17)) { + return "obu_trimming_status_flag"; + } else { + return "reserved"; + } +} + +static const char* _g_iamf_codec_type_strings[] = {"None", "OPUS", "AAC-LC", + "FLAC", "LPCM"}; + +const char* iamf_codec_type_string(iamf_codec_type_t type) { + if (iamf_codec_type_check(type)) { + return _g_iamf_codec_type_strings[type]; + } + return "None"; +} + +static const char* _g_audio_element_type_strings[] = { + "Channel Based", "Scene Based", "Object Based"}; + +const char* iamf_audio_element_type_string(iamf_audio_element_type_t type) { + return type > ck_audio_element_type_none && type < ck_audio_element_type_count + ? _g_audio_element_type_strings[type] + : "None"; +} + +static const char* _g_parameter_block_type_strings[] = { + "Mix Gain", "Demixing", "Recon Gain", "Polar", + "Cartesian8", "Cartesian16", "Dual Polar", "Dual Cartesian8", + "Dual Cartesian16", "Momentary Loudness"}; +const char* iamf_parameter_block_type_string(iamf_parameter_type_t type) { + return type > ck_iamf_parameter_type_none && + type < ck_iamf_parameter_type_count + ? _g_parameter_block_type_strings[type] + : "None"; +} + +static const char* _g_ambisonics_mode_strings[] = { + "Ambisonics Mono Mode", "Ambisonics Projection Mode"}; + +const char* iamf_ambisonics_mode_string(iamf_ambisonics_mode_t mode) { + return mode > ck_ambisonics_mode_none && mode < ck_ambisonics_mode_count + ? _g_ambisonics_mode_strings[mode] + : "None"; +} + +static const char* _g_sound_system_strings[] = { + "Sound System A (0+2+0)", + "Sound System B (0+5+0)", + "Sound System C (2+5+0)", + "Sound System D (4+5+0)", + "Sound System E (4+5+1)", + "Sound System F (3+7+0)", + "Sound System G (4+9+0)", + "Sound System H (9+10+3)", + "Sound System I (0+7+0)", + "Sound System J (4+7+0)", + "Sound System Ext. 712 (2+7+0)", + "Sound System Ext. 312 (2+3+0)", + "Mono", + "Sound System Ext. 916 (6+9+0)", + "Sound System Ext. 7154 (5+7+4)"}; + +const char* iamf_sound_system_string(iamf_sound_system_t sound_system) { + return sound_system > SOUND_SYSTEM_NONE && sound_system < SOUND_SYSTEM_END + ? _g_sound_system_strings[sound_system] + : "None"; +} + +static const char* _g_loudspeaker_layout_strings[] = { + "Mono", "Stereo", "5.1ch", "5.1.2ch", "5.1.4ch", + "7.1ch", "7.1.2ch", "7.1.4ch", "3.1.2ch", "Binaural"}; + +const char* iamf_loudspeaker_layout_string(iamf_loudspeaker_layout_t layout) { + if (iamf_audio_layer_base_layout_check(layout)) + return _g_loudspeaker_layout_strings[layout]; + if (layout == def_iamf_loudspeaker_layout_expanded) return "Expanded"; + return "None"; +} + +static const char* _g_expanded_loudspeaker_layout_strings[] = { + "LFE", "Stereo-S", "Stereo-SS", "Stereo-RS", "Stereo-TF", + "Stereo-TB", "Top-4ch", "3.0ch", "9.1.6ch", "Stereo-F", + "Stereo-Si", "Stereo-TpSi", "Top-6ch", "10.2.9.3ch", "LFE-Pair", + "Bottom-3ch", "7.1.5.4ch", "Bottom-4ch", "Top-1ch", "Top-5ch"}; + +const char* iamf_expanded_loudspeaker_layout_string( + iamf_expanded_loudspeaker_layout_t layout) { + return iamf_audio_layer_expanded_layout_check(layout) + ? _g_expanded_loudspeaker_layout_strings[layout] + : "None"; +} + +static const char* _g_channel_strings[] = { + "none", "l7/l5/l", "r7/r5/r", "c", "lfe", "sl7/sl", "sr7/sr", + "bl7/bl", "br7/br", "hfl", "hfr", "hbl", "hbr", "mono", + "l2", "r2", "tl", "tr", "l3", "r3", "sl5", + "sr5", "hl", "hr", "wl", "wr", "hsl", "hsr"}; + +const char* iamf_channel_name(iamf_channel_t ch) { + return ch < ck_iamf_channel_count ? _g_channel_strings[ch] : "none"; +} + +const char* iamf_layout_string(iamf_layout_t layout) { + switch (layout.type) { + case ck_iamf_layout_type_loudspeakers_ss_convention: + return iamf_sound_system_string((iamf_sound_system_t)layout.sound_system); + case ck_iamf_layout_type_binaural: + return "Binaural"; + default: + return "None"; + } +} diff --git a/code/src/iamf_dec/iamf_string.h b/code/src/iamf_dec/iamf_string.h new file mode 100755 index 00000000..6d0b18e5 --- /dev/null +++ b/code/src/iamf_dec/iamf_string.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_string.h + * @brief IAMF string APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_STRING_H__ +#define __IAMF_STRING_H__ + +#include "iamf_obu_all.h" + +const char *iamf_error_code_string(int errno_); +const char *iamf_profile_type_string(iamf_profile_t profile); +const char *iamf_obu_type_string(iamf_obu_type_t type); +const char *iamf_obu_header_flag2_string(iamf_obu_type_t type); +const char *iamf_codec_type_string(iamf_codec_type_t type); +const char *iamf_audio_element_type_string(iamf_audio_element_type_t type); +const char *iamf_parameter_block_type_string(iamf_parameter_type_t type); +const char *iamf_ambisonics_mode_string(iamf_ambisonics_mode_t mode); +const char *iamf_sound_system_string(iamf_sound_system_t sound_system); +const char *iamf_loudspeaker_layout_string(iamf_loudspeaker_layout_t layout); +const char *iamf_expanded_loudspeaker_layout_string( + iamf_expanded_loudspeaker_layout_t layout); +const char *iamf_layout_type_string(iamf_layout_type_t type); +const char *iamf_layout_string(iamf_layout_t layout); +const char *iamf_channel_name(iamf_channel_t ch); + +#endif //__IAMF_STRING_H__ diff --git a/code/src/iamf_dec/iamf_synchronizer.c b/code/src/iamf_dec/iamf_synchronizer.c new file mode 100755 index 00000000..36a4785e --- /dev/null +++ b/code/src/iamf_dec/iamf_synchronizer.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_synchronizer.c + * @brief IAMF audio synchronizer implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "iamf_synchronizer.h" + +#include +#include + +#include "clog.h" +#include "cqueue.h" +#include "iamf_private_definitions.h" + +#undef def_log_tag +#define def_log_tag "IAMF_SYNC" + +#define def_syr_str "IAMF Synchronizer" + +typedef struct AudioBlocksCache { + uint32_t id; + queue_t* audio_blocks; + uint32_t delay; + uint32_t skip; +} audio_blocks_cache_t; + +/** + * @brief IAMF audio synchronizer structure + * Used to synchronize audio data across multiple presentation elements + */ +typedef struct IamfAudioSynchronizer { + vector_t* audio_blocks_caches; // vector +} iamf_synchronizer_t; + +static void audio_blocks_cache_delete(audio_blocks_cache_t* cache) { + if (!cache) return; + if (cache->audio_blocks) + queue_free(cache->audio_blocks, + (func_value_wrap_ptr_free_t)iamf_audio_block_delete); + def_free(cache); +} + +/** + * @brief Create a new audio blocks cache + * This function allocates memory for a new audio blocks cache and initializes + * it + * + * @param id ID of the audio cache + * @return Pointer to the newly created cache, NULL on failure + */ +static audio_blocks_cache_t* audio_blocks_cache_new(uint32_t id) { + // Allocate memory for new cache + audio_blocks_cache_t* new_cache = def_mallocz(audio_blocks_cache_t, 1); + if (!new_cache) { + def_err_msg_enomem("audio blocks cache", def_syr_str); + return NULL; + } + + // Initialize the cache + new_cache->id = id; + new_cache->delay = 0; // Default delay + + // Create queue for audio blocks + new_cache->audio_blocks = queue_new(); + if (!new_cache->audio_blocks) { + def_err_msg_enomem("audio blocks queue", def_syr_str); + def_free(new_cache); + return NULL; + } + + return new_cache; +} + +static int audio_block_cache_required_data(audio_blocks_cache_t* cache, + iamf_audio_block_t* block) { + uint32_t offset = 0; + uint32_t needed_samples = 0; + int ret = IAMF_OK; + + if (!cache || !block) return IAMF_ERR_BAD_ARG; + if (queue_is_empty(cache->audio_blocks)) return IAMF_ERR_INVALID_STATE; + + needed_samples = iamf_audio_block_available_samples(block); + + debug("required samples %d for block ID %u", needed_samples, block->id); + + if (block->skip) offset += block->skip; + if (block->second_skip) offset += block->second_skip; + + do { + iamf_audio_block_t* cblock = def_value_wrap_type_ptr( + iamf_audio_block_t, queue_at(cache->audio_blocks, 0)); + uint32_t _offset; + + if (!cblock) { + warning("Failed to get audio block from cache for ID %u", cache->id); + ret = IAMF_ERR_INTERNAL; + } + + _offset = cache->skip + cblock->skip + cblock->second_skip; + + if (cache->skip + needed_samples < + iamf_audio_block_available_samples(cblock)) { + iamf_audio_block_partial_copy_data(block, offset, cblock, _offset, + needed_samples); + cache->skip += needed_samples; + offset += needed_samples; + needed_samples = 0; + } else { + value_wrap_t v; + uint32_t available_samples = + iamf_audio_block_available_samples(cblock) - cache->skip; + available_samples = def_min(available_samples, needed_samples); + iamf_audio_block_partial_copy_data(block, offset, cblock, _offset, + available_samples); + needed_samples -= available_samples; + cache->skip = 0; + queue_pop(cache->audio_blocks, &v); + iamf_audio_block_delete(cblock); + offset += available_samples; + } + + } while (!queue_is_empty(cache->audio_blocks) && needed_samples > 0); + + if (ret == IAMF_OK && !needed_samples) { + if (block->skip) cache->delay += block->skip; + if (block->second_skip) cache->delay += block->second_skip; + } + + debug("cache info: ID %u, delay %u, skip %u, blocks %d", cache->id, + cache->delay, cache->skip, queue_length(cache->audio_blocks)); + + return ret; +} + +/** + * @brief Create a new audio synchronizer + * This function allocates memory for a new synchronizer and initializes it + * + * @return Pointer to the newly created synchronizer, NULL on failure + */ +iamf_synchronizer_t* iamf_synchronizer_create(void) { + iamf_synchronizer_t* synchronizer = def_mallocz(iamf_synchronizer_t, 1); + if (synchronizer) { + synchronizer->audio_blocks_caches = vector_new(); + if (!synchronizer->audio_blocks_caches) { + def_err_msg_enomem("audio block caches", def_syr_str); + iamf_synchronizer_destroy(synchronizer); + return 0; + } + } + + return synchronizer; +} + +/** + * @brief Destroy an audio synchronizer + * This function frees all resources associated with the synchronizer + * + * @param synchronizer Pointer to the synchronizer to destroy + */ +void iamf_synchronizer_destroy(iamf_synchronizer_t* synchronizer) { + if (!synchronizer) return; + if (synchronizer->audio_blocks_caches) + vector_free(synchronizer->audio_blocks_caches, + (func_value_wrap_ptr_free_t)audio_blocks_cache_delete); + def_free(synchronizer); +} + +/** + * @brief Add audio cache to the synchronizer + * This function adds a new audio cache to the synchronizer for processing + * + * @param synchronizer Pointer to the synchronizer + * @param id ID of the audio cache to add + * @return 0 on success, error code on failure + */ +int iamf_synchronizer_add_audio_cache(iamf_synchronizer_t* synchronizer, + uint32_t id) { + // Check for valid synchronizer + if (!synchronizer) { + error("Invalid synchronizer pointer"); + return IAMF_ERR_BAD_ARG; + } + + // Check if a cache with the same ID already exists + int cache_count = vector_size(synchronizer->audio_blocks_caches); + for (int i = 0; i < cache_count; ++i) { + value_wrap_t* val = vector_at(synchronizer->audio_blocks_caches, i); + if (val && val->ptr) { + audio_blocks_cache_t* cache = (audio_blocks_cache_t*)val->ptr; + if (cache->id == id) { + debug("Audio cache with ID %u already exists", id); + return IAMF_OK; // Cache already exists, nothing to do + } + } + } + + // Create new cache using the helper function + audio_blocks_cache_t* new_cache = audio_blocks_cache_new(id); + if (!new_cache) { + error("Failed to create audio cache with ID %u", id); + return IAMF_ERR_ALLOC_FAIL; + } + + // Add cache to vector + value_wrap_t cache_wrap = def_value_wrap_instance_ptr(new_cache); + if (vector_push(synchronizer->audio_blocks_caches, cache_wrap) < 0) { + error("Failed to add audio cache to vector"); + audio_blocks_cache_delete(new_cache); + return IAMF_ERR_INTERNAL; + } + + debug("Added audio cache with ID %u", id); + return IAMF_OK; +} + +// Helper function to find a cache by ID +static audio_blocks_cache_t* find_cache_by_id(iamf_synchronizer_t* synchronizer, + uint32_t id) { + if (!synchronizer) return NULL; + + int cache_count = vector_size(synchronizer->audio_blocks_caches); + for (int i = 0; i < cache_count; ++i) { + value_wrap_t* val = vector_at(synchronizer->audio_blocks_caches, i); + if (val && val->ptr) { + audio_blocks_cache_t* cache = (audio_blocks_cache_t*)val->ptr; + if (cache->id == id) { + return cache; + } + } + } + return NULL; +} + +int iamf_synchronizer_sync_audio_blocks(iamf_synchronizer_t* synchronizer, + iamf_audio_block_t* audio_blocks[], + int count) { + if (!synchronizer || !audio_blocks || count <= 0) { + error("Invalid parameters"); + return IAMF_ERR_BAD_ARG; + } + + iamf_audio_block_t default_block; + memset(&default_block, 0, sizeof(iamf_audio_block_t)); + + for (int i = 0; i < count; ++i) { + if (audio_blocks[i]) { + default_block.capacity_per_channel = + def_max(default_block.capacity_per_channel, + audio_blocks[i]->capacity_per_channel); + default_block.num_samples_per_channel = + def_max(default_block.num_samples_per_channel, + audio_blocks[i]->num_samples_per_channel); + default_block.skip = def_max(default_block.skip, audio_blocks[i]->skip); + default_block.padding = + def_max(default_block.padding, audio_blocks[i]->padding); + default_block.second_skip = + def_max(default_block.second_skip, audio_blocks[i]->second_skip); + default_block.second_padding = def_max(default_block.second_padding, + audio_blocks[i]->second_padding); + } + } + + debug( + "Default block: capacity_per_channel=%u, num_samples_per_channel=%u, " + "skip=%u, padding=%u, second_skip=%u, second_padding=%u", + default_block.capacity_per_channel, default_block.num_samples_per_channel, + default_block.skip, default_block.padding, default_block.second_skip, + default_block.second_padding); + + for (int i = 0; i < count; ++i) { + iamf_audio_block_t* block = audio_blocks[i]; + iamf_audio_block_t required_block; + audio_blocks_cache_t* cache; + + if (!block) continue; + + cache = find_cache_by_id(synchronizer, block->id); + if (!cache) { + warn("Cache for ID %u not found, skipping block", block->id); + continue; + } + + if (queue_is_empty(cache->audio_blocks) && + block->num_samples_per_channel == + default_block.num_samples_per_channel && + block->second_skip == default_block.second_skip && + block->skip == default_block.skip) + continue; + + debug("cache audio block for ID %u", block->id); + + if (block->data) { + iamf_audio_block_t* copied_block = + iamf_audio_block_default_new(block->id); + if (!copied_block) { + def_err_msg_enomem("copied audio block", def_syr_str); + continue; + } + + *copied_block = *block; + debug( + "Copied block: capacity_per_channel=%u, num_samples_per_channel=%u," + "skip=%u, padding=%u, second_skip=%u, second_padding=%u", + copied_block->capacity_per_channel, + copied_block->num_samples_per_channel, copied_block->skip, + copied_block->padding, copied_block->second_skip, + copied_block->second_padding); + + if (queue_push(cache->audio_blocks, + def_value_wrap_instance_ptr(copied_block)) < 0) { + error("Failed to add copied block to cache for ID %u", block->id); + copied_block->data = 0; + iamf_audio_block_delete(copied_block); + continue; + } + } + + memset(&required_block, 0, sizeof(iamf_audio_block_t)); + if (iamf_audio_block_resize(&required_block, + default_block.capacity_per_channel, + block->num_channels) != IAMF_OK) { + def_err_msg_enomem("required audio block", def_syr_str); + continue; + } + + required_block.id = block->id; + iamf_audio_block_samples_info_copy(&required_block, &default_block); + + if (audio_block_cache_required_data(cache, &required_block) != IAMF_OK) { + warning("Failed to get required data from cache for ID %u", block->id); + continue; + } + + *block = required_block; + } + + return IAMF_OK; +} diff --git a/code/src/iamf_dec/iamf_synchronizer.h b/code/src/iamf_dec/iamf_synchronizer.h new file mode 100755 index 00000000..43927333 --- /dev/null +++ b/code/src/iamf_dec/iamf_synchronizer.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_synchronizer.h + * @brief IAMF audio synchronizer APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_SYNCHRONIZER_H__ +#define __IAMF_SYNCHRONIZER_H__ + +#include + +#include "cqueue.h" +#include "cvector.h" +#include "iamf_audio_block.h" + +typedef struct IamfAudioSynchronizer iamf_synchronizer_t; + +/** + * @brief Create a new audio synchronizer + * This function allocates memory for a new synchronizer and initializes it + * + * @return Pointer to the newly created synchronizer, NULL on failure + */ +iamf_synchronizer_t* iamf_synchronizer_create(void); + +/** + * @brief Destroy an audio synchronizer + * This function frees all resources associated with the synchronizer + * + * @param synchronizer Pointer to the synchronizer to destroy + */ +void iamf_synchronizer_destroy(iamf_synchronizer_t* synchronizer); + +/** + * @brief Add audio cache to the synchronizer + * This function adds a new audio cache to the synchronizer for processing + * + * @param synchronizer Pointer to the synchronizer + * @param id ID of the audio cache to add + * @return 0 on success, error code on failure + */ +int iamf_synchronizer_add_audio_cache(iamf_synchronizer_t* synchronizer, + uint32_t id); + +/** + * @brief Synchronize audio blocks + * This function synchronizes audio blocks across multiple presentation elements + * + * @param synchronizer Pointer to the synchronizer + * @param audio_blocks Array of audio blocks to synchronize + * @param count Number of audio blocks in the array + * @return IAMF_OK on success, error code on failure + */ +int iamf_synchronizer_sync_audio_blocks(iamf_synchronizer_t* synchronizer, + iamf_audio_block_t* audio_blocks[], + int count); +#endif // __IAMF_SYNCHRONIZER_H__ diff --git a/code/src/iamf_dec/iamf_types.h b/code/src/iamf_dec/iamf_types.h new file mode 100755 index 00000000..41fea0d3 --- /dev/null +++ b/code/src/iamf_dec/iamf_types.h @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_types.h + * @brief Internal definition. + * @version 0.1 + * @date Created 03/03/2023 + **/ + +#ifndef __IAMF_TYPES_H__ +#define __IAMF_TYPES_H__ + +#include "IAMF_defines.h" + +typedef enum EIamfCodecId { + ck_iamf_codec_id_none = 0, + ck_iamf_codec_id_opus = 0x7375704f, // 'Opus' + ck_iamf_codec_id_aac = 0x6134706d, // 'mp4a' (AAC) + ck_iamf_codec_id_flac = 0x43614c66, // 'fLaC' (FLAC) + ck_iamf_codec_id_lpcm = 0x6d637069, // 'ipcm' (LPCM) +} iamf_codec_id_t; + +typedef enum EIamfCodecType { + ck_iamf_codec_type_none, + ck_iamf_codec_type_opus, + ck_iamf_codec_type_aac, + ck_iamf_codec_type_flac, + ck_iamf_codec_type_lpcm, +} iamf_codec_type_t; + +typedef enum EIamfReconChannel { + ck_iamf_channel_recon_l, + ck_iamf_channel_recon_c, + ck_iamf_channel_recon_r, + ck_iamf_channel_recon_ls, + ck_iamf_channel_recon_rs, + ck_iamf_channel_recon_ltf, + ck_iamf_channel_recon_rtf, + ck_iamf_channel_recon_lb, + ck_iamf_channel_recon_rb, + ck_iamf_channel_recon_ltb, + ck_iamf_channel_recon_rtb, + ck_iamf_channel_recon_lfe, + ck_iamf_channel_recon_count, + + ck_iamf_channel_recon_rss = ck_iamf_channel_recon_rs, + ck_iamf_channel_recon_lss = ck_iamf_channel_recon_ls, + ck_iamf_channel_recon_rtr = ck_iamf_channel_recon_rtb, + ck_iamf_channel_recon_ltr = ck_iamf_channel_recon_ltb, + ck_iamf_channel_recon_rsr = ck_iamf_channel_recon_rb, + ck_iamf_channel_recon_lrs = ck_iamf_channel_recon_lb, +} iamf_recon_channel_t; + +typedef enum EIamfChannel { + /// @brief None channel + ck_iamf_channel_none, + /// @brief Left 7.1 channel + ck_iamf_channel_l7, + /// @brief Right 7.1 channel + ck_iamf_channel_r7, + /// @brief Center channel + ck_iamf_channel_c, + /// @brief Low frequency effects channel + ck_iamf_channel_lfe, + /// @brief Side left 7.1 channel + ck_iamf_channel_sl7, + /// @brief Side right 7.1 channel + ck_iamf_channel_sr7, + /// @brief Back left 7.1 channel + ck_iamf_channel_bl7, + /// @brief Back right 7.1 channel + ck_iamf_channel_br7, + /// @brief High front left channel + ck_iamf_channel_hfl, + /// @brief High front right channel + ck_iamf_channel_hfr, + /// @brief High back left channel + ck_iamf_channel_hbl, + /// @brief High back right channel + ck_iamf_channel_hbr, + /// @brief Mono channel + ck_iamf_channel_mono, + /// @brief Left 2.0 channel + ck_iamf_channel_l2, + /// @brief Right 2.0 channel + ck_iamf_channel_r2, + /// @brief Top left channel + ck_iamf_channel_tl, + /// @brief Top right channel + ck_iamf_channel_tr, + /// @brief Left 3.0 channel + ck_iamf_channel_l3, + /// @brief Right 3.0 channel + ck_iamf_channel_r3, + /// @brief Side left 5.1 channel + ck_iamf_channel_sl5, + /// @brief Side right 5.1 channel + ck_iamf_channel_sr5, + /// @brief High left channel + ck_iamf_channel_hl, + /// @brief High right channel + ck_iamf_channel_hr, + /// @brief Channel count + ck_iamf_channel_count, + + /// @brief Left 5.1 channel (alias for left 7.1) + ck_iamf_channel_l5 = ck_iamf_channel_l7, + /// @brief Right 5.1 channel (alias for right 7.1) + ck_iamf_channel_r5 = ck_iamf_channel_r7, +} iamf_channel_t; + +typedef enum EIamfAudioFrameFlag { + ck_audio_frame_planar = 0x1, +} iamf_audio_frame_flag; + +typedef enum EStreamMode { + ck_stream_mode_ambisonics_none, + ck_stream_mode_ambisonics_mono, + ck_stream_mode_ambisonics_projection +} stream_mode_t; + +typedef enum EIamfLoudspeakerLayout { + ck_iamf_loudspeaker_layout_none = -1, + ck_iamf_loudspeaker_layout_mono = 0, // 1.0.0 + ck_iamf_loudspeaker_layout_stereo, // 2.0.0 + ck_iamf_loudspeaker_layout_510, // 5.1.0 + ck_iamf_loudspeaker_layout_512, // 5.1.2 + ck_iamf_loudspeaker_layout_514, // 5.1.4 + ck_iamf_loudspeaker_layout_710, // 7.1.0 + ck_iamf_loudspeaker_layout_712, // 7.1.2 + ck_iamf_loudspeaker_layout_714, // 7.1.4 + ck_iamf_loudspeaker_layout_312, // 3.1.2 + ck_iamf_loudspeaker_layout_binaural, // binaural + ck_iamf_loudspeaker_layout_count, + + // expanded layout for version 1.1. + /// @brief The low-frequency effects subset (LFE) of 7.1.4ch + ck_iamf_loudspeaker_layout_expanded_lfe = 0x10, + /// @brief The surround subset (Ls/Rs) of 5.1.4ch + ck_iamf_loudspeaker_layout_expanded_stereo_s, + /// @brief The side surround subset (Lss/Rss) of 7.1.4ch + ck_iamf_loudspeaker_layout_expanded_stereo_ss, + /// @brief The rear surround subset (Lrs/Rrs) of 7.1.4ch + ck_iamf_loudspeaker_layout_expanded_stereo_rs, + /// @brief The top front subset (Ltf/Rtf) of 7.1.4ch + ck_iamf_loudspeaker_layout_expanded_stereo_tf, + /// @brief The top back subset (Ltb/Rtb) of 7.1.4ch + ck_iamf_loudspeaker_layout_expanded_stereo_tb, + /// @brief The top 4 channels (Ltf/Rtf/Ltb/Rtb) of 7.1.4ch + ck_iamf_loudspeaker_layout_expanded_top_4ch, + /// @brief The front 3 channels (L/C/R) of 7.1.4ch + ck_iamf_loudspeaker_layout_expanded_3ch, + /// @brief The subset of Loudspeaker configuration for Sound System H (9+10+3) + /// of [ITU-2051-3] + ck_iamf_loudspeaker_layout_expanded_916, + /// @brief The front subset (FL/FR) of 9.1.6ch + ck_iamf_loudspeaker_layout_expanded_stereo_f, + /// @brief The side subset (SiL/SiR) of 9.1.6ch + ck_iamf_loudspeaker_layout_expanded_stereo_si, + /// @brief The top side subset (TpSiL/TpSiR) of 9.1.6ch + ck_iamf_loudspeaker_layout_expanded_stereo_tpsi, + /// @brief The top 6 channels (TpFL/TpFR/TpSiL/TpSiR/TpBL/TpBR) of 9.1.6ch + ck_iamf_loudspeaker_layout_expanded_top_6ch, + /// @brief Loudspeaker configuration for Sound System H (9+10+3) of + /// [ITU-2051-3] + ck_iamf_loudspeaker_layout_expanded_a293, + /// @brief The low-frequency effects subset (LFE1/LFE2) of 10.2.9.3ch + ck_iamf_loudspeaker_layout_expanded_lfe_pair, + /// @brief The bottom 3 channels (BtFL/BtFC/BtFR) of 10.2.9.3ch + ck_iamf_loudspeaker_layout_expanded_bottom_3ch, + /// @brief Loudspeaker configuration with the top and the bottom speakers + /// added to Loudspeaker configuration for Sound System J (4+7+0) of + /// [ITU-2051-3] + ck_iamf_loudspeaker_layout_expanded_7154, + /// @brief The bottom 4 channels (BtFL/BtFR/BtBL/BtBR) of 7.1.5.4ch + ck_iamf_loudspeaker_layout_expanded_bottom_4ch, + /// @brief The top subset (TpC) of 7.1.5.4ch + ck_iamf_loudspeaker_layout_expanded_top_1ch, + /// @brief The top 5 channels (Ltf/Rtf/TpC/Ltb/Rtb) of 7.1.5.4ch + ck_iamf_loudspeaker_layout_expanded_top_5ch, + /// @brief The end of expanded loudspeaker layout + ck_iamf_loudspeaker_layout_expanded_end, +} iamf_loudspeaker_layout_t; + +/** + * @brief Expanded loudspeaker layout in @expanded_loudspeaker_layout + */ +typedef enum EIamfExpandedLoudspeakerLayout { + ck_iamf_expanded_loudspeaker_layout_lfe = 0, // LFE + ck_iamf_expanded_loudspeaker_layout_stereo_s, // Ls/Rs + ck_iamf_expanded_loudspeaker_layout_stereo_ss, // Lss/Rss + ck_iamf_expanded_loudspeaker_layout_stereo_rs, // Lrs/Rrs + ck_iamf_expanded_loudspeaker_layout_stereo_tf, // Ltf/Rtf + ck_iamf_expanded_loudspeaker_layout_stereo_tb, // Ltb/Rtb + ck_iamf_expanded_loudspeaker_layout_top_4ch, // Ltf/Rtf/Ltb/Rtb + ck_iamf_expanded_loudspeaker_layout_3ch, // L/C/R + ck_iamf_expanded_loudspeaker_layout_916, // 9.1.6 + ck_iamf_expanded_loudspeaker_layout_stereo_f, // FL/FR + ck_iamf_expanded_loudspeaker_layout_stereo_si, // SiL/SiR + ck_iamf_expanded_loudspeaker_layout_stereo_tpsi, // TpSiL/TpSiR + ck_iamf_expanded_loudspeaker_layout_top_6ch, // TpFL/TpFR/TpSiL/TpSiR/TpBL/TpBR + ck_iamf_expanded_loudspeaker_layout_a293, // Loudspeaker configuration for + // Sound System H (9+10+3) of + // [ITU-2051-3] + ck_iamf_expanded_loudspeaker_layout_lfe_pair, // LFE1/LFE2 of 10.2.9.3ch + ck_iamf_expanded_loudspeaker_layout_bottom_3ch, // BtFL/BtFC/BtFR + // of 10.2.9.3ch + ck_iamf_expanded_loudspeaker_layout_7154, // Loudspeaker configuration with + // top and bottom speakers added to + // Sound System J (4+7+0) of + // [ITU-2051-3] + ck_iamf_expanded_loudspeaker_layout_bottom_4ch, // BtFL/BtFR/BtBL/BtBR + // of 7.1.5.4ch + ck_iamf_expanded_loudspeaker_layout_top_1ch, // TpC of 7.1.5.4ch + ck_iamf_expanded_loudspeaker_layout_top_5ch, // Ltf/Rtf/TpC/Ltb/Rtb + // of 7.1.5.4ch + ck_iamf_expanded_loudspeaker_layout_count, +} iamf_expanded_loudspeaker_layout_t; + +typedef enum EIamfOutputGainChannel { + ck_iamf_channel_gain_rtf, + ck_iamf_channel_gain_ltf, + ck_iamf_channel_gain_rs, + ck_iamf_channel_gain_ls, + ck_iamf_channel_gain_r, + ck_iamf_channel_gain_l, + ck_iamf_channel_gain_count +} iamf_output_gain_channel_t; + +typedef enum EElementGainOffsetType { + ck_element_gain_offset_type_value = 0, + ck_element_gain_offset_type_range, +} element_gain_offset_type_t; + +typedef struct MixFactors { + float alpha; + float beta; + float gamma; + float delta; + int w_idx_offset; +} mix_factors_t; + +typedef struct AudioCodecParameter { + iamf_codec_type_t type; + + uint32_t sample_rate; + union { + uint32_t sample_format; + struct { + uint8_t sample_type; + uint8_t bits_per_sample; + uint8_t big_endian; + uint8_t interleaved; + }; + }; + uint32_t frame_size; +} audio_codec_parameter_t; + +typedef enum EIamfLayoutType { + ck_iamf_layout_type_not_defined = 0, + ck_iamf_layout_type_loudspeakers_ss_convention = 2, + ck_iamf_layout_type_binaural, +} iamf_layout_type_t; + +typedef struct IamfLayout { + iamf_layout_type_t type; + union { + int sound_system; + }; +} iamf_layout_t; + +typedef struct { + uint32_t azimuth; + uint32_t elevation; + uint32_t distance; +} encoded_polar_t; + +typedef struct { + uint32_t x; + uint32_t y; + uint32_t z; +} encoded_cartesian_t; + +typedef IAMF_SoundSystem iamf_sound_system_t; +typedef IAMF_SamplingRate iamf_sampling_rate_t; +typedef IAMF_SampleBitDepth iamf_sample_bit_depth_t; + +#endif /* __IAMF_TYPES_H__ */ diff --git a/code/src/iamf_dec/iamf_utils.c b/code/src/iamf_dec/iamf_utils.c new file mode 100755 index 00000000..81a168b4 --- /dev/null +++ b/code/src/iamf_dec/iamf_utils.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file IAMF_utils.c + * @brief Utils. + * @version 2.0.0 + * @date Created 03/03/2023 + **/ + +#include "iamf_utils.h" + +#include + +#include "iamf_private_definitions.h" + +iamf_codec_type_t iamf_codec_type_get(iamf_codec_id_t codec_id) { + if (codec_id == ck_iamf_codec_id_aac) return ck_iamf_codec_type_aac; + if (codec_id == ck_iamf_codec_id_opus) return ck_iamf_codec_type_opus; + if (codec_id == ck_iamf_codec_id_flac) return ck_iamf_codec_type_flac; + if (codec_id == ck_iamf_codec_id_lpcm) return ck_iamf_codec_type_lpcm; + return ck_iamf_codec_type_none; +} + +int iamf_codec_type_check(iamf_codec_type_t type) { + return type > ck_iamf_codec_type_none && type <= ck_iamf_codec_type_lpcm; +} + +int iamf_codec_id_check(iamf_codec_id_t codec_id) { + return codec_id == ck_iamf_codec_id_opus || + codec_id == ck_iamf_codec_id_aac || + codec_id == ck_iamf_codec_id_flac || codec_id == ck_iamf_codec_id_lpcm; +} + +int iamf_audio_layer_base_layout_check(iamf_loudspeaker_layout_t type) { + return type >= ck_iamf_loudspeaker_layout_mono && + type < ck_iamf_loudspeaker_layout_count; +} + +int iamf_audio_layer_expanded_layout_check( + iamf_expanded_loudspeaker_layout_t type) { + return type >= ck_iamf_expanded_loudspeaker_layout_lfe && + type < ck_iamf_expanded_loudspeaker_layout_count; +} + +iamf_loudspeaker_layout_t iamf_audio_layer_layout_get( + iamf_loudspeaker_layout_t base, + iamf_expanded_loudspeaker_layout_t expanded) { + if (iamf_audio_layer_base_layout_check(base)) return base; + if (iamf_audio_layer_expanded_layout_check(expanded) && + base == def_iamf_loudspeaker_layout_expanded) + return def_iamf_loudspeaker_layout_expanded_mask + expanded; + return ck_iamf_loudspeaker_layout_none; +} + +int bit1_count(uint32_t value) { + int n = 0; + for (; value; ++n) { + value &= (value - 1); + } + return n; +} + +static float q16_1xy_float(int16_t q, int frac) { + return ((float)q) * powf(2.0f, (float)-frac); +} + +float iamf_q15_to_float(int16_t q) { return q16_1xy_float(q, 15); } +float iamf_gain_q78_to_db(int16_t q78) { return q16_1xy_float(q78, 8); } +float iamf_gain_q78_to_linear(int16_t q78) { + return f32_db_to_linear(q16_1xy_float(q78, 8)); +} + +static float iamf_divide_255f(uint8_t val) { return ((float)val / 255.0f); } +float iamf_recon_gain_linear(int8_t gain) { return iamf_divide_255f(gain); } +float iamf_divide_128f(uint8_t val) { return ((float)val / (powf(2.0f, 8.f))); } + +float f32_db_to_linear(float db) { return powf(10.0f, 0.05f * db); } + +int iamf_ambisionisc_get_order(uint32_t channels) { + if (channels == 1) return 0; + if (channels == 4) return 1; + if (channels == 9) return 2; + if (channels == 16) return 3; + if (channels == 25) return 4; + return -1; +} + +int iamf_sound_system_check(iamf_sound_system_t ss) { + return ss > SOUND_SYSTEM_NONE && ss < SOUND_SYSTEM_END; +} + +uint32_t iamf_fraction_transform(fraction_t f, uint32_t dem) { + uint64_t num = 0; + if (!dem || !f.denominator) return 0; + if (f.denominator == dem) return f.numerator; + num = ((uint64_t)f.numerator * dem + f.denominator - 1) / f.denominator; + return (uint32_t)num; +} + +float iamf_fraction_transform_float(fraction_t f, uint32_t dem) { + if (!dem || !f.denominator) return 0.0f; + if (f.denominator == dem) return (float)f.numerator; + return ((float)f.numerator * dem) / (float)f.denominator; +} + +int16_t iamf_u32_to_i16(uint32_t v, uint32_t num_bits) { + int16_t val = (int16_t)v; + if (num_bits >= 16) return val; + val <<= (16 - num_bits); + val >>= (16 - num_bits); + return val; +} + +float iamf_u32_to_f32(uint32_t v, uint32_t bits) { + float val = (float)v; + if (bits) val /= ((1 << bits) - 1); + return val; +} + +float iamf_i16_to_f32(int16_t v, uint32_t bits) { + float val = (float)v; + if (bits) val /= ((1 << (bits - 1)) - 1); + return val; +} diff --git a/code/src/iamf_dec/iamf_utils.h b/code/src/iamf_dec/iamf_utils.h new file mode 100755 index 00000000..540f38f6 --- /dev/null +++ b/code/src/iamf_dec/iamf_utils.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_utils.h + * @brief Utils APIs. + * @version 2.0.0 + * @date Created 03/03/2023 + **/ + +#ifndef __IAMF_UITLS_H__ +#define __IAMF_UITLS_H__ + +#include +#include +#include + +#include "IAMF_defines.h" +#include "cvalue.h" +#include "iamf_types.h" +#include "oar_base.h" + +iamf_codec_type_t iamf_codec_type_get(uint32_t codec_id); +int iamf_codec_type_check(iamf_codec_type_t cid); +int iamf_codec_id_check(iamf_codec_id_t cid); + +int iamf_audio_layer_base_layout_check(iamf_loudspeaker_layout_t type); +int iamf_audio_layer_expanded_layout_check( + iamf_expanded_loudspeaker_layout_t type); +iamf_expanded_loudspeaker_layout_t iamf_audio_layer_expanded_layout_get( + iamf_loudspeaker_layout_t type); +iamf_loudspeaker_layout_t iamf_audio_layer_layout_get( + iamf_loudspeaker_layout_t base, + iamf_expanded_loudspeaker_layout_t expanded); + +int bit1_count(uint32_t value); + +float iamf_q15_to_float(int16_t q); +float iamf_gain_q78_to_db(int16_t q78); +float iamf_gain_q78_to_linear(int16_t q78); +float iamf_recon_gain_linear(int8_t gain); +float iamf_divide_128f(uint8_t val); +float f32_db_to_linear(float db); + +int iamf_ambisionisc_get_order(uint32_t channels); +int iamf_sound_system_check(iamf_sound_system_t ss); + +// int iamf_layout_is_equal(iamf_layout_t a, iamf_layout_t b); +uint32_t iamf_fraction_transform(fraction_t f, uint32_t dem); +float iamf_fraction_transform_float(fraction_t f, uint32_t dem); + +int16_t iamf_u32_to_i16(uint32_t v, uint32_t bits); +float iamf_u32_to_f32(uint32_t v, uint32_t bits); +float iamf_i16_to_f32(int16_t v, uint32_t bits); + +#endif /* __IAMF_UITLS_H__ */ diff --git a/code/src/iamf_dec/m2b_rdr.c b/code/src/iamf_dec/m2b_rdr.c deleted file mode 100755 index 6620621f..00000000 --- a/code/src/iamf_dec/m2b_rdr.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/* -AOM-IAMF Standard Deliverable Status: -This software module is out of scope and not part of the IAMF Final Deliverable. -*/ - -/** - * @file m2b_rdr.c - * @brief Multichannels to Binaural rendering. - * @version 0.1 - * @date Created 03/03/2023 - **/ - -#include "ae_rdr.h" - -#if ENABLE_MULTICHANNEL_TO_BINAURAL -#if defined(_WIN32) -#pragma comment(lib, "iamf2bear.lib") -#endif -#include "bear/iamf_bear_api.h" -// Multichannel to Binaural Renderer(BEAR) -void IAMF_element_renderer_init_M2B(binaural_filter_t* binaural_f, - uint32_t in_layout, int custom_sp_flags, - uint64_t elm_id, int frame_size, - int sample_rate) { - int i; - - if (binaural_f->m2b_init != 1) { - binaural_f->m2b_api = CreateBearAPI(NULL); // load default.tf - for (i = 0; i < N_SOURCE_ELM; i++) { - binaural_f->m2b_elm_id[i] = -1; - binaural_f->m2b_source_id[i] = -1; - } - binaural_f->m2b_init = 1; - } - - if (binaural_f->m2b_api) { - for (i = 0; i < N_SOURCE_ELM; i++) { - if (binaural_f->m2b_elm_id[i] == -1) break; - } - if (i < N_SOURCE_ELM) { - binaural_f->m2b_source_id[i] = ConfigureBearDirectSpeakerChannel( - binaural_f->m2b_api, (int)in_layout, custom_sp_flags, - (size_t)frame_size, sample_rate); - binaural_f->m2b_elm_id[i] = elm_id; - } - } -} - -void IAMF_element_renderer_deinit_M2B(binaural_filter_t* binaural_f, - uint64_t elm_id) { - int i; - - if (binaural_f->m2b_init != 0) { - for (i = 0; i < N_SOURCE_ELM; i++) { - if (binaural_f->m2b_elm_id[i] == elm_id) { - if (binaural_f->m2b_source_id[i] >= 0) { - DestroyBearChannel(binaural_f->m2b_api, binaural_f->m2b_source_id[i]); - binaural_f->m2b_elm_id[i] = -1; - binaural_f->m2b_source_id[i] = -1; - } - } - } - for (i = 0; i < N_SOURCE_ELM; i++) { - if (binaural_f->m2b_source_id[i] >= 0) { - break; - } - } - if (i == N_SOURCE_ELM) { - DestroyBearAPI(binaural_f->m2b_api); - binaural_f->m2b_init = 0; - } - } -} - -int IAMF_element_renderer_render_M2B(binaural_filter_t* binaural_f, - uint64_t elm_id, float* in[], float* out[], - int nsamples) { - float** sin = (float**)in; - float** sout = (float**)out; - int i; - if (binaural_f->m2b_init != 0) { - for (i = 0; i < N_SOURCE_ELM; i++) { - if (binaural_f->m2b_elm_id[i] == elm_id) { - SetBearDirectSpeakerChannel(binaural_f->m2b_api, - binaural_f->m2b_source_id[i], sin); - GetBearRenderedAudio(binaural_f->m2b_api, binaural_f->m2b_source_id[i], - sout); - return 0; - } - } - } - return -1; -} -#endif diff --git a/code/src/iamf_dec/m2m_rdr.c b/code/src/iamf_dec/m2m_rdr.c deleted file mode 100644 index 16bbb19e..00000000 --- a/code/src/iamf_dec/m2m_rdr.c +++ /dev/null @@ -1,1478 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/* -AOM-IAMF Standard Deliverable Status: -This software module is out of scope and not part of the IAMF Final Deliverable. -*/ - -/** - * @file m2m_rdr.c - * @brief Multichannels to Multichannels rendering. - * @version 0.1 - * @date Created 03/03/2023 - **/ -#include "ae_rdr.h" - -// The gain matrices below are generated to comply with EAR Direct Speakers -// renderer ([ITU2127-0]), except for 3.1.2ch and 7.1.2ch. When playback layout -// is 3.1.2ch and 7.1.2ch, the gain matrices follow 7.3.2.1 of IAMF. When input -// layout is 3.1.2ch and 7.1.2ch, the gain matrices are generated with the -// processing below. 3.1.2ch -> 5.1.2ch -> Playback layout 7.1.2ch -> 7.1.4ch -> -// Playback layout - -float mono_bs020[][2] = {{0.70710678, 0.70710678}}; -float mono_bs050[][6] = {{0, 0, 1.0, 0, 0, 0}}; -float mono_bs250[][8] = {{0, 0, 1.0, 0, 0, 0, 0, 0}}; -float mono_bs450[][10] = {{0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}}; -float mono_bs451[][11] = {{0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}}; -float mono_bs370[][12] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -float mono_bs490[][14] = {{0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -float mono_bs9A3[][24] = { - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -float mono_bs070[][8] = {{0, 0, 1.0, 0, 0, 0, 0, 0}}; -float mono_bs470[][12] = {{0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -float mono_iamf312[][6] = {{0, 0, 1.0, 0, 0, 0}}; -float mono_iamf712[][10] = {{0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}}; -float mono_mono[][1] = {{1.0}}; -float mono_iamf916[][16] = { // mono -> bs9A3 -> iamf916 - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; // C -/////////////////////////////// - -// 'M+030', 'M-030' -float stereo_bs020[][2] = {{1.0, 0}, {0, 1.0}}; -// 'M+030', 'M-030', 'M+000', 'LFE1', 'M+110', 'M-110' -float stereo_bs050[][6] = {{1.0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0}}; -// 'M+030', 'M-030', 'M+000', 'LFE1', 'M+110', 'M-110', 'U+030', 'U-030' -float stereo_bs250[][8] = {{1.0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0}}; -// 'M+030', 'M-030', 'M+000', 'LFE1', 'M+110', 'M-110', 'U+030', 'U-030', -// 'U+110', 'U-110' -float stereo_bs450[][10] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}}; -// 'M+030', 'M-030', 'M+000', 'LFE1', 'M+110', 'M-110', 'U+030', 'U-030', -// 'U+110', 'U-110', 'B+000' -float stereo_bs451[][11] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -// 'M+000', 'M+030', 'M-030', 'U+045', 'U-045', 'M+090', 'M-090', 'M+135', -// 'M-135', 'UH+180', 'LFE1', 'LFE2' -float stereo_bs370[][12] = {{0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -// 'M+030', 'M-030', 'M+000', 'LFE1', 'M+090', 'M-090', 'M+135', 'M-135', -// 'U+045', 'U-045', 'U+135', 'U-135', 'M+SC', 'M-SC' -float stereo_bs490[][14] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -// 'M+060', 'M-060', 'M+000', 'LFE1', 'M+135', 'M-135', 'M+030', 'M-030', -// 'M+180', 'LFE2', 'M+090', 'M-090', 'U+045', 'U-045', 'U+000', 'T+000', -// 'U+135', 'U-135', 'U+090', 'U-090', 'U+180', 'B+000', 'B+045', 'B-045' -float stereo_bs9A3[][24] = { - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -// 'M+030', 'M-030', 'M+000', 'LFE1', 'M+090', 'M-090', 'M+135', 'M-135' -float stereo_bs070[][8] = {{1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0}}; -// 'M+030', 'M-030', 'M+000', 'LFE1', 'M+090', 'M-090', 'M+135', 'M-135', -// 'U+045', 'U-045', 'U+135', 'U-135' -float stereo_bs470[][12] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -// 'M+030', 'M-030', 'M+000', 'LFE1', 'U+030', 'U-030' -float stereo_iamf312[][6] = {{1.0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0}}; -// 'M+030', 'M-030', 'M+000', 'LFE1', 'M+090', 'M-090', 'M+135', 'M-135', -// 'U+045', 'U-045' -float stereo_iamf712[][10] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}}; -float stereo_mono[][1] = {{0.5}, {0.5}}; -float stereo_iamf916[][16] = { - // stereo -> bs9A3 -> iamf916 - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0} // R -}; -/////////////////////////// - -float iamf51_bs020[][2] = {{1.0, 0}, - {0, 1.0}, - {0.7071067811865476, 0.7071067811865476}, - {0, 0}, - {0.7071067811865476, 0}, - {0, 0.7071067811865476}}; -float iamf51_bs050[][6] = {{1.0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0}, - {0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 1.0}}; -float iamf51_bs250[][8] = { - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 0, 0, 1.0, 0, 0}}; -float iamf51_bs450[][10] = { - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}}; -float iamf51_bs451[][11] = { - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}}; -float iamf51_bs370[][12] = {{0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}}; -float iamf51_bs490[][14] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}}; -float iamf51_bs9A3[][24] = { - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -float iamf51_bs070[][8] = { - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0}}; -float iamf51_bs470[][12] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}}; -float iamf51_iamf312[][6] = {{1.0, 0, 0, 0, 0, 0}, // L - {0, 1.0, 0, 0, 0, 0}, // R - {0, 0, 1.0, 0, 0, 0}, // C - {0, 0, 0, 1.0, 0, 0}, // Lfe - {0.70710678, 0, 0, 0, 0, 0}, // Ls - {0, 0.70710678, 0, 0, 0, 0}}; // Rs -float iamf51_iamf712[][10] = { - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}; -float iamf51_mono[][1] = {{0.5}, - {0.5}, - {0.7071067811865476}, - {0}, - {0.3535533905932738}, - {0.3535533905932738}}; -float iamf51_iamf916[][16] = { - // iamf51 -> bs9A3 -> iamf916 - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Ls - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // Rs -}; -////////////////////// - -float iamf512_bs020[][2] = {{1.0, 0}, - {0, 1.0}, - {0.7071067811865476, 0.7071067811865476}, - {0, 0}, - {0.7071067811865476, 0}, - {0, 0.7071067811865476}, - {1.0, 0}, - {0, 1.0}}; -float iamf512_bs050[][6] = {{1.0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0}, - {0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 1.0}, - {1.0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0}}; -float iamf512_bs250[][8] = { - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 0, 0, 1.0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0}}; -float iamf512_bs450[][10] = { - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}}; -float iamf512_bs451[][11] = { - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}}; -float iamf512_bs370[][12] = {{0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}}; -float iamf512_bs490[][14] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}}; -float iamf512_bs9A3[][24] = { - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -float iamf512_bs070[][8] = { - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0}, - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}}; -float iamf512_bs470[][12] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}}; -float iamf512_iamf312[][6] = {{1.0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0}, - {0, 0, 0, 0, 0, 1.0}}; -float iamf512_iamf712[][10] = { - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0}}; -float iamf512_mono[][1] = {{0.5}, - {0.5}, - {0.7071067811865476}, - {0}, - {0.3535533905932738}, - {0.3535533905932738}, - {0.5}, - {0.5}}; -float iamf512_iamf916[][16] = { - // iamf512 -> iamf512_bs9A3 -> iamf916 - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Ls - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Rs - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // Hfl - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0} // Hfr -}; -//////////////////////////////////////////////////// - -float iamf514_bs020[][2] = {{1.0, 0}, - {0, 1.0}, - {0.7071067811865476, 0.7071067811865476}, - {0, 0}, - {0.7071067811865476, 0}, - {0, 0.7071067811865476}, - {1.0, 0}, - {0, 1.0}, - {0.7071067811865476, 0}, - {0, 0.7071067811865476}}; -float iamf514_bs050[][6] = {{1.0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0}, - {0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 1.0}, - {1.0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 1.0}}; -float iamf514_bs250[][8] = { - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 0, 0, 1.0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0}, - {0, 0, 0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 0, 0, 1.0, 0, 0}}; -float iamf514_bs450[][10] = { - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0}}; -float iamf514_bs451[][11] = { - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}}; -float iamf514_bs370[][12] = { - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0, 0.7071067811865476, 0, 0}, - {0, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0.7071067811865476, 0, 0}}; -float iamf514_bs490[][14] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}}; -float iamf514_bs9A3[][24] = { - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}}; -float iamf514_bs070[][8] = { - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0}, - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0}}; -float iamf514_bs470[][12] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0}}; -float iamf514_iamf312[][6] = {{1.0, 0, 0, 0, 0, 0}, // L - {0, 1.0, 0, 0, 0, 0}, // R - {0, 0, 1.0, 0, 0, 0}, // C - {0, 0, 0, 1.0, 0, 0}, // Lfe - {0.70710678, 0, 0, 0, 0, 0}, // Ls - {0, 0.70710678, 0, 0, 0, 0}, // Rs - {0, 0, 0, 0, 1.0, 0}, // Hfl - {0, 0, 0, 0, 0, 1.0}, // Hfr - {0, 0, 0, 0, 0.70710678, 0}, // Hbl - {0, 0, 0, 0, 0, 0.70710678}}; // Hbr -// 5.1.4->7.1.4->7.1.2 -float iamf514_iamf712[][10] = {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, - {0, 0, 0, 0, 0, 0, 0, 0, 0.7071067811865476, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0.7071067811865476}}; -float iamf514_mono[][1] = {{0.5}, - {0.5}, - {0.7071067811865476}, - {0}, - {0.3535533905932738}, - {0.3535533905932738}, - {0.5}, - {0.5}, - {0.3535533905932738}, - {0.3535533905932738}}; -float iamf514_iamf916[][16] = { - // iamf514 -> bs9A3 -> iamf916 - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Ls - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Rs - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // Hfl - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, // Hfr - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, // Hbl - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0} // Hbr -}; -///////////////////////////////////// - -float iamf71_bs020[][2] = {{1, 0}, - {0, 1}, - {0.7071067811865476, 0.7071067811865476}, - {0, 0}, - {0.7071067811865476, 0}, - {0, 0.7071067811865476}, - {0.7071067811865476, 0}, - {0, 0.7071067811865476}}; -float iamf71_bs050[][6] = {{1, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0}, - {0, 0, 0, 1, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476}, - {0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 1}}; -float iamf71_bs250[][8] = { - {1, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0}}; -float iamf71_bs450[][10] = { - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0}}; -float iamf71_bs451[][11] = { - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}}; -float iamf71_bs370[][12] = { - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}}; -float iamf71_bs490[][14] = {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}; -float iamf71_bs9A3[][24] = { - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -float iamf71_bs070[][8] = { - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 0, 0, 1.0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0}}; -float iamf71_bs470[][12] = { - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}}; -float iamf71_iamf312[][6] = {{1.0, 0, 0, 0, 0, 0}, // L - {0.0, 1.0, 0, 0, 0, 0}, // R - {0.0, 0, 1.0, 0, 0, 0}, // C - {0.0, 0, 0, 1.0, 0, 0}, // Lfe - {0.70710678, 0, 0, 0, 0, 0}, // Ls - {0, 0.70710678, 0, 0, 0, 0}, // Rs - {0.70710678, 0, 0, 0, 0, 0}, // Lb - {0, 0.70710678, 0, 0, 0, 0}}; // Rb -float iamf71_iamf712[][10] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, // Lfe - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, // Ls - {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, // Rs - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, // Lb - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}}; // Rb -float iamf71_mono[][1] = {{0.5}, - {0.5}, - {0.7071067811865476}, - {0}, - {0.3535533905932738}, - {0.3535533905932738}, - {0.3535533905932738}, - {0.3535533905932738}}; -float iamf71_iamf916[][16] = { - // iamf71 -> bs9A3 -> iamf916 - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, // Ls - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // Rs - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Lb - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // Rb -}; -/////////////////////////////////////// - -float iamf712_bs020[][2] = {{1, 0}, - {0, 1}, - {0.7071067811865476, 0.7071067811865476}, - {0, 0}, - {0.7071067811865476, 0}, - {0, 0.7071067811865476}, - {0.7071067811865476, 0}, - {0, 0.7071067811865476}, - {1, 0}, - {0, 1}}; -float iamf712_bs050[][6] = { - {1, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0}, - {0, 0, 0, 1, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476}, - {0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 1}, - {1, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0}}; -float iamf712_bs250[][8] = { - {1, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 0, 0, 1}}; -float iamf712_bs450[][10] = { - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}; -float iamf712_bs451[][11] = { - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}}; -float iamf712_bs370[][12] = { - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}, // LFE - {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, // Ls - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, // Rs - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, // Lb - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, // Rb - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, // HL --> CH(UH+180)??? - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}}; // HR --> CH(UH+180)??? -float iamf712_bs490[][14] = { - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Ls - {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, // Rs - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, // Lb - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, // Rb - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, // HL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}}; // HR -float iamf712_bs9A3[][24] = { - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -float iamf712_bs070[][8] = { - {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 1}, - {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}}; // HR -float iamf712_bs470[][12] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, // Ls - {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, // Rs - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, // Lb - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, // Rb - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, // HL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}}; // HR -float iamf712_iamf312[][6] = {{1.0, 0, 0, 0, 0, 0}, // L - {0, 1.0, 0, 0, 0, 0}, // R - {0, 0, 1.0, 0, 0, 0}, // C - {0, 0, 0, 1.0, 0, 0}, // Lfe - {0.70710678, 0, 0, 0, 0, 0}, // Ls - {0, 0.70710678, 0, 0, 0, 0}, // Rs - {0.70710678, 0, 0, 0, 0, 0}, // Lb - {0, 0.70710678, 0, 0, 0, 0}, // Rb - {0, 0, 0, 0, 1.0, 0}, // Hfl - {0, 0, 0, 0, 0, 1.0}}; // Hfr -float iamf712_iamf712[][10] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, // Ls - {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, // Rs - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, // Lb - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}, // Rb - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}, // HL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0}}; // HR -float iamf712_mono[][1] = {{0.5}, - {0.5}, - {0.7071067811865476}, - {0}, - {0.3535533905932738}, - {0.3535533905932738}, - {0.3535533905932738}, - {0.3535533905932738}, - {0.5}, - {0.5}}; -float iamf712_iamf916[][16] = { - // iamf712 -> bs9A3 -> iamf916 - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, // Ls - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // Rs - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Lb - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Rb - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // Hfl - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0} // Hfr -}; -/////////////////////////////////////// - -float iamf714_bs020[][2] = {{1, 0}, - {0, 1}, - {0.7071067811865476, 0.7071067811865476}, - {0, 0}, - {0.7071067811865476, 0}, - {0, 0.7071067811865476}, - {0.7071067811865476, 0}, - {0, 0.7071067811865476}, - {1, 0}, - {0, 1}, - {0.7071067811865476, 0}, - {0, 0.7071067811865476}}; -float iamf714_bs050[][6] = { - {1, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0}, - {0, 0, 0, 1, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476}, - {0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 1}, - {1, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 1}}; -float iamf714_bs250[][8] = { - {1, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 0, 0, 1}, - {0, 0, 0, 0, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0}}; -float iamf714_bs450[][10] = { - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}; -float iamf714_bs451[][11] = { - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0, 0}, - {0, 0.7071067811865476, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}}; -float iamf714_bs370[][12] = { - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0, 0.7071067811865476, 0, 0}, - {0, 0, 0, 0, 0.7071067811865476, 0, 0, 0, 0, 0.7071067811865476, 0, 0}}; -float iamf714_bs490[][14] = {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}; -float iamf714_bs9A3[][24] = { - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}; -float iamf714_bs070[][8] = {{1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 1}, - {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 1}}; -float iamf714_bs470[][12] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0}}; -float iamf714_iamf312[][6] = {{1.0, 0, 0, 0, 0, 0}, // L - {0, 1.0, 0, 0, 0, 0}, // R - {0, 0, 1.0, 0, 0, 0}, // C - {0, 0, 0, 1.0, 0, 0}, // Lfe - {0.70710678, 0, 0, 0, 0, 0}, // Ls - {0, 0.70710678, 0, 0, 0, 0}, // Rs - {0.70710678, 0, 0, 0, 0, 0}, // Lb - {0, 0.70710678, 0, 0, 0, 0}, // Rb - {0, 0, 0, 0, 1.0, 0}, // Hfl - {0, 0, 0, 0, 0, 1.0}, // Hfr - {0, 0, 0, 0, 0.70710678, 0}, // Hbl - {0, 0, 0, 0, 0, 0.70710678}}; // Hbr -float iamf714_iamf712[][10] = {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, - {0, 0, 0, 0, 0, 0, 0, 0, 0.7071067811865476, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0.7071067811865476}}; -float iamf714_mono[][1] = {{0.5}, - {0.5}, - {0.7071067811865476}, - {0}, - {0.3535533905932738}, - {0.3535533905932738}, - {0.3535533905932738}, - {0.3535533905932738}, - {0.5}, - {0.5}, - {0.3535533905932738}, - {0.3535533905932738}}; -float iamf714_iamf916[][16] = { - // iamf714 -> bs9A3 -> iamf916 - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, // Ls - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // Rs - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Lb - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Rb - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // Hfl - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, // Hfr - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, // Hbl - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0} // Hbr -}; -/////////////////////////////////////// - -float iamf312_bs020[][2] = {{1.0, 0}, {0, 1.0}, {0.70710678, 0.70710678}, - {0, 0}, {1.0, 0}, {0, 1.0}}; -float iamf312_bs050[][6] = {{1.0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0}, - {1.0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0}}; -float iamf312_bs250[][8] = { - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0}}; -float iamf312_bs450[][10] = { - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}}; -float iamf312_bs451[][11] = { - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}}; -float iamf312_bs370[][12] = {{0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}}; -float iamf312_bs490[][14] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0}}; -float iamf312_bs9A3[][24] = { - {0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; -float iamf312_bs070[][8] = { - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0}, {0, 0, 0, 1.0, 0, 0, 0, 0}, - {1.0, 0, 0, 0, 0, 0, 0, 0}, {0, 1.0, 0, 0, 0, 0, 0, 0}}; -float iamf312_bs470[][12] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, 0}}; -float iamf312_iamf312[][6] = {{1.0, 0, 0, 0, 0, 0}, // L - {0, 1.0, 0, 0, 0, 0}, // R - {0, 0, 1.0, 0, 0, 0}, // C - {0, 0, 0, 1.0, 0, 0}, // Lfe - {0, 0, 0, 0, 1.0, 0}, // Hfl - {0, 0, 0, 0, 0, 1.0}}; // Hfr -// 3.1.2->7.1.4->7.1.2 -float iamf312_iamf712[][10] = {{1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // L - {0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0}, // R - {0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0}, // C - {0, 0, 0, 1.0, 0, 0, 0, 0, 0, 0}, // Lfe - {0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0}, // Hfl - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0}}; // Hfr -float iamf312_mono[][1] = {{0.5}, {0.5}, {0.70710678}, {0.0}, {0.5}, {0.5}}; -float iamf312_iamf916[][16] = { // iamf312 -> bs9A3 -> iamf916 - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}}; -//////////////////////////////// -float iamf916_bs020[][2] = {{1, 0}, // FL - {0, 1}, // FR - {0.70710678, 0.70710678}, // FC - {0, 0}, // LFE - {0.70710678, 0}, // BL - {0, 0.70710678}, // BR - {1, 0}, // FLc - {0, 1}, // FRc - {0.70710678, 0}, // SiL - {0, 0.70710678}, // SiR - {1, 0}, // TpFL - {0, 1}, // TpFR - {0.70710678, 0}, // TpBL - {0, 0.70710678}, // TpBR - {0.70710678, 0}, // TpSiL - {0, 0.70710678}}; // TpSiR -float iamf916_bs050[][6] = { - // FL / FR / FC / LFE / LS / RS - {0.81649658, 0, 0, 0, 0.57735027, 0}, // FL - {0, 0.81649658, 0, 0, 0, 0.57735027}, // FR - {0, 0, 1, 0, 0, 0}, // FC - {0, 0, 0, 1, 0, 0}, // LFE - {0, 0, 0, 0, 1, 0}, // BL - {0, 0, 0, 0, 0, 1}, // BR - {1, 0, 0, 0, 0, 0}, // FLc - {0, 1, 0, 0, 0, 0}, // FRc - {0.57735027, 0, 0, 0, 0.81649658, 0}, // SiL - {0, 0.57735027, 0, 0, 0, 0.81649658}, // SiR - {1, 0, 0, 0, 0, 0}, // TpFL - {0, 1, 0, 0, 0, 0}, // TpFR - {0, 0, 0, 0, 1, 0}, // TpBL - {0, 0, 0, 0, 0, 1}, // TpBR - {0.70710678, 0, 0, 0, 0.70710678, 0}, // TpSiL - {0, 0.70710678, 0, 0, 0, 0.70710678}}; // TpSiR -float iamf916_bs250[][8] = { - // FL / FR / FC / LFE / LS / RS / TpFL / TpFR - {0.81649658, 0, 0, 0, 0.57735027, 0, 0, 0}, // FL - {0, 0.81649658, 0, 0, 0, 0.57735027, 0, 0}, // FR - {0, 0, 1, 0, 0, 0, 0, 0}, // FC - {0, 0, 0, 1, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 1, 0, 0, 0}, // BL - {0, 0, 0, 0, 0, 1, 0, 0}, // BR - {1, 0, 0, 0, 0, 0, 0, 0}, // FLc - {0, 1, 0, 0, 0, 0, 0, 0}, // FRc - {0.57735027, 0, 0, 0, 0.81649658, 0, 0, 0}, // SiL - {0, 0.57735027, 0, 0, 0, 0.81649658, 0, 0}, // SiR - {0, 0, 0, 0, 0, 0, 1, 0}, // TpFL - {0, 0, 0, 0, 0, 0, 0, 1}, // TpFR - {0, 0, 0, 0, 1, 0, 0, 0}, // TpBL - {0, 0, 0, 0, 0, 1, 0, 0}, // TpBR - {0, 0, 0, 0, 0.70710678, 0, 0.70710678, 0}, // TpSiL - {0, 0, 0, 0, 0, 0.70710678, 0, 0.70710678}}; // TpSiR -float iamf916_bs450[][10] = { - // FL / FR / FC / LFE / LS / RS / TpFL / TpFR / TpLS / TpRS - {0.81649658, 0, 0, 0, 0.57735027, 0, 0, 0, 0, 0}, // FL - {0, 0.81649658, 0, 0, 0, 0.57735027, 0, 0, 0, 0}, // FR - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, // FC - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // BL - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, // BR - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FLc - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // FRc - {0.57735027, 0, 0, 0, 0.81649658, 0, 0, 0, 0, 0}, // SiL - {0, 0.57735027, 0, 0, 0, 0.81649658, 0, 0, 0, 0}, // SiR - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, // TpFL - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, // TpFR - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, // TpBL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, // TpBR - {0, 0, 0, 0, 0, 0, 0.70710678, 0, 0.70710678, 0}, // TpSiL - {0, 0, 0, 0, 0, 0, 0, 0.70710678, 0, 0.70710678}}; // TpSiR -float iamf916_bs451[][11] = { - // FL / FR / FC / LFE / LS / RS / TpFL / TpFR / TpLS / TpRS / BtFC - {0.81649658, 0, 0, 0, 0.57735027, 0, 0, 0, 0, 0, 0}, // FL - {0, 0.81649658, 0, 0, 0, 0.57735027, 0, 0, 0, 0, 0}, // FR - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // FC - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // BL - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // BR - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FLc - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FRc - {0.57735027, 0, 0, 0, 0.81649658, 0, 0, 0, 0, 0, 0}, // SiL - {0, 0.57735027, 0, 0, 0, 0.81649658, 0, 0, 0, 0, 0}, // SiR - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, // TpFL - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, // TpFR - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, // TpBL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, // TpBR - {0, 0, 0, 0, 0, 0, 0.70710678, 0, 0.70710678, 0, 0}, // TpSiL - {0, 0, 0, 0, 0, 0, 0, 0.70710678, 0, 0.70710678, 0}}; // TpSiR -float iamf916_bs370[][12] = { - // FC / FL / FR / TpFL / TpFR / SiL / SiR / BL / BR / TpBC / LFE1 / LFE2 - {0, 0.70710678, 0, 0, 0, 0.70710678, 0, 0, 0, 0, 0, 0}, // FL - {0, 0, 0.70710678, 0, 0, 0, 0.70710678, 0, 0, 0, 0, 0}, // FR - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FC - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, // LFE - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, // BL - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, // BR - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FLc - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FRc - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // SiL - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // SiR - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // TpFL - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, // TpFR - {0, 0, 0, 0.57735027, 0, 0, 0, 0, 0, 0.81649658, 0, 0}, // TpBL - {0, 0, 0, 0, 0.57735027, 0, 0, 0, 0, 0.81649658, 0, 0}, // TpBR - {0, 0, 0, 0.81649658, 0, 0, 0, 0, 0, 0.57735027, 0, 0}, // TpSiL - {0, 0, 0, 0, 0.81649658, 0, 0, 0, 0, 0.57735027, 0, 0}}; // TpSiR -float iamf916_bs490[][14] = { - // FL/FR/FC/LFE/SiL/SiR/BL/BR/TpFL/TpFR/TpBL/TpBR/SCFL/SCFR - {0.70710678, 0, 0, 0, 0.70710678, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FL - {0, 0.70710678, 0, 0, 0, 0.70710678, 0, 0, 0, 0, 0, 0, 0, 0}, // FR - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FC - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, // BL - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // BR - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FLc - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FRc - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // SiL - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // SiR - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // TpFL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, // TpFR - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, // TpBL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, // TpBR - {0, 0, 0, 0, 0, 0, 0, 0, 0.70710678, 0, 0.70710678, 0, 0, 0}, // TpSiL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0.70710678, 0, 0.70710678, 0, 0}}; // TpSiR -float iamf916_bs9A3[][24] = {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FL - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FR - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FC - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // BL - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // BR - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FLc - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FRc - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // SiL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // SiR - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // TpFL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // TpFR - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, // TpBL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // TpBR - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // TpSiL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}}; // TpSiR -float iamf916_bs070[][8] = {{0.70710678, 0, 0, 0, 0.70710678, 0, 0, 0}, // FL - {0, 0.70710678, 0, 0, 0, 0.70710678, 0, 0}, // FR - {0, 0, 1, 0, 0, 0, 0, 0}, // FC - {0, 0, 0, 1, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 0, 0, 1, 0}, // BL - {0, 0, 0, 0, 0, 0, 0, 1}, // BR - {1, 0, 0, 0, 0, 0, 0, 0}, // FLc - {0, 1, 0, 0, 0, 0, 0, 0}, // FRc - {0, 0, 0, 0, 1, 0, 0, 0}, // SiL - {0, 0, 0, 0, 0, 1, 0, 0}, // SiR - {1, 0, 0, 0, 0, 0, 0, 0}, // TpFL - {0, 1, 0, 0, 0, 0, 0, 0}, // TpFR - {0, 0, 0, 0, 0, 0, 1, 0}, // TpBL - {0, 0, 0, 0, 0, 0, 0, 1}, // TpBR - {0, 0, 0, 0, 1, 0, 0, 0}, // TpSiL - {0, 0, 0, 0, 0, 1, 0, 0}}; // TpSiR -float iamf916_bs470[][12] = { - {0.70710678, 0, 0, 0, 0.70710678, 0, 0, 0, 0, 0, 0, 0}, // FL - {0, 0.70710678, 0, 0, 0, 0.70710678, 0, 0, 0, 0, 0, 0}, // FR - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FC - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // BL - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, // BR - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FLc - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FRc - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, // SiL - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // SiR - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, // TpFL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, // TpFR - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, // TpBL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, // TpBR - {0, 0, 0, 0, 0, 0, 0, 0, 0.70710678, 0, 0.70710678, 0}, // TpSiL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0.70710678, 0, 0.70710678} // TpSiR -}; -float iamf916_iamf312[][6] = { - // iamf916->iamf714->iamf312 - {1.20710678, 0., 0., 0., 0., 0.}, // FL - {0., 1.20710678, 0., 0., 0., 0.}, // FR - {0., 0., 1., 0., 0., 0.}, // FC - {0., 0., 0., 1, 0., 0.}, // LFE - {0.70710678, 0., 0., 0., 0., 0.}, // BL - {0., 0.70710678, 0., 0., 0., 0.}, // BR - {1., 0., 0., 0., 0., 0.}, // FLc - {0., 1., 0., 0., 0., 0.}, // FRc - {0.70710678, 0., 0., 0., 0., 0.}, // SiL - {0., 0.70710678, 0., 0., 0., 0.}, // SiR - {0., 0., 0., 0., 1., 0.}, // TpFL - {0., 0., 0., 0., 0., 1.}, // TpFR - {0., 0., 0., 0., 0.70710678, 0.}, // TpBL - {0., 0., 0., 0., 0., 0.70710678}, // TpBR - {0., 0., 0., 0., 1.20710678, 0.}, // TpSiL - {0., 0., 0., 0., 0., 1.20710678} // TpSiR -}; -float iamf916_iamf712[][10] = { - // iamf916->iamf714->iamf712 - // L / R / C / LFE / LS / RS / BL / BR / HFL / HFR - {0.70710678, 0, 0, 0, 0.70710678, 0, 0, 0, 0, 0}, // FL - {0, 0.70710678, 0, 0, 0, 0.70710678, 0, 0, 0, 0}, // FR - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, // FC - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, // BL - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, // BR - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FLc - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // FRc - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // SiL - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, // SiR - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, // TpFL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, // TpFR - {0, 0, 0, 0, 0, 0, 0, 0, 0.70710678, 0}, // TpBL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0.70710678}, // TpBR - {0, 0, 0, 0, 0, 0, 0, 0, 1.20710678, 0}, // TpSiL - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1.20710678} // TpSiR -}; -float iamf916_mono[][1] = { - // iamf916->bs020->mono - {0.5}, // FL - {0.5}, // FR - {0.70710678}, // FC - {0}, // LFE - {0.35355339}, // BL - {0.35355339}, // BR - {0.5}, // FLc - {0.5}, // FRc - {0.35355339}, // SiL - {0.35355339}, // SiR - {0.5}, // TpFL - {0.5}, // TpFR - {0.35355339}, // TpBL - {0.35355339}, // TpBR - {0.35355339}, // TpSiL - {0.35355339} // TpSiR -}; -float iamf916_iamf916[][16] = { - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FL(M+060) - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FR(M-060) - {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FC(M+000) - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // LFE - {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // BL(M+135) - {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // BR(M-135) - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // FLc(M+030) - {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // FRc(M-030) - {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, // SiL(M+090) - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // SiR(M-090) - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, // TpFL(U+045) - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, // TpFR(U-045) - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, // TpBL(U+135) - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, // TpBR(U-135) - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, // TpSiL(U+090) - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} // TpSiR(U-090) -}; -//////////////////////////////// - -struct m2m_rdr_t m2m_rdr_tab[] = { - {IAMF_MONO, BS2051_A, (float *)mono_bs020, 1, 2}, - {IAMF_MONO, BS2051_B, (float *)mono_bs050, 1, 6}, - {IAMF_MONO, BS2051_C, (float *)mono_bs250, 1, 8}, - {IAMF_MONO, BS2051_D, (float *)mono_bs450, 1, 10}, - {IAMF_MONO, BS2051_E, (float *)mono_bs451, 1, 11}, - {IAMF_MONO, BS2051_F, (float *)mono_bs370, 1, 12}, - {IAMF_MONO, BS2051_G, (float *)mono_bs490, 1, 14}, - {IAMF_MONO, BS2051_H, (float *)mono_bs9A3, 1, 24}, - {IAMF_MONO, BS2051_I, (float *)mono_bs070, 1, 8}, - {IAMF_MONO, BS2051_J, (float *)mono_bs470, 1, 12}, - {IAMF_MONO, IAMF_312, (float *)mono_iamf312, 1, 6}, - {IAMF_MONO, IAMF_712, (float *)mono_iamf712, 1, 10}, - {IAMF_MONO, IAMF_BINAURAL, (float *)mono_bs020, 1, 2}, - {IAMF_MONO, IAMF_MONO, (float *)mono_mono, 1, 1}, - {IAMF_MONO, IAMF_916, (float *)mono_iamf916, 1, 16}, - - {IAMF_STEREO, BS2051_A, (float *)stereo_bs020, 2, 2}, - {IAMF_STEREO, BS2051_B, (float *)stereo_bs050, 2, 6}, - {IAMF_STEREO, BS2051_C, (float *)stereo_bs250, 2, 8}, - {IAMF_STEREO, BS2051_D, (float *)stereo_bs450, 2, 10}, - {IAMF_STEREO, BS2051_E, (float *)stereo_bs451, 2, 11}, - {IAMF_STEREO, BS2051_F, (float *)stereo_bs370, 2, 12}, - {IAMF_STEREO, BS2051_G, (float *)stereo_bs490, 2, 14}, - {IAMF_STEREO, BS2051_H, (float *)stereo_bs9A3, 2, 24}, - {IAMF_STEREO, BS2051_I, (float *)stereo_bs070, 2, 8}, - {IAMF_STEREO, BS2051_J, (float *)stereo_bs470, 2, 12}, - {IAMF_STEREO, IAMF_312, (float *)stereo_iamf312, 2, 6}, - {IAMF_STEREO, IAMF_712, (float *)stereo_iamf712, 2, 10}, - {IAMF_STEREO, IAMF_BINAURAL, (float *)stereo_bs020, 2, 2}, - {IAMF_STEREO, IAMF_MONO, (float *)stereo_mono, 2, 1}, - {IAMF_STEREO, IAMF_916, (float *)stereo_iamf916, 2, 16}, - - {IAMF_312, BS2051_A, (float *)iamf312_bs020, 6, 2}, - {IAMF_312, BS2051_B, (float *)iamf312_bs050, 6, 6}, - {IAMF_312, BS2051_C, (float *)iamf312_bs250, 6, 8}, - {IAMF_312, BS2051_D, (float *)iamf312_bs450, 6, 10}, - {IAMF_312, BS2051_E, (float *)iamf312_bs451, 6, 11}, - {IAMF_312, BS2051_F, (float *)iamf312_bs370, 6, 12}, - {IAMF_312, BS2051_G, (float *)iamf312_bs490, 6, 14}, - {IAMF_312, BS2051_H, (float *)iamf312_bs9A3, 6, 24}, - {IAMF_312, BS2051_I, (float *)iamf312_bs070, 6, 8}, - {IAMF_312, BS2051_J, (float *)iamf312_bs470, 6, 12}, - {IAMF_312, IAMF_312, (float *)iamf312_iamf312, 6, 6}, - {IAMF_312, IAMF_712, (float *)iamf312_iamf712, 6, 10}, - {IAMF_312, IAMF_BINAURAL, (float *)iamf312_bs020, 6, 2}, - {IAMF_312, IAMF_MONO, (float *)iamf312_mono, 6, 1}, - {IAMF_312, IAMF_916, (float *)iamf312_iamf916, 6, 16}, - - {IAMF_51, BS2051_A, (float *)iamf51_bs020, 6, 2}, - {IAMF_51, BS2051_B, (float *)iamf51_bs050, 6, 6}, - {IAMF_51, BS2051_C, (float *)iamf51_bs250, 6, 8}, - {IAMF_51, BS2051_D, (float *)iamf51_bs450, 6, 10}, - {IAMF_51, BS2051_E, (float *)iamf51_bs451, 6, 11}, - {IAMF_51, BS2051_F, (float *)iamf51_bs370, 6, 12}, - {IAMF_51, BS2051_G, (float *)iamf51_bs490, 6, 14}, - {IAMF_51, BS2051_H, (float *)iamf51_bs9A3, 6, 24}, - {IAMF_51, BS2051_I, (float *)iamf51_bs070, 6, 8}, - {IAMF_51, BS2051_J, (float *)iamf51_bs470, 6, 12}, - {IAMF_51, IAMF_312, (float *)iamf51_iamf312, 6, 6}, - {IAMF_51, IAMF_712, (float *)iamf51_iamf712, 6, 10}, - {IAMF_51, IAMF_BINAURAL, (float *)iamf51_bs020, 6, 2}, - {IAMF_51, IAMF_MONO, (float *)iamf51_mono, 6, 1}, - {IAMF_51, IAMF_916, (float *)iamf51_iamf916, 6, 16}, - - {IAMF_512, BS2051_A, (float *)iamf512_bs020, 8, 2}, - {IAMF_512, BS2051_B, (float *)iamf512_bs050, 8, 6}, - {IAMF_512, BS2051_C, (float *)iamf512_bs250, 8, 8}, - {IAMF_512, BS2051_D, (float *)iamf512_bs450, 8, 10}, - {IAMF_512, BS2051_E, (float *)iamf512_bs451, 8, 11}, - {IAMF_512, BS2051_F, (float *)iamf512_bs370, 8, 12}, - {IAMF_512, BS2051_G, (float *)iamf512_bs490, 8, 14}, - {IAMF_512, BS2051_H, (float *)iamf512_bs9A3, 8, 24}, - {IAMF_512, BS2051_I, (float *)iamf512_bs070, 8, 8}, - {IAMF_512, BS2051_J, (float *)iamf512_bs470, 8, 12}, - {IAMF_512, IAMF_312, (float *)iamf512_iamf312, 8, 6}, - {IAMF_512, IAMF_712, (float *)iamf512_iamf712, 8, 10}, - {IAMF_512, IAMF_BINAURAL, (float *)iamf512_bs020, 8, 2}, - {IAMF_512, IAMF_MONO, (float *)iamf512_mono, 8, 1}, - {IAMF_512, IAMF_916, (float *)iamf512_iamf916, 8, 16}, - - {IAMF_514, BS2051_A, (float *)iamf514_bs020, 10, 2}, - {IAMF_514, BS2051_B, (float *)iamf514_bs050, 10, 6}, - {IAMF_514, BS2051_C, (float *)iamf514_bs250, 10, 8}, - {IAMF_514, BS2051_D, (float *)iamf514_bs450, 10, 10}, - {IAMF_514, BS2051_E, (float *)iamf514_bs451, 10, 11}, - {IAMF_514, BS2051_F, (float *)iamf514_bs370, 10, 12}, - {IAMF_514, BS2051_G, (float *)iamf514_bs490, 10, 14}, - {IAMF_514, BS2051_H, (float *)iamf514_bs9A3, 10, 24}, - {IAMF_514, BS2051_I, (float *)iamf514_bs070, 10, 8}, - {IAMF_514, BS2051_J, (float *)iamf514_bs470, 10, 12}, - {IAMF_514, IAMF_312, (float *)iamf514_iamf312, 10, 6}, - {IAMF_514, IAMF_712, (float *)iamf514_iamf712, 10, 10}, - {IAMF_514, IAMF_BINAURAL, (float *)iamf514_bs020, 10, 2}, - {IAMF_514, IAMF_MONO, (float *)iamf514_mono, 10, 1}, - {IAMF_514, IAMF_916, (float *)iamf514_iamf916, 10, 16}, - - {IAMF_71, BS2051_A, (float *)iamf71_bs020, 8, 2}, - {IAMF_71, BS2051_B, (float *)iamf71_bs050, 8, 6}, - {IAMF_71, BS2051_C, (float *)iamf71_bs250, 8, 8}, - {IAMF_71, BS2051_D, (float *)iamf71_bs450, 8, 10}, - {IAMF_71, BS2051_E, (float *)iamf71_bs451, 8, 11}, - {IAMF_71, BS2051_F, (float *)iamf71_bs370, 8, 12}, - {IAMF_71, BS2051_G, (float *)iamf71_bs490, 8, 14}, - {IAMF_71, BS2051_H, (float *)iamf71_bs9A3, 8, 24}, - {IAMF_71, BS2051_I, (float *)iamf71_bs070, 8, 8}, - {IAMF_71, BS2051_J, (float *)iamf71_bs470, 8, 12}, - {IAMF_71, IAMF_312, (float *)iamf71_iamf312, 8, 6}, - {IAMF_71, IAMF_712, (float *)iamf71_iamf712, 8, 10}, - {IAMF_71, IAMF_BINAURAL, (float *)iamf71_bs020, 8, 2}, - {IAMF_71, IAMF_MONO, (float *)iamf71_mono, 8, 1}, - {IAMF_71, IAMF_916, (float *)iamf71_iamf916, 8, 16}, - - {IAMF_712, BS2051_A, (float *)iamf712_bs020, 10, 2}, - {IAMF_712, BS2051_B, (float *)iamf712_bs050, 10, 6}, - {IAMF_712, BS2051_C, (float *)iamf712_bs250, 10, 8}, - {IAMF_712, BS2051_D, (float *)iamf712_bs450, 10, 10}, - {IAMF_712, BS2051_E, (float *)iamf712_bs451, 10, 11}, - {IAMF_712, BS2051_F, (float *)iamf712_bs370, 10, 12}, - {IAMF_712, BS2051_G, (float *)iamf712_bs490, 10, 14}, - {IAMF_712, BS2051_H, (float *)iamf712_bs9A3, 10, 24}, - {IAMF_712, BS2051_I, (float *)iamf712_bs070, 10, 8}, - {IAMF_712, BS2051_J, (float *)iamf712_bs470, 10, 12}, - {IAMF_712, IAMF_312, (float *)iamf712_iamf312, 10, 6}, - {IAMF_712, IAMF_712, (float *)iamf712_iamf712, 10, 10}, - {IAMF_712, IAMF_BINAURAL, (float *)iamf712_bs020, 10, 2}, - {IAMF_712, IAMF_MONO, (float *)iamf712_mono, 10, 1}, - {IAMF_712, IAMF_916, (float *)iamf712_iamf916, 10, 16}, - - {IAMF_714, BS2051_A, (float *)iamf714_bs020, 12, 2}, - {IAMF_714, BS2051_B, (float *)iamf714_bs050, 12, 6}, - {IAMF_714, BS2051_C, (float *)iamf714_bs250, 12, 8}, - {IAMF_714, BS2051_D, (float *)iamf714_bs450, 12, 10}, - {IAMF_714, BS2051_E, (float *)iamf714_bs451, 12, 11}, - {IAMF_714, BS2051_F, (float *)iamf714_bs370, 12, 12}, - {IAMF_714, BS2051_G, (float *)iamf714_bs490, 12, 14}, - {IAMF_714, BS2051_H, (float *)iamf714_bs9A3, 12, 24}, - {IAMF_714, BS2051_I, (float *)iamf714_bs070, 12, 8}, - {IAMF_714, BS2051_J, (float *)iamf714_bs470, 12, 12}, - {IAMF_714, IAMF_312, (float *)iamf714_iamf312, 12, 6}, - {IAMF_714, IAMF_712, (float *)iamf714_iamf712, 12, 10}, - {IAMF_714, IAMF_BINAURAL, (float *)iamf714_bs020, 12, 2}, - {IAMF_714, IAMF_MONO, (float *)iamf714_mono, 12, 1}, - {IAMF_714, IAMF_916, (float *)iamf714_iamf916, 12, 16}, - - {IAMF_BINAURAL, BS2051_A, (float *)stereo_bs020, 2, 2}, - {IAMF_BINAURAL, BS2051_B, (float *)stereo_bs050, 2, 6}, - {IAMF_BINAURAL, BS2051_C, (float *)stereo_bs250, 2, 8}, - {IAMF_BINAURAL, BS2051_D, (float *)stereo_bs450, 2, 10}, - {IAMF_BINAURAL, BS2051_E, (float *)stereo_bs451, 2, 11}, - {IAMF_BINAURAL, BS2051_F, (float *)stereo_bs370, 2, 12}, - {IAMF_BINAURAL, BS2051_G, (float *)stereo_bs490, 2, 14}, - {IAMF_BINAURAL, BS2051_H, (float *)stereo_bs9A3, 2, 24}, - {IAMF_BINAURAL, BS2051_I, (float *)stereo_bs070, 2, 8}, - {IAMF_BINAURAL, BS2051_J, (float *)stereo_bs470, 2, 12}, - {IAMF_BINAURAL, IAMF_312, (float *)stereo_iamf312, 2, 6}, - {IAMF_BINAURAL, IAMF_712, (float *)stereo_iamf712, 2, 10}, - {IAMF_BINAURAL, IAMF_BINAURAL, (float *)stereo_bs020, 2, 2}, - {IAMF_BINAURAL, IAMF_MONO, (float *)stereo_mono, 2, 1}, - {IAMF_BINAURAL, IAMF_916, (float *)stereo_iamf916, 2, 16}, - - {IAMF_916, BS2051_A, (float *)iamf916_bs020, 16, 2}, - {IAMF_916, BS2051_B, (float *)iamf916_bs050, 16, 6}, - {IAMF_916, BS2051_C, (float *)iamf916_bs250, 16, 8}, - {IAMF_916, BS2051_D, (float *)iamf916_bs450, 16, 10}, - {IAMF_916, BS2051_E, (float *)iamf916_bs451, 16, 11}, - {IAMF_916, BS2051_F, (float *)iamf916_bs370, 16, 12}, - {IAMF_916, BS2051_G, (float *)iamf916_bs490, 16, 14}, - {IAMF_916, BS2051_H, (float *)iamf916_bs9A3, 16, 24}, - {IAMF_916, BS2051_I, (float *)iamf916_bs070, 16, 8}, - {IAMF_916, BS2051_J, (float *)iamf916_bs470, 16, 12}, - {IAMF_916, IAMF_312, (float *)iamf916_iamf312, 16, 6}, - {IAMF_916, IAMF_712, (float *)iamf916_iamf712, 16, 10}, - {IAMF_916, IAMF_BINAURAL, (float *)iamf916_bs020, 16, 2}, - {IAMF_916, IAMF_MONO, (float *)iamf916_mono, 16, 1}, - {IAMF_916, IAMF_916, (float *)iamf916_iamf916, 16, 16}}; - -BS2051_SPLABEL iamf_stereo_spl[] = {SP_MP030, SP_MM030}; -BS2051_SPLABEL iamf_51_spl[] = {SP_MP030, SP_MM030, SP_MP000, - SP_LFE1, SP_MP110, SP_MM110}; -BS2051_SPLABEL iamf_512_spl[] = {SP_MP030, SP_MM030, SP_MP000, SP_LFE1, - SP_MP110, SP_MM110, SP_UP030, SP_UM030}; -BS2051_SPLABEL iamf_514_spl[] = {SP_MP030, SP_MM030, SP_MP000, SP_LFE1, - SP_MP110, SP_MM110, SP_UP030, SP_UM030, - SP_UP110, SP_UM110}; -BS2051_SPLABEL iamf_71_spl[] = {SP_MP030, SP_MM030, SP_MP000, SP_LFE1, - SP_MP090, SP_MM090, SP_MP135, SP_MM135}; -BS2051_SPLABEL iamf_714_spl[] = {SP_MP030, SP_MM030, SP_MP000, SP_LFE1, - SP_MP090, SP_MM090, SP_MP135, SP_MM135, - SP_UP045, SP_UM045, SP_UP135, SP_UM135}; -BS2051_SPLABEL iamf_mono_spl[] = {SP_MP000}; -BS2051_SPLABEL iamf_712_spl[] = {SP_MP030, SP_MM030, SP_MP000, SP_LFE1, - SP_MP090, SP_MM090, SP_MP135, SP_MM135, - SP_UP045, SP_UM045}; -BS2051_SPLABEL iamf_312_spl[] = {SP_MP030, SP_MM030, SP_MP000, - SP_LFE1, SP_UP030, SP_UM030}; -BS2051_SPLABEL iamf_916_spl[] = {SP_MP060, SP_MM060, SP_MP000, SP_LFE1, - SP_MP135, SP_MM135, SP_MP030, SP_MM030, - SP_MP090, SP_MM090, SP_UP045, SP_UM045, - SP_UP135, SP_UM135, SP_UP090, SP_UM090}; - -struct iamf_splabel_per_layout_t { - IAMF_SOUND_SYSTEM system; - int channels; - BS2051_SPLABEL *sp_labels; -} iamf_splabel_per_layout[] = { - {IAMF_STEREO, 2, iamf_stereo_spl}, {IAMF_51, 6, iamf_51_spl}, - {IAMF_512, 8, iamf_512_spl}, {IAMF_514, 10, iamf_514_spl}, - {IAMF_71, 8, iamf_71_spl}, {IAMF_714, 12, iamf_714_spl}, - {IAMF_MONO, 1, iamf_mono_spl}, {IAMF_712, 10, iamf_712_spl}, - {IAMF_312, 6, iamf_312_spl}, {IAMF_BINAURAL, 2, iamf_stereo_spl}, - {IAMF_916, 16, iamf_916_spl}}; - -/* -Layout in: Predefined Direct speaker input channel layout -Layout out: Predefined Direct speaker output channel layout -float *outMatrix: Conversion Matrix (MatrixSize = number of out channels x -number of in channels) -*/ -int IAMF_element_renderer_get_M2M_matrix(IAMF_SP_LAYOUT *in_layout, - IAMF_SP_LAYOUT *out_layout, - struct m2m_rdr_t *outMatrix) { - int i; - - if (in_layout->sp_type == 0 && - out_layout->sp_type == - 0) { // PRE-DEFINED LAYOUT(input) to PRE-DEFINED LAYOUT(output) - for (i = 0; i < sizeof(m2m_rdr_tab) / sizeof(struct m2m_rdr_t); i++) { - if (m2m_rdr_tab[i].in == in_layout->sp_layout.predefined_sp->system && - m2m_rdr_tab[i].out == out_layout->sp_layout.predefined_sp->system) { - *outMatrix = m2m_rdr_tab[i]; - return (0); - } - } - } - - return (-1); -} - -/* -Layout in: Custom speaker input layout in render_config() -Layout out: Predefined Direct speaker output channel layout -speaker output layout float *outMatrix: Conversion Matrix (MatrixSize = number -of out channels x number of in channels) -*/ -int IAMF_element_renderer_get_M2M_custom_matrix(IAMF_SP_LAYOUT *in_layout, - IAMF_SP_LAYOUT *out_layout, - struct m2m_rdr_t *outMatrix, - int *chmap) { - int i, j, k, m; - IAMF_CUSTOM_SP_LAYOUT *in_sp; - BS2051_SPLABEL in_sp_flags; - - m = 0; - if (in_layout->sp_type == 1 && - out_layout->sp_type == - 0) { // IAMF_CUSTOM_SP_LAYOUT(input) to PRE-DEFINED LAYOUT(output) - for (i = 0; i < sizeof(m2m_rdr_tab) / sizeof(struct m2m_rdr_t); i++) { - if (m2m_rdr_tab[i].in == in_layout->sp_layout.custom_sp->system && - m2m_rdr_tab[i].out == out_layout->sp_layout.predefined_sp->system) { - *outMatrix = m2m_rdr_tab[i]; - - in_sp = in_layout->sp_layout.custom_sp; - for (j = 0; j < sizeof(iamf_splabel_per_layout) / - sizeof(struct iamf_splabel_per_layout_t); - j++) { - if (in_sp->system == iamf_splabel_per_layout[j].system) { - in_sp_flags = in_sp->sp_flags; - for (k = 0; k < iamf_splabel_per_layout[j].channels; k++) { - if (in_sp_flags & iamf_splabel_per_layout[j].sp_labels[k]) { - chmap[m] = k; - m++; - } - } - outMatrix->m = m; - return (0); - } - } - } - } - } - - return (-1); -} - -// Predefined Multichannel to Multichannel Renderer -int IAMF_element_renderer_render_M2M(const Arch *arch, - struct m2m_rdr_t *m2mMatrix, float *in[], - float *out[], int nsamples) { - (*arch->rendering.multiply_channels_by_matrix)(m2mMatrix->mat, m2mMatrix->m, - m2mMatrix->n, 0, m2mMatrix->n, - 1, in, out, nsamples); - - return (0); -} - -// Custom Multichannel to Multichannel Renderer -int IAMF_element_renderer_render_M2M_custom(const Arch *arch, - struct m2m_rdr_t *m2mMatrix, - float *in[], float *out[], - int nsamples, int *chmap) { - (*arch->rendering.multiply_channels_by_matrix)( - m2mMatrix->mat, m2mMatrix->m, m2mMatrix->n, chmap, m2mMatrix->n, 1, in, - out, nsamples); - - return (0); -} diff --git a/code/src/iamf_dec/obu/animated_parameter.c b/code/src/iamf_dec/obu/animated_parameter.c new file mode 100755 index 00000000..ca5070f4 --- /dev/null +++ b/code/src/iamf_dec/obu/animated_parameter.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file animated_parameter.c + * @brief Animated parameter implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "animated_parameter.h" + +#include + +#include "iamf_private_definitions.h" +#include "iamf_utils.h" + +#undef def_log_tag +#define def_log_tag "AMT_PMT" + +int animated_parameter_data_read_bits(bits_io_context_t *bits_r, + uint32_t n_bits, + iamf_animation_type_t type, + apd_u32_t *param) { + int ret = IAMF_OK; + if (!bits_r || !param) return IAMF_ERR_BAD_ARG; + + switch (type) { + case ck_iamf_animation_type_step: + param->start = bits_ior_le32(bits_r, n_bits); + break; + case ck_iamf_animation_type_linear: + param->start = bits_ior_le32(bits_r, n_bits); + case ck_iamf_animation_type_inter_linear: + param->end = bits_ior_le32(bits_r, n_bits); + break; + case ck_iamf_animation_type_bezier: + param->start = bits_ior_le32(bits_r, n_bits); + case ck_iamf_animation_type_inter_bezier: + param->end = bits_ior_le32(bits_r, n_bits); + param->control = bits_ior_le32(bits_r, n_bits); + param->control_relative_time = bits_ior_le32(bits_r, 8); + break; + default: + error("Unknown animation type: %u", type); + ret = IAMF_ERR_BAD_ARG; + break; + } + + return ret; +} diff --git a/code/src/iamf_dec/obu/animated_parameter.h b/code/src/iamf_dec/obu/animated_parameter.h new file mode 100755 index 00000000..b39b1a09 --- /dev/null +++ b/code/src/iamf_dec/obu/animated_parameter.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file animated_parameter.h + * @brief Animated parameter APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __ANIMATED_PARAMETER_H__ +#define __ANIMATED_PARAMETER_H__ + +#include + +#include "animation.h" +#include "iorw.h" + +/** + * Animated Parameter definitions. + */ + +typedef enum EIamfAnimationType { + ck_iamf_animation_type_step, + ck_iamf_animation_type_linear, + ck_iamf_animation_type_bezier, + ck_iamf_animation_type_inter_linear, + ck_iamf_animation_type_inter_bezier +} iamf_animation_type_t; + +#define def_animated_parameter_data_type_definition(T1, T2) \ + typedef struct AnimatedParameterData_##T1##_##T2 { \ + T1 start; \ + T1 end; \ + T1 control; \ + T2 control_relative_time; \ + } animated_parameter_data_##T1##_##T2##_t + +#define def_animated_parameter_data_type(T1, T2) \ + animated_parameter_data_##T1##_##T2##_t + +def_animated_parameter_data_type_definition(uint32_t, uint32_t); +def_animated_parameter_data_type_definition(int16_t, float); + +#define apd_u32_t def_animated_parameter_data_type(uint32_t, uint32_t) + +#define def_animated_parameter_type_definition(prefix, T1, T2) \ + typedef struct AnimatedParameter_##T1##_##T2 { \ + animation_type_t animation_type; \ + def_animated_parameter_data_type(T1, T2) data; \ + } prefix##_animated_parameter_##T1##_##T2##_t + +def_animated_parameter_type_definition(obu, uint32_t, uint32_t); +def_animated_parameter_type_definition(obu, int16_t, float); + +#define def_animated_parameter_type(prefix, T1, T2) \ + prefix##_animated_parameter_##T1##_##T2##_t + +#define ap_t(prefix, T1, T2) def_animated_parameter_type(prefix, T1, T2) +#define ap_u32_t ap_t(obu, uint32_t, uint32_t) + +int animated_parameter_data_read_bits(bits_io_context_t *bits_r, + uint32_t n_bits, + iamf_animation_type_t type, + apd_u32_t *param); + +#define def_animated_parameter_data_convert_bits_function(dst, src, num_bits, \ + convert_func) \ + do { \ + (dst)->start = convert_func((src)->start, (num_bits)); \ + (dst)->end = convert_func((src)->end, (num_bits)); \ + (dst)->control = convert_func((src)->control, (num_bits)); \ + (dst)->control_relative_time = \ + iamf_divide_128f((src)->control_relative_time); \ + } while (0) + +#endif // __ANIMATED_PARAMETER_H__ diff --git a/code/src/iamf_dec/obu/audio_element_obu.c b/code/src/iamf_dec/obu/audio_element_obu.c new file mode 100755 index 00000000..5a5f5e93 --- /dev/null +++ b/code/src/iamf_dec/obu/audio_element_obu.c @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomia.org/license/patent. + */ + +/** + * @file audio_element_obu.c + * @brief Audio element OBU implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "audio_element_obu.h" + +#include "iamf_layout.h" +#include "iamf_private_definitions.h" +#include "iamf_string.h" +#include "parameter_base.h" + +#ifdef SUPPORT_VERIFIER +#include "vlogging_tool_sr.h" +#endif + +#undef def_log_tag +#define def_log_tag "OBU_AE" +#define def_cco_str "Audio Element OBU" + +static int _obu_ae_common_init(iamf_audio_element_obu_t *obu, uint32_t id, + iamf_audio_element_type_t type, + io_context_t *ior); +static void _obu_ae_common_clear(iamf_audio_element_obu_t *obu); +static channel_based_audio_element_obu_t *_obu_ae_channel_based_new( + uint32_t id, io_context_t *ior); +static void _obu_ae_channel_based_free(channel_based_audio_element_obu_t *cae); +static scene_based_audio_element_obu_t *_obu_ae_scene_based_new( + uint32_t id, io_context_t *ior); +static void _obu_ae_scene_based_free(scene_based_audio_element_obu_t *sae); +static object_based_audio_element_obu_t *_obu_ae_object_based_new( + uint32_t id, io_context_t *ior); +static void _obu_ae_object_based_free(object_based_audio_element_obu_t *oae); + +static int _obu_ae_check(iamf_audio_element_obu_t *obu); +static int _obu_ae_channel_based_check_profile( + channel_based_audio_element_obu_t *cae, iamf_profile_t profile); +static int _obu_ae_scene_based_check_profile( + scene_based_audio_element_obu_t *sae, iamf_profile_t profile); +static int _obu_ae_find_parameter(value_wrap_t item, value_wrap_t key); + +iamf_audio_element_obu_t *iamf_audio_element_obu_new(io_context_t *ior) { + io_context_t *r = ior; + iamf_audio_element_obu_t *obu = 0; + uint32_t val; + uint32_t type; + + val = ior_leb128_u32(r); // audio element id + type = ior_8(r) >> 5 & 0x07; // audio element type + + if (type == ck_audio_element_type_channel_based) { + channel_based_audio_element_obu_t *cae = + _obu_ae_channel_based_new(val, ior); + if (cae) obu = def_audio_element_obu_ptr(cae); + } else if (type == ck_audio_element_type_scene_based) { + scene_based_audio_element_obu_t *sae = _obu_ae_scene_based_new(val, ior); + if (sae) obu = def_audio_element_obu_ptr(sae); + } else if (type == ck_audio_element_type_object_based) { + object_based_audio_element_obu_t *oae = _obu_ae_object_based_new(val, ior); + if (oae) obu = def_audio_element_obu_ptr(oae); + } else { + warning("Unsupported type %u of audio element %u", type, val); + return 0; + } + + if (!obu) { + def_err_msg_enomem(def_cco_str, def_iamf_ustr); + return 0; + } + +#if SUPPORT_VERIFIER + vlog_obu(ck_iamf_obu_audio_element, obu, 0, 0); +#endif + + if (_obu_ae_check(obu) != def_pass) { + iamf_audio_element_obu_free(obu); + return 0; + } + + return obu; +} + +void iamf_audio_element_obu_free(iamf_audio_element_obu_t *obu) { + if (!obu) return; + + if (obu->audio_element_type == ck_audio_element_type_channel_based) { + _obu_ae_channel_based_free(def_channel_based_audio_element_obu_ptr(obu)); + } else if (obu->audio_element_type == ck_audio_element_type_scene_based) { + _obu_ae_scene_based_free(def_scene_based_audio_element_obu_ptr(obu)); + } else if (obu->audio_element_type == ck_audio_element_type_object_based) { + _obu_ae_object_based_free(def_object_based_audio_element_obu_ptr(obu)); + } else { + warning("Unknown audio element type %u", obu->audio_element_type); + _obu_ae_common_clear(obu); + } +} + +int iamf_audio_element_obu_check_profile(iamf_audio_element_obu_t *obu, + iamf_profile_t profile) { + if (obu->audio_element_type == ck_audio_element_type_channel_based) + return _obu_ae_channel_based_check_profile( + def_channel_based_audio_element_obu_ptr(obu), profile); + if (obu->audio_element_type == ck_audio_element_type_scene_based) + return _obu_ae_scene_based_check_profile( + def_scene_based_audio_element_obu_ptr(obu), profile); + if (obu->audio_element_type == ck_audio_element_type_object_based && + profile > ck_iamf_profile_base_enhanced) + return def_pass; + return def_error; +} + +parameter_base_t *iamf_audio_element_obu_get_parameter( + iamf_audio_element_obu_t *obu, iamf_parameter_type_t type) { + value_wrap_t *v = 0; + + if (!obu || !obu->parameters) return 0; + if (type != ck_iamf_parameter_type_demixing && + type != ck_iamf_parameter_type_recon_gain) + return 0; + + v = array_find(obu->parameters, def_value_wrap_instance_u32(type), + _obu_ae_find_parameter); + return v ? v->ptr : 0; +} + +int _obu_ae_common_init(iamf_audio_element_obu_t *obu, uint32_t id, + iamf_audio_element_type_t type, io_context_t *ior) { + uint32_t val = 0; + io_context_t *r = ior; + + obu->obu.obu_type = ck_iamf_obu_audio_element; + obu->audio_element_id = id; + obu->audio_element_type = type; + obu->codec_config_id = ior_leb128_u32(r); + + val = ior_leb128_u32(r); // num_substreams + info( + "Audio element id(%u), audio element type(%s<%d>), " + "codec config id(%u), sub-streams count(%u)", + obu->audio_element_id, + iamf_audio_element_type_string(obu->audio_element_type), + obu->audio_element_type, obu->codec_config_id, val); + + obu->audio_substream_ids = array_new(val); + if (!obu->audio_substream_ids) { + def_err_msg_enomem("substream ids", def_cco_str); + return IAMF_ERR_ALLOC_FAIL; + } + + info("Sub-stream ids:"); + for (uint32_t i = 0; i < val; ++i) { + value_wrap_t *v = array_at(obu->audio_substream_ids, i); + v->u32 = ior_leb128_u32(r); + info("\t%u", v->u32); + } + + val = ior_leb128_u32(r); // num_parameters + info("Element parameters count %u", val); + if (val) { + obu->parameters = array_new(val); + if (!obu->parameters) { + def_err_msg_enomem("parameters", def_cco_str); + return IAMF_ERR_ALLOC_FAIL; + } + } + + for (uint32_t i = 0; i < val; ++i) { + value_wrap_t *v = 0; + type = ior_leb128_u32(r); + if (type != ck_iamf_parameter_type_demixing && + type != ck_iamf_parameter_type_recon_gain) { + uint32_t size = ior_leb128_u32(r); + ior_skip(r, size); + warning( + "Don't support parameter type(%u) in Audio Element OBU(%u), " + "parameter definition bytes %u.", + type, obu->audio_element_id, size); + continue; + } + + v = array_at(obu->parameters, i); + v->ptr = iamf_parameter_base_new(r, type); + if (!v->ptr) { + def_err_msg_enomem("parameter", def_cco_str); + continue; + } + } + + return IAMF_OK; +} + +void _obu_ae_common_clear(iamf_audio_element_obu_t *obu) { + if (obu->audio_substream_ids) array_free(obu->audio_substream_ids, 0); + if (obu->parameters) + array_free(obu->parameters, def_default_free_ptr(iamf_parameter_base_free)); +} + +static obu_channel_layer_config_t *_obu_ae_channel_layout_config_new( + io_context_t *ior, uint32_t layer) { + io_context_t *r = ior; + uint32_t val; + obu_channel_layer_config_t *layer_config = + def_mallocz(obu_channel_layer_config_t, 1); + + if (!layer_config) { + def_err_msg_enomem("channel layer config", def_cco_str); + return 0; + } + + val = ior_8(r); + layer_config->loudspeaker_layout = val >> 4 & 0x0f; + layer_config->output_gain_is_present_flag = val >> 3 & 0x01; + layer_config->recon_gain_is_present_flag = val >> 2 & 0x01; + layer_config->substream_count = ior_8(r); + layer_config->coupled_substream_count = ior_8(r); + + info( + "\tLayer[%u] info: loudspeaker layout(%u:%s), " + "output gain is present flag(%u), recon gain is present flag(%u), " + "substreams count(%u), coupled substreams count(%u)", + layer, layer_config->loudspeaker_layout, + iamf_loudspeaker_layout_string(layer_config->loudspeaker_layout), + layer_config->output_gain_is_present_flag, + layer_config->recon_gain_is_present_flag, layer_config->substream_count, + layer_config->coupled_substream_count); + + if (layer_config->output_gain_is_present_flag) { + layer_config->output_gain_info.output_gain_flag = ior_8(r) >> 2 & 0x3f; + layer_config->output_gain_info.output_gain = (int16_t)ior_b16(r); + layer_config->output_gain_info.output_gain_linear = + iamf_gain_q78_to_linear(layer_config->output_gain_info.output_gain); + info( + "\t\tOutput gain : output gain flag(0x%04x), output gain(0x%04x), " + "linear gain(%f)", + layer_config->output_gain_info.output_gain_flag, + layer_config->output_gain_info.output_gain, + layer_config->output_gain_info.output_gain_linear); + } + + if (!layer && layer_config->loudspeaker_layout == + def_iamf_loudspeaker_layout_expanded) { + layer_config->expanded_loudspeaker_layout = ior_8(r); + info("\t\tExpanded loudspeaker layout(%u:%s)", + layer_config->expanded_loudspeaker_layout, + iamf_expanded_loudspeaker_layout_string( + layer_config->expanded_loudspeaker_layout)); + } + + return layer_config; +} + +static int _obu_ae_channel_based_init(channel_based_audio_element_obu_t *cae, + io_context_t *ior) { + io_context_t *r = ior; + uint32_t val; + + val = ior_8(r) >> 5 & 0x07; // num_layers + if (!val) return IAMF_ERR_BAD_ARG; + + cae->channel_audio_layer_configs = array_new(val); + if (!cae->channel_audio_layer_configs) { + def_err_msg_enomem("channel layer configs", def_cco_str); + return IAMF_ERR_ALLOC_FAIL; + } + info("Scalable channel layout config, number of layers %u", val); + + for (uint32_t i = 0; i < val; ++i) { + obu_channel_layer_config_t *layer_config = + _obu_ae_channel_layout_config_new(r, i); + if (!layer_config) continue; + def_value_wrap_ptr(array_at(cae->channel_audio_layer_configs, i)) = + layer_config; + } + return IAMF_OK; +} + +channel_based_audio_element_obu_t *_obu_ae_channel_based_new( + uint32_t id, io_context_t *ior) { + channel_based_audio_element_obu_t *cae = 0; + iamf_audio_element_obu_t *obu = 0; + + cae = def_mallocz(channel_based_audio_element_obu_t, 1); + if (!cae) { + def_err_msg_enomem("Channel Based Audio Element OBU", def_iamf_ustr); + return 0; + } + + obu = def_audio_element_obu_ptr(cae); + + if (_obu_ae_common_init(obu, id, ck_audio_element_type_channel_based, ior) != + IAMF_OK || + _obu_ae_channel_based_init(cae, ior) != IAMF_OK) { + _obu_ae_channel_based_free(cae); + return 0; + } + + return cae; +} + +void _obu_ae_channel_based_free(channel_based_audio_element_obu_t *cae) { + if (!cae) return; + _obu_ae_common_clear(&cae->base); + if (cae->channel_audio_layer_configs) + array_free(cae->channel_audio_layer_configs, def_default_free_ptr(free)); + free(cae); +} + +static int _obu_ae_scene_based_init(scene_based_audio_element_obu_t *sae, + io_context_t *ior) { + int ret = IAMF_OK; + io_context_t *r = ior; + + sae->ambisonics_mode = ior_leb128_u32(r); + if (sae->ambisonics_mode == ck_ambisonics_mode_mono) { + sae->output_channel_count = ior_8(r); + sae->substream_count = ior_8(r); + sae->mapping_size = sae->output_channel_count; + sae->channel_mapping = def_malloc(uint8_t, sae->mapping_size); + if (!sae->channel_mapping) { + def_err_msg_enomem("mono mapping", def_cco_str); + return IAMF_ERR_ALLOC_FAIL; + } + ior_read(r, sae->channel_mapping, sae->output_channel_count); + + info( + "%s(%u), output channel count(%u), substream count(%u), channel " + "mapping " + "size %u", + iamf_ambisonics_mode_string(sae->ambisonics_mode), sae->ambisonics_mode, + sae->output_channel_count, sae->substream_count, + sae->output_channel_count); + + } else if (sae->ambisonics_mode == ck_ambisonics_mode_projection) { + sae->output_channel_count = ior_8(r); + sae->substream_count = ior_8(r); + sae->coupled_substream_count = ior_8(r); + sae->mapping_size = (sae->substream_count + sae->coupled_substream_count) * + sae->output_channel_count; + sae->mapping_size *= sizeof(int16_t); + sae->demixing_matrix = def_malloc(uint8_t, sae->mapping_size); + if (!sae->demixing_matrix) { + def_err_msg_enomem("projection mapping", def_cco_str); + return IAMF_ERR_ALLOC_FAIL; + } + + ior_read(r, sae->demixing_matrix, sae->mapping_size); + + debug( + "%s<%u>, output channel count(%u), substream count(%u), " + "coupled substream count(%u), demixing matrix (%u x %u) size(%u) ", + iamf_ambisonics_mode_string(sae->ambisonics_mode), sae->ambisonics_mode, + sae->output_channel_count, sae->substream_count, + sae->coupled_substream_count, sae->output_channel_count, + sae->substream_count + sae->coupled_substream_count, sae->mapping_size); + + } else { + warning("Invalid ambisonics mode(%u)", sae->ambisonics_mode); + ret = IAMF_ERR_BAD_ARG; + } + return ret; +} + +scene_based_audio_element_obu_t *_obu_ae_scene_based_new(uint32_t id, + io_context_t *ior) { + scene_based_audio_element_obu_t *sae = 0; + + sae = def_mallocz(scene_based_audio_element_obu_t, 1); + if (!sae) { + def_err_msg_enomem("Scene Based Audio Element OBU", def_iamf_ustr); + return 0; + } + + if (_obu_ae_common_init(&sae->base, id, ck_audio_element_type_scene_based, + ior) != IAMF_OK || + _obu_ae_scene_based_init(sae, ior) != IAMF_OK) { + _obu_ae_scene_based_free(sae); + return 0; + } + return sae; +} + +void _obu_ae_scene_based_free(scene_based_audio_element_obu_t *sae) { + _obu_ae_common_clear(&sae->base); + def_free(sae->channel_mapping); + def_free(sae); +} + +static int _obu_ae_object_based_init(object_based_audio_element_obu_t *oae, + io_context_t *ior) { + io_context_t *r = ior; + uint32_t val = ior_leb128_u32(r); + + if (val > 0) { + oae->num_objects = ior_8(r); + ior_skip(r, val - 1); + } + info("Number of objects %u", oae->num_objects); + + return oae->num_objects > 0 ? IAMF_OK : IAMF_ERR_BAD_ARG; +} + +object_based_audio_element_obu_t *_obu_ae_object_based_new(uint32_t id, + io_context_t *ior) { + object_based_audio_element_obu_t *oae = 0; + + oae = def_mallocz(object_based_audio_element_obu_t, 1); + if (!oae) { + def_err_msg_enomem("Object Based Audio Element OBU", def_iamf_ustr); + return 0; + } + if (_obu_ae_common_init(&oae->base, id, ck_audio_element_type_object_based, + ior) != IAMF_OK || + _obu_ae_object_based_init(oae, ior) != IAMF_OK) { + _obu_ae_object_based_free(oae); + return 0; + } + debug("New object_based_audio_element_obu_t %p", oae); + return oae; +} + +void _obu_ae_object_based_free(object_based_audio_element_obu_t *oae) { + _obu_ae_common_clear(&oae->base); + def_free(oae); +} + +static int _obu_ae_channel_based_check(channel_based_audio_element_obu_t *cae) { + if (array_size(cae->base.parameters) > 2) + warning("Channle based audio element(%u) has more than two parameters.", + cae->base.audio_element_id); + + cae->max_valid_layers = 0; + if (cae->channel_audio_layer_configs) { + uint32_t channels = 0; + int n = array_size(cae->channel_audio_layer_configs); + if (!n) { + warning("Element (%u) doesn't have valid layer.", + cae->base.audio_element_id); + return def_error; + } + + for (int i = 0; i < n; ++i) { + obu_channel_layer_config_t *layer_config = def_value_wrap_optional_ptr( + array_at(cae->channel_audio_layer_configs, i)); + + if (cae->max_valid_layers == i) { + channels += (layer_config->substream_count + + layer_config->coupled_substream_count); + if (iamf_audio_layer_base_layout_check( + layer_config->loudspeaker_layout) && + (layer_config->substream_count > 0) && + (iamf_loudspeaker_layout_get_info(layer_config->loudspeaker_layout) + ->channels == channels)) { + ++cae->max_valid_layers; + } else if (!i && n == 1 && + layer_config->loudspeaker_layout == + def_iamf_loudspeaker_layout_expanded) { + if (iamf_audio_layer_expanded_layout_check( + layer_config->expanded_loudspeaker_layout)) { + cae->max_valid_layers = 1; + } else { + warning("Layer[%d] info : invalid expanded layout %d", i, + cae->max_valid_layers); + } + } else if (i || layer_config->loudspeaker_layout != + def_iamf_loudspeaker_layout_expanded) { + warning("Element (%u) Layer %d: Invalid loudspeaker layout %u", + cae->base.audio_element_id, i, + layer_config->loudspeaker_layout); + break; + } + } + } + info("Valid layers %u", cae->max_valid_layers); + } + return cae->max_valid_layers ? def_pass : def_error; +} + +int _obu_ae_channel_based_check_profile(channel_based_audio_element_obu_t *cae, + iamf_profile_t profile) { + array_t *configs = cae->channel_audio_layer_configs; + + if (array_size(configs) == 1 && profile <= ck_iamf_profile_base) { + obu_channel_layer_config_t *layer_config = + def_value_wrap_optional_ptr(array_at(configs, 0)); + if (layer_config && + !iamf_audio_layer_base_layout_check(layer_config->loudspeaker_layout)) { + warning("Element (%u) doesn't support layout %u in profile %u.", + cae->base.audio_element_id, layer_config->loudspeaker_layout, + profile); + return def_error; + } + } + return def_pass; +} + +static int _obu_ae_scene_based_check(scene_based_audio_element_obu_t *sae) { + int channels = sae->substream_count + sae->coupled_substream_count; + + if (array_size(sae->base.parameters) > 0) + warning("Scene based audio element(%u) has parameter.", + sae->base.audio_element_id); + + if (iamf_ambisionisc_get_order(sae->output_channel_count) < 0 || + sae->output_channel_count < channels) { + warning( + "Invalid output channel count %d or invalid input channels %d in " + "ambisonics mode", + sae->output_channel_count, channels); + return def_error; + } + return def_pass; +} + +static int _obu_ae_object_based_check(object_based_audio_element_obu_t *oae) { + if (array_size(oae->base.parameters) > 0) + warning("Object based audio element(%u) has parameter.", + oae->base.audio_element_id); + + if (oae->num_objects <= 0) { + warning("Object based audio element(%u) has no objects.", + oae->base.audio_element_id); + return def_error; + } + return def_pass; +} + +int _obu_ae_scene_based_check_profile(scene_based_audio_element_obu_t *sae, + iamf_profile_t profile) { + int channels = sae->substream_count + sae->coupled_substream_count; + const iamf_profile_info_t *info = iamf_profile_info_get(profile); + if (channels > info->max_amb_channels) { + warning("Invalid channels %d in ambisonics mode, it should less than %d", + channels, info->max_amb_channels); + return def_error; + } + return def_pass; +} + +int _obu_ae_check(iamf_audio_element_obu_t *obu) { + if (obu->audio_element_type == ck_audio_element_type_channel_based) + return _obu_ae_channel_based_check( + def_channel_based_audio_element_obu_ptr(obu)); + if (obu->audio_element_type == ck_audio_element_type_scene_based) + return _obu_ae_scene_based_check( + def_scene_based_audio_element_obu_ptr(obu)); + if (obu->audio_element_type == ck_audio_element_type_object_based) + return _obu_ae_object_based_check( + def_object_based_audio_element_obu_ptr(obu)); + return def_error; +} + +int _obu_ae_find_parameter(value_wrap_t item, value_wrap_t key) { + return item.ptr + ? def_value_wrap_type_ptr(parameter_base_t, &item)->type == key.u32 + : 0; +} diff --git a/code/src/iamf_dec/obu/audio_element_obu.h b/code/src/iamf_dec/obu/audio_element_obu.h new file mode 100755 index 00000000..97dd90cb --- /dev/null +++ b/code/src/iamf_dec/obu/audio_element_obu.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file audio_element_obu.h + * @brief Audio element OBU APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __AUDIO_ELEMENT_OBU_H__ +#define __AUDIO_ELEMENT_OBU_H__ + +#include "carray.h" +#include "iamf_obu.h" + +/** + * Audio Element OBU. + * */ + +#define def_audio_element_obu_ptr(a) ((iamf_audio_element_obu_t *)a) +#define def_channel_based_audio_element_obu_ptr(a) \ + ((channel_based_audio_element_obu_t *)a) +#define def_scene_based_audio_element_obu_ptr(a) \ + ((scene_based_audio_element_obu_t *)a) +#define def_object_based_audio_element_obu_ptr(a) \ + ((object_based_audio_element_obu_t *)a) + +typedef enum EIamfAudioElementType { + ck_audio_element_type_none = -1, + ck_audio_element_type_channel_based, + ck_audio_element_type_scene_based, + ck_audio_element_type_object_based, + ck_audio_element_type_count +} iamf_audio_element_type_t; + +typedef enum EIamfAmbisonicsMode { + ck_ambisonics_mode_none = -1, + ck_ambisonics_mode_mono, + ck_ambisonics_mode_projection, + ck_ambisonics_mode_count +} iamf_ambisonics_mode_t; + +typedef struct ObuOutputGainInfo { + uint32_t output_gain_flag; + int output_gain; + float output_gain_linear; +} obu_output_gain_info_t; + +typedef struct ObuChannelLayerConfig { + uint32_t loudspeaker_layout; + uint32_t output_gain_is_present_flag; + uint32_t recon_gain_is_present_flag; + uint32_t substream_count; + uint32_t coupled_substream_count; + obu_output_gain_info_t output_gain_info; + uint32_t expanded_loudspeaker_layout; +} obu_channel_layer_config_t; + +typedef struct IamfAudioElementObu { + iamf_obu_t obu; + + uint32_t audio_element_id; + uint32_t audio_element_type; + + uint32_t codec_config_id; + + array_t *audio_substream_ids; // array + array_t *parameters; // array + +} iamf_audio_element_obu_t; + +typedef struct ChannelBasedAudioElementObu { + iamf_audio_element_obu_t base; + + uint32_t max_valid_layers; // max valid layers + array_t *channel_audio_layer_configs; // array +} channel_based_audio_element_obu_t; + +typedef struct SceneBasedAudioElementObu { + iamf_audio_element_obu_t base; + + uint32_t ambisonics_mode; + uint32_t output_channel_count; // C + uint32_t substream_count; // N + uint32_t coupled_substream_count; // M + union { + uint8_t *channel_mapping; // C array + uint8_t *demixing_matrix; // (N + M) x C matrix) + }; + uint32_t mapping_size; +} scene_based_audio_element_obu_t; + +typedef struct ObjectBasedAudioElementObu { + iamf_audio_element_obu_t base; + + uint32_t num_objects; +} object_based_audio_element_obu_t; + +typedef struct ReservedAudioElementObu { + iamf_audio_element_obu_t base; +} reserved_audio_element_obu_t; + +iamf_audio_element_obu_t *iamf_audio_element_obu_new(io_context_t *ior); +void iamf_audio_element_obu_free(iamf_audio_element_obu_t *obu); +int iamf_audio_element_obu_check_profile(iamf_audio_element_obu_t *obu, + iamf_profile_t profile); +parameter_base_t *iamf_audio_element_obu_get_parameter( + iamf_audio_element_obu_t *obu, iamf_parameter_type_t type); + +#endif // __AUDIO_ELEMENT_OBU_H__ diff --git a/code/src/iamf_dec/obu/audio_frame_obu.c b/code/src/iamf_dec/obu/audio_frame_obu.c new file mode 100755 index 00000000..341ff0a7 --- /dev/null +++ b/code/src/iamf_dec/obu/audio_frame_obu.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file audio_frame_obu.c + * @brief Audio frame OBU implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "audio_frame_obu.h" + +#include "clog.h" +#include "iamf_private_definitions.h" +#include "iamf_string.h" + +#ifdef SUPPORT_VERIFIER +#include "vlogging_tool_sr.h" +#endif + +#undef def_log_tag +#define def_log_tag "OBU_AF" + +iamf_audio_frame_obu_t *iamf_audio_frame_obu_new(io_context_t *ior, + iamf_obu_header_t *header) { + iamf_audio_frame_obu_t *obu = 0; + io_context_t *r = ior; + uint32_t size = 0; + + obu = def_mallocz(iamf_audio_frame_obu_t, 1); + if (!obu) { + def_err_msg_enomem("Audio Frame OBU", def_iamf_ustr); + return 0; + } + + obu->obu.obu_type = header->obu_type; + + if (obu->obu.obu_type == ck_iamf_obu_audio_frame) { + obu->audio_substream_id = ior_leb128_u32(r); + } else { + obu->audio_substream_id = obu->obu.obu_type - ck_iamf_obu_audio_frame_id0; + } + obu->num_samples_to_trim_at_end = header->num_samples_to_trim_at_end; + obu->num_samples_to_trim_at_start = header->num_samples_to_trim_at_start; + size = ioc_remain(r); + + obu->audio_frame = buffer_wrap_new(size); + if (!obu->audio_frame) { + iamf_audio_frame_obu_free(obu); + def_err_msg_enomem("audio frame", "Audio Frame OBU"); + return 0; + } + + ior_read(r, obu->audio_frame->data, size); + + debug( + "Audio Frame OBU: audio_substream_id=%u, num_samples_to_trim_at_start=%u," + "num_samples_to_trim_at_end=%u, size=%u", + obu->audio_substream_id, obu->num_samples_to_trim_at_start, + obu->num_samples_to_trim_at_end, size); + +#if SUPPORT_VERIFIER + vlog_obu(ck_iamf_obu_audio_frame, obu, obu->num_samples_to_trim_at_start, + obu->num_samples_to_trim_at_end); +#endif + + return obu; +} + +void iamf_audio_frame_obu_free(iamf_audio_frame_obu_t *obu) { + if (!obu) return; + if (obu->audio_frame) buffer_wrap_free(obu->audio_frame); + free(obu); +} diff --git a/code/src/iamf_dec/obu/audio_frame_obu.h b/code/src/iamf_dec/obu/audio_frame_obu.h new file mode 100755 index 00000000..b5916bad --- /dev/null +++ b/code/src/iamf_dec/obu/audio_frame_obu.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file audio_frame_obu.h + * @brief Audio frame OBU APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __AUDIO_FRAME_OBU_H__ +#define __AUDIO_FRAME_OBU_H__ + +#include "iamf_obu.h" + +/** + * Audio Frame OBU. + * */ + +#define def_audio_frame_obu_ptr(a) ((iamf_audio_frame_obu_t *)(a)) +typedef struct IamfAudioFrameObu { + iamf_obu_t obu; + + uint32_t audio_substream_id; + + uint32_t num_samples_to_trim_at_end; + uint32_t num_samples_to_trim_at_start; + + buffer_wrap_t *audio_frame; +} iamf_audio_frame_obu_t; + +iamf_audio_frame_obu_t *iamf_audio_frame_obu_new(io_context_t *ior, + iamf_obu_header_t *header); +void iamf_audio_frame_obu_free(iamf_audio_frame_obu_t *obu); +#endif // __AUDIO_FRAME_OBU_H__ diff --git a/code/src/iamf_dec/obu/codec_config_obu.c b/code/src/iamf_dec/obu/codec_config_obu.c new file mode 100755 index 00000000..bae3a06b --- /dev/null +++ b/code/src/iamf_dec/obu/codec_config_obu.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file codec_config_obu.c + * @brief Codec config OBU implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "codec_config_obu.h" + +#include "iamf_private_definitions.h" +#include "iamf_string.h" +#include "iamf_utils.h" + +#ifdef SUPPORT_VERIFIER +#include "vlogging_tool_sr.h" +#endif + +#undef def_log_tag +#define def_log_tag "OBU_CC" + +static int _obu_cc_check(iamf_codec_config_obu_t *obu); +static int _obu_cc_decoder_config_parse(iamf_codec_type_t type, + io_context_t *ioc, + audio_codec_parameter_t *param); + +iamf_codec_config_obu_t *iamf_codec_config_obu_new(io_context_t *ior) { + iamf_codec_config_obu_t *obu = 0; + io_context_t *r = ior; + uint32_t decoder_config_size = 0; + + obu = def_mallocz(iamf_codec_config_obu_t, 1); + if (!obu) { + def_err_msg_enomem("Codec Config OBU", def_iamf_ustr); + return 0; + } + + obu->obu.obu_type = ck_iamf_obu_codec_config; + + obu->codec_config_id = ior_leb128_u32(r); + ior_read(r, (uint8_t *)&obu->codec_id, 4); + obu->num_samples_per_frame = ior_leb128_u32(r); + obu->audio_roll_distance = (int16_t)ior_b16(r); + decoder_config_size = r->size - r->idx; + obu->decoder_config = buffer_wrap_new(decoder_config_size); + + if (!obu->decoder_config) { + def_err_msg_enomem("decoder config", "Codec Config OBU"); + iamf_codec_config_obu_free(obu); + return 0; + } + + ior_read(r, obu->decoder_config->data, decoder_config_size); + + info( + "Codec cofing id(%u), codec id(%.4s), samples per frame(%u), " + "roll distance (%d), decoder config size(%u)", + obu->codec_config_id, (char *)&obu->codec_id, obu->num_samples_per_frame, + obu->audio_roll_distance, obu->decoder_config->size); + +#if SUPPORT_VERIFIER + vlog_obu(ck_iamf_obu_codec_config, obu, 0, 0); +#endif + + if (_obu_cc_check(obu) != def_pass) { + iamf_codec_config_obu_free(obu); + return 0; + } + + return obu; +} + +void iamf_codec_config_obu_free(iamf_codec_config_obu_t *obu) { + if (obu->decoder_config) buffer_wrap_free(obu->decoder_config); + free(obu); +} + +int iamf_codec_config_obu_get_parameter(iamf_codec_config_obu_t *obu, + audio_codec_parameter_t *param) { + io_context_t ioc, *r; + int ret; + + if (!obu || !param) return IAMF_ERR_BAD_ARG; + + r = &ioc; + + param->type = iamf_codec_type_get(obu->codec_id); + param->frame_size = obu->num_samples_per_frame; + + ioc_init(&ioc, obu->decoder_config->data, obu->decoder_config->size); + + ret = _obu_cc_decoder_config_parse(param->type, r, param); + if (ret != IAMF_OK) return ret; + + return IAMF_OK; +} + +static int _obu_cc_codec_id_check(uint32_t codec_id) { + return iamf_codec_id_check(codec_id) ? def_pass : def_error; +} + +#define def_opus_version_max 15 +static int _obu_cc_decoder_config_check(uint32_t codec, buffer_wrap_t *buffer) { + if (iamf_codec_type_get(codec) == ck_iamf_codec_type_opus) { + if (buffer && buffer->data[0] > def_opus_version_max) { + warning("Opus config invalid: version %u should less than %u.", + buffer->data[0], def_opus_version_max); + return def_error; + } + } + + return def_pass; +} + +int _obu_cc_check(iamf_codec_config_obu_t *obu) { + if (_obu_cc_codec_id_check(obu->codec_id) != def_pass) { + warning("Codec config id(%u), invalid codec(%.4s)", obu->codec_config_id, + (char *)&obu->codec_id); + return def_error; + } + + if (!obu->num_samples_per_frame) { + error( + "Codec config id(%u), number of samples per frame should not be zero.", + obu->codec_config_id); + return def_error; + } + + if (_obu_cc_decoder_config_check(obu->codec_id, obu->decoder_config) != + def_pass) { + warning("Codec config id(%u), codec(%.4s), decoder config is invalid, ", + obu->codec_config_id, (char *)&obu->codec_id); + return def_error; + } + + return def_pass; +} + +static int _obu_cc_opus_decoder_config_parse(io_context_t *ioc, + audio_codec_parameter_t *param) { + /** + * @brief OPUS Specific + * b08: version + * b08: channel count + * b16: pre-skip + * b32: input sample rate + * b16: output gain + * b08: mapping family + */ + + // https://aomediacodec.github.io/iamf/v1.1.0.html#opus-specific + // The sample rate used for computing offsets SHALL be 48k Hz. + param->sample_rate = def_default_sampling_rate; + param->bits_per_sample = SAMPLE_BIT_DEPTH_16; + return IAMF_OK; +} + +static int _obu_cc_aac_decoder_config_parse(io_context_t *ioc, + audio_codec_parameter_t *param) { + int ret, type; + io_context_t *r = ioc; + bits_io_context_t bits_ioc, *bits_r; + static uint32_t sf[] = {96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000, + 7350, 0, 0, 0}; + bits_r = &bits_ioc; + bits_ioc_init(bits_r, r); + + /* DecoderConfigDescriptor */ + ior_8(r); + ior_expandable(r); + ior_skip(r, 13); + + /* DecSpecificInfoTag */ + ior_8(r); + ior_expandable(r); + + type = bits_ior_le32(bits_r, 5); + if (type == 31) type = bits_ior_le32(bits_r, 6); + + ret = bits_ior_le32(bits_r, 4); + if (ret == 0xf) + param->sample_rate = bits_ior_le32(bits_r, 24); + else + param->sample_rate = sf[ret]; + return IAMF_OK; +} + +static int _obu_cc_flac_decoder_config_parse(io_context_t *ioc, + audio_codec_parameter_t *param) { + io_context_t *r = ioc; + uint32_t val = 0; + int last, type, size, ret = IAMF_ERR_BAD_ARG; + while (1) { + val = ior_b32(r); + + /** + * @brief METADATA_BLOCK_HEADER + * b01: last metadata block flag + * b07: block_type + * 0x00: STREAMINFO + * b24: length of metdata * + */ + last = val >> 31 & 0x01; + type = val >> 24 & 0x7f; + size = val & 0xffffff; + + if (!type) { + /** + * @brief METADATA_BLOCK_STREAMINFO + * b16: min_block_size + * b16: max_block_size + * b24: min_frame_size + * b24: max_frame_size + * b20: sample_rate + * b03: number_of_channels - 1 + * b05: bits_per_sample - 1 + * b36: total_samples + * b128: MD5 sum * + */ + ior_skip(r, 10); + val = ior_b32(r); + param->sample_rate = val >> 12 & 0xfffff; + param->bits_per_sample = (val >> 4 & 0x1f) + 1; + ret = IAMF_OK; + break; + } else + ior_skip(r, size); + + if (last) break; + } + return ret; +} + +static int _obu_cc_pcm_decoder_config_parse(io_context_t *ioc, + audio_codec_parameter_t *param) { + io_context_t *r = ioc; + + /** + * @brief LPCM Specific + * b08: sample_format_flags: 0x01 - big endian, 0x00 - little endian + * b08: sample_size + * b32: sample_rate + */ + param->big_endian = !ior_8(r); + param->bits_per_sample = ior_8(r); + param->sample_rate = ior_b32(r); + return IAMF_OK; +} + +int _obu_cc_decoder_config_parse(iamf_codec_type_t type, io_context_t *ioc, + audio_codec_parameter_t *param) { + int ret = IAMF_OK; + switch (type) { + case ck_iamf_codec_type_opus: + ret = _obu_cc_opus_decoder_config_parse(ioc, param); + break; + case ck_iamf_codec_type_aac: + ret = _obu_cc_aac_decoder_config_parse(ioc, param); + break; + case ck_iamf_codec_type_flac: + ret = _obu_cc_flac_decoder_config_parse(ioc, param); + break; + case ck_iamf_codec_type_lpcm: + ret = _obu_cc_pcm_decoder_config_parse(ioc, param); + break; + default: + ret = IAMF_ERR_BAD_ARG; + break; + } + + if (ret == IAMF_OK && !param->sample_format) + param->sample_format = def_audio_sample_format_default; + + return ret; +} diff --git a/code/src/iamf_dec/obu/codec_config_obu.h b/code/src/iamf_dec/obu/codec_config_obu.h new file mode 100755 index 00000000..314e092b --- /dev/null +++ b/code/src/iamf_dec/obu/codec_config_obu.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file codec_config_obu.h + * @brief Codec config OBU APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __CODEC_CONFIG_OBU_H__ +#define __CODEC_CONFIG_OBU_H__ + +#include "iamf_obu.h" +#include "iamf_types.h" + +#define def_codec_config_obu_ptr(a) ((iamf_codec_config_obu_t *)a) + +/** + * Codec Config OBU. + * */ + +typedef struct IamfCodecConfigObu { + iamf_obu_t obu; + + uint32_t codec_config_id; + + // codec config + uint32_t codec_id; + uint32_t num_samples_per_frame; + int audio_roll_distance; + + buffer_wrap_t *decoder_config; +} iamf_codec_config_obu_t; + +iamf_codec_config_obu_t *iamf_codec_config_obu_new(io_context_t *ior); +void iamf_codec_config_obu_free(iamf_codec_config_obu_t *obu); +int iamf_codec_config_obu_get_parameter(iamf_codec_config_obu_t *obu, + audio_codec_parameter_t *param); +#endif // __CODEC_CONFIG_OBU_H__ diff --git a/code/src/iamf_dec/obu/ia_sequence_header_obu.c b/code/src/iamf_dec/obu/ia_sequence_header_obu.c new file mode 100755 index 00000000..56219221 --- /dev/null +++ b/code/src/iamf_dec/obu/ia_sequence_header_obu.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file ia_sequence_header_obu.c + * @brief IAMF sequence header OBU implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "ia_sequence_header_obu.h" + +#include "iamf_private_definitions.h" +#include "iamf_string.h" +#include "iamf_types.h" + +#ifdef SUPPORT_VERIFIER +#include "vlogging_tool_sr.h" +#endif + +#undef def_log_tag +#define def_log_tag "OBU_SH" + +static int _obu_sh_check(iamf_sequence_header_obu_t *obu); + +iamf_sequence_header_obu_t *iamf_sequence_header_obu_new(io_context_t *ioc) { + iamf_sequence_header_obu_t *obu = 0; + io_context_t *r = ioc; + + obu = def_mallocz(iamf_sequence_header_obu_t, 1); + if (!obu) { + def_err_msg_enomem("IA Sequence Header OBU", def_iamf_ustr); + return 0; + } + + obu->obu.obu_type = ck_iamf_obu_sequence_header; + + ior_read(r, (uint8_t *)&obu->iamf_code, 4); + obu->primary_profile = ior_8(r); + obu->additional_profile = ior_8(r); + + info("Ia code(%.4s), primary profile(%u), additional profile(%u).", + (char *)&obu->iamf_code, obu->primary_profile, obu->additional_profile); + +#if SUPPORT_VERIFIER + vlog_obu(ck_iamf_obu_sequence_header, obu, 0, 0); +#endif + + if (_obu_sh_check(obu) != def_pass) { + iamf_sequence_header_obu_free(obu); + obu = 0; + } + return obu; +} + +void iamf_sequence_header_obu_free(iamf_sequence_header_obu_t *obu) { + free(obu); +} + +static int _obu_sh_valid_profile(uint8_t primary, uint8_t addional) { + return primary < def_iamf_profile_count && primary <= addional; +} + +int _obu_sh_check(iamf_sequence_header_obu_t *obu) { + union { + uint32_t _id; + uint8_t _4cc[4]; + } code = {._4cc = {'i', 'a', 'm', 'f'}}; + + if (obu->iamf_code != code._id) { + error("Invalid iamf code(%.4s).", (char *)&obu->iamf_code); + return def_error; + } + + if (!_obu_sh_valid_profile(obu->primary_profile, obu->additional_profile)) { + error("Invalid primary profile(%u) or additional profile(%u).", + obu->primary_profile, obu->additional_profile); + return def_error; + } + + return def_pass; +} diff --git a/code/src/iamf_dec/obu/ia_sequence_header_obu.h b/code/src/iamf_dec/obu/ia_sequence_header_obu.h new file mode 100755 index 00000000..27219680 --- /dev/null +++ b/code/src/iamf_dec/obu/ia_sequence_header_obu.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file ia_sequence_header_obu.h + * @brief IAMF sequence header OBU APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IA_SEQUENCE_HEADER_OBU_H__ +#define __IA_SEQUENCE_HEADER_OBU_H__ + +#include "iamf_obu.h" + +/** + * IAMF Sequence Header OBU. + * */ + +#define def_iamf_sequence_header_obu_ptr(a) ((iamf_sequence_header_obu_t *)a) + +typedef struct IamfSequenceHeaderObu { + iamf_obu_t obu; + + uint32_t iamf_code; + uint32_t primary_profile; + uint32_t additional_profile; +} iamf_sequence_header_obu_t; + +iamf_sequence_header_obu_t *iamf_sequence_header_obu_new(io_context_t *ioc); +void iamf_sequence_header_obu_free(iamf_sequence_header_obu_t *obu); +#endif // __IA_SEQUENCE_HEADER_OBU_H__ diff --git a/code/src/iamf_dec/obu/iamf_obu.c b/code/src/iamf_dec/obu/iamf_obu.c new file mode 100755 index 00000000..b05677c0 --- /dev/null +++ b/code/src/iamf_dec/obu/iamf_obu.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_obu.c + * @brief OBU raw APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include +#include + +#include "IAMF_defines.h" +#include "clog.h" +#include "iamf_obu_all.h" +#include "iamf_private_definitions.h" +#include "iamf_string.h" + +#ifdef IA_DBG +#include "debug/iamf_obu_debug.h" +#endif + +// obu_type(5) + obu_redundant_copy(1) + obu_trimming_status_flag(1) + +// obu_extension_flag(1) + obu_size(min:8) +#define def_iamf_obu_min_size 2 + +// 4. Profiles +// The maximum size of an OBU (an OBU Header followed by the OBU payload) SHALL +// be limited to 2MB(2^21). +#define def_iamf_obu_max_size 2097152 + +#undef def_log_tag +#define def_log_tag "IAMF_OBU" + +// ============================================================================================== +static int _iamf_obu_header_init(iamf_obu_header_t *h) { + memset(h, 0, sizeof(iamf_obu_header_t)); + h->obu_type = ck_iamf_obu_none; + return IAMF_OK; +} + +static int _iamf_obu_type_is_audio_frame(iamf_obu_type_t type) { + return type >= ck_iamf_obu_audio_frame && + type <= ck_iamf_obu_audio_frame_id17; +} + +static int _iamf_obu_raw_parse_header(io_context_t *ior, iamf_obu_header_t *h) { + io_context_t *r = ior; + uint32_t obu_extension_flag = 0; + uint32_t val = ior_8(r); + uint32_t obu_size = 0; + + h->obu_type = (val >> 3) & 0x1f; + h->obu_redundant_copy = (val >> 2) & 0x01; + h->obu_trimming_status_flag = (val >> 1) & 0x01; + obu_extension_flag = val & 0x01; + + trace( + "obu header: obu_type(%s<%d>), obu_redundant_copy(%u), " + "%s(%u), obu_extension_flag(%u)", + iamf_obu_type_string(h->obu_type), h->obu_type, h->obu_redundant_copy, + iamf_obu_header_flag2_string(h->obu_type), h->obu_trimming_status_flag, + obu_extension_flag); + + obu_size = ior_leb128_u32(r); + trace("obu header: obu_size(%u)", obu_size); + + if (_iamf_obu_type_is_audio_frame(h->obu_type) && + h->obu_trimming_status_flag) { + h->num_samples_to_trim_at_end = ior_leb128_u32(r); + h->num_samples_to_trim_at_start = ior_leb128_u32(r); + trace( + "obu header: num_samples_to_trim_at_end(%u), " + "num_samples_to_trim_at_start(%u)", + h->num_samples_to_trim_at_end, h->num_samples_to_trim_at_start); + } + + if (obu_extension_flag) { + uint32_t extension_header_size = ior_leb128_u32(r); + ior_skip(r, extension_header_size); // extension_header_bytes + trace("obu header: extension_header_size(%u)", extension_header_size); + } + + return IAMF_OK; +} + +static int _iamf_obu_raw_parse_body(io_context_t *ior, + iamf_obu_header_t *header, + iamf_obu_extra_parameters_t *extra, + iamf_obu_t **obu) { + int ret = IAMF_OK; + switch (header->obu_type) { + case ck_iamf_obu_sequence_header: + *obu = (iamf_obu_t *)iamf_sequence_header_obu_new(ior); + break; + case ck_iamf_obu_codec_config: + *obu = (iamf_obu_t *)iamf_codec_config_obu_new(ior); + break; + case ck_iamf_obu_audio_element: + *obu = (iamf_obu_t *)iamf_audio_element_obu_new(ior); + break; + case ck_iamf_obu_mix_presentation: + *obu = (iamf_obu_t *)iamf_mix_presentation_obu_new(ior, header); + break; + case ck_iamf_obu_parameter_block: + if (extra) + *obu = (iamf_obu_t *)iamf_parameter_block_obu_new( + ior, &extra->pbo_interfaces); + break; + case ck_iamf_obu_temporal_delimiter: + *obu = (iamf_obu_t *)iamf_temporal_delimiter_obu_new(ior, header); + break; + case ck_iamf_obu_metadata: + *obu = (iamf_obu_t *)iamf_metadata_obu_new(ior); + break; + default: + if (header->obu_type >= ck_iamf_obu_audio_frame && + header->obu_type <= ck_iamf_obu_audio_frame_id17) { + *obu = (iamf_obu_t *)iamf_audio_frame_obu_new(ior, header); + } else if (header->obu_type != ck_iamf_obu_temporal_delimiter) { + warning("Reserved OBU type %u", header->obu_type); + } + break; + } + + if (*obu && header->obu_redundant_copy) + (*obu)->obu_flags = ck_iamf_obu_flag_redundant; + return ret; +} + +static int iamf_obu_raw_init(iamf_obu_raw_t *raw, uint8_t *data, + uint32_t size) { + ioc_init(&raw->ioctx, data, size); + return 0; +} + +// ============================================================================================== + +uint32_t iamf_obu_raw_split(uint8_t *data, uint32_t size, iamf_obu_raw_t *raw) { + io_context_t ioc, *r; + uint32_t val; + + if (size < def_iamf_obu_min_size) return 0; + + r = &ioc; + ioc_init(r, data, size); + ior_8(r); + val = ior_leb128_u32(r); + + if (val > ioc_remain(r)) return 0; + + ior_skip(r, val); + val = ioc_tell(r); + iamf_obu_raw_init(raw, data, val); + +#ifdef IA_DBG + obu_dump(data, val, (data[0] >> 3) & 0x1f); +#endif + + return val; +} + +int iamf_obu_raw_check(iamf_obu_raw_t *raw) { + return !(!raw->ioctx.buffer || raw->ioctx.size < def_iamf_obu_min_size || + raw->ioctx.size > def_iamf_obu_max_size); +} + +int iamf_obu_raw_is_reserved_obu(iamf_obu_raw_t *raw, iamf_profile_t profile) { + iamf_obu_type_t type = ck_iamf_obu_none; + + if (!iamf_obu_raw_check(raw)) return 0; + + type = (raw->ioctx.buffer[0] >> 3) & 0x1f; + return (type >= ck_iamf_obu_reserved_start && + type <= ck_iamf_obu_reserved_end) || + (profile > ck_iamf_profile_base_enhanced + ? 0 + : type == ck_iamf_obu_metadata); +} + +iamf_obu_t *iamf_obu_new(iamf_obu_raw_t *raw, + iamf_obu_extra_parameters_t *param) { + iamf_obu_t *obu = 0; + io_context_t *r; + iamf_obu_header_t header; + + r = &raw->ioctx; + + _iamf_obu_header_init(&header); + trace("raw obu size(%u)", ioc_remain(r)); + _iamf_obu_raw_parse_header(r, &header); + trace("obu header size(%u), obu body size(%u)", ioc_tell(r), ioc_remain(r)); + _iamf_obu_raw_parse_body(r, &header, param, &obu); + + return obu; +} + +void iamf_obu_free(iamf_obu_t *obu) { + if (!obu) return; + + trace("freeing obu type %s<%d>", iamf_obu_type_string(obu->obu_type), + obu->obu_type); + switch (obu->obu_type) { + case ck_iamf_obu_sequence_header: + iamf_sequence_header_obu_free((iamf_sequence_header_obu_t *)obu); + break; + case ck_iamf_obu_codec_config: + iamf_codec_config_obu_free((iamf_codec_config_obu_t *)obu); + break; + case ck_iamf_obu_audio_element: + iamf_audio_element_obu_free((iamf_audio_element_obu_t *)obu); + break; + case ck_iamf_obu_mix_presentation: + iamf_mix_presentation_obu_free((iamf_mix_presentation_obu_t *)obu); + break; + case ck_iamf_obu_parameter_block: + iamf_parameter_block_obu_free((iamf_parameter_block_obu_t *)obu); + break; + case ck_iamf_obu_temporal_delimiter: + iamf_temporal_delimiter_obu_free((iamf_temporal_delimiter_obu_t *)obu); + break; + case ck_iamf_obu_metadata: + iamf_metadata_obu_free((iamf_metadata_obu_t *)obu); + break; + default: + if (_iamf_obu_type_is_audio_frame(obu->obu_type)) + iamf_audio_frame_obu_free((iamf_audio_frame_obu_t *)obu); + break; + } +} + +int iamf_obu_is_descriptor(iamf_obu_t *obu) { + return obu->obu_type == ck_iamf_obu_sequence_header || + obu->obu_type == ck_iamf_obu_codec_config || + obu->obu_type == ck_iamf_obu_audio_element || + obu->obu_type == ck_iamf_obu_metadata || + obu->obu_type == ck_iamf_obu_mix_presentation; +} + +int iamf_obu_is_redundant_copy(iamf_obu_t *obu) { + return obu->obu_flags & ck_iamf_obu_flag_redundant; +} + +const iamf_profile_info_t *iamf_profile_info_get(iamf_profile_t profile) { + static const iamf_profile_info_t _profile_limit[def_iamf_profile_count] = { + {1, 16, 16, 1, 1}, // simple profile + {2, 18, 16, 1, 1}, // base profile + {28, 28, 25, 1, 1}, // base-enhanced profile + {18, 18, 16, 2, 2}, // base-advanced profile + {18, 18, 16, 2, 2}, // advanced profile 1 + {28, 28, 25, 2, 2}, // advanced profile 2 + }; + + if (profile < def_iamf_profile_count) return &_profile_limit[profile]; + return 0; +} + +iamf_tag_t *iamf_tag_new(io_context_t *ior) { + io_context_t *r = ior; + iamf_tag_t *tag = def_mallocz(iamf_tag_t, 1); + + if (tag) { + ior_string(r, tag->name, sizeof(string128_t)); + ior_string(r, tag->value, sizeof(string128_t)); + } + + return tag; +} diff --git a/code/src/iamf_dec/obu/iamf_obu.h b/code/src/iamf_dec/obu/iamf_obu.h new file mode 100755 index 00000000..bbba1694 --- /dev/null +++ b/code/src/iamf_dec/obu/iamf_obu.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_obu.h + * @brief OBU APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_OBU_H__ +#define __IAMF_OBU_H__ + +#include "IAMF_defines.h" +#include "carray.h" +#include "cbuffer.h" +#include "parameter_base.h" + +/// @brief The IA profile. +typedef enum EIamfProfile { + /// @brief the invalid profile. + ck_iamf_profile_none = -1, + /// @brief the simple profile. + ck_iamf_profile_simple, + /// @brief the base profile. + ck_iamf_profile_base, + /// @brief the base-enhanced profile. + ck_iamf_profile_base_enhanced, + /// @brief the base advanced profile. + ck_iamf_profile_base_advanced, + /// @brief the advanced profile 1. + ck_iamf_profile_advanced_1, + /// @brief the advanced profile 2. + ck_iamf_profile_advanced_2, +} iamf_profile_t; + +typedef enum EIamfObuType { + ck_iamf_obu_none = -1, + ck_iamf_obu_codec_config, + ck_iamf_obu_audio_element, + ck_iamf_obu_mix_presentation, + ck_iamf_obu_parameter_block, + ck_iamf_obu_temporal_delimiter, + ck_iamf_obu_audio_frame, + ck_iamf_obu_audio_frame_id0, + ck_iamf_obu_audio_frame_id1, + ck_iamf_obu_audio_frame_id2, + ck_iamf_obu_audio_frame_id3, + ck_iamf_obu_audio_frame_id4, + ck_iamf_obu_audio_frame_id5, + ck_iamf_obu_audio_frame_id6, + ck_iamf_obu_audio_frame_id7, + ck_iamf_obu_audio_frame_id8, + ck_iamf_obu_audio_frame_id9, + ck_iamf_obu_audio_frame_id10, + ck_iamf_obu_audio_frame_id11, + ck_iamf_obu_audio_frame_id12, + ck_iamf_obu_audio_frame_id13, + ck_iamf_obu_audio_frame_id14, + ck_iamf_obu_audio_frame_id15, + ck_iamf_obu_audio_frame_id16, + ck_iamf_obu_audio_frame_id17, + ck_iamf_obu_metadata, + ck_iamf_obu_reserved_start, + ck_iamf_obu_reserved_end = 30, + ck_iamf_obu_sequence_header = 31, + ck_iamf_obu_count, +} iamf_obu_type_t; + +typedef enum EIamfObuFlag { + ck_iamf_obu_flag_redundant = 0x1, +} iamf_obu_flag_t; + +typedef struct IamfObuRaw { + io_context_t ioctx; +} iamf_obu_raw_t; + +typedef struct IamfObuHeader { + iamf_obu_type_t obu_type; + uint8_t obu_redundant_copy; + union { + struct { + uint8_t obu_trimming_status_flag; + uint32_t num_samples_to_trim_at_end; + uint32_t num_samples_to_trim_at_start; + }; + + uint8_t is_not_key_frame; + uint8_t optional_fields_flag; + uint8_t reserved; + }; +} iamf_obu_header_t; + +typedef struct IamfObu { + iamf_obu_type_t obu_type; + uint32_t obu_flags; +} iamf_obu_t; + +typedef char(string128_t)[128]; + +typedef struct IamfTag { + string128_t name; + string128_t value; +} iamf_tag_t; + +typedef parameter_base_t *(*fun_get_parameter_base_t)(void *, uint32_t); +typedef array_t *(*fun_get_recon_gain_present_flags_t)(void *, uint32_t); + +typedef struct IamfParameterBlockObuExtraInterfaces { + void *this; + fun_get_parameter_base_t get_parameter_base; + fun_get_recon_gain_present_flags_t get_recon_gain_present_flags; +} iamf_pbo_extra_interfaces_t; + +typedef struct IamfObuExtraParameters { + iamf_pbo_extra_interfaces_t pbo_interfaces; +} iamf_obu_extra_parameters_t; + +typedef struct IamfProfileInfo { + /// @brief The maximum number of elements in a mix-presentation. + const uint32_t max_elements; + /// @brief The maximum number of channels in a mix-presentation. + const uint32_t max_channels; + /// @brief The maximum number of channels in a ambisonics element. + const uint32_t max_amb_channels; + /// @brief The maximum number of sub-mixes in a mix-presentation. + const uint32_t max_sub_mixes; + /// @brief The maximum value of headphone rendering mode. + const uint32_t max_available_headphone_rendering_mode; +} iamf_profile_info_t; + +uint32_t iamf_obu_raw_split(uint8_t *data, uint32_t size, iamf_obu_raw_t *raw); +int iamf_obu_raw_check(iamf_obu_raw_t *raw); +int iamf_obu_raw_is_reserved_obu(iamf_obu_raw_t *raw, iamf_profile_t profile); +iamf_obu_t *iamf_obu_new(iamf_obu_raw_t *raw, + iamf_obu_extra_parameters_t *param); +void iamf_obu_free(iamf_obu_t *obu); + +int iamf_obu_is_descriptor(iamf_obu_t *obu); +int iamf_obu_is_redundant_copy(iamf_obu_t *obu); + +const iamf_profile_info_t *iamf_profile_info_get(iamf_profile_t profile); + +iamf_tag_t *iamf_tag_new(io_context_t *ior); + +#endif // __IAMF_OBU_H__ diff --git a/code/src/iamf_dec/obu/iamf_obu_all.h b/code/src/iamf_dec/obu/iamf_obu_all.h new file mode 100755 index 00000000..b64babee --- /dev/null +++ b/code/src/iamf_dec/obu/iamf_obu_all.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamf_obu_all.h + * @brief IAMF OBU all APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMF_OBU_ALL_H__ +#define __IAMF_OBU_ALL_H__ + +#include "audio_element_obu.h" +#include "audio_frame_obu.h" +#include "codec_config_obu.h" +#include "ia_sequence_header_obu.h" +#include "iamf_obu.h" +#include "metadata_obu.h" +#include "mix_presentation_obu.h" +#include "parameter_block_obu.h" +#include "temporal_delimiter_obu.h" + +#endif // __IAMF_OBU_ALL_H__ diff --git a/code/src/iamf_dec/obu/metadata_obu.c b/code/src/iamf_dec/obu/metadata_obu.c new file mode 100755 index 00000000..db62ac9b --- /dev/null +++ b/code/src/iamf_dec/obu/metadata_obu.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file metadata_obu.c + * @brief Metadata OBU implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "metadata_obu.h" + +#include +#include + +#include "iamf_private_definitions.h" +#include "iamf_string.h" + +#ifdef SUPPORT_VERIFIER +#include "vlogging_tool_sr.h" +#endif + +#undef def_log_tag +#define def_log_tag "OBU_MD" +#define def_metadata_str "Metadata OBU" + +static void _metadata_itut_t35_delete(metadata_itut_t35_t *metadata); + +static metadata_itut_t35_t *_metadata_itut_t35_new(io_context_t *ior) { + io_context_t *r = ior; + metadata_itut_t35_t *metadata = 0; + + metadata = (metadata_itut_t35_t *)def_mallocz(metadata_itut_t35_t, 1); + if (!metadata) { + def_err_msg_enomem("Metadata ITU-T T.35", def_metadata_str); + return 0; + } + + metadata->metadata.obu.obu_type = ck_iamf_obu_metadata; + metadata->metadata.metadata_type = ck_iamf_metadata_type_itut_t35; + + // Read country code + metadata->itu_t_t35_country_code = ior_8(r); + info("ITU-T T.35 Country Code: 0x%02X", metadata->itu_t_t35_country_code); + + // If country code is 0xFF, read country code extension byte + if (metadata->itu_t_t35_country_code == 0xFF) { + metadata->itu_t_t35_country_code_extension_byte = ior_8(r); + info("ITU-T T.35 Country Code Extension Byte: 0x%02X", + metadata->itu_t_t35_country_code_extension_byte); + } + + // Calculate and read payload data + metadata->itu_t_t35_payload_size = ioc_remain(r); + + if (metadata->itu_t_t35_payload_size > 0) { + metadata->itu_t_t35_payload_bytes = + (uint8_t *)def_malloc(uint8_t, metadata->itu_t_t35_payload_size); + if (!metadata->itu_t_t35_payload_bytes) { + def_err_msg_enomem("ITU-T T.35 payload bytes", def_metadata_str); + _metadata_itut_t35_delete(metadata); + return 0; + } + + // Read payload data + ior_read(r, metadata->itu_t_t35_payload_bytes, + metadata->itu_t_t35_payload_size); + } else { + metadata->itu_t_t35_payload_bytes = 0; + } + info("ITU-T T.35 Payload Size: %u bytes", metadata->itu_t_t35_payload_size); + + return metadata; +} + +void _metadata_itut_t35_delete(metadata_itut_t35_t *metadata) { + if (!metadata) return; + + def_free(metadata->itu_t_t35_payload_bytes); + metadata->itu_t_t35_payload_bytes = 0; + metadata->itu_t_t35_payload_size = 0; + def_free(metadata); +} + +static void _metadata_iamf_tags_delete(metadata_iamf_tags *metadata); + +static metadata_iamf_tags *_metadata_iamf_tags_new(io_context_t *ior) { + io_context_t *r = ior; + metadata_iamf_tags *metadata = 0; + int n = 0; + + metadata = (metadata_iamf_tags *)def_malloc(metadata_iamf_tags, 1); + if (!metadata) { + def_err_msg_enomem("Metadata IAMF Tags", def_metadata_str); + return 0; + } + + metadata->metadata.obu.obu_type = ck_iamf_obu_metadata; + metadata->metadata.metadata_type = ck_iamf_metadata_type_iamf_tags; + + n = ior_8(r); + info("IAMF Tags count: %d", n); + if (n > 0) { + metadata->tags = array_new(n); + if (!metadata->tags) { + def_err_msg_enomem("IAMF Tags array", def_metadata_str); + _metadata_iamf_tags_delete(metadata); + return 0; + } + + for (int i = 0; i < n; i++) { + iamf_tag_t *tag = iamf_tag_new(r); + if (!tag) { + def_err_msg_enomem("IAMF Tag", def_metadata_str); + _metadata_iamf_tags_delete(metadata); + return 0; + } + def_value_wrap_ptr(array_at(metadata->tags, i)) = tag; + } + } + + return metadata; +} + +void _metadata_iamf_tags_delete(metadata_iamf_tags *metadata) { + if (!metadata) return; + + array_free(metadata->tags, free); + def_free(metadata); +} + +iamf_metadata_obu_t *iamf_metadata_obu_new(io_context_t *ior) { + io_context_t *r = ior; + iamf_metadata_obu_t *obu = 0; + uint32_t metadata_type; + + if (!ior) { + error("Invalid I/O context"); + return 0; + } + + metadata_type = ior_leb128_u32(r); + info("New Metadata OBU, type: %u", metadata_type); + + switch (metadata_type) { + case ck_iamf_metadata_type_itut_t35: { + metadata_itut_t35_t *itu_t35_metadata = _metadata_itut_t35_new(r); + obu = (iamf_metadata_obu_t *)itu_t35_metadata; + break; + } + + case ck_iamf_metadata_type_iamf_tags: { + metadata_iamf_tags *tags_metadata = _metadata_iamf_tags_new(r); + obu = (iamf_metadata_obu_t *)tags_metadata; + break; + } + + default: + warning("Unsupport metadata type: %u", metadata_type); + return 0; + } + +#if SUPPORT_VERIFIER + vlog_obu(ck_iamf_obu_metadata, obu, 0, 0); +#endif + + return obu; +} + +void iamf_metadata_obu_free(iamf_metadata_obu_t *obu) { + if (!obu) return; + + debug("Free iamf_metadata_obu_t %p", obu); + + switch (obu->metadata_type) { + case ck_iamf_metadata_type_itut_t35: { + metadata_itut_t35_t *itu_t35_metadata = (metadata_itut_t35_t *)obu; + _metadata_itut_t35_delete(itu_t35_metadata); + break; + } + case ck_iamf_metadata_type_iamf_tags: { + metadata_iamf_tags *tags_metadata = (metadata_iamf_tags *)obu; + _metadata_iamf_tags_delete(tags_metadata); + break; + } + default: + // For other types, just free the basic structure + def_free(obu); + } +} diff --git a/code/src/iamf_dec/obu/metadata_obu.h b/code/src/iamf_dec/obu/metadata_obu.h new file mode 100755 index 00000000..ec9eef80 --- /dev/null +++ b/code/src/iamf_dec/obu/metadata_obu.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file metadata_obu.h + * @brief Metadata OBU APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __METADATA_OBU_H__ +#define __METADATA_OBU_H__ + +#include "iamf_obu.h" + +/** + * Metadata OBU. + * */ + +typedef enum EIamfMetadataType { + ck_iamf_metadata_type_reserved_0 = 0, + ck_iamf_metadata_type_itut_t35 = 1, + ck_iamf_metadata_type_iamf_tags = 2, + ck_iamf_metadata_type_reserved_start = 3, + ck_iamf_metadata_type_reserved_end = 63, + ck_iamf_metadata_type_unregistered_user_private_start = 64, + ck_iamf_metadata_type_unregistered_user_private_end = 127, + ck_iamf_metadata_type_reserved_future_start = 128 +} iamf_metadata_type_t; + +typedef struct IamfMetadataObu { + iamf_obu_t obu; + iamf_metadata_type_t metadata_type; +} iamf_metadata_obu_t; + +typedef struct MetadataITUTT35 { + iamf_metadata_obu_t metadata; + uint8_t itu_t_t35_country_code; + uint8_t + itu_t_t35_country_code_extension_byte; // Present if + // itu_t_t35_country_code == 0xFF + uint8_t *itu_t_t35_payload_bytes; + uint32_t itu_t_t35_payload_size; +} metadata_itut_t35_t; + +typedef struct MetadataIamfTags { + iamf_metadata_obu_t metadata; + array_t *tags; // array of iamf_tag_t *'s. +} metadata_iamf_tags; + +iamf_metadata_obu_t *iamf_metadata_obu_new(io_context_t *ior); +void iamf_metadata_obu_free(iamf_metadata_obu_t *obu); +#endif // __METADATA_OBU_H__ diff --git a/code/src/iamf_dec/obu/mix_presentation_obu.c b/code/src/iamf_dec/obu/mix_presentation_obu.c new file mode 100755 index 00000000..491954af --- /dev/null +++ b/code/src/iamf_dec/obu/mix_presentation_obu.c @@ -0,0 +1,760 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file mix_presentation_obu.c + * @brief Mix presentation OBU implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "mix_presentation_obu.h" + +#include "audio_element_obu.h" +#include "iamf_layout.h" +#include "iamf_private_definitions.h" +#include "iamf_string.h" +#include "iamf_types.h" + +#ifdef SUPPORT_VERIFIER +#include "vlogging_tool_sr.h" +#endif + +#undef def_log_tag +#define def_log_tag "OBU_MP" +#define def_mp_str "Mix Presentation OBU" + +#define def_loudness_info_type_base \ + (def_loudness_info_type_true_peak | def_loudness_info_type_anchored) + +static int _obu_mp_read_n_strings(io_context_t *r, uint32_t count, + array_t *array); +static obu_sub_mix_t *_obu_mp_sub_mix_new(io_context_t *ior, + uint32_t count_label); +static void _obu_mp_sub_mix_free(obu_sub_mix_t *sub); +static void _obu_mp_loudness_info_free(obu_loudness_info_t *info); +static int _obu_mp_check(iamf_mix_presentation_obu_t *obu); +static int _obu_mp_find_audio_element(value_wrap_t a, value_wrap_t b); +static int _obu_mp_tag_check(const char *name, const char *value); + +iamf_mix_presentation_obu_t *iamf_mix_presentation_obu_new( + io_context_t *ior, iamf_obu_header_t *header) { + io_context_t *r = ior; + iamf_mix_presentation_obu_t *obu = 0; + uint32_t count_label, val; + + obu = def_mallocz(iamf_mix_presentation_obu_t, 1); + if (!obu) { + def_err_msg_enomem(def_mp_str, def_iamf_ustr); + return 0; + } + + obu->obu.obu_type = ck_iamf_obu_mix_presentation; + + obu->mix_presentation_id = ior_leb128_u32(r); + count_label = ior_leb128_u32(r); // count_label + + if (count_label > 0) { + obu->annotations_languages = array_new(count_label); + obu->localized_presentation_annotations = array_new(count_label); + + if (!obu->annotations_languages || + !obu->localized_presentation_annotations) { + if (!obu->annotations_languages) + def_err_msg_enomem("languages", def_mp_str); + if (!obu->localized_presentation_annotations) + def_err_msg_enomem("annotations", def_mp_str); + iamf_mix_presentation_obu_free(obu); + return 0; + } + + info("Mix presentation id(%u), count label(%u).", obu->mix_presentation_id, + count_label); + + _obu_mp_read_n_strings(r, count_label, obu->annotations_languages); + _obu_mp_read_n_strings(r, count_label, + obu->localized_presentation_annotations); + + for (uint32_t i = 0; i < count_label; ++i) { + info("label(%u):", i); + info("\tAnnotation language: %s", + (char *)def_value_wrap_ptr(array_at(obu->annotations_languages, i))); + info("\tLocalized presentation annotation: %s", + (char *)def_value_wrap_ptr( + array_at(obu->localized_presentation_annotations, i))); + } + } + + val = ior_leb128_u32(r); // num_sub_mixes + obu->sub_mixes = array_new(val); + + if (!obu->sub_mixes) { + def_err_msg_enomem("sub-mixes", def_mp_str); + iamf_mix_presentation_obu_free(obu); + return 0; + } + + info("Number of sub mixes(%u):", val); + + for (uint32_t i = 0; i < val; ++i) { + obu_sub_mix_t *sub = _obu_mp_sub_mix_new(r, count_label); + if (!sub) { + def_err_msg_enomem("sub mix", def_mp_str); + iamf_mix_presentation_obu_free(obu); + return 0; + } + def_value_wrap_ptr(array_at(obu->sub_mixes, i)) = sub; + } + + val = ioc_remain(r); + + if (val) { + val = ior_8(r); + info("Number of mix presentation tags(%u):", val); + if (val) { + obu->mix_presentation_tags = array_new(val); + if (!obu->mix_presentation_tags) { + def_err_msg_enomem("tags", def_mp_str); + iamf_mix_presentation_obu_free(obu); + return 0; + } + + for (uint32_t i = 0; i < val; ++i) { + value_wrap_t *v = 0; + iamf_tag_t *tag = iamf_tag_new(r); + if (!tag) { + iamf_mix_presentation_obu_free(obu); + return 0; + } + info("\tTag(%u): (%s:%s)", i, tag->name, tag->value); + v = array_at(obu->mix_presentation_tags, i); + v->ptr = tag; + } + } + + if (header && header->optional_fields_flag) { + uint32_t size = ior_leb128_u32(r); + obu->preferred_loudspeaker_renderer = ior_8(r); + obu->preferred_binaural_renderer = ior_8(r); + ior_skip(r, size - 2); + info( + "Preferred loudspeaker renderer(%u), preferred binaural renderer(%u)", + obu->preferred_loudspeaker_renderer, + obu->preferred_binaural_renderer); + } + } + +#if SUPPORT_VERIFIER + vlog_obu(ck_iamf_obu_mix_presentation, obu, 0, 0); +#endif + + if (!_obu_mp_check(obu)) { + iamf_mix_presentation_obu_free(obu); + return 0; + } + + return obu; +} + +void iamf_mix_presentation_obu_free(iamf_mix_presentation_obu_t *obu) { + if (!obu) return; + + if (obu->annotations_languages) array_free(obu->annotations_languages, free); + if (obu->localized_presentation_annotations) + array_free(obu->localized_presentation_annotations, free); + if (obu->sub_mixes) + array_free(obu->sub_mixes, def_default_free_ptr(_obu_mp_sub_mix_free)); + if (obu->mix_presentation_tags) array_free(obu->mix_presentation_tags, free); + + free(obu); +} + +int iamf_mix_presentation_obu_check_profile(iamf_mix_presentation_obu_t *obu, + vector_t *audio_element_obus, + iamf_profile_t profile) { + value_wrap_t v; + obu_sub_mix_t *sub = 0; + int n = 0; + obu_audio_element_config_t *aelem_config; + iamf_audio_element_obu_t *audio_element_obu; + int channels = 0, elements = 0; + const iamf_profile_info_t *info = iamf_profile_info_get(profile); + + n = array_size(obu->sub_mixes); + if (n > info->max_sub_mixes) { + warning( + "Too many sub mixes %u (should be <= %u) in mix presentation %u for " + "%s(%u", + n, info->max_sub_mixes, obu->mix_presentation_id, + iamf_profile_type_string(profile), profile); + return def_error; + } + + for (int i = 0; i < n; ++i) { + int num = 0; + sub = def_value_wrap_optional_ptr(array_at(obu->sub_mixes, i)); + num = array_size(sub->audio_element_configs); + elements += num; + + if (elements > info->max_elements) { + warning( + "Too many elements %u (should be <= %u) in mix presentation %u for " + "%s(%u)", + elements, info->max_elements, obu->mix_presentation_id, + iamf_profile_type_string(profile), profile); + return def_error; + } + + for (int e = 0; e < num; ++e) { + aelem_config = + def_value_wrap_optional_ptr(array_at(sub->audio_element_configs, e)); + if (vector_find(audio_element_obus, + def_value_wrap_instance_u32(aelem_config->element_id), + _obu_mp_find_audio_element, &v) < 0) { + warning("Invalid element %u in mix presentation %u", + aelem_config->element_id, obu->mix_presentation_id); + return def_error; + } + + if (aelem_config->rendering_config.headphones_rendering_mode > + info->max_available_headphone_rendering_mode) { + warning( + "Invalid headphones rendering mode %d in element %u of mix " + "presentation %u for profile %s(%u).", + aelem_config->rendering_config.headphones_rendering_mode, + aelem_config->element_id, obu->mix_presentation_id, + iamf_profile_type_string(profile), profile); + return def_error; + } + + audio_element_obu = v.ptr; + if (audio_element_obu->audio_element_type == + ck_audio_element_type_channel_based) { + channel_based_audio_element_obu_t *cae = + def_channel_based_audio_element_obu_ptr(audio_element_obu); + obu_channel_layer_config_t *layer_config = + def_value_wrap_optional_ptr(array_at( + cae->channel_audio_layer_configs, cae->max_valid_layers - 1)); + channels += iamf_loudspeaker_layout_get_info( + iamf_audio_layer_layout_get( + layer_config->loudspeaker_layout, + layer_config->expanded_loudspeaker_layout)) + ->channels; + } else if (audio_element_obu->audio_element_type == + ck_audio_element_type_scene_based) { + scene_based_audio_element_obu_t *sae = + def_scene_based_audio_element_obu_ptr(audio_element_obu); + channels += sae->output_channel_count; + } else if (audio_element_obu->audio_element_type == + ck_audio_element_type_object_based) { + object_based_audio_element_obu_t *oae = + def_object_based_audio_element_obu_ptr(audio_element_obu); + channels += oae->num_objects; + } + + if (channels > info->max_channels) { + warning("Id (%u) has %d channels, more than %u", + obu->mix_presentation_id, channels, info->max_channels); + return def_error; + } + } + } + + return def_pass; +} + +int _obu_mp_read_n_strings(io_context_t *ior, uint32_t count, array_t *array) { + io_context_t *r = ior; + string128_t str; + for (uint32_t i = 0; i < count; ++i) { + value_wrap_t *v = 0; + string128_t *s = def_mallocz(string128_t, 1); + + v = array_at(array, i); + if (!s) { + def_err_msg_enomem("string128", def_mp_str); + s = &str; + } else { + v->ptr = s; + } + + ior_string(r, (char *)s, sizeof(string128_t)); + } + return IAMF_OK; +} + +static int _obu_mp_rendering_config_init(obu_rendering_config_t *config, + io_context_t *ior) { + io_context_t *r = ior; + uint32_t val; + int ret = IAMF_OK; + + val = ior_8(r); + + config->headphones_rendering_mode = val >> 6 & 0x3; + if (val >> 5 & 0x1) + config->flags |= def_rendering_config_flag_element_gain_offset; + config->binaural_filter_profile = val >> 3 & 0x03; + config->rendering_config_extension_size = ior_leb128_u32(r); + if (config->rendering_config_extension_size > 0) { + uint32_t pos = ioc_tell(ior); + uint32_t num_parameters = ior_leb128_u32(r); + if (num_parameters > 0) { + config->parameters = array_new(num_parameters); + info("Rendering config parameters(%u)", num_parameters); + if (!config->parameters) { + def_err_msg_enomem("parameters", def_mp_str); + ret = IAMF_ERR_ALLOC_FAIL; + } else { + for (uint32_t j = 0; j < num_parameters; ++j) { + value_wrap_t *v = 0; + iamf_parameter_type_t param_definition_type = ior_leb128_u32(r); + debug("Parameter definition type %u", param_definition_type); + if (iamf_parameter_type_is_coordinate(param_definition_type)) { + parameter_base_t *param = + iamf_parameter_base_new(r, param_definition_type); + if (!param) { + def_err_msg_enomem("parameter", def_mp_str); + ret = IAMF_ERR_ALLOC_FAIL; + break; + } + v = array_at(config->parameters, j); + v->ptr = param; + } else { + uint32_t rendering_config_params_extension_size = ior_leb128_u32(r); + ior_skip(r, rendering_config_params_extension_size); + } + } + } + } + if (config->flags & def_rendering_config_flag_element_gain_offset) { + config->element_gain_offset_type = ior_8(r); + if (config->element_gain_offset_type == + ck_element_gain_offset_type_value) { + config->element_gain_offset.value = (int16_t)ior_b16(r); + + debug("encoded element gain offset value 0x%04x", + config->element_gain_offset.value); + + config->element_gain_offset_db.value = + config->element_gain_offset_db.min = + config->element_gain_offset_db.max = + iamf_gain_q78_to_db(config->element_gain_offset.value); + + info("element gain offset value %f dB", + config->element_gain_offset_db.value); + } else if (config->element_gain_offset_type == + ck_element_gain_offset_type_range) { + float min, max; + config->element_gain_offset.value = (int16_t)ior_b16(r); + config->element_gain_offset.min = (int16_t)ior_b16(r); + config->element_gain_offset.max = (int16_t)ior_b16(r); + + debug( + "encoded element gain offset value 0x%04x, min 0x%04x, max 0x%04x", + def_lsb_16bits(config->element_gain_offset.value), + def_lsb_16bits(config->element_gain_offset.min), + def_lsb_16bits(config->element_gain_offset.max)); + + min = iamf_gain_q78_to_db(config->element_gain_offset.min); + if (min > 0.f) min = 0.f; + max = iamf_gain_q78_to_db(config->element_gain_offset.max); + if (max < 0.f) max = 0.f; + + config->element_gain_offset_db.value = + iamf_gain_q78_to_db(config->element_gain_offset.value); + config->element_gain_offset_db.min = + min + config->element_gain_offset_db.value; + config->element_gain_offset_db.max = + max + config->element_gain_offset_db.value; + + info("element gain offset value %f dB, min %f dB, max %f dB", + config->element_gain_offset_db.value, + config->element_gain_offset_db.min, + config->element_gain_offset_db.max); + } else { + config->rendering_config_extension_size = ior_leb128_u32(r); + ior_skip(r, config->rendering_config_extension_size); + } + } + ior_skip(r, + config->rendering_config_extension_size - (ioc_tell(ior) - pos)); + } + + info("%s: headphones rendering mode(%u), binaural filter profile(%u)", + def_mp_str, config->headphones_rendering_mode, + config->binaural_filter_profile); + info("%s: skip extension size(%u)", def_mp_str, + config->rendering_config_extension_size); + + return IAMF_OK; +} + +static void _obu_mp_audio_element_config_free( + obu_audio_element_config_t *config) { + if (!config) return; + if (config->localized_element_annotations) + array_free(config->localized_element_annotations, free); + if (config->rendering_config.parameters) + array_free(config->rendering_config.parameters, + def_default_free_ptr(iamf_parameter_base_free)); + mix_gain_parameter_base_clear(&config->element_mix_gain); + free(config); +} + +static obu_audio_element_config_t *_obu_mp_audio_element_config_new( + io_context_t *ior, uint32_t count_label) { + io_context_t *r = ior; + obu_audio_element_config_t *config = + def_mallocz(obu_audio_element_config_t, 1); + + if (!config) { + def_err_msg_enomem("audio element config", def_mp_str); + return 0; + } + + config->element_id = ior_leb128_u32(r); + info("Element id(%u)", config->element_id); + if (count_label) { + config->localized_element_annotations = array_new(count_label); + if (!config->localized_element_annotations) { + def_err_msg_enomem("localized element annotations", def_mp_str); + _obu_mp_audio_element_config_free(config); + return 0; + } + + _obu_mp_read_n_strings(r, count_label, + config->localized_element_annotations); + + for (uint32_t i = 0; i < count_label; ++i) { + info("Localized element annotation: %s", + (char *)def_value_wrap_ptr( + array_at(config->localized_element_annotations, i))); + } + } + + _obu_mp_rendering_config_init(&config->rendering_config, r); + info("%s: element mix gain:", def_mp_str); + mix_gain_parameter_base_init(&config->element_mix_gain, r); + + return config; +} + +static iamf_layout_t *_obu_mp_layout_new(io_context_t *ior) { + io_context_t *r = ior; + uint32_t val; + iamf_layout_t *layout = def_mallocz(iamf_layout_t, 1); + + if (!layout) { + def_err_msg_enomem("layout", def_mp_str); + return 0; + } + + val = ior_8(r); + layout->type = val >> 6 & 0x03; + if (layout->type == ck_iamf_layout_type_loudspeakers_ss_convention) { + layout->sound_system = val >> 2 & 0x0f; + info("Layout type(%u), %s<%u>", layout->type, + iamf_sound_system_string(layout->sound_system), layout->sound_system); + } else { + info("Layout type(%u)", layout->type); + } + + return layout; +} + +static obu_anchored_loudness_info_t *_obu_mp_anchor_loudness_new( + io_context_t *ior) { + io_context_t *r = ior; + obu_anchored_loudness_info_t *anchor = + def_mallocz(obu_anchored_loudness_info_t, 1); + + if (!anchor) { + def_err_msg_enomem("anchor loudness", def_mp_str); + return 0; + } + + anchor->anchor_element = ior_8(r); + anchor->anchored_loudness = (int16_t)ior_b16(r); + info("Auchor loundess > anchor element(%u), anchored loudness(0x%04x)", + anchor->anchor_element, anchor->anchored_loudness); + + return anchor; +} + +void _obu_mp_loudness_info_free(obu_loudness_info_t *info) { + if (!info) return; + if (info->anchored_loudnesses) array_free(info->anchored_loudnesses, free); + momentary_loudness_parameter_base_clear( + &info->momentary_loudness.momentary_loudness_param); + if (info->momentary_loudness.bin_count) + array_free(info->momentary_loudness.bin_count, 0); + free(info); +} + +static obu_loudness_info_t *_obu_mp_loudness_info_new(io_context_t *ior) { + io_context_t *r = ior; + obu_loudness_info_t *loudness = def_mallocz(obu_loudness_info_t, 1); + if (!loudness) { + def_err_msg_enomem("loundess info", def_mp_str); + return 0; + } + + loudness->info_type = ior_8(r); + loudness->integrated_loudness = (int16_t)ior_b16(r); + loudness->digital_peak = (int16_t)ior_b16(r); + + info( + "Loudness > info type(0x%x), integrated loudness %f dB(0x%04x), " + "digital peak %f dB(0x%04x)", + loudness->info_type, iamf_gain_q78_to_db(loudness->integrated_loudness), + def_lsb_16bits(loudness->integrated_loudness), + iamf_gain_q78_to_db(loudness->digital_peak), + def_lsb_16bits(loudness->digital_peak)); + + if (loudness->info_type & def_loudness_info_type_true_peak) { + loudness->true_peak = (int16_t)ior_b16(r); + info("Loudness > true peak(0x%04x)", loudness->true_peak); + } + + if (loudness->info_type & def_loudness_info_type_anchored) { + uint32_t val = ior_8(r); + info("%s: loudness > number of anchor loudness(%u)", def_mp_str, val); + + if (val) { + loudness->anchored_loudnesses = array_new(val); + if (!loudness->anchored_loudnesses) { + def_err_msg_enomem("anchor loudnesses", def_mp_str); + _obu_mp_loudness_info_free(loudness); + return 0; + } + + for (uint32_t i = 0; i < val; ++i) { + value_wrap_t *v = 0; + obu_anchored_loudness_info_t *anchor = _obu_mp_anchor_loudness_new(r); + if (!anchor) { + _obu_mp_loudness_info_free(loudness); + return 0; + } + v = array_at(loudness->anchored_loudnesses, i); + v->ptr = anchor; + } + } + } + + if (loudness->info_type & ~def_loudness_info_type_base) { + uint32_t size = ior_leb128_u32(r); + uint32_t s = ioc_tell(r); + + if (loudness->info_type & def_loudness_info_type_momentary) { + momentary_loudness_parameter_base_init( + &loudness->momentary_loudness.momentary_loudness_param, r); + uint32_t val = ior_b16(r); + loudness->momentary_loudness.num_bin_pairs_minus_one = (val >> 13) & 0x7; + loudness->momentary_loudness.bin_width_minus_one = (val >> 7) & 0x3f; + loudness->momentary_loudness.first_bin_center = (val >> 1) & 0x3f; + + val = (loudness->momentary_loudness.num_bin_pairs_minus_one + 1) * 2; + loudness->momentary_loudness.bin_count = array_new(val); + for (int i = 0; i < val; ++i) { + if (!loudness->momentary_loudness.bin_count) + ior_leb128_u32(r); + else + def_value_wrap_u32(array_at(loudness->momentary_loudness.bin_count, + i)) = ior_leb128_u32(r); + } + } + + if (loudness->info_type & def_loudness_info_type_range) { + loudness->loudness_range = ior_8(r); + loudness->loudness_range >>= 2; + } + + size = size - (ioc_tell(r) - s); + if (size > 0) ior_skip(r, size); + } + + return loudness; +} + +static void _obu_mp_sub_mix_free(obu_sub_mix_t *sub) { + if (!sub) return; + + if (sub->audio_element_configs) + array_free(sub->audio_element_configs, + def_default_free_ptr(_obu_mp_audio_element_config_free)); + mix_gain_parameter_base_clear(&sub->output_mix_gain); + + if (sub->loudness_layouts) array_free(sub->loudness_layouts, free); + if (sub->loudness) + array_free(sub->loudness, def_default_free_ptr(_obu_mp_loudness_info_free)); + free(sub); +} + +obu_sub_mix_t *_obu_mp_sub_mix_new(io_context_t *ior, uint32_t count_label) { + io_context_t *r = ior; + uint32_t val; + obu_sub_mix_t *sub = def_mallocz(obu_sub_mix_t, 1); + + if (!sub) { + def_err_msg_enomem("sub mix", def_mp_str); + return 0; + } + + val = ior_leb128_u32(r); // num_audio_elements + info("Number of audio elements(%u): ", val); + if (val) { + sub->audio_element_configs = array_new(val); + if (!sub->audio_element_configs) { + def_err_msg_enomem("audio element configs", def_mp_str); + _obu_mp_sub_mix_free(sub); + return 0; + } + for (uint32_t i = 0; i < val; ++i) { + obu_audio_element_config_t *config = + _obu_mp_audio_element_config_new(r, count_label); + if (!config) { + _obu_mp_sub_mix_free(sub); + return 0; + } + def_value_wrap_ptr(array_at(sub->audio_element_configs, i)) = config; + } + } + + info("Output mix gain:"); + if (mix_gain_parameter_base_init(&sub->output_mix_gain, r) != IAMF_OK) { + _obu_mp_sub_mix_free(sub); + return 0; + } + + val = ior_leb128_u32(r); // num_layouts + info("Number of layouts(%u)", val); + if (val) { + sub->loudness_layouts = array_new(val); + sub->loudness = array_new(val); + + if (!sub->loudness_layouts || !sub->loudness) { + if (!sub->loudness_layouts) + def_err_msg_enomem("loudness layouts", def_mp_str); + if (!sub->loudness) def_err_msg_enomem("loudness", def_mp_str); + _obu_mp_sub_mix_free(sub); + return 0; + } + + for (uint32_t i = 0; i < val; ++i) { + obu_loudness_info_t *loudness = 0; + iamf_layout_t *loudness_layout = _obu_mp_layout_new(r); + + if (!loudness_layout) { + _obu_mp_sub_mix_free(sub); + return 0; + } + def_value_wrap_ptr(array_at(sub->loudness_layouts, i)) = loudness_layout; + + loudness = _obu_mp_loudness_info_new(r); + if (!loudness) { + _obu_mp_sub_mix_free(sub); + return 0; + } + def_value_wrap_ptr(array_at(sub->loudness, i)) = loudness; + } + } + + return sub; +} + +int _obu_mp_check(iamf_mix_presentation_obu_t *obu) { + int num = array_size(obu->sub_mixes); + + if (num > def_max_sub_mixes) { + warning("id(%u): num_sub_mixes should be <= %d.", obu->mix_presentation_id, + def_max_sub_mixes); + return def_error; + } + + for (int i = 0; i < num; ++i) { + int n; + obu_sub_mix_t *sub = + def_value_wrap_optional_ptr(array_at(obu->sub_mixes, i)); + if (!sub) { + warning("id(%u): sub mix (%d) should not be null.", + obu->mix_presentation_id, i); + return def_error; + } + + n = array_size(sub->audio_element_configs); + if (!n) { + warning("id(%u): num_audio_elements should not be set to 0.", + obu->mix_presentation_id); + return def_error; + } + + for (int i = 0; i < n; ++i) { + obu_audio_element_config_t *aelem_config = + def_value_wrap_optional_ptr(array_at(sub->audio_element_configs, i)); + + if (aelem_config->rendering_config.headphones_rendering_mode > + HEADPHONES_RENDERING_MODE_HEAD_LOCKED) { + warning( + "Invalid headphones rendering mode %d in element %u of mix " + "presentation %u", + aelem_config->rendering_config.headphones_rendering_mode, + aelem_config->element_id, obu->mix_presentation_id); + return def_error; + } + } + + n = array_size(sub->loudness_layouts); + for (int i = 0; i < n; ++i) { + iamf_layout_t *layout = + def_value_wrap_optional_ptr(array_at(sub->loudness_layouts, i)); + if (layout->type == ck_iamf_layout_type_loudspeakers_ss_convention && + !iamf_sound_system_check(layout->sound_system)) { + warning("Find unsupported sound system %d in mix presentation %u.", + layout->sound_system, obu->mix_presentation_id); + } + } + } + + num = array_size(obu->mix_presentation_tags); + for (int i = 0; i < num; ++i) { + iamf_tag_t *tag = + def_value_wrap_optional_ptr(array_at(obu->mix_presentation_tags, i)); + if (_obu_mp_tag_check(tag->name, tag->value) != def_pass) + warning("Invalid tag name %s or value %s.", tag->name, tag->value); + } + return def_pass; +} + +static int _obu_mp_find_audio_element(value_wrap_t a, value_wrap_t b) { + return ((iamf_audio_element_obu_t *)a.ptr)->audio_element_id == b.u32; +} + +static int _obu_mp_tag_check(const char *name, const char *value) { + static const char *const _content_type_values[] = {"sub-mix2_system_sound"}; + + if (strcmp(name, "content_language") == 0) { + if (strlen(value) != 3) return def_error; + } else if (strcmp(name, "content_type") == 0) { + int num_values = + sizeof(_content_type_values) / sizeof(_content_type_values[0]); + int is_valid = 0; + for (int i = 0; i < num_values; ++i) { + if (strcmp(value, _content_type_values[i]) == 0) { + is_valid = 1; + break; + } + } + if (!is_valid) return def_error; + } + return def_pass; +} diff --git a/code/src/iamf_dec/obu/mix_presentation_obu.h b/code/src/iamf_dec/obu/mix_presentation_obu.h new file mode 100755 index 00000000..0f4974fe --- /dev/null +++ b/code/src/iamf_dec/obu/mix_presentation_obu.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file mix_presentation_obu.h + * @brief Mix presentation OBU APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __MIX_PRESENTATION_OBU_H__ +#define __MIX_PRESENTATION_OBU_H__ + +#include "cvector.h" +#include "iamf_obu.h" + +/** + * Mix Presentation OBU + * */ + +#define def_mix_presentation_obu_ptr(a) ((iamf_mix_presentation_obu_t *)a) + +#define def_rendering_config_flag_element_gain_offset (1 << 5) + +#define def_loudness_info_type_true_peak 1 +#define def_loudness_info_type_anchored 2 +#define def_loudness_info_type_live 4 +#define def_loudness_info_type_momentary 8 +#define def_loudness_info_type_range 0x10 + +#define def_loudness_info_type_all \ + (def_loudness_info_type_true_peak | def_loudness_info_type_anchored | \ + def_loudness_info_type_live | def_loudness_info_type_momentary | \ + def_loudness_info_type_range) + +typedef enum EPreferredLoudspeakerRenderer { + ck_loudspeaker_renderer_none = 0, +} preferred_loudspeaker_renderer_t; + +typedef enum EPreferredBinauralRenderer { + ck_binaural_renderer_none = 0, +} preferred_binaural_renderer_t; + +typedef struct SubMix obu_sub_mix_t; + +typedef struct IamfMixPresentationObu { + iamf_obu_t obu; + + uint32_t mix_presentation_id; + array_t *annotations_languages; // array + array_t *localized_presentation_annotations; // array + + array_t *sub_mixes; // array; + + array_t *mix_presentation_tags; // array + + uint32_t preferred_loudspeaker_renderer; + uint32_t preferred_binaural_renderer; +} iamf_mix_presentation_obu_t; + +typedef struct AnchoredLoudnessInfo { + uint32_t anchor_element; + int anchored_loudness; +} obu_anchored_loudness_info_t; + +typedef struct MomentaryLoudness { + momentary_loudness_parameter_base_t momentary_loudness_param; + uint8_t num_bin_pairs_minus_one; + uint8_t bin_width_minus_one; + uint8_t first_bin_center; + array_t *bin_count; // array +} momentary_loudness_t; + +typedef struct LoudnessInfo { + uint32_t info_type; + int integrated_loudness; + int digital_peak; + int true_peak; + + array_t *anchored_loudnesses; // array + momentary_loudness_t momentary_loudness; + uint32_t loudness_range; +} obu_loudness_info_t; + +typedef struct RenderingConfig { + uint32_t headphones_rendering_mode; + uint32_t flags; + uint32_t binaural_filter_profile; + array_t *parameters; // array + + uint32_t element_gain_offset_type; // 0: value, 1: range + struct { + int16_t value; + int16_t min; + int16_t max; + } element_gain_offset; + struct { + float value; + float min; + float max; + } element_gain_offset_db; + + uint32_t rendering_config_extension_size; +} obu_rendering_config_t; + +typedef struct AudioElementConfig { + uint32_t element_id; + array_t *localized_element_annotations; // array + obu_rendering_config_t rendering_config; + mix_gain_parameter_base_t element_mix_gain; +} obu_audio_element_config_t; + +struct SubMix { + array_t *audio_element_configs; // array + + mix_gain_parameter_base_t output_mix_gain; + + array_t *loudness_layouts; // array; + array_t *loudness; // array; +}; + +iamf_mix_presentation_obu_t *iamf_mix_presentation_obu_new( + io_context_t *ior, iamf_obu_header_t *header); +void iamf_mix_presentation_obu_free(iamf_mix_presentation_obu_t *obu); +int iamf_mix_presentation_obu_check_profile(iamf_mix_presentation_obu_t *obu, + vector_t *audio_element_obus, + iamf_profile_t profile); +#endif // __MIX_PRESENTATION_OBU_H__ diff --git a/code/src/iamf_dec/obu/parameter_base.c b/code/src/iamf_dec/obu/parameter_base.c new file mode 100755 index 00000000..8b6c1659 --- /dev/null +++ b/code/src/iamf_dec/obu/parameter_base.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file parameter_base.c + * @brief Parameter base implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "parameter_base.h" + +#include "iamf_private_definitions.h" +#include "iamf_string.h" +#include "iamf_utils.h" + +#undef def_log_tag +#define def_log_tag "OBU_PB" +#define def_pb_str "Parameter Base" + +static demixing_info_parameter_base_t *_obu_pb_demixing_new(io_context_t *ior); +static recon_gain_parameter_base_t *_obu_pb_recon_gain_new(io_context_t *ior); +static mix_gain_parameter_base_t *_obu_pb_mix_gain_new(io_context_t *ior); +static momentary_loudness_parameter_base_t *_obu_pb_momentary_loudness_new( + io_context_t *ior); +static polars_parameter_base_t *_obu_pb_polars_new(io_context_t *ior, + uint32_t num_polars); +static cartesians_parameter_base_t *_obu_pb_cartesians_new( + io_context_t *ior, iamf_parameter_type_t type, uint32_t num_cartesians); +static void _obu_pb_clear(parameter_base_t *param); +static int _obu_pb_init(parameter_base_t *param_base, + iamf_parameter_type_t type, io_context_t *r); +static int _obu_pb_mix_gain_init(mix_gain_parameter_base_t *mix_gain_param, + io_context_t *ior); + +parameter_base_t *iamf_parameter_base_new(io_context_t *ior, + iamf_parameter_type_t type) { + io_context_t *r = ior; + parameter_base_t *param = 0; + + if (type == ck_iamf_parameter_type_demixing) { + demixing_info_parameter_base_t *dxm_param = _obu_pb_demixing_new(r); + param = def_param_base_ptr(dxm_param); + } else if (type == ck_iamf_parameter_type_recon_gain) { + recon_gain_parameter_base_t *recon_gain_param = _obu_pb_recon_gain_new(r); + param = def_param_base_ptr(recon_gain_param); + } else if (type == ck_iamf_parameter_type_mix_gain) { + mix_gain_parameter_base_t *mix_gain_param = _obu_pb_mix_gain_new(r); + param = def_param_base_ptr(mix_gain_param); + } else if (type == ck_iamf_parameter_type_polar) { + polars_parameter_base_t *single_pos_param = _obu_pb_polars_new(r, 1); + param = def_param_base_ptr(single_pos_param); + } else if (type == ck_iamf_parameter_type_dual_polar) { + polars_parameter_base_t *dual_pos_param = _obu_pb_polars_new(r, 2); + param = def_param_base_ptr(dual_pos_param); + } else if (type == ck_iamf_parameter_type_cartesian_8 || + type == ck_iamf_parameter_type_cartesian_16) { + cartesians_parameter_base_t *single_cart_param = + _obu_pb_cartesians_new(r, type, 1); + param = def_param_base_ptr(single_cart_param); + } else if (type == ck_iamf_parameter_type_dual_cartesian_8 || + type == ck_iamf_parameter_type_dual_cartesian_16) { + cartesians_parameter_base_t *dual_cart_param = + _obu_pb_cartesians_new(r, type, 2); + param = def_param_base_ptr(dual_cart_param); + } else if (type == ck_iamf_parameter_type_momentary_loudness) { + momentary_loudness_parameter_base_t *momentary_loudness_param = + _obu_pb_momentary_loudness_new(r); + param = def_param_base_ptr(momentary_loudness_param); + } else { + error("Invalid parameter type %d", type); + return 0; + } + + return param; +} + +void iamf_parameter_base_free(parameter_base_t *param) { + if (!param) return; + _obu_pb_clear(param); + free(param); +} + +int mix_gain_parameter_base_init(mix_gain_parameter_base_t *mix_gain_param, + io_context_t *ior) { + if (!mix_gain_param || !ior) return IAMF_ERR_BAD_ARG; + + int ret = + _obu_pb_init(&mix_gain_param->base, ck_iamf_parameter_type_mix_gain, ior); + return ret == IAMF_OK ? _obu_pb_mix_gain_init(mix_gain_param, ior) : ret; +} + +void mix_gain_parameter_base_clear(mix_gain_parameter_base_t *mix_gain_param) { + if (mix_gain_param) _obu_pb_clear(&mix_gain_param->base); +} + +int momentary_loudness_parameter_base_init( + momentary_loudness_parameter_base_t *momentary_loudness_param, + io_context_t *ior) { + if (!momentary_loudness_param || !ior) return IAMF_ERR_BAD_ARG; + return _obu_pb_init(&momentary_loudness_param->base, + ck_iamf_parameter_type_momentary_loudness, ior); +} + +void momentary_loudness_parameter_base_clear( + momentary_loudness_parameter_base_t *momentary_loudness_param) { + if (momentary_loudness_param) _obu_pb_clear(&momentary_loudness_param->base); +} + +int iamf_parameter_type_is_polar(iamf_parameter_type_t type) { + return type == ck_iamf_parameter_type_polar || + type == ck_iamf_parameter_type_dual_polar; +} + +int iamf_parameter_type_is_cartesian(iamf_parameter_type_t type) { + return type == ck_iamf_parameter_type_cartesian_8 || + type == ck_iamf_parameter_type_cartesian_16 || + type == ck_iamf_parameter_type_dual_cartesian_8 || + type == ck_iamf_parameter_type_dual_cartesian_16; +} + +int iamf_parameter_type_is_coordinate(iamf_parameter_type_t type) { + return iamf_parameter_type_is_polar(type) || + iamf_parameter_type_is_cartesian(type); +} + +uint32_t iamf_parameter_type_get_cartesian_bit_depth( + iamf_parameter_type_t type) { + switch (type) { + case ck_iamf_parameter_type_cartesian_8: + case ck_iamf_parameter_type_dual_cartesian_8: + return def_cartesian_8_num_bits; + case ck_iamf_parameter_type_cartesian_16: + case ck_iamf_parameter_type_dual_cartesian_16: + return def_cartesian_16_num_bits; + default: + error("Invalid cartesian parameter type %d for bit depth retrieval", + type); + return 0; + } +} + +int _obu_pb_init(parameter_base_t *param_base, iamf_parameter_type_t type, + io_context_t *r) { + uint32_t val; + + param_base->type = type; + param_base->parameter_id = ior_leb128_u32(r); + param_base->parameter_rate = ior_leb128_u32(r); + val = ior_8(r); + param_base->param_definition_mode = (val >> 7) & 0x01; + info( + "Parameter type(%u), parameter id(%u), parameter rate(%u), " + "parameter definition mode(%u)", + param_base->type, param_base->parameter_id, param_base->parameter_rate, + param_base->param_definition_mode); + if (!param_base->param_definition_mode) { + param_base->duration = ior_leb128_u32(r); + param_base->constant_subblock_duration = ior_leb128_u32(r); + info("duration(%u), constant segment interval(%u)", param_base->duration, + param_base->constant_subblock_duration); + if (!param_base->constant_subblock_duration) { + val = ior_leb128_u32(r); // num_subblocks + info("Number of subblocks(%u):", val); + if (val > 0) { + param_base->subblock_durations = array_new(val); + if (!param_base->subblock_durations) { + def_err_msg_enomem("subblock durations", def_pb_str); + return IAMF_ERR_ALLOC_FAIL; + } + + for (uint32_t i = 0; i < val; ++i) { + value_wrap_t *v = array_at(param_base->subblock_durations, i); + v->u32 = ior_leb128_u32(r); + info("\tSubblock(%d) duration(%u)", i, v->u32); + } + } + } + } + + return IAMF_OK; +} + +static int _obu_pb_demixing_init(demixing_info_parameter_base_t *dxm_param, + io_context_t *ior) { + io_context_t *r = ior; + dxm_param->dmixp_mode = ior_8(r) >> 5 & 0x07; + dxm_param->default_w = ior_8(r) >> 4 & 0x0f; + info("Default mode(%u), weight index(%u)", dxm_param->dmixp_mode, + dxm_param->default_w); + return IAMF_OK; +} + +demixing_info_parameter_base_t *_obu_pb_demixing_new(io_context_t *ior) { + parameter_base_t *param = 0; + demixing_info_parameter_base_t *dxm_param = + def_mallocz(demixing_info_parameter_base_t, 1); + + if (!dxm_param) { + def_err_msg_enomem("demixing parameter base", def_pb_str); + return 0; + } + + param = def_param_base_ptr(dxm_param); + if (_obu_pb_init(param, ck_iamf_parameter_type_demixing, ior) != IAMF_OK || + _obu_pb_demixing_init(dxm_param, ior) != IAMF_OK) { + iamf_parameter_base_free(param); + return 0; + } + + return dxm_param; +} + +recon_gain_parameter_base_t *_obu_pb_recon_gain_new(io_context_t *ior) { + parameter_base_t *param = 0; + recon_gain_parameter_base_t *recon_gain_param = + def_mallocz(recon_gain_parameter_base_t, 1); + + if (!recon_gain_param) { + def_err_msg_enomem("recon gain parameter base", def_pb_str); + return 0; + } + + param = def_param_base_ptr(recon_gain_param); + if (_obu_pb_init(param, ck_iamf_parameter_type_recon_gain, ior) != IAMF_OK) { + iamf_parameter_base_free(param); + return 0; + } + + return recon_gain_param; +} + +int _obu_pb_mix_gain_init(mix_gain_parameter_base_t *mix_gain_param, + io_context_t *ior) { + io_context_t *r = ior; + mix_gain_param->default_mix_gain = (int16_t)ior_b16(r); + mix_gain_param->default_mix_gain_db = + iamf_gain_q78_to_db(mix_gain_param->default_mix_gain); + info("Default mix gain %f(%x) dB", mix_gain_param->default_mix_gain_db, + mix_gain_param->default_mix_gain); + return IAMF_OK; +} + +mix_gain_parameter_base_t *_obu_pb_mix_gain_new(io_context_t *ior) { + mix_gain_parameter_base_t *mix_gain_param = + def_mallocz(mix_gain_parameter_base_t, 1); + + if (!mix_gain_param) { + def_err_msg_enomem("mix gain parameter base", def_pb_str); + return 0; + } + + if (mix_gain_parameter_base_init(mix_gain_param, ior) != IAMF_OK) { + parameter_base_t *param = def_param_base_ptr(mix_gain_param); + iamf_parameter_base_free(param); + return 0; + } + + return mix_gain_param; +} + +static int _obu_pb_polars_init(polars_parameter_base_t *pos_param, + io_context_t *ior, uint32_t num_polars) { + bits_io_context_t bits_ioc, *bits_r; + + bits_r = &bits_ioc; + bits_ioc_init(bits_r, ior); + + pos_param->num_polars = num_polars; + for (int i = 0; i < num_polars; i++) { + pos_param->encoded_default_polars[i].azimuth = + bits_ior_le32(bits_r, def_azimuth_num_bits); + pos_param->encoded_default_polars[i].elevation = + bits_ior_le32(bits_r, def_elevation_num_bits); + pos_param->encoded_default_polars[i].distance = + bits_ior_le32(bits_r, def_distance_num_bits); + info("Encoded Position(%d) azimuth(%02x), elevation(%02x), distance(%02x)", + i, pos_param->encoded_default_polars[i].azimuth, + pos_param->encoded_default_polars[i].elevation, + pos_param->encoded_default_polars[i].distance); + + pos_param->default_polars[i].azimuth = def_azimuth_clip(iamf_u32_to_i16( + pos_param->encoded_default_polars[i].azimuth, def_azimuth_num_bits)); + pos_param->default_polars[i].elevation = def_elevation_clip( + iamf_u32_to_i16(pos_param->encoded_default_polars[i].elevation, + def_elevation_num_bits)); + pos_param->default_polars[i].distance = def_distance_clip(iamf_u32_to_f32( + pos_param->encoded_default_polars[i].distance, def_distance_num_bits)); + + info("Position(%d) azimuth(%f), elevation(%f), distance(%f)", i, + pos_param->default_polars[i].azimuth, + pos_param->default_polars[i].elevation, + pos_param->default_polars[i].distance); + } + + return IAMF_OK; +} + +polars_parameter_base_t *_obu_pb_polars_new(io_context_t *ior, + uint32_t num_polars) { + polars_parameter_base_t *pos_param = def_mallocz(polars_parameter_base_t, 1); + if (!pos_param) { + def_err_msg_enomem("position parameter base", def_pb_str); + return 0; + } + + if (_obu_pb_init(&pos_param->base, + num_polars == 1 ? ck_iamf_parameter_type_polar + : ck_iamf_parameter_type_dual_polar, + ior) != IAMF_OK || + _obu_pb_polars_init(pos_param, ior, num_polars) != IAMF_OK) { + iamf_parameter_base_free(def_param_base_ptr(pos_param)); + return 0; + } + + return pos_param; +} + +static int _obu_pb_cartesians_init(cartesians_parameter_base_t *cart_param, + io_context_t *ior, + iamf_parameter_type_t type, + uint32_t num_cartesians) { + bits_io_context_t bits_ioc, *bits_r; + uint32_t num_bits; + + bits_r = &bits_ioc; + bits_ioc_init(bits_r, ior); + + num_bits = iamf_parameter_type_get_cartesian_bit_depth(type); + if (!num_bits) { + error("Invalid cartesian parameter type %d for initialization", type); + return IAMF_ERR_BAD_ARG; + } + + cart_param->num_cartesians = num_cartesians; + for (int i = 0; i < num_cartesians; i++) { + cart_param->encoded_default_cartesians[i].x = + bits_ior_le32(bits_r, num_bits); + cart_param->encoded_default_cartesians[i].y = + bits_ior_le32(bits_r, num_bits); + cart_param->encoded_default_cartesians[i].z = + bits_ior_le32(bits_r, num_bits); + + cart_param->default_cartesians[i].x = def_clip_normalized(iamf_i16_to_f32( + iamf_u32_to_i16(cart_param->encoded_default_cartesians[i].x, num_bits), + num_bits)); + cart_param->default_cartesians[i].y = def_clip_normalized(iamf_i16_to_f32( + iamf_u32_to_i16(cart_param->encoded_default_cartesians[i].y, num_bits), + num_bits)); + cart_param->default_cartesians[i].z = def_clip_normalized(iamf_i16_to_f32( + iamf_u32_to_i16(cart_param->encoded_default_cartesians[i].z, num_bits), + num_bits)); + + info("Cartesian(%d) x(%f), y(%f), z(%f)", i, + cart_param->default_cartesians[i].x, + cart_param->default_cartesians[i].y, + cart_param->default_cartesians[i].z); + } + + return IAMF_OK; +} + +static cartesians_parameter_base_t *_obu_pb_cartesians_new( + io_context_t *ior, iamf_parameter_type_t type, uint32_t num_cartesians) { + cartesians_parameter_base_t *cart_param = + def_mallocz(cartesians_parameter_base_t, 1); + if (!cart_param) { + def_err_msg_enomem("cartesian parameter base", def_pb_str); + return 0; + } + + if (_obu_pb_init(&cart_param->base, type, ior) != IAMF_OK || + _obu_pb_cartesians_init(cart_param, ior, type, num_cartesians) != + IAMF_OK) { + iamf_parameter_base_free(def_param_base_ptr(cart_param)); + return 0; + } + + return cart_param; +} + +momentary_loudness_parameter_base_t *_obu_pb_momentary_loudness_new( + io_context_t *ior) { + momentary_loudness_parameter_base_t *momentary_loudness_param = + def_mallocz(momentary_loudness_parameter_base_t, 1); + + if (!momentary_loudness_param) { + def_err_msg_enomem("momentary loudness parameter base", def_pb_str); + return 0; + } + + if (momentary_loudness_parameter_base_init(momentary_loudness_param, ior) != + IAMF_OK) { + parameter_base_t *param = def_param_base_ptr(momentary_loudness_param); + iamf_parameter_base_free(param); + return 0; + } + + return momentary_loudness_param; +} + +void _obu_pb_clear(parameter_base_t *param) { + if (param->subblock_durations) array_free(param->subblock_durations, 0); +} diff --git a/code/src/iamf_dec/obu/parameter_base.h b/code/src/iamf_dec/obu/parameter_base.h new file mode 100755 index 00000000..1a0fc76b --- /dev/null +++ b/code/src/iamf_dec/obu/parameter_base.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file parameter_base.h + * @brief Parameter base APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __PARAMETER_BASE_H__ +#define __PARAMETER_BASE_H__ + +#include "IAMF_defines.h" +#include "carray.h" +#include "iamf_private_definitions.h" +#include "iamf_types.h" +#include "iorw.h" +#include "oar_base.h" + +#define def_demixing_info_param_base_ptr(a) \ + ((demixing_info_parameter_base_t *)a) +#define def_param_base_ptr(a) def_ptr(parameter_base, a) +#define def_mix_gain_parameter_base_ptr(a) def_ptr(mix_gain_parameter_base, a) +#define def_polars_parameter_base_ptr(a) def_ptr(polars_parameter_base, a) +#define def_cartesians_parameter_base_ptr(a) \ + def_ptr(cartesians_parameter_base, a) + +typedef enum EIamfParameterType { + ck_iamf_parameter_type_none = -1, + ck_iamf_parameter_type_mix_gain = 0, + ck_iamf_parameter_type_demixing, + ck_iamf_parameter_type_recon_gain, + ck_iamf_parameter_type_polar, + ck_iamf_parameter_type_cartesian_8, + ck_iamf_parameter_type_cartesian_16, + ck_iamf_parameter_type_dual_polar, + ck_iamf_parameter_type_dual_cartesian_8, + ck_iamf_parameter_type_dual_cartesian_16, + ck_iamf_parameter_type_momentary_loudness, + ck_iamf_parameter_type_count, +} iamf_parameter_type_t; + +typedef struct ParameterBase { + uint32_t type; + uint32_t parameter_id; + uint32_t parameter_rate; + uint32_t param_definition_mode; + uint32_t duration; + uint32_t constant_subblock_duration; + array_t *subblock_durations; // array +} parameter_base_t; + +typedef struct DemixingInfoParameterBase { + parameter_base_t base; + uint32_t dmixp_mode; + uint32_t default_w; +} demixing_info_parameter_base_t; + +typedef struct ReconGainParameterBase { + parameter_base_t base; +} recon_gain_parameter_base_t; + +typedef struct MixGainParameterBase { + parameter_base_t base; + int16_t default_mix_gain; + float default_mix_gain_db; +} mix_gain_parameter_base_t; + +typedef struct PolarsParameterBase { + parameter_base_t base; + + uint32_t num_polars; + encoded_polar_t encoded_default_polars[def_max_audio_objects]; + polar_t default_polars[def_max_audio_objects]; +} polars_parameter_base_t; + +typedef struct CartesiansParameterBase { + parameter_base_t base; + + uint32_t num_cartesians; + encoded_cartesian_t encoded_default_cartesians[def_max_audio_objects]; + + /** + * @brief Following the Cartesian coordinates axes for Objects in + * [ITU-2076-2], the X, Y, Z coordinate values are provided as normalized + * values where 1.0 and -1.0 are on the surface of the cube, with the origin + * being the centre of the cube. The direction of each axes are: + * + * X: left to right, with positive values to the right. + * Y: front to back, with positive values to the front. + * Z: top to bottom, with positive values to the top. + */ + cartesian_t default_cartesians[def_max_audio_objects]; +} cartesians_parameter_base_t; + +typedef struct MomentaryLoudnessParameterBase { + parameter_base_t base; +} momentary_loudness_parameter_base_t; + +parameter_base_t *iamf_parameter_base_new(io_context_t *ior, + iamf_parameter_type_t type); +void iamf_parameter_base_free(parameter_base_t *param); + +int mix_gain_parameter_base_init(mix_gain_parameter_base_t *mix_gain_param, + io_context_t *ior); +void mix_gain_parameter_base_clear(mix_gain_parameter_base_t *mix_gain_param); + +int momentary_loudness_parameter_base_init( + momentary_loudness_parameter_base_t *momentary_loudness_param, + io_context_t *ior); +void momentary_loudness_parameter_base_clear( + momentary_loudness_parameter_base_t *momentary_loudness_param); + +int iamf_parameter_type_is_polar(iamf_parameter_type_t type); +int iamf_parameter_type_is_cartesian(iamf_parameter_type_t type); +int iamf_parameter_type_is_coordinate(iamf_parameter_type_t type); +uint32_t iamf_parameter_type_get_cartesian_bit_depth( + iamf_parameter_type_t type); + +#endif //__PARAMETER_BASE_H__ diff --git a/code/src/iamf_dec/obu/parameter_block_obu.c b/code/src/iamf_dec/obu/parameter_block_obu.c new file mode 100755 index 00000000..c876473b --- /dev/null +++ b/code/src/iamf_dec/obu/parameter_block_obu.c @@ -0,0 +1,557 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file parameter_block_obu.c + * @brief Parameter block OBU implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "parameter_block_obu.h" + +#include "iamf_private_definitions.h" +#include "iamf_string.h" +#include "iamf_utils.h" + +#ifdef SUPPORT_VERIFIER +#include "vlogging_tool_sr.h" +#endif + +#undef def_log_tag +#define def_log_tag "OBU_PBK" +#define def_pbo_str "Parameter Block OBU" + +#define def_iamf_u32_to_i16_to_f32(v, bits) \ + iamf_i16_to_f32(iamf_u32_to_i16((v), (bits)), (bits)) + +#define def_iamf_animated_data_clip(data, _clip) \ + do { \ + (data)->start = _clip((data)->start); \ + (data)->end = _clip((data)->end); \ + (data)->control = _clip((data)->control); \ + } while (0) + +static parameter_subblock_t *_obu_pb_subblock_new( + io_context_t *, parameter_base_t *, uint32_t, + iamf_pbo_extra_interfaces_t *); +static void _obu_pb_recon_gain_info_parameter_subblock_free( + recon_gain_parameter_subblock_t *); + +iamf_parameter_block_obu_t *iamf_parameter_block_obu_new( + io_context_t *ior, iamf_pbo_extra_interfaces_t *interfaces) { + iamf_parameter_block_obu_t *obu = 0; + parameter_base_t *base = 0; + io_context_t *r = ior; + uint32_t parameter_id; + uint32_t num_subblocks = 0; + + if (!interfaces || !interfaces->get_parameter_base) { + warning("invalid input parameters: interfaces(%p), get base(%p)", + interfaces, interfaces ? interfaces->get_parameter_base : 0); + return 0; + } + + parameter_id = ior_leb128_u32(r); + base = interfaces->get_parameter_base(interfaces->this, parameter_id); + if (!base) { + debug("failed to get parameter base %u from extra", parameter_id); + return 0; + } + + obu = def_mallocz(iamf_parameter_block_obu_t, 1); + if (!obu) { + def_err_msg_enomem(def_pbo_str, def_iamf_ustr); + return 0; + } + + obu->obu.obu_type = ck_iamf_obu_parameter_block; + obu->base = base; + + if (obu->base->param_definition_mode) { + obu->duration = ior_leb128_u32(r); + obu->constant_subblock_duration = ior_leb128_u32(r); + if (!obu->constant_subblock_duration) num_subblocks = ior_leb128_u32(r); + } else { + obu->duration = base->duration; + obu->constant_subblock_duration = base->constant_subblock_duration; + if (!obu->constant_subblock_duration) + num_subblocks = array_size(base->subblock_durations); + } + + if (obu->constant_subblock_duration) + num_subblocks = obu->duration / obu->constant_subblock_duration + + (obu->duration % obu->constant_subblock_duration ? 1 : 0); + + info( + "Parameter type(%s<%u>), id(%u) , rate(%u), mode(%u), duration(%u), " + "constant subblock duration(%u), number of subblocks(%u)", + iamf_parameter_block_type_string(base->type), base->type, + base->parameter_id, base->parameter_rate, base->param_definition_mode, + obu->duration, obu->constant_subblock_duration, num_subblocks); + + obu->subblocks = array_new(num_subblocks); + if (!obu->subblocks) { + def_err_msg_enomem("subblocks", def_pbo_str); + iamf_parameter_block_obu_free(obu); + return 0; + } + + for (uint32_t i = 0; i < num_subblocks; ++i) { + parameter_subblock_t *subblock = 0; + uint32_t subblock_duration = 0; + + if (!obu->constant_subblock_duration) { + if (base->param_definition_mode) { + subblock_duration = ior_leb128_u32(r); + } else { + subblock_duration = array_at(base->subblock_durations, i)->u32; + } + } else { + if (i == num_subblocks - 1 && + obu->duration % obu->constant_subblock_duration) + subblock_duration = obu->duration % obu->constant_subblock_duration; + else + subblock_duration = obu->constant_subblock_duration; + } + + info("Subblock(%d), duration(%u)", i, subblock_duration); + + subblock = _obu_pb_subblock_new(r, base, subblock_duration, interfaces); + if (!subblock) { + iamf_parameter_block_obu_free(obu); + return 0; + } + + array_at(obu->subblocks, i)->ptr = subblock; + } + +#if SUPPORT_VERIFIER + vlog_obu(ck_iamf_obu_parameter_block, obu, 0, 0); +#endif + + return obu; +} + +void iamf_parameter_block_obu_free(iamf_parameter_block_obu_t *obu) { + if (!obu) return; + if (obu->subblocks) + array_free(obu->subblocks, + def_default_free_ptr(iamf_parameter_subblock_free)); + free(obu); +} + +void iamf_parameter_subblock_free(parameter_subblock_t *subblock) { + if (!subblock) return; + + switch (subblock->type) { + case ck_iamf_parameter_type_mix_gain: + case ck_iamf_parameter_type_demixing: + case ck_iamf_parameter_type_polar: + case ck_iamf_parameter_type_dual_polar: + case ck_iamf_parameter_type_cartesian_8: + case ck_iamf_parameter_type_cartesian_16: + case ck_iamf_parameter_type_dual_cartesian_8: + case ck_iamf_parameter_type_dual_cartesian_16: + case ck_iamf_parameter_type_momentary_loudness: + free(subblock); + break; + + case ck_iamf_parameter_type_recon_gain: + _obu_pb_recon_gain_info_parameter_subblock_free( + (recon_gain_parameter_subblock_t *)subblock); + break; + + default: + break; + } +} + +static int _obu_pb_animated_parameter_gain_db(animated_float32_t *dst, + ap_u32_t *src) { + if (!dst || !src) return IAMF_ERR_BAD_ARG; + + dst->animation_type = src->animation_type; + dst->data.start = + iamf_gain_q78_to_db(iamf_u32_to_i16(src->data.start, def_q78_num_bits)); + dst->data.end = + iamf_gain_q78_to_db(iamf_u32_to_i16(src->data.end, def_q78_num_bits)); + dst->data.control = + iamf_gain_q78_to_db(iamf_u32_to_i16(src->data.control, def_q78_num_bits)); + dst->data.control_relative_time = + iamf_divide_128f(src->data.control_relative_time); + + return IAMF_OK; +} + +static mix_gain_parameter_subblock_t *_obu_pb_mix_gain_parameter_subblock_new( + io_context_t *ior, uint32_t duration) { + io_context_t *r = ior; + bits_io_context_t bits_ioc, *bits_r; + mix_gain_parameter_subblock_t *data = + def_mallocz(mix_gain_parameter_subblock_t, 1); + + if (!data) { + def_err_msg_enomem("mix gain parameter data", def_pbo_str); + return 0; + } + + bits_r = &bits_ioc; + + data->base.type = ck_iamf_parameter_type_mix_gain; + data->base.subblock_duration = duration; + data->gain.animation_type = ior_leb128_u32(r); + + bits_ioc_init(bits_r, r); + animated_parameter_data_read_bits( + bits_r, def_q78_num_bits, data->gain.animation_type, &data->gain.data); + _obu_pb_animated_parameter_gain_db(&data->gain_db, &data->gain); + info( + " Mix gain: animated type(%u), start(%f), end(%f), " + "control(%f), control relative time(%f).", + data->gain_db.animation_type, data->gain_db.data.start, + data->gain_db.data.end, data->gain_db.data.control, + data->gain_db.data.control_relative_time); + + debug("New mix gain parameter %p ", data); + return data; +} + +static demixing_info_parameter_subblock_t * +_obu_pb_demixing_info_parameter_subblock_new(io_context_t *ior, + uint32_t duration) { + io_context_t *r = ior; + demixing_info_parameter_subblock_t *data = + def_mallocz(demixing_info_parameter_subblock_t, 1); + + if (!data) { + def_err_msg_enomem("demixing info parameter data", def_pbo_str); + return 0; + } + + data->base.type = ck_iamf_parameter_type_demixing; + data->base.subblock_duration = duration; + data->demixing_mode = ior_8(r) >> 5 & 0x07; + info("\tDemixing parameter data: mode %u", data->demixing_mode); + + return data; +} + +static void _obu_pb_recon_gain_free(recon_gain_t *gain) { + if (!gain) return; + if (gain->recon_gain) array_free(gain->recon_gain, 0); + if (gain->recon_gain_linear) array_free(gain->recon_gain_linear, 0); + free(gain); +} + +static recon_gain_t *_obu_pb_recon_gain_new(io_context_t *ior, int index) { + io_context_t *r = ior; + int size = 0; + recon_gain_t *recon_gain = def_mallocz(recon_gain_t, 1); + if (!recon_gain) { + def_err_msg_enomem("recon gain", def_pbo_str); + return 0; + } + + recon_gain->layer = index; + recon_gain->recon_gain_flags = ior_leb128_u32(r); + size = bit1_count(recon_gain->recon_gain_flags); + recon_gain->recon_gain = array_new(size); + recon_gain->recon_gain_linear = array_new(size); + if (!recon_gain->recon_gain || !recon_gain->recon_gain_linear) { + def_err_msg_enomem("recon gain values", def_pbo_str); + _obu_pb_recon_gain_free(recon_gain); + return 0; + } + + info("\tRecon gain info: layer %d, flags 0x%08x", index, + recon_gain->recon_gain_flags); + for (int i = 0; i < size; ++i) { + uint32_t val = ior_8(r); + debug("\t\tChannel %d, gain 0x%02x(%f)", i, val, + iamf_recon_gain_linear(val)); + array_at(recon_gain->recon_gain, i)->u32 = val; + array_at(recon_gain->recon_gain_linear, i)->f32 = + iamf_recon_gain_linear(val); + } + + return recon_gain; +} + +void _obu_pb_recon_gain_info_parameter_subblock_free( + recon_gain_parameter_subblock_t *data) { + if (!data) return; + if (data->recon_gains) + array_free(data->recon_gains, + def_default_free_ptr(_obu_pb_recon_gain_free)); + free(data); +} + +static recon_gain_parameter_subblock_t * +_obu_pb_recon_gain_info_parameter_subblock_new( + io_context_t *ior, uint32_t duration, uint32_t id, + iamf_pbo_extra_interfaces_t *interfaces) { + io_context_t *r = ior; + recon_gain_parameter_subblock_t *data = 0; + array_t *recon_gain_present_flags = 0; + int size = 0; + + if (!interfaces || !interfaces->get_recon_gain_present_flags) { + warning( + "Invalid input parameters: interfaces(%p) or " + "get_recon_gain_present_flags(%p)", + interfaces, interfaces ? interfaces->get_recon_gain_present_flags : 0); + return 0; + } + + recon_gain_present_flags = + interfaces->get_recon_gain_present_flags(interfaces->this, id); + if (!recon_gain_present_flags) { + error("Failed to get recon gain flags for parameter id %u", id); + return 0; + } + + data = def_mallocz(recon_gain_parameter_subblock_t, 1); + if (!data) { + def_err_msg_enomem("recon gain info parameter data", def_pbo_str); + return 0; + } + + size = array_size(recon_gain_present_flags); + data->base.type = ck_iamf_parameter_type_recon_gain; + data->base.subblock_duration = duration; + + data->recon_gains = array_new(size); + if (!data->recon_gains) { + def_err_msg_enomem("recon gains", def_pbo_str); + _obu_pb_recon_gain_info_parameter_subblock_free(data); + return 0; + } + + for (int i = 0; i < size; ++i) { + uint32_t flags = def_value_wrap_u32(array_at(recon_gain_present_flags, i)); + if (flags) { + recon_gain_t *recon_gain = _obu_pb_recon_gain_new(r, i); + if (!recon_gain) { + _obu_pb_recon_gain_info_parameter_subblock_free(data); + return 0; + } + def_value_wrap_ptr(array_at(data->recon_gains, i)) = recon_gain; + } + } + + array_free(recon_gain_present_flags, 0); + + return data; +} + +static polars_parameter_subblock_t *_obu_pb_polars_parameter_subblock_new( + io_context_t *ior, uint32_t duration, uint32_t count) { + io_context_t *r = ior; + polars_parameter_subblock_t *data; + bits_io_context_t bits_ioc, *bits_r; + + if (count < 1 || count > def_max_audio_objects) { + error("Invalid polar count: %u (must be 1-%d)", count, + def_max_audio_objects); + return 0; + } + + data = def_mallocz(polars_parameter_subblock_t, 1); + if (!data) { + def_err_msg_enomem("polars parameter data", def_pbo_str); + return 0; + } + + data->base.type = count == 1 ? ck_iamf_parameter_type_polar + : ck_iamf_parameter_type_dual_polar; + data->base.subblock_duration = duration; + data->num_polars = count; + data->animation_type = ior_leb128_u32(r); + bits_r = &bits_ioc; + bits_ioc_init(bits_r, r); + + for (int i = 0; i < count && i < def_max_audio_objects; ++i) { + animated_parameter_data_read_bits(bits_r, def_azimuth_num_bits, + data->animation_type, + &data->encoded_polars[i].azimuth); + animated_parameter_data_read_bits(bits_r, def_elevation_num_bits, + data->animation_type, + &data->encoded_polars[i].elevation); + animated_parameter_data_read_bits(bits_r, def_distance_num_bits, + data->animation_type, + &data->encoded_polars[i].distance); + + data->polars[i].animation_type = (animation_type_t)data->animation_type; + def_animated_parameter_data_convert_bits_function( + &data->polars[i].azimuth, &data->encoded_polars[i].azimuth, + def_azimuth_num_bits, iamf_u32_to_i16); + def_animated_parameter_data_convert_bits_function( + &data->polars[i].elevation, &data->encoded_polars[i].elevation, + def_elevation_num_bits, iamf_u32_to_i16); + def_animated_parameter_data_convert_bits_function( + &data->polars[i].distance, &data->encoded_polars[i].distance, + def_distance_num_bits, iamf_u32_to_f32); + + def_iamf_animated_data_clip(&data->polars[i].azimuth, def_azimuth_clip); + def_iamf_animated_data_clip(&data->polars[i].elevation, def_elevation_clip); + def_iamf_animated_data_clip(&data->polars[i].distance, def_distance_clip); + } + + if (data->animation_type != ck_iamf_animation_type_step && + data->animation_type != ck_iamf_animation_type_inter_linear) { + error("Unsupported animation type %u for polar parameter", + data->animation_type); + iamf_parameter_subblock_free(def_parameter_subblock_ptr(data)); + data = 0; + } + return data; +} + +static cartesians_parameter_subblock_t * +_obu_pb_cartesians_parameter_subblock_new(io_context_t *ior, uint32_t duration, + iamf_parameter_type_t type, + uint32_t count) { + io_context_t *r = ior; + cartesians_parameter_subblock_t *data; + bits_io_context_t bits_ioc, *bits_r; + uint32_t num_bits = iamf_parameter_type_get_cartesian_bit_depth(type); + + if (count < 1 || count > def_max_audio_objects) { + error("Invalid cartesian count: %u (must be 1-%d)", count, + def_max_audio_objects); + return 0; + } + + if (!num_bits) return 0; + + data = def_mallocz(cartesians_parameter_subblock_t, 1); + if (!data) { + def_err_msg_enomem("cartesians parameter data", def_pbo_str); + return 0; + } + + data->base.type = type; + data->base.subblock_duration = duration; + data->num_cartesians = count; + data->animation_type = ior_leb128_u32(r); + + bits_r = &bits_ioc; + bits_ioc_init(bits_r, r); + + for (int i = 0; i < count && i < def_max_audio_objects; ++i) { + animated_parameter_data_read_bits(bits_r, num_bits, data->animation_type, + &data->encoded_cartesians[i].x); + animated_parameter_data_read_bits(bits_r, num_bits, data->animation_type, + &data->encoded_cartesians[i].y); + animated_parameter_data_read_bits(bits_r, num_bits, data->animation_type, + &data->encoded_cartesians[i].z); + + data->cartesians[i].animation_type = (animation_type_t)data->animation_type; + def_animated_parameter_data_convert_bits_function( + &data->cartesians[i].x, &data->encoded_cartesians[i].x, num_bits, + def_iamf_u32_to_i16_to_f32); + def_animated_parameter_data_convert_bits_function( + &data->cartesians[i].y, &data->encoded_cartesians[i].y, num_bits, + def_iamf_u32_to_i16_to_f32); + def_animated_parameter_data_convert_bits_function( + &data->cartesians[i].z, &data->encoded_cartesians[i].z, num_bits, + def_iamf_u32_to_i16_to_f32); + + def_iamf_animated_data_clip(&data->cartesians[i].x, def_clip_normalized); + def_iamf_animated_data_clip(&data->cartesians[i].y, def_clip_normalized); + def_iamf_animated_data_clip(&data->cartesians[i].z, def_clip_normalized); + } + + if (data->animation_type != ck_iamf_animation_type_step && + data->animation_type != ck_iamf_animation_type_inter_linear && + data->animation_type != ck_iamf_animation_type_inter_bezier) { + error("Unsupported animation type %u for cartesian parameter", + data->animation_type); + iamf_parameter_subblock_free(def_parameter_subblock_ptr(data)); + data = 0; + } + return data; +} + +static momentary_loudness_parameter_subblock_t * +_obu_pb_momentary_loudness_parameter_subblock_new(io_context_t *ior, + uint32_t duration) { + io_context_t *r = ior; + momentary_loudness_parameter_subblock_t *data = + def_mallocz(momentary_loudness_parameter_subblock_t, 1); + + if (!data) { + def_err_msg_enomem("momentary loudness parameter data", def_pbo_str); + return 0; + } + + data->base.type = ck_iamf_parameter_type_momentary_loudness; + data->base.subblock_duration = duration; + data->momentary_loudness = ior_8(r); + data->momentary_loudness >>= 2; + info("\tMomentary loudness parameter data: value %u", + data->momentary_loudness); + + return data; +} + +parameter_subblock_t *_obu_pb_subblock_new( + io_context_t *ior, parameter_base_t *base, uint32_t duration, + iamf_pbo_extra_interfaces_t *interfaces) { + parameter_subblock_t *data = 0; + io_context_t *r = ior; + + switch (base->type) { + case ck_iamf_parameter_type_mix_gain: + data = def_parameter_subblock_ptr( + _obu_pb_mix_gain_parameter_subblock_new(r, duration)); + break; + case ck_iamf_parameter_type_demixing: + data = def_parameter_subblock_ptr( + _obu_pb_demixing_info_parameter_subblock_new(r, duration)); + break; + case ck_iamf_parameter_type_recon_gain: + data = def_parameter_subblock_ptr( + _obu_pb_recon_gain_info_parameter_subblock_new( + r, duration, base->parameter_id, interfaces)); + break; + case ck_iamf_parameter_type_polar: + case ck_iamf_parameter_type_dual_polar: + data = def_parameter_subblock_ptr(_obu_pb_polars_parameter_subblock_new( + r, duration, base->type == ck_iamf_parameter_type_polar ? 1 : 2)); + break; + case ck_iamf_parameter_type_cartesian_8: + case ck_iamf_parameter_type_cartesian_16: + data = + def_parameter_subblock_ptr(_obu_pb_cartesians_parameter_subblock_new( + r, duration, base->type, 1)); + break; + case ck_iamf_parameter_type_dual_cartesian_8: + case ck_iamf_parameter_type_dual_cartesian_16: + data = + def_parameter_subblock_ptr(_obu_pb_cartesians_parameter_subblock_new( + r, duration, base->type, 2)); + break; + case ck_iamf_parameter_type_momentary_loudness: + data = def_parameter_subblock_ptr( + _obu_pb_momentary_loudness_parameter_subblock_new(r, duration)); + break; + + default: { + info("invalid type %u", base->type); + break; + } + } + + return data; +} diff --git a/code/src/iamf_dec/obu/parameter_block_obu.h b/code/src/iamf_dec/obu/parameter_block_obu.h new file mode 100755 index 00000000..4d00cd22 --- /dev/null +++ b/code/src/iamf_dec/obu/parameter_block_obu.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file parameter_block_obu.h + * @brief Parameter block OBU APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __PARAMETER_BLOCK_OBU_H__ +#define __PARAMETER_BLOCK_OBU_H__ + +#include "animated_parameter.h" +#include "carray.h" +#include "cvector.h" +#include "iamf_obu.h" +#include "iamf_private_definitions.h" +#include "parameter_base.h" + +/** + * Parameter Block OBU. + * */ + +#define def_demixing_info_parameter_subblock_ptr(a) \ + ((demixing_info_parameter_subblock_t *)a) + +#define def_recon_gain_parameter_subblock_ptr(a) \ + ((recon_gain_parameter_subblock_t *)a) +#define def_parameter_block_obu_ptr(a) def_ptr(iamf_parameter_block_obu, a) +#define def_parameter_subblock_ptr(a) def_ptr(parameter_subblock, a) +#define def_mix_gain_parameter_subblock_ptr(a) \ + def_ptr(mix_gain_parameter_subblock, a) +#define def_polars_parameter_subblock_ptr(a) \ + def_ptr(polars_parameter_subblock, a) +#define def_cartesians_parameter_subblock_ptr(a) \ + def_ptr(cartesians_parameter_subblock, a) +#define def_momentary_loudness_parameter_subblock_ptr(a) \ + def_ptr(momentary_loudness_parameter_subblock, a) + +typedef struct IamfParameterBlockObu { + iamf_obu_t obu; + parameter_base_t *base; + uint32_t duration; + uint32_t constant_subblock_duration; + + array_t *subblocks; // array; +} iamf_parameter_block_obu_t; + +typedef struct ParameterSubblock { + iamf_parameter_type_t type; + uint32_t subblock_duration; +} parameter_subblock_t; + +typedef struct MixGainParameterSubblock { + parameter_subblock_t base; + ap_u32_t gain; + animated_float32_t gain_db; +} mix_gain_parameter_subblock_t; + +typedef struct DemixingInfoParameterSubblock { + parameter_subblock_t base; + uint32_t demixing_mode; +} demixing_info_parameter_subblock_t; + +typedef struct ReconGainInfoParameterSubblock { + parameter_subblock_t base; + array_t *recon_gains; // array; +} recon_gain_parameter_subblock_t; + +typedef struct ReconGain { + uint32_t layer; + uint32_t recon_gain_flags; + array_t *recon_gain; // array + array_t *recon_gain_linear; // array; // need to remove +} recon_gain_t; + +typedef struct PolarsParameterSubblock { + parameter_subblock_t base; + + uint32_t num_polars; + iamf_animation_type_t animation_type; + struct { + apd_u32_t azimuth, elevation, distance; + } encoded_polars[def_max_audio_objects]; + animated_polar_t polars[def_max_audio_objects]; +} polars_parameter_subblock_t; + +typedef struct CartesiansParameterSubblock { + parameter_subblock_t base; + + uint32_t num_cartesians; + iamf_animation_type_t animation_type; + + struct { + apd_u32_t x, y, z; + } encoded_cartesians[def_max_audio_objects]; + animated_cartesian_t cartesians[def_max_audio_objects]; +} cartesians_parameter_subblock_t; + +typedef struct MomentaryLoudnessParameterSubblock { + parameter_subblock_t base; + uint32_t momentary_loudness; +} momentary_loudness_parameter_subblock_t; + +iamf_parameter_block_obu_t *iamf_parameter_block_obu_new( + io_context_t *ior, iamf_pbo_extra_interfaces_t *interfaces); +void iamf_parameter_block_obu_free(iamf_parameter_block_obu_t *obu); +void iamf_parameter_subblock_free(parameter_subblock_t *subblock); +#endif // __PARAMETER_BLOCK_OBU_H__ diff --git a/code/src/iamf_dec/obu/temporal_delimiter_obu.c b/code/src/iamf_dec/obu/temporal_delimiter_obu.c new file mode 100755 index 00000000..384c20b5 --- /dev/null +++ b/code/src/iamf_dec/obu/temporal_delimiter_obu.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file temporal_delimiter_obu.c + * @brief Temporal delimiter OBU implementation. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#include "temporal_delimiter_obu.h" + +#include "iamf_private_definitions.h" +#include "iamf_string.h" + +#undef def_log_tag +#define def_log_tag "OBU_TD" + +iamf_temporal_delimiter_obu_t *iamf_temporal_delimiter_obu_new( + io_context_t *ior, iamf_obu_header_t *header) { + iamf_temporal_delimiter_obu_t *obu = 0; + + obu = def_mallocz(iamf_temporal_delimiter_obu_t, 1); + if (!obu) { + def_err_msg_enomem("Temporal Delimiter OBU", def_iamf_ustr); + return 0; + } + + obu->obu.obu_type = ck_iamf_obu_temporal_delimiter; + obu->key_frame = !header->is_not_key_frame; + + return obu; +} + +void iamf_temporal_delimiter_obu_free(iamf_temporal_delimiter_obu_t *obu) { + if (!obu) return; + + debug("Free iamf_temporal_delimiter_obu_t %p", obu); + + def_free(obu); +} diff --git a/code/src/iamf_dec/obu/temporal_delimiter_obu.h b/code/src/iamf_dec/obu/temporal_delimiter_obu.h new file mode 100755 index 00000000..1365dd72 --- /dev/null +++ b/code/src/iamf_dec/obu/temporal_delimiter_obu.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file temporal_delimiter_obu.h + * @brief Temporal delimiter OBU APIs. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __TEMPORAL_DELIMITER_OBU_H__ +#define __TEMPORAL_DELIMITER_OBU_H__ + +#include "iamf_obu.h" + +#define def_temporal_delimiter_obu_ptr(a) \ + def_ptr(iamf_temporal_delimiter_obu, a) + +/** + * Temporal Delimiter OBU. + * */ + +typedef struct IamfTemporalDelimiterObu { + iamf_obu_t obu; + uint8_t key_frame; +} iamf_temporal_delimiter_obu_t; + +iamf_temporal_delimiter_obu_t *iamf_temporal_delimiter_obu_new( + io_context_t *ior, iamf_obu_header_t *header); +void iamf_temporal_delimiter_obu_free(iamf_temporal_delimiter_obu_t *obu); +#endif // __TEMPORAL_DELIMITER_OBU_H__ diff --git a/code/src/iamf_dec/queue_t.c b/code/src/iamf_dec/queue_t.c deleted file mode 100755 index c0770bc1..00000000 --- a/code/src/iamf_dec/queue_t.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file queue_t.c - * @brief Queue APIs. - * @version 0.1 - * @date Created 23/05/2023 - **/ - -#include "queue_t.h" - -#include - -typedef struct _node_t node_t; -struct _node_t { - void *entity; - node_t *next; -}; - -struct _queue_t { - node_t *front; - node_t *rear; - int count; -}; - -queue_t *queue_new() { - queue_t *q = 0; - q = (queue_t *)calloc(1, sizeof(queue_t)); - return q; -} - -int queue_push(queue_t *q, void *e) { - if (!q || !e) return -1; - node_t *n = 0; - n = (node_t *)calloc(1, sizeof(node_t)); - if (!n) return -2; - n->entity = e; - if (!q->rear) - q->rear = n; - else { - q->rear->next = n; - q->rear = n; - } - ++q->count; - if (!q->front) q->front = q->rear; - return q->count - 1; -} - -void *queue_pop(queue_t *q) { - void *e = 0; - node_t *n = 0; - - if (!q || queue_is_empty(q)) return 0; - - n = q->front; - e = n->entity; - q->front = n->next; - if (!q->front) q->rear = 0; - --q->count; - free(n); - return e; -} - -void *queue_take(queue_t *q, int i) { - void *e = 0; - node_t *n = 0; - - if (!q || queue_length(q) <= i) return 0; - - n = q->front; - for (int k = 0; k < i; ++k) { - n = n->next; - } - e = n->entity; - return e; -} - -int queue_is_empty(queue_t *q) { - if (!q) return 1; - return !q->count; -} - -int queue_length(queue_t *q) { - if (!q) return 0; - return q->count; -} - -void queue_free(queue_t *q) { - if (q) free(q); -} diff --git a/code/src/iamf_dec/queue_t.h b/code/src/iamf_dec/queue_t.h deleted file mode 100755 index e34cf4ce..00000000 --- a/code/src/iamf_dec/queue_t.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2024, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * www.aomedia.org/license/patent. - */ - -/** - * @file queue_t.h - * @brief Queue APIs. - * @version 0.1 - * @date Created 23/05/2023 - **/ - - -#ifndef _QUEUE_H_ -#define _QUEUE_H_ - -typedef struct _queue_t queue_t; - -queue_t *queue_new(); -int queue_push(queue_t *, void *); -void *queue_pop(queue_t *); -void *queue_take(queue_t *, int); -int queue_is_empty(queue_t *); -int queue_length(queue_t *); -void queue_free(queue_t *); - -#endif /* _QUEUE_H_ */ diff --git a/code/src/iamf_dec/speex_resampler.h b/code/src/iamf_dec/speex_resampler.h index 27eefc5c..c97c7cae 100755 --- a/code/src/iamf_dec/speex_resampler.h +++ b/code/src/iamf_dec/speex_resampler.h @@ -28,11 +28,6 @@ POSSIBILITY OF SUCH DAMAGE. */ -/* -AOM-IAMF Standard Deliverable Status: -This software module is out of scope and not part of the IAMF Final Deliverable. -*/ - /** * @file speex_resampler.h * @brief Resampler APIs. @@ -40,7 +35,6 @@ This software module is out of scope and not part of the IAMF Final Deliverable. * @date Created 03/03/2023 **/ - #ifndef SPEEX_RESAMPLER_H #define SPEEX_RESAMPLER_H @@ -56,243 +50,233 @@ extern "C" { #define SPEEX_RESAMPLER_QUALITY_VOIP 3 #define SPEEX_RESAMPLER_QUALITY_DESKTOP 5 - enum { - RESAMPLER_ERR_SUCCESS = 0, - RESAMPLER_ERR_ALLOC_FAILED = 1, - RESAMPLER_ERR_BAD_STATE = 2, - RESAMPLER_ERR_INVALID_ARG = 3, - RESAMPLER_ERR_PTR_OVERLAP = 4, - RESAMPLER_ERR_OVERFLOW = 5, - - RESAMPLER_ERR_MAX_ERROR - }; - struct SpeexResamplerState_; - typedef struct SpeexResamplerState_ SpeexResamplerState; - typedef int(*resampler_basic_func)(SpeexResamplerState *, uint32_t, const float *, uint32_t *, float *, uint32_t *); - struct SpeexResamplerState_ { - uint32_t in_rate; - uint32_t out_rate; - uint32_t num_rate; - uint32_t den_rate; - - int quality; - uint32_t nb_channels; - uint32_t filt_len; - uint32_t mem_alloc_size; - uint32_t buffer_size; - int int_advance; - int frac_advance; - float cutoff; - uint32_t oversample; - int initialised; - int started; - - /* These are per-channel */ - int32_t *last_sample; - uint32_t *samp_frac_num; - uint32_t *magic_samples; - - float *mem; - float *sinc_table; - uint32_t sinc_table_length; - resampler_basic_func resampler_ptr; - - int in_stride; - int out_stride; - }; - - /** Create a new resampler with integer input and output rates. - * @param nb_channels Number of channels to be processed - * @param in_rate Input sampling rate (integer number of Hz). - * @param out_rate Output sampling rate (integer number of Hz). - * @param quality Resampling quality between 0 and 10, where 0 has poor quality - * and 10 has very high quality. - * @return Newly created resampler state - * @retval NULL Error: not enough memory - */ - SpeexResamplerState *speex_resampler_init(uint32_t nb_channels, - uint32_t in_rate, - uint32_t out_rate, - int quality, - int *err); - - /** Create a new resampler with fractional input/output rates. The sampling - * rate ratio is an arbitrary rational number with both the numerator and - * denominator being 32-bit integers. - * @param nb_channels Number of channels to be processed - * @param ratio_num Numerator of the sampling rate ratio - * @param ratio_den Denominator of the sampling rate ratio - * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). - * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). - * @param quality Resampling quality between 0 and 10, where 0 has poor quality - * and 10 has very high quality. - * @return Newly created resampler state - * @retval NULL Error: not enough memory - */ - SpeexResamplerState *speex_resampler_init_frac(uint32_t nb_channels, - uint32_t ratio_num, - uint32_t ratio_den, - uint32_t in_rate, - uint32_t out_rate, - int quality, - int *err); - - /** Destroy a resampler state. - * @param st Resampler state - */ - void speex_resampler_destroy(SpeexResamplerState *st); - - /** Resample an int array. The input and output buffers must *not* overlap. - * @param st Resampler state - * @param channel_index Index of the channel to process for the multi-channel - * base (0 otherwise) - * @param in Input buffer - * @param in_len Number of input samples in the input buffer. Returns the number - * of samples processed - * @param out Output buffer - * @param out_len Size of the output buffer. Returns the number of samples written - */ - int speex_resampler_process_int(SpeexResamplerState *st, - uint32_t channel_index, - const int16_t *in, - uint32_t *in_len, - int16_t *out, - uint32_t *out_len); - - /** Resample an interleaved int array. The input and output buffers must *not* overlap. - * @param st Resampler state - * @param in Input buffer - * @param in_len Number of input samples in the input buffer. Returns the number - * of samples processed. This is all per-channel. - * @param out Output buffer - * @param out_len Size of the output buffer. Returns the number of samples written. - * This is all per-channel. - */ - int speex_resampler_process_interleaved_int(SpeexResamplerState *st, - const int16_t *in, - uint32_t *in_len, - int16_t *out, - uint32_t *out_len); - - /** Set (change) the input/output sampling rates (integer value). - * @param st Resampler state - * @param in_rate Input sampling rate (integer number of Hz). - * @param out_rate Output sampling rate (integer number of Hz). - */ - int speex_resampler_set_rate(SpeexResamplerState *st, - uint32_t in_rate, - uint32_t out_rate); - - /** Get the current input/output sampling rates (integer value). - * @param st Resampler state - * @param in_rate Input sampling rate (integer number of Hz) copied. - * @param out_rate Output sampling rate (integer number of Hz) copied. - */ - void speex_resampler_get_rate(SpeexResamplerState *st, - uint32_t *in_rate, - uint32_t *out_rate); - - /** Set (change) the input/output sampling rates and resampling ratio - * (fractional values in Hz supported). - * @param st Resampler state - * @param ratio_num Numerator of the sampling rate ratio - * @param ratio_den Denominator of the sampling rate ratio - * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). - * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). - */ - int speex_resampler_set_rate_frac(SpeexResamplerState *st, - uint32_t ratio_num, - uint32_t ratio_den, - uint32_t in_rate, - uint32_t out_rate); - - /** Get the current resampling ratio. This will be reduced to the least - * common denominator. - * @param st Resampler state - * @param ratio_num Numerator of the sampling rate ratio copied - * @param ratio_den Denominator of the sampling rate ratio copied - */ - void speex_resampler_get_ratio(SpeexResamplerState *st, - uint32_t *ratio_num, - uint32_t *ratio_den); - - /** Set (change) the conversion quality. - * @param st Resampler state - * @param quality Resampling quality between 0 and 10, where 0 has poor - * quality and 10 has very high quality. - */ - int speex_resampler_set_quality(SpeexResamplerState *st, - int quality); - - /** Get the conversion quality. - * @param st Resampler state - * @param quality Resampling quality between 0 and 10, where 0 has poor - * quality and 10 has very high quality. - */ - void speex_resampler_get_quality(SpeexResamplerState *st, - int *quality); - - /** Set (change) the input stride. - * @param st Resampler state - * @param stride Input stride - */ - void speex_resampler_set_input_stride(SpeexResamplerState *st, - uint32_t stride); - - /** Get the input stride. - * @param st Resampler state - * @param stride Input stride copied - */ - void speex_resampler_get_input_stride(SpeexResamplerState *st, - uint32_t *stride); - - /** Set (change) the output stride. - * @param st Resampler state - * @param stride Output stride - */ - void speex_resampler_set_output_stride(SpeexResamplerState *st, - uint32_t stride); - - /** Get the output stride. - * @param st Resampler state copied - * @param stride Output stride - */ - void speex_resampler_get_output_stride(SpeexResamplerState *st, - uint32_t *stride); - - /** Get the latency introduced by the resampler measured in input samples. - * @param st Resampler state - */ - int speex_resampler_get_input_latency(SpeexResamplerState *st); - - /** Get the latency introduced by the resampler measured in output samples. - * @param st Resampler state - */ - int speex_resampler_get_output_latency(SpeexResamplerState *st); - - /** Make sure that the first samples to go out of the resamplers don't have - * leading zeros. This is only useful before starting to use a newly created - * resampler. It is recommended to use that when resampling an audio file, as - * it will generate a file with the same length. For real-time processing, - * it is probably easier not to use this call (so that the output duration - * is the same for the first frame). - * @param st Resampler state - */ - int speex_resampler_skip_zeros(SpeexResamplerState *st); - - /** Reset a resampler so a new (unrelated) stream can be processed. - * @param st Resampler state - */ - int speex_resampler_reset_mem(SpeexResamplerState *st); - - /** Returns the English meaning for an error code - * @param err Error code - * @return English string - */ - const char *speex_resampler_strerror(int err); - - int speex_resampler_process_float(SpeexResamplerState *st, uint32_t channel_index, const float *in, uint32_t *in_len, float *out, uint32_t *out_len); - int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, uint32_t *in_len, float *out, uint32_t *out_len); +enum { + RESAMPLER_ERR_SUCCESS = 0, + RESAMPLER_ERR_ALLOC_FAILED = 1, + RESAMPLER_ERR_BAD_STATE = 2, + RESAMPLER_ERR_INVALID_ARG = 3, + RESAMPLER_ERR_PTR_OVERLAP = 4, + RESAMPLER_ERR_OVERFLOW = 5, + + RESAMPLER_ERR_MAX_ERROR +}; +struct SpeexResamplerState_; +typedef struct SpeexResamplerState_ SpeexResamplerState; +typedef int (*resampler_basic_func)(SpeexResamplerState *, uint32_t, + const float *, uint32_t *, float *, + uint32_t *); +struct SpeexResamplerState_ { + uint32_t in_rate; + uint32_t out_rate; + uint32_t num_rate; + uint32_t den_rate; + + int quality; + uint32_t nb_channels; + uint32_t filt_len; + uint32_t mem_alloc_size; + uint32_t buffer_size; + int int_advance; + int frac_advance; + float cutoff; + uint32_t oversample; + int initialised; + int started; + + /* These are per-channel */ + int32_t *last_sample; + uint32_t *samp_frac_num; + uint32_t *magic_samples; + + float *mem; + float *sinc_table; + uint32_t sinc_table_length; + resampler_basic_func resampler_ptr; + + int in_stride; + int out_stride; +}; + +/** Create a new resampler with integer input and output rates. + * @param nb_channels Number of channels to be processed + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init(uint32_t nb_channels, + uint32_t in_rate, uint32_t out_rate, + int quality, int *err); + +/** Create a new resampler with fractional input/output rates. The sampling + * rate ratio is an arbitrary rational number with both the numerator and + * denominator being 32-bit integers. + * @param nb_channels Number of channels to be processed + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init_frac( + uint32_t nb_channels, uint32_t ratio_num, uint32_t ratio_den, + uint32_t in_rate, uint32_t out_rate, int quality, int *err); + +/** Destroy a resampler state. + * @param st Resampler state + */ +void speex_resampler_destroy(SpeexResamplerState *st); + +/** Resample an int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param channel_index Index of the channel to process for the multi-channel + * base (0 otherwise) + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples + * written + */ +int speex_resampler_process_int(SpeexResamplerState *st, uint32_t channel_index, + const int16_t *in, uint32_t *in_len, + int16_t *out, uint32_t *out_len); + +/** Resample an interleaved int array. The input and output buffers must *not* + * overlap. + * @param st Resampler state + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed. This is all per-channel. + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples + * written. This is all per-channel. + */ +int speex_resampler_process_interleaved_int(SpeexResamplerState *st, + const int16_t *in, uint32_t *in_len, + int16_t *out, uint32_t *out_len); + +/** Set (change) the input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + */ +int speex_resampler_set_rate(SpeexResamplerState *st, uint32_t in_rate, + uint32_t out_rate); + +/** Get the current input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz) copied. + * @param out_rate Output sampling rate (integer number of Hz) copied. + */ +void speex_resampler_get_rate(SpeexResamplerState *st, uint32_t *in_rate, + uint32_t *out_rate); + +/** Set (change) the input/output sampling rates and resampling ratio + * (fractional values in Hz supported). + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + */ +int speex_resampler_set_rate_frac(SpeexResamplerState *st, uint32_t ratio_num, + uint32_t ratio_den, uint32_t in_rate, + uint32_t out_rate); + +/** Get the current resampling ratio. This will be reduced to the least + * common denominator. + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio copied + * @param ratio_den Denominator of the sampling rate ratio copied + */ +void speex_resampler_get_ratio(SpeexResamplerState *st, uint32_t *ratio_num, + uint32_t *ratio_den); + +/** Set (change) the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +int speex_resampler_set_quality(SpeexResamplerState *st, int quality); + +/** Get the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +void speex_resampler_get_quality(SpeexResamplerState *st, int *quality); + +/** Set (change) the input stride. + * @param st Resampler state + * @param stride Input stride + */ +void speex_resampler_set_input_stride(SpeexResamplerState *st, uint32_t stride); + +/** Get the input stride. + * @param st Resampler state + * @param stride Input stride copied + */ +void speex_resampler_get_input_stride(SpeexResamplerState *st, + uint32_t *stride); + +/** Set (change) the output stride. + * @param st Resampler state + * @param stride Output stride + */ +void speex_resampler_set_output_stride(SpeexResamplerState *st, + uint32_t stride); + +/** Get the output stride. + * @param st Resampler state copied + * @param stride Output stride + */ +void speex_resampler_get_output_stride(SpeexResamplerState *st, + uint32_t *stride); + +/** Get the latency introduced by the resampler measured in input samples. + * @param st Resampler state + */ +int speex_resampler_get_input_latency(SpeexResamplerState *st); + +/** Get the latency introduced by the resampler measured in output samples. + * @param st Resampler state + */ +int speex_resampler_get_output_latency(SpeexResamplerState *st); + +/** Make sure that the first samples to go out of the resamplers don't have + * leading zeros. This is only useful before starting to use a newly created + * resampler. It is recommended to use that when resampling an audio file, as + * it will generate a file with the same length. For real-time processing, + * it is probably easier not to use this call (so that the output duration + * is the same for the first frame). + * @param st Resampler state + */ +int speex_resampler_skip_zeros(SpeexResamplerState *st); + +/** Reset a resampler so a new (unrelated) stream can be processed. + * @param st Resampler state + */ +int speex_resampler_reset_mem(SpeexResamplerState *st); + +/** Returns the English meaning for an error code + * @param err Error code + * @return English string + */ +const char *speex_resampler_strerror(int err); + +int speex_resampler_process_float(SpeexResamplerState *st, + uint32_t channel_index, const float *in, + uint32_t *in_len, float *out, + uint32_t *out_len); +int speex_resampler_process_interleaved_float(SpeexResamplerState *st, + const float *in, uint32_t *in_len, + float *out, uint32_t *out_len); #ifdef __cplusplus } diff --git a/code/src/iamf_dec/vlogging_tool_sr.c b/code/src/iamf_dec/vlogging_tool_sr.c index 8761a395..8775160a 100755 --- a/code/src/iamf_dec/vlogging_tool_sr.c +++ b/code/src/iamf_dec/vlogging_tool_sr.c @@ -27,9 +27,8 @@ #include #include -#include "IAMF_OBU.h" -#include "IAMF_utils.h" -#include "bitstream.h" +#include "iamf_utils.h" +#include "obu/iamf_obu_all.h" #include "vlogging_tool_sr.h" #define LOG_BUFFER_SIZE 100000 @@ -282,41 +281,97 @@ int write_yaml_form(char* log, uint8_t indent, const char* format, ...) { return ret; } +#if defined(SUPPORT_VERIFIER) +/** + * @brief Writes IAMF sequence header OBU information to log + * + * This function logs the sequence header OBU data including IAMF code, + * primary profile, and additional profile information in YAML format. + * + * @param idx The index/ID of the OBU being logged + * @param obu Pointer to the IAMF sequence header OBU data + * @param log Buffer to write the log output to + * + * @note This function performs input validation and will handle NULL pointers + * gracefully by writing an error message to the log. + */ static void write_sequence_header_log(uint64_t idx, void* obu, char* log) { - IAMF_Version* mc_obu = (IAMF_Version*)obu; + // Input validation + if (!obu) { + log += write_prefix(LOG_OBU, log); + log += write_yaml_form(log, 0, "IaSequenceHeaderOBU_%u:", idx); + log += write_yaml_form(log, 0, "- error: \"NULL OBU pointer\""); + write_postfix(LOG_OBU, log); + return; + } + + if (!log) { + return; // Cannot log if buffer is NULL + } + // Cast to the correct structure type + iamf_sequence_header_obu_t* sequence_header = + (iamf_sequence_header_obu_t*)obu; + + // Write log header log += write_prefix(LOG_OBU, log); - log += write_yaml_form(log, 0, "IaSequenceHeaderOBU_%llu:", idx); - log += write_yaml_form(log, 0, "- ia_code: %u", htonl2(mc_obu->iamf_code)); - log += - write_yaml_form(log, 1, "primary_profile: %u", mc_obu->primary_profile); + log += write_yaml_form(log, 0, "IaSequenceHeaderOBU_%u:", idx); + + // Write IAMF code with proper byte order conversion + uint32_t iamf_code_host = htonl2(sequence_header->iamf_code); + log += write_yaml_form(log, 0, "- ia_code: %u", iamf_code_host); + + // Write profile information + log += write_yaml_form(log, 1, "primary_profile: %u", + sequence_header->primary_profile); log += write_yaml_form(log, 1, "additional_profile: %u", - mc_obu->additional_profile); + sequence_header->additional_profile); + + // Write log footer write_postfix(LOG_OBU, log); } +/** + * @brief Writes IAMF codec config OBU information to log + * + * This function logs the codec config OBU data including codec ID, samples per + * frame, and decoder-specific configuration information in YAML format. It + * supports multiple codec types (AAC, FLAC, Opus, LPCM) with detailed parsing + * of their respective decoder configurations. + * + * @param idx The index/ID of the OBU being logged + * @param obu Pointer to the IAMF codec config OBU data + * @param log Buffer to write the log output to + * + * @note This function performs input validation and will handle NULL pointers + * gracefully by writing an error message to the log. + */ static void write_codec_config_log(uint64_t idx, void* obu, char* log) { - IAMF_CodecConf* cc_obu = (IAMF_CodecConf*)obu; + iamf_codec_config_obu_t* codec_config = (iamf_codec_config_obu_t*)obu; log += write_prefix(LOG_OBU, log); log += write_yaml_form(log, 0, "CodecConfigOBU_%llu:", idx); - log += - write_yaml_form(log, 0, "- codec_config_id: %llu", cc_obu->codec_conf_id); + log += write_yaml_form(log, 0, "- codec_config_id: %u", + codec_config->codec_config_id); log += write_yaml_form(log, 1, "codec_config:"); - log += write_yaml_form(log, 2, "codec_id: %u", htonl2(cc_obu->codec_id)); - log += write_yaml_form(log, 2, "num_samples_per_frame: %llu", - cc_obu->nb_samples_per_frame); log += - write_yaml_form(log, 2, "audio_roll_distance: %d", cc_obu->roll_distance); + write_yaml_form(log, 2, "codec_id: %u", htonl2(codec_config->codec_id)); + log += write_yaml_form(log, 2, "num_samples_per_frame: %u", + codec_config->num_samples_per_frame); + log += write_yaml_form(log, 2, "audio_roll_distance: %d", + codec_config->audio_roll_distance); // NOTE: Self parsing - if (cc_obu->codec_id == get_4cc_codec_id('m', 'p', '4', 'a') || - cc_obu->codec_id == get_4cc_codec_id('e', 's', 'd', 's')) { + if (codec_config->codec_id == get_4cc_codec_id('m', 'p', '4', 'a') || + codec_config->codec_id == get_4cc_codec_id('e', 's', 'd', 's')) { log += write_yaml_form(log, 2, "decoder_config_aac:"); - BitStream b; - bs(&b, cc_obu->decoder_conf, cc_obu->decoder_conf_size); + io_context_t io_ctx; + bits_io_context_t bits_ctx; + ioc_init(&io_ctx, codec_config->decoder_config->data, + codec_config->decoder_config->size); + bits_ioc_init(&bits_ctx, &io_ctx); // decoder_config_descriptor_tag // object_type_indication @@ -338,51 +393,58 @@ static void write_codec_config_log(uint64_t idx, void* obu, char* log) { // - extension_flag log += write_yaml_form(log, 3, "decoder_config_descriptor_tag: %u", - bs_get32b(&b, 8)); + bits_ior_le32(&bits_ctx, 8)); + log += write_yaml_form(log, 3, "object_type_indication: %u", + bits_ior_le32(&bits_ctx, 8)); log += - write_yaml_form(log, 3, "object_type_indication: %u", bs_get32b(&b, 8)); - log += write_yaml_form(log, 3, "stream_type: %u", bs_get32b(&b, 6)); - log += write_yaml_form(log, 3, "upstream: %u", bs_get32b(&b, 1)); - bs_skip(&b, 1); // reserved + write_yaml_form(log, 3, "stream_type: %u", bits_ior_le32(&bits_ctx, 6)); + log += write_yaml_form(log, 3, "upstream: %u", bits_ior_le32(&bits_ctx, 1)); + bits_ior_le32(&bits_ctx, 1); // reserved - bs_get32b(&b, 24); // buffer_size_db - bs_get32b(&b, 32); // max_bitrate - bs_get32b(&b, 32); // average_bit_rate + bits_ior_le32(&bits_ctx, 24); // buffer_size_db + bits_ior_le32(&bits_ctx, 32); // max_bitrate + bits_ior_le32(&bits_ctx, 32); // average_bit_rate log += write_yaml_form(log, 3, "decoder_specific_info:"); log += write_yaml_form(log, 4, "decoder_specific_info_descriptor_tag: %u", - bs_get32b(&b, 8)); - log += write_yaml_form(log, 4, "audio_object_type: %u", bs_get32b(&b, 5)); + bits_ior_le32(&bits_ctx, 8)); + log += write_yaml_form(log, 4, "audio_object_type: %u", + bits_ior_le32(&bits_ctx, 5)); uint8_t sample_frequency_index = - bs_get32b(&b, 4); // sample_frequency_index + bits_ior_le32(&bits_ctx, 4); // sample_frequency_index if (sample_frequency_index == 0xf) { - bs_get32b(&b, 24); // sampling_frequency + bits_ior_le32(&bits_ctx, 24); // sampling_frequency } - log += - write_yaml_form(log, 4, "channel_configuration: %u", bs_get32b(&b, 4)); + log += write_yaml_form(log, 4, "channel_configuration: %u", + bits_ior_le32(&bits_ctx, 4)); log += write_yaml_form(log, 3, "ga_specific_config:"); - log += write_yaml_form(log, 4, "frame_length_flag: %u", bs_get32b(&b, 1)); - log += - write_yaml_form(log, 4, "depends_on_core_coder: %u", bs_get32b(&b, 1)); - log += write_yaml_form(log, 4, "extension_flag: %u", bs_get32b(&b, 1)); - } else if (cc_obu->codec_id == get_4cc_codec_id('f', 'L', 'a', 'C')) { + log += write_yaml_form(log, 4, "frame_length_flag: %u", + bits_ior_le32(&bits_ctx, 1)); + log += write_yaml_form(log, 4, "depends_on_core_coder: %u", + bits_ior_le32(&bits_ctx, 1)); + log += write_yaml_form(log, 4, "extension_flag: %u", + bits_ior_le32(&bits_ctx, 1)); + } else if (codec_config->codec_id == get_4cc_codec_id('f', 'L', 'a', 'C')) { // "fLaC", METADATA_BLOCK log += write_yaml_form(log, 2, "decoder_config_flac:"); log += write_yaml_form(log, 3, "metadata_blocks:"); - BitStream b; - bs(&b, cc_obu->decoder_conf, cc_obu->decoder_conf_size); + io_context_t io_ctx; + bits_io_context_t bits_ctx; + ioc_init(&io_ctx, codec_config->decoder_config->data, + codec_config->decoder_config->size); + bits_ioc_init(&bits_ctx, &io_ctx); uint8_t last_metadata_block_flag = 0; uint8_t block_type = 0; uint32_t metadata_data_block_length = 0; do { - last_metadata_block_flag = bs_get32b(&b, 1); - block_type = bs_get32b(&b, 7); - metadata_data_block_length = bs_get32b(&b, 24); + last_metadata_block_flag = bits_ior_le32(&bits_ctx, 1); + block_type = bits_ior_le32(&bits_ctx, 7); + metadata_data_block_length = bits_ior_le32(&bits_ctx, 24); log += write_yaml_form(log, 4, "- header:"); log += write_yaml_form(log, 6, "last_metadata_block_flag: %u", @@ -403,27 +465,27 @@ static void write_codec_config_log(uint64_t idx, void* obu, char* log) { // <36> // <128> - uint16_t minimum_block_size = bs_get32b(&b, 16); - uint16_t maximum_block_size = bs_get32b(&b, 16); - uint32_t minumum_frame_size = bs_get32b(&b, 24); - uint32_t maximum_frame_size = bs_get32b(&b, 24); - uint32_t sample_rate = bs_get32b(&b, 20); - ; - uint8_t number_of_channels = bs_get32b(&b, 3); - uint8_t bits_per_sample = bs_get32b(&b, 5); + uint16_t minimum_block_size = bits_ior_le32(&bits_ctx, 16); + uint16_t maximum_block_size = bits_ior_le32(&bits_ctx, 16); + uint32_t minumum_frame_size = bits_ior_le32(&bits_ctx, 24); + uint32_t maximum_frame_size = bits_ior_le32(&bits_ctx, 24); + uint32_t sample_rate = bits_ior_le32(&bits_ctx, 20); + uint8_t number_of_channels = bits_ior_le32(&bits_ctx, 3); + uint8_t bits_per_sample = bits_ior_le32(&bits_ctx, 5); uint64_t total_samples_in_stream = 0; uint8_t md5_signature[16] = { 0, }; uint64_t be_value = 0; // uint8_t be_value[8] = { 0, }; - bs_read(&b, (uint8_t*)&be_value, 4); + ior_read(&io_ctx, (uint8_t*)&be_value, 4); be_value <<= 32; + // ior_read(&io_ctx, (uint8_t*)&be_value + 4, 4); // htonll2 total_samples_in_stream = htonll2(be_value); - bs_read(&b, (uint8_t*)md5_signature, 16); + ior_read(&io_ctx, (uint8_t*)md5_signature, 16); log += write_yaml_form(log, 5, "stream_info:"); @@ -451,114 +513,167 @@ static void write_codec_config_log(uint64_t idx, void* obu, char* log) { } log += write_yaml_form(log, 6, "md5_signature: %s", hex_string); } + } while (last_metadata_block_flag == 0); + } else if (codec_config->codec_id == get_4cc_codec_id('O', 'p', 'u', 's') || + codec_config->codec_id == get_4cc_codec_id('d', 'O', 'p', 's')) { + log += write_yaml_form(log, 2, "decoder_config_opus:"); - } while (!last_metadata_block_flag); + io_context_t io_ctx; + bits_io_context_t bits_ctx; + ioc_init(&io_ctx, codec_config->decoder_config->data, + codec_config->decoder_config->size); + bits_ioc_init(&bits_ctx, &io_ctx); - } else if (cc_obu->codec_id == get_4cc_codec_id('O', 'p', 'u', 's') || - cc_obu->codec_id == get_4cc_codec_id('d', 'O', 'p', 's')) { - uint8_t version = readu8(cc_obu->decoder_conf, 0); - uint8_t output_channel_count = readu8(cc_obu->decoder_conf, 1); - uint16_t pre_skip = readu16be(cc_obu->decoder_conf, 2); - uint32_t input_sample_rate = readu32be(cc_obu->decoder_conf, 4); - uint16_t output_gain = readu16be(cc_obu->decoder_conf, 8); - uint8_t channel_mapping_family = readu8(cc_obu->decoder_conf, 10); + // <8> + uint8_t version = bits_ior_le32(&bits_ctx, 8); + uint8_t channel_count = bits_ior_le32(&bits_ctx, 8); + uint16_t pre_skip = bits_ior_le32(&bits_ctx, 16); + uint32_t input_sample_rate = bits_ior_le32(&bits_ctx, 32); + uint16_t output_gain = (int16_t)bits_ior_le32(&bits_ctx, 16); + uint8_t mapping_family = bits_ior_le32(&bits_ctx, 8); - log += write_yaml_form(log, 2, "decoder_config_opus:"); log += write_yaml_form(log, 3, "version: %u", version); - log += write_yaml_form(log, 3, "output_channel_count: %u", - output_channel_count); + log += write_yaml_form(log, 3, "output_channel_count: %u", channel_count); log += write_yaml_form(log, 3, "pre_skip: %u", pre_skip); log += write_yaml_form(log, 3, "input_sample_rate: %lu", input_sample_rate); - log += write_yaml_form(log, 3, "output_gain: %u", output_gain); - log += - write_yaml_form(log, 3, "mapping_family: %u", channel_mapping_family); - } else if (cc_obu->codec_id == get_4cc_codec_id('i', 'p', 'c', 'm')) { - uint8_t sample_format_flags = readu8(cc_obu->decoder_conf, 0); - uint8_t sample_size = readu8(cc_obu->decoder_conf, 1); - uint32_t sample_rate = readu32be(cc_obu->decoder_conf, 2); + log += write_yaml_form(log, 3, "output_gain: %d", output_gain); + log += write_yaml_form(log, 3, "mapping_family: %u", mapping_family); + } else if (codec_config->codec_id == get_4cc_codec_id('i', 'p', 'c', 'm')) { log += write_yaml_form(log, 2, "decoder_config_lpcm:"); + + io_context_t io_ctx, *r; + ioc_init(&io_ctx, codec_config->decoder_config->data, + codec_config->decoder_config->size); + + r = &io_ctx; + uint8_t sample_format_flags = ior_8(r); + uint8_t sample_size = ior_8(r); + uint32_t sample_rate = ior_b32(r); + log += write_yaml_form(log, 3, "sample_format_flags: %u", sample_format_flags); log += write_yaml_form(log, 3, "sample_size: %u", sample_size); log += write_yaml_form(log, 3, "sample_rate: %lu", sample_rate); } + write_postfix(LOG_OBU, log); } +/** + * @brief Writes IAMF audio element OBU information to log + * + * This function logs the audio element OBU data including element ID, type, + * codec configuration, substream IDs, and parameters in YAML format. It + * supports both channel-based and scene-based audio elements with their + * respective configuration details. + * + * @param idx The index/ID of the OBU being logged + * @param obu Pointer to the IAMF audio element OBU data + * @param log Buffer to write the log output to + * + * @note This function performs input validation and will handle NULL pointers + * gracefully by writing an error message to the log. + */ static void write_audio_element_log(uint64_t idx, void* obu, char* log) { - IAMF_Element* ae_obu = (IAMF_Element*)obu; + iamf_audio_element_obu_t* audio_element = (iamf_audio_element_obu_t*)obu; log += write_prefix(LOG_OBU, log); - log += write_yaml_form(log, 0, "AudioElementOBU_%llu:", idx); - log += - write_yaml_form(log, 0, "- audio_element_id: %llu", ae_obu->element_id); - log += - write_yaml_form(log, 1, "audio_element_type: %u", ae_obu->element_type); - log += - write_yaml_form(log, 1, "codec_config_id: %llu", ae_obu->codec_config_id); - log += write_yaml_form(log, 1, "num_substreams: %llu", ae_obu->nb_substreams); + log += write_yaml_form(log, 0, "AudioElementOBU_%u:", idx); + log += write_yaml_form(log, 0, "- audio_element_id: %u", + audio_element->audio_element_id); + log += write_yaml_form(log, 1, "audio_element_type: %u", + audio_element->audio_element_type); + log += write_yaml_form(log, 1, "codec_config_id: %u", + audio_element->codec_config_id); + log += write_yaml_form(log, 1, "num_substreams: %u", + audio_element->audio_substream_ids + ? array_size(audio_element->audio_substream_ids) + : 0); log += write_yaml_form(log, 1, "audio_substream_ids:"); - for (uint64_t i = 0; i < ae_obu->nb_substreams; ++i) { - log += write_yaml_form(log, 1, "- %llu", ae_obu->substream_ids[i]); + if (audio_element->audio_substream_ids) { + int32_t substream_count = array_size(audio_element->audio_substream_ids); + for (int32_t i = 0; i < substream_count; ++i) { + uint32_t substream_id = + def_value_wrap_i32(array_at(audio_element->audio_substream_ids, i)); + log += write_yaml_form(log, 1, "- %u", substream_id); + } } - log += write_yaml_form(log, 1, "num_parameters: %llu", ae_obu->nb_parameters); - if (ae_obu->nb_parameters) { + log += write_yaml_form( + log, 1, "num_parameters: %u", + audio_element->parameters ? array_size(audio_element->parameters) : 0); + if (audio_element->parameters && array_size(audio_element->parameters) > 0) { log += write_yaml_form(log, 1, "audio_element_params:"); - for (uint64_t i = 0; i < ae_obu->nb_parameters; ++i) { - ParameterBase* param = ae_obu->parameters[i]; + int32_t param_count = array_size(audio_element->parameters); + for (int32_t i = 0; i < param_count; ++i) { + parameter_base_t* param = def_value_wrap_type_ptr( + parameter_base_t, array_at(audio_element->parameters, i)); if (!param) continue; log += - write_yaml_form(log, 1, "- param_definition_type: %llu", param->type); + write_yaml_form(log, 1, "- param_definition_type: %u", param->type); - if (param->type == IAMF_PARAMETER_TYPE_DEMIXING) { - DemixingParameter* dp = (DemixingParameter*)param; + if (param->type == ck_iamf_parameter_type_demixing) { + demixing_info_parameter_base_t* dp = + (demixing_info_parameter_base_t*)param; log += write_yaml_form(log, 2, "demixing_param:"); log += write_yaml_form(log, 3, "param_definition:"); - log += write_yaml_form(log, 4, "parameter_id: %llu", dp->base.id); - log += write_yaml_form(log, 4, "parameter_rate: %llu", dp->base.rate); log += - write_yaml_form(log, 4, "param_definition_mode: %u", dp->base.mode); - if (dp->base.mode == 0) { - log += write_yaml_form(log, 4, "duration: %llu", dp->base.duration); - log += write_yaml_form(log, 4, "num_subblocks: %llu", - dp->base.nb_segments); - log += write_yaml_form(log, 4, "constant_subblock_duration: %llu", - dp->base.constant_segment_interval); - if (dp->base.constant_segment_interval == 0) { + write_yaml_form(log, 4, "parameter_id: %lu", dp->base.parameter_id); + log += write_yaml_form(log, 4, "parameter_rate: %lu", + dp->base.parameter_rate); + log += write_yaml_form(log, 4, "param_definition_mode: %u", + dp->base.param_definition_mode); + if (dp->base.param_definition_mode == 0) { + log += write_yaml_form(log, 4, "duration: %lu", dp->base.duration); + int32_t subblock_count = dp->base.subblock_durations + ? array_size(dp->base.subblock_durations) + : dp->base.constant_subblock_duration > 0 + ? 1 + : 0; + log += write_yaml_form(log, 4, "num_subblocks: %lu", subblock_count); + log += write_yaml_form(log, 4, "constant_subblock_duration: %lu", + dp->base.constant_subblock_duration); + if (dp->base.constant_subblock_duration == 0 && + dp->base.subblock_durations) { log += write_yaml_form(log, 4, "subblock_durations:"); - for (uint64_t j = 0; j < dp->base.nb_segments; ++j) { - log += write_yaml_form(log, 4, "- %llu", - dp->base.segments[j].segment_interval); + for (int32_t j = 0; j < subblock_count; ++j) { + uint32_t duration = + def_value_wrap_i32(array_at(dp->base.subblock_durations, j)); + log += write_yaml_form(log, 4, "- %u", duration); } } } log += write_yaml_form(log, 3, "default_demixing_info_parameter_data:"); - log += write_yaml_form(log, 4, "dmixp_mode: %lu", dp->mode); - - log += write_yaml_form(log, 3, "default_w: %lu", dp->w); - } else if (param->type == IAMF_PARAMETER_TYPE_RECON_GAIN) { - ReconGainParameter* rp = (ReconGainParameter*)param; + log += write_yaml_form(log, 4, "dmixp_mode: %lu", dp->dmixp_mode); + log += write_yaml_form(log, 3, "default_w: %lu", dp->default_w); + } else if (param->type == ck_iamf_parameter_type_recon_gain) { + recon_gain_parameter_base_t* rg = (recon_gain_parameter_base_t*)param; log += write_yaml_form(log, 2, "recon_gain_param:"); - log += write_yaml_form(log, 3, "param_definition:"); - log += write_yaml_form(log, 4, "parameter_id: %llu", rp->base.id); - log += write_yaml_form(log, 4, "parameter_rate: %llu", rp->base.rate); - log += - write_yaml_form(log, 4, "param_definition_mode: %u", rp->base.mode); - if (rp->base.mode == 0) { - log += write_yaml_form(log, 4, "duration: %llu", rp->base.duration); - log += write_yaml_form(log, 4, "num_subblocks: %llu", - rp->base.nb_segments); - log += write_yaml_form(log, 4, "constant_subblock_duration: %llu", - rp->base.constant_segment_interval); - if (rp->base.constant_segment_interval == 0) { + log += write_yaml_form(log, 4, "parameter_id: %u", param->parameter_id); + log += write_yaml_form(log, 4, "parameter_rate: %u", + param->parameter_rate); + log += write_yaml_form(log, 4, "param_definition_mode: %u", + param->param_definition_mode); + if (param->param_definition_mode == 0) { + log += write_yaml_form(log, 4, "duration: %lu", rg->base.duration); + int32_t subblock_count = rg->base.subblock_durations + ? array_size(rg->base.subblock_durations) + : rg->base.constant_subblock_duration > 0 + ? 1 + : 0; + log += write_yaml_form(log, 4, "num_subblocks: %lu", subblock_count); + log += write_yaml_form(log, 4, "constant_subblock_duration: %u", + param->constant_subblock_duration); + if (param->constant_subblock_duration == 0 && + param->subblock_durations) { log += write_yaml_form(log, 4, "subblock_durations:"); - for (uint64_t j = 0; j < rp->base.nb_segments; ++j) { - log += write_yaml_form(log, 4, "- %llu", - rp->base.segments[j].segment_interval); + for (int32_t j = 0; j < subblock_count; ++j) { + uint32_t duration = + def_value_wrap_i32(array_at(param->subblock_durations, j)); + log += write_yaml_form(log, 4, "- %u", duration); } } } @@ -566,324 +681,681 @@ static void write_audio_element_log(uint64_t idx, void* obu, char* log) { } } - if (ae_obu->element_type == AUDIO_ELEMENT_TYPE_CHANNEL_BASED) { + if (audio_element->audio_element_type == + ck_audio_element_type_channel_based) { log += write_yaml_form(log, 1, "scalable_channel_layout_config:"); - log += write_yaml_form(log, 2, "num_layers: %u", - ae_obu->channels_conf->nb_layers); + channel_based_audio_element_obu_t* channel_element = + (channel_based_audio_element_obu_t*)audio_element; + int32_t layer_count = + channel_element->channel_audio_layer_configs + ? array_size(channel_element->channel_audio_layer_configs) + : 0; + log += write_yaml_form(log, 2, "num_layers: %u", layer_count); log += write_yaml_form(log, 2, "channel_audio_layer_configs:"); - for (uint32_t i = 0; i < ae_obu->channels_conf->nb_layers; ++i) { - ChannelLayerConf* layer_conf = &ae_obu->channels_conf->layer_conf_s[i]; + for (int32_t i = 0; i < layer_count; ++i) { + obu_channel_layer_config_t* layer_config = def_value_wrap_type_ptr( + obu_channel_layer_config_t, + array_at(channel_element->channel_audio_layer_configs, i)); log += write_yaml_form(log, 2, "- loudspeaker_layout: %u", - layer_conf->loudspeaker_layout); + layer_config->loudspeaker_layout); log += write_yaml_form(log, 3, "output_gain_is_present_flag: %u", - layer_conf->output_gain_flag); + layer_config->output_gain_is_present_flag); log += write_yaml_form(log, 3, "recon_gain_is_present_flag: %u", - layer_conf->recon_gain_flag); + layer_config->recon_gain_is_present_flag); log += write_yaml_form(log, 3, "substream_count: %u", - layer_conf->nb_substreams); + layer_config->substream_count); log += write_yaml_form(log, 3, "coupled_substream_count: %u", - layer_conf->nb_coupled_substreams); - if (layer_conf->output_gain_flag) { + layer_config->coupled_substream_count); + if (layer_config->output_gain_is_present_flag) { log += write_yaml_form(log, 3, "output_gain_flag: %u", - layer_conf->output_gain_info->output_gain_flag); + layer_config->output_gain_info.output_gain_flag); log += write_yaml_form(log, 3, "output_gain: %d", - layer_conf->output_gain_info->output_gain); + layer_config->output_gain_info.output_gain); } - if (!i && layer_conf->loudspeaker_layout == 0xf) + if (!i && layer_config->loudspeaker_layout == 0xf) log += write_yaml_form(log, 3, "expanded_loudspeaker_layout: %u", - layer_conf->expanded_loudspeaker_layout); + layer_config->expanded_loudspeaker_layout); } - } else if (ae_obu->element_type == AUDIO_ELEMENT_TYPE_SCENE_BASED) { - // log += write_yaml_form(log, 0, "- scene_based:"); + } else if (audio_element->audio_element_type == + ck_audio_element_type_scene_based) { log += write_yaml_form(log, 1, "ambisonics_config:"); - - AmbisonicsConf* ambisonics_conf = ae_obu->ambisonics_conf; - log += write_yaml_form(log, 2, "ambisonics_mode: %llu", - ambisonics_conf->ambisonics_mode); - if (ambisonics_conf->ambisonics_mode == AMBISONICS_MONO) { + scene_based_audio_element_obu_t* scene_element = + (scene_based_audio_element_obu_t*)audio_element; + log += write_yaml_form(log, 2, "ambisonics_mode: %u", + scene_element->ambisonics_mode); + if (scene_element->ambisonics_mode == ck_ambisonics_mode_mono) { log += write_yaml_form(log, 2, "ambisonics_mono_config:"); log += write_yaml_form(log, 3, "output_channel_count: %u", - ambisonics_conf->output_channel_count); + scene_element->output_channel_count); log += write_yaml_form(log, 3, "substream_count: %u", - ambisonics_conf->substream_count); - + scene_element->substream_count); log += write_yaml_form(log, 3, "channel_mapping:"); - for (uint64_t i = 0; i < ambisonics_conf->mapping_size; ++i) { - log += write_yaml_form(log, 3, "- %u", ambisonics_conf->mapping[i]); + for (uint32_t i = 0; i < scene_element->mapping_size; ++i) { + log += + write_yaml_form(log, 3, "- %u", scene_element->channel_mapping[i]); } - } else if (ambisonics_conf->ambisonics_mode == AMBISONICS_PROJECTION) { + } else if (scene_element->ambisonics_mode == + ck_ambisonics_mode_projection) { log += write_yaml_form(log, 2, "ambisonics_projection_config:"); log += write_yaml_form(log, 3, "output_channel_count: %u", - ambisonics_conf->output_channel_count); + scene_element->output_channel_count); log += write_yaml_form(log, 3, "substream_count: %u", - ambisonics_conf->substream_count); + scene_element->substream_count); log += write_yaml_form(log, 3, "coupled_substream_count: %u", - ambisonics_conf->coupled_substream_count); + scene_element->coupled_substream_count); log += write_yaml_form(log, 3, "demixing_matrix:"); - for (uint64_t i = 0; i < ambisonics_conf->mapping_size; i += 2) { - int16_t value = (ambisonics_conf->mapping[i] << 8) | - ambisonics_conf->mapping[i + 1]; - log += write_yaml_form(log, 3, "- %d", value); + for (int i = 0; i < scene_element->mapping_size; i += 2) { + log += write_yaml_form(log, 3, "- %d", + scene_element->demixing_matrix[i] << 8 | + scene_element->demixing_matrix[i + 1]); } } + } else if (audio_element->audio_element_type == + ck_audio_element_type_object_based) { + log += write_yaml_form(log, 1, "objects_config:"); + object_based_audio_element_obu_t* object_element = + (object_based_audio_element_obu_t*)audio_element; + log += + write_yaml_form(log, 2, "num_objects: %u", object_element->num_objects); } write_postfix(LOG_OBU, log); } +/** + * @brief Writes IAMF mix presentation OBU information to log + * + * This function logs the mix presentation OBU data including mix presentation + * ID, annotations, sub-mixes, audio elements, layouts, and loudness information + * in YAML format. + * + * @param idx The index/ID of the OBU being logged + * @param obu Pointer to the IAMF mix presentation OBU data + * @param log Buffer to write the log output to + * + * @note This function performs input validation and will handle NULL pointers + * gracefully by writing an error message to the log. + */ static void write_mix_presentation_log(uint64_t idx, void* obu, char* log) { - IAMF_MixPresentation* mp_obu = (IAMF_MixPresentation*)obu; + iamf_mix_presentation_obu_t* mix_presentation = + (iamf_mix_presentation_obu_t*)obu; log += write_prefix(LOG_OBU, log); log += write_yaml_form(log, 0, "MixPresentationOBU_%llu:", idx); - log += write_yaml_form(log, 0, "- mix_presentation_id: %llu", - mp_obu->mix_presentation_id); - log += write_yaml_form(log, 1, "count_label: %llu", mp_obu->num_labels); + log += write_yaml_form(log, 0, "- mix_presentation_id: %u", + mix_presentation->mix_presentation_id); + log += + write_yaml_form(log, 1, "count_label: %u", + mix_presentation->annotations_languages + ? array_size(mix_presentation->annotations_languages) + : 0); log += write_yaml_form(log, 1, "annotations_language:"); - for (uint64_t i = 0; i < mp_obu->num_labels; ++i) { - log += write_yaml_form(log, 1, "- \"%s\"", mp_obu->annotations_language[i]); + if (mix_presentation->annotations_languages) { + int32_t label_count = array_size(mix_presentation->annotations_languages); + for (int32_t i = 0; i < label_count; ++i) { + string128_t* lang = def_value_wrap_type_ptr( + string128_t, array_at(mix_presentation->annotations_languages, i)); + log += write_yaml_form(log, 1, "- \"%s\"", *lang); + } } log += write_yaml_form(log, 1, "localized_presentation_annotations:"); - for (uint64_t i = 0; i < mp_obu->num_labels; ++i) { - log += write_yaml_form(log, 1, "- \"%s\"", - mp_obu->localized_presentation_annotations[i]); + if (mix_presentation->localized_presentation_annotations) { + int32_t annotation_count = + array_size(mix_presentation->localized_presentation_annotations); + for (int32_t i = 0; i < annotation_count; ++i) { + string128_t* annotation = def_value_wrap_type_ptr( + string128_t, + array_at(mix_presentation->localized_presentation_annotations, i)); + log += write_yaml_form(log, 1, "- \"%s\"", *annotation); + } } - log += write_yaml_form(log, 1, "num_sub_mixes: %llu", mp_obu->num_sub_mixes); + log += write_yaml_form(log, 1, "num_sub_mixes: %u", + mix_presentation->sub_mixes + ? array_size(mix_presentation->sub_mixes) + : 0); log += write_yaml_form(log, 1, "sub_mixes:"); - for (uint64_t i = 0; i < mp_obu->num_sub_mixes; ++i) { - SubMixPresentation* submix = &mp_obu->sub_mixes[i]; - log += write_yaml_form(log, 1, "- num_audio_elements: %llu", - submix->nb_elements); - log += write_yaml_form(log, 2, "audio_elements:"); - for (uint64_t j = 0; j < submix->nb_elements; ++j) { - ElementConf* conf_s = &submix->conf_s[j]; - log += write_yaml_form(log, 2, "- audio_element_id: %llu", - conf_s->element_id); - log += write_yaml_form(log, 3, "localized_element_annotations:"); - for (uint64_t k = 0; k < mp_obu->num_labels; ++k) { - log += write_yaml_form(log, 3, "- \"%s\"", - conf_s->localized_element_annotations[k]); - } + if (mix_presentation->sub_mixes) { + int32_t submix_count = array_size(mix_presentation->sub_mixes); + for (int32_t i = 0; i < submix_count; ++i) { + obu_sub_mix_t* submix = def_value_wrap_type_ptr( + obu_sub_mix_t, array_at(mix_presentation->sub_mixes, i)); + log += write_yaml_form(log, 1, "- num_audio_elements: %u", + submix->audio_element_configs + ? array_size(submix->audio_element_configs) + : 0); + log += write_yaml_form(log, 2, "audio_elements:"); + if (submix->audio_element_configs) { + int32_t element_count = array_size(submix->audio_element_configs); + for (int32_t j = 0; j < element_count; ++j) { + obu_audio_element_config_t* element_config = def_value_wrap_type_ptr( + obu_audio_element_config_t, + array_at(submix->audio_element_configs, j)); + log += write_yaml_form(log, 2, "- audio_element_id: %u", + element_config->element_id); + log += write_yaml_form(log, 3, "localized_element_annotations:"); + if (element_config->localized_element_annotations) { + int32_t annotation_count = + array_size(element_config->localized_element_annotations); + for (int32_t k = 0; k < annotation_count; ++k) { + string128_t* element_annotation = def_value_wrap_type_ptr( + string128_t, + array_at(element_config->localized_element_annotations, k)); + log += write_yaml_form(log, 3, "- \"%s\"", *element_annotation); + } + } - log += write_yaml_form(log, 3, "rendering_config:"); - log += write_yaml_form(log, 4, "headphones_rendering_mode: %u", - conf_s->conf_r.headphones_rendering_mode); - log += write_yaml_form(log, 4, "rendering_config_extension_size: %u", - conf_s->conf_r.rendering_config_extension_size); - - log += write_yaml_form(log, 3, "element_mix_gain:"); - log += write_yaml_form(log, 4, "param_definition:"); - log += write_yaml_form(log, 5, "parameter_id: %llu", - conf_s->element_mix_gain.base.id); - log += write_yaml_form(log, 5, "parameter_rate: %llu", - conf_s->element_mix_gain.base.rate); - log += write_yaml_form(log, 5, "param_definition_mode: %u", - conf_s->element_mix_gain.base.mode); - if (conf_s->element_mix_gain.base.mode == 0) { - log += write_yaml_form(log, 5, "duration: %llu", - conf_s->element_mix_gain.base.duration); - log += write_yaml_form(log, 5, "num_subblocks: %llu", - conf_s->element_mix_gain.base.nb_segments); - log += write_yaml_form( - log, 5, "constant_subblock_duration: %llu", - conf_s->element_mix_gain.base.constant_segment_interval); - if (conf_s->element_mix_gain.base.constant_segment_interval == 0) { - log += write_yaml_form(log, 5, "subblock_durations:"); - for (uint64_t k = 0; k < conf_s->element_mix_gain.base.nb_segments; - ++k) { + log += write_yaml_form(log, 3, "rendering_config:"); + log += write_yaml_form( + log, 4, "headphones_rendering_mode: %u", + element_config->rendering_config.headphones_rendering_mode); + log += write_yaml_form( + log, 4, "binaural_filter_profile: %u", + element_config->rendering_config.binaural_filter_profile); + // log += write_yaml_form( + // log, 4, "rendering_config_extension_size: %u", + // element_config->rendering_config.rendering_config_extension_size); + + if (element_config->rendering_config.parameters) { + log += + write_yaml_form(log, 4, "rendering_config_param_definitions:"); + parameter_base_t* param = def_value_wrap_type_ptr( + parameter_base_t, + array_at(element_config->rendering_config.parameters, 0)); + + if (param) { + if (param->type == ck_iamf_parameter_type_polar) { + polars_parameter_base_t* polar_param = + (polars_parameter_base_t*)param; + log += write_yaml_form(log, 5, "- param_definition_type: %u", + param->type); + log += write_yaml_form(log, 6, "polar_param_definition:"); + log += write_yaml_form(log, 7, "param_definition:"); + log += write_yaml_form(log, 8, "parameter_id: %u", + param->parameter_id); + log += write_yaml_form(log, 8, "parameter_rate: %u", + param->parameter_rate); + log += write_yaml_form(log, 8, "param_definition_mode: %u", + param->param_definition_mode); + log += write_yaml_form(log, 7, "default_azimuth: %f", + polar_param->default_polars[0].azimuth); + log += + write_yaml_form(log, 7, "default_elevation: %f", + polar_param->default_polars[0].elevation); + log += write_yaml_form( + log, 7, "default_distance: %f", + polar_param->default_polars[0].distance * 127); + } else if (param->type == ck_iamf_parameter_type_cartesian_8) { + cartesians_parameter_base_t* cart_param = + (cartesians_parameter_base_t*)param; + log += write_yaml_form(log, 5, "- param_definition_type: %u", + param->type); + log += write_yaml_form(log, 6, "cart8_param_definition:"); + log += write_yaml_form(log, 7, "param_definition:"); + log += write_yaml_form(log, 8, "parameter_id: %u", + param->parameter_id); + log += write_yaml_form(log, 8, "parameter_rate: %u", + param->parameter_rate); + log += write_yaml_form(log, 8, "param_definition_mode: %u", + param->param_definition_mode); + log += + write_yaml_form(log, 7, "default_x: %f", + cart_param->default_cartesians[0].x * 127); + log += + write_yaml_form(log, 7, "default_y: %f", + cart_param->default_cartesians[0].y * 127); + log += + write_yaml_form(log, 7, "default_z: %f", + cart_param->default_cartesians[0].z * 127); + } else if (param->type == ck_iamf_parameter_type_cartesian_16) { + cartesians_parameter_base_t* cart_param = + (cartesians_parameter_base_t*)param; + log += write_yaml_form(log, 5, "- param_definition_type: %u", + param->type); + log += write_yaml_form(log, 6, "cart16_param_definition:"); + log += write_yaml_form(log, 7, "param_definition:"); + log += write_yaml_form(log, 8, "parameter_id: %u", + param->parameter_id); + log += write_yaml_form(log, 8, "parameter_rate: %u", + param->parameter_rate); + log += write_yaml_form(log, 8, "param_definition_mode: %u", + param->param_definition_mode); + log += write_yaml_form( + log, 7, "default_x: %f", + cart_param->default_cartesians[0].x * 32767); + log += write_yaml_form( + log, 7, "default_y: %f", + cart_param->default_cartesians[0].y * 32767); + log += write_yaml_form( + log, 7, "default_z: %f", + cart_param->default_cartesians[0].z * 32767); + } else if (param->type == ck_iamf_parameter_type_dual_polar) { + polars_parameter_base_t* polar_param = + (polars_parameter_base_t*)param; + log += write_yaml_form(log, 5, "- param_definition_type: %u", + param->type); + log += write_yaml_form(log, 6, "dual_polar_param_definition:"); + log += write_yaml_form(log, 7, "param_definition:"); + log += write_yaml_form(log, 8, "parameter_id: %u", + param->parameter_id); + log += write_yaml_form(log, 8, "parameter_rate: %u", + param->parameter_rate); + log += write_yaml_form(log, 8, "param_definition_mode: %u", + param->param_definition_mode); + log += write_yaml_form(log, 7, "default_first_azimuth: %f", + polar_param->default_polars[0].azimuth); + log += + write_yaml_form(log, 7, "default_first_elevation: %f", + polar_param->default_polars[0].elevation); + log += write_yaml_form( + log, 7, "default_first_distance: %f", + polar_param->default_polars[0].distance * 127); + log += write_yaml_form(log, 7, "default_second_azimuth: %f", + polar_param->default_polars[1].azimuth); + log += + write_yaml_form(log, 7, "default_second_elevation: %f", + polar_param->default_polars[1].elevation); + log += write_yaml_form( + log, 7, "default_second_distance: %f", + polar_param->default_polars[1].distance * 127); + } else if (param->type == + ck_iamf_parameter_type_dual_cartesian_8) { + cartesians_parameter_base_t* cart_param = + (cartesians_parameter_base_t*)param; + log += write_yaml_form(log, 5, "- param_definition_type: %u", + param->type); + log += write_yaml_form(log, 6, "dual_cart8_param_definition:"); + log += write_yaml_form(log, 7, "param_definition:"); + log += write_yaml_form(log, 8, "parameter_id: %u", + param->parameter_id); + log += write_yaml_form(log, 8, "parameter_rate: %u", + param->parameter_rate); + log += write_yaml_form(log, 8, "param_definition_mode: %u", + param->param_definition_mode); + log += + write_yaml_form(log, 7, "default_first_x: %f", + cart_param->default_cartesians[0].x * 127); + log += + write_yaml_form(log, 7, "default_first_y: %f", + cart_param->default_cartesians[0].y * 127); + log += + write_yaml_form(log, 7, "default_first_z: %f", + cart_param->default_cartesians[0].z * 127); + log += + write_yaml_form(log, 7, "default_second_x: %f", + cart_param->default_cartesians[1].x * 127); + log += + write_yaml_form(log, 7, "default_second_y: %f", + cart_param->default_cartesians[1].y * 127); + log += + write_yaml_form(log, 7, "default_second_z: %f", + cart_param->default_cartesians[1].z * 127); + } else if (param->type == + ck_iamf_parameter_type_dual_cartesian_16) { + cartesians_parameter_base_t* cart_param = + (cartesians_parameter_base_t*)param; + log += write_yaml_form(log, 5, "- param_definition_type: %u", + param->type); + log += write_yaml_form(log, 6, "dual_cart16_param_definition:"); + log += write_yaml_form(log, 7, "param_definition:"); + log += write_yaml_form(log, 8, "parameter_id: %u", + param->parameter_id); + log += write_yaml_form(log, 8, "parameter_rate: %u", + param->parameter_rate); + log += write_yaml_form(log, 8, "param_definition_mode: %u", + param->param_definition_mode); + log += write_yaml_form( + log, 7, "default_first_x: %f", + cart_param->default_cartesians[0].x * 32767); + log += write_yaml_form( + log, 7, "default_first_y: %f", + cart_param->default_cartesians[0].y * 32767); + log += write_yaml_form( + log, 7, "default_first_z: %f", + cart_param->default_cartesians[0].z * 32767); + log += write_yaml_form( + log, 7, "default_second_x: %f", + cart_param->default_cartesians[1].x * 32767); + log += write_yaml_form( + log, 7, "default_second_y: %f", + cart_param->default_cartesians[1].y * 32767); + log += write_yaml_form( + log, 7, "default_second_z: %f", + cart_param->default_cartesians[1].z * 32767); + } + } + } + + if (element_config->rendering_config.flags & + def_rendering_config_flag_element_gain_offset) { + log += write_yaml_form(log, 4, "element_gain_offset_config:"); log += write_yaml_form( - log, 6, "- %llu", - conf_s->element_mix_gain.base.segments[k].segment_interval); + log, 4, "- element_gain_offset_type: %u", + element_config->rendering_config.element_gain_offset_type); + if (element_config->rendering_config.element_gain_offset_type == + ck_element_gain_offset_type_value) { + log += write_yaml_form(log, 5, "value_type:"); + log += write_yaml_form(log, 6, "element_gain_offset:"); + log += write_yaml_form( + log, 7, "q7_dot8: %d", + element_config->rendering_config.element_gain_offset.value); + } else if (element_config->rendering_config + .element_gain_offset_type == + ck_element_gain_offset_type_range) { + log += write_yaml_form(log, 5, "range_type:"); + log += write_yaml_form(log, 6, "default_element_gain_offset:"); + log += write_yaml_form( + log, 7, "q7_dot8: %d", + element_config->rendering_config.element_gain_offset.value); + log += write_yaml_form(log, 6, "min_element_gain_offset:"); + log += write_yaml_form( + log, 7, "q7_dot8: %d", + element_config->rendering_config.element_gain_offset.min); + log += write_yaml_form(log, 6, "max_element_gain_offset:"); + log += write_yaml_form( + log, 7, "q7_dot8: %d", + element_config->rendering_config.element_gain_offset.max); + } } - } - } - log += write_yaml_form(log, 4, "default_mix_gain: %d", - conf_s->element_mix_gain.mix_gain); - } - MixGainParameter output_mix_gain = submix->output_mix_gain; - log += write_yaml_form(log, 2, "output_mix_gain:"); - log += write_yaml_form(log, 3, "param_definition:"); - log += - write_yaml_form(log, 4, "parameter_id: %llu", output_mix_gain.base.id); - log += write_yaml_form(log, 4, "parameter_rate: %llu", - output_mix_gain.base.rate); - log += write_yaml_form(log, 4, "param_definition_mode: %u", - output_mix_gain.base.mode); - if (output_mix_gain.base.mode == 0) { - log += write_yaml_form(log, 4, "duration: %llu", - output_mix_gain.base.duration); - log += write_yaml_form(log, 4, "num_subblocks: %llu", - output_mix_gain.base.nb_segments); - log += write_yaml_form(log, 4, "constant_subblock_duration: %llu", - output_mix_gain.base.constant_segment_interval); - if (output_mix_gain.base.constant_segment_interval == 0) { - log += write_yaml_form(log, 4, "subblock_durations:"); - for (uint64_t k = 0; k < output_mix_gain.base.nb_segments; ++k) { + log += write_yaml_form(log, 3, "element_mix_gain:"); + log += write_yaml_form(log, 4, "param_definition:"); log += write_yaml_form( - log, 4, "- %llu", - output_mix_gain.base.segments[k].segment_interval); + log, 5, "parameter_id: %u", + element_config->element_mix_gain.base.parameter_id); + log += write_yaml_form( + log, 5, "parameter_rate: %u", + element_config->element_mix_gain.base.parameter_rate); + log += write_yaml_form( + log, 5, "param_definition_mode: %u", + element_config->element_mix_gain.base.param_definition_mode); + if (element_config->element_mix_gain.base.param_definition_mode == + 0) { + log += + write_yaml_form(log, 5, "duration: %u", + element_config->element_mix_gain.base.duration); + log += write_yaml_form( + log, 5, "num_subblocks: %u", + element_config->element_mix_gain.base.subblock_durations + ? array_size(element_config->element_mix_gain.base + .subblock_durations) + : element_config->element_mix_gain.base + .constant_subblock_duration + ? 1 + : 0); + log += write_yaml_form(log, 5, "constant_subblock_duration: %u", + element_config->element_mix_gain.base + .constant_subblock_duration); + if (element_config->element_mix_gain.base + .constant_subblock_duration == 0 && + element_config->element_mix_gain.base.subblock_durations) { + log += write_yaml_form(log, 5, "subblock_durations:"); + int32_t subblock_count = array_size( + element_config->element_mix_gain.base.subblock_durations); + for (int32_t k = 0; k < subblock_count; ++k) { + uint32_t duration = def_value_wrap_i32(array_at( + element_config->element_mix_gain.base.subblock_durations, + k)); + log += write_yaml_form(log, 6, "- %u", duration); + } + } + } + log += write_yaml_form( + log, 4, "default_mix_gain: %d", + element_config->element_mix_gain.default_mix_gain); } } - } - log += write_yaml_form(log, 3, "default_mix_gain: %d", - output_mix_gain.mix_gain); - - log += write_yaml_form(log, 2, "num_layouts: %llu", submix->num_layouts); - log += write_yaml_form(log, 2, "layouts:"); - for (uint64_t j = 0; j < submix->num_layouts; ++j) { - if (!submix->layouts[j]) continue; - // layout - log += write_yaml_form(log, 2, "- loudness_layout:"); - - uint32_t layout_type = submix->layouts[j]->type; - log += write_yaml_form(log, 4, "layout_type: %lu", layout_type); - - if (layout_type == IAMF_LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION) { - log += write_yaml_form(log, 4, "ss_layout:"); - - SoundSystemLayout* ss = SOUND_SYSTEM_LAYOUT(submix->layouts[j]); - log += write_yaml_form(log, 5, "sound_system: %u", ss->sound_system); + log += write_yaml_form(log, 2, "output_mix_gain:"); + log += write_yaml_form(log, 3, "param_definition:"); + log += write_yaml_form(log, 4, "parameter_id: %u", + submix->output_mix_gain.base.parameter_id); + log += write_yaml_form(log, 4, "parameter_rate: %u", + submix->output_mix_gain.base.parameter_rate); + log += + write_yaml_form(log, 4, "param_definition_mode: %u", + submix->output_mix_gain.base.param_definition_mode); + if (submix->output_mix_gain.base.param_definition_mode == 0) { + log += write_yaml_form(log, 4, "duration: %u", + submix->output_mix_gain.base.duration); + log += write_yaml_form( + log, 4, "num_subblocks: %u", + submix->output_mix_gain.base.subblock_durations + ? array_size(submix->output_mix_gain.base.subblock_durations) + : submix->output_mix_gain.base.constant_subblock_duration ? 1 + : 0); + log += write_yaml_form( + log, 4, "constant_subblock_duration: %u", + submix->output_mix_gain.base.constant_subblock_duration); + if (submix->output_mix_gain.base.constant_subblock_duration == 0 && + submix->output_mix_gain.base.subblock_durations) { + log += write_yaml_form(log, 4, "subblock_durations:"); + int32_t subblock_count = + array_size(submix->output_mix_gain.base.subblock_durations); + for (int32_t k = 0; k < subblock_count; ++k) { + uint32_t duration = def_value_wrap_i32( + array_at(submix->output_mix_gain.base.subblock_durations, k)); + log += write_yaml_form(log, 4, "- %u", duration); + } + } } + log += write_yaml_form(log, 3, "default_mix_gain: %d", + submix->output_mix_gain.default_mix_gain); + + log += write_yaml_form( + log, 2, "num_layouts: %u", + submix->loudness_layouts ? array_size(submix->loudness_layouts) : 0); + + log += write_yaml_form(log, 2, "layouts:"); + if (submix->loudness_layouts) { + int32_t layout_count = array_size(submix->loudness_layouts); + for (int32_t j = 0; j < layout_count; ++j) { + iamf_layout_t* layout = def_value_wrap_type_ptr( + iamf_layout_t, array_at(submix->loudness_layouts, j)); + log += write_yaml_form(log, 2, "- loudness_layout:"); + uint32_t layout_type = layout->type; + log += write_yaml_form(log, 4, "layout_type: %lu", layout_type); + + if (layout_type == ck_iamf_layout_type_loudspeakers_ss_convention) { + log += write_yaml_form(log, 4, "ss_layout:"); + log += write_yaml_form(log, 5, "sound_system: %u", + layout->sound_system); + } - // loudness - log += write_yaml_form(log, 3, "loudness:"); - log += write_yaml_form(log, 4, "info_type_bit_masks: [%u]", - submix->loudness[j].info_type); - log += write_yaml_form(log, 4, "integrated_loudness: %d", - submix->loudness[j].integrated_loudness); - log += write_yaml_form(log, 4, "digital_peak: %d", - submix->loudness[j].digital_peak); - if (submix->loudness[j].info_type & 1) { - log += write_yaml_form(log, 4, "true_peak: %d", - submix->loudness[j].true_peak); - } + log += write_yaml_form(log, 3, "loudness:"); + obu_loudness_info_t* loudness = def_value_wrap_type_ptr( + obu_loudness_info_t, array_at(submix->loudness, j)); + log += write_yaml_form(log, 4, "info_type_bit_masks: [%u]", + loudness->info_type); + log += write_yaml_form(log, 4, "integrated_loudness: %d", + loudness->integrated_loudness); + log += write_yaml_form(log, 4, "digital_peak: %d", + loudness->digital_peak); + if (loudness->info_type & 1) { + log += + write_yaml_form(log, 4, "true_peak: %d", loudness->true_peak); + } - if (submix->loudness[j].info_type & 2) { - log += write_yaml_form(log, 4, "anchored_loudness:"); - log += write_yaml_form(log, 5, "num_anchored_loudness: %u", - submix->loudness[j].num_anchor_loudness); - - if (submix->loudness[j].num_anchor_loudness) { - log += write_yaml_form(log, 5, "anchor_elements:"); - for (uint8_t k = 0; k < submix->loudness[j].num_anchor_loudness; - ++k) { - anchor_loudness_t anchor_loudness_info = - submix->loudness[j].anchor_loudness[k]; - log += write_yaml_form(log, 5, "- anchor_element: %u", - anchor_loudness_info.anchor_element); - log += write_yaml_form(log, 6, "anchored_loudness: %d", - anchor_loudness_info.anchored_loudness); + if (loudness->info_type & 2) { + log += write_yaml_form(log, 4, "anchored_loudness:"); + if (loudness->anchored_loudnesses) { + int32_t anchor_count = array_size(loudness->anchored_loudnesses); + log += write_yaml_form(log, 5, "num_anchored_loudness: %d", + anchor_count); + if (anchor_count > 0) { + log += write_yaml_form(log, 5, "anchor_elements:"); + for (int32_t k = 0; k < anchor_count; ++k) { + obu_anchored_loudness_info_t* anchor_info = + def_value_wrap_type_ptr( + obu_anchored_loudness_info_t, + array_at(loudness->anchored_loudnesses, k)); + log += write_yaml_form(log, 5, "- anchor_element: %u", + anchor_info->anchor_element); + log += write_yaml_form(log, 6, "anchored_loudness: %d", + anchor_info->anchored_loudness); + } + } + } } } } } } - if (mp_obu->num_name_value_tags > 0) { - log += write_yaml_form(log, 1, "mix_presentation_tags:"); - log += write_yaml_form(log, 2, "num_tags: %u", mp_obu->num_name_value_tags); + log += write_yaml_form(log, 1, "mix_presentation_tags:"); + if (mix_presentation->mix_presentation_tags && + array_size(mix_presentation->mix_presentation_tags) > 0) { + log += write_yaml_form(log, 2, "num_tags: %u", + array_size(mix_presentation->mix_presentation_tags)); log += write_yaml_form(log, 2, "tags:"); - for (uint8_t i = 0; i < mp_obu->num_name_value_tags; ++i) { - log += - write_yaml_form(log, 2, "- tag_name: \"%s\"", mp_obu->tags[i].name); - log += - write_yaml_form(log, 3, "tag_value: \"%s\"", mp_obu->tags[i].value); + int32_t tag_count = array_size(mix_presentation->mix_presentation_tags); + for (int32_t i = 0; i < tag_count; ++i) { + iamf_tag_t* tag = def_value_wrap_type_ptr( + iamf_tag_t, array_at(mix_presentation->mix_presentation_tags, i)); + log += write_yaml_form(log, 2, "- tag_name: \"%s\"", tag->name); + log += write_yaml_form(log, 3, "tag_value: \"%s\"", tag->value); } + } else { + log += write_yaml_form(log, 2, "num_tags: %u", 0); } + + log += write_yaml_form(log, 1, "optional_fields:"); + log += write_yaml_form(log, 2, "preferred_loudspeaker_renderer: %u", + mix_presentation->preferred_loudspeaker_renderer); + log += write_yaml_form(log, 2, "preferred_binaural_renderer: %u", + mix_presentation->preferred_binaural_renderer); + write_postfix(LOG_OBU, log); } +/** + * @brief Writes IAMF parameter block OBU information to log + * + * This function logs the parameter block OBU data including parameter ID, + * duration, subblock information, and parameter-specific data in YAML format. + * It supports mix gain, demixing, and reconstruction gain parameters with their + * respective animation types and data. + * + * @param idx The index/ID of the OBU being logged + * @param obu Pointer to the IAMF parameter block OBU data + * @param log Buffer to write the log output to + * + * @note This function performs input validation and will handle NULL pointers + * gracefully by writing an error message to the log. + */ static void write_parameter_block_log(uint64_t idx, void* obu, char* log) { - IAMF_Parameter* para = (IAMF_Parameter*)obu; + iamf_parameter_block_obu_t* param_block = (iamf_parameter_block_obu_t*)obu; log += write_prefix(LOG_OBU, log); log += write_yaml_form(log, 0, "ParameterBlockOBU_%llu:", idx); - log += write_yaml_form(log, 0, "- parameter_id: %llu", para->id); - log += write_yaml_form(log, 1, "duration: %llu", para->duration); - log += write_yaml_form(log, 1, "num_subblocks: %llu", para->nb_segments); - log += write_yaml_form(log, 1, "constant_subblock_duration: %llu", - para->constant_segment_interval); + log += write_yaml_form(log, 0, "- parameter_id: %u", + param_block->base->parameter_id); + log += write_yaml_form(log, 1, "duration: %u", param_block->duration); + log += write_yaml_form( + log, 1, "num_subblocks: %u", + param_block->subblocks ? array_size(param_block->subblocks) : 0); + log += write_yaml_form(log, 1, "constant_subblock_duration: %u", + param_block->constant_subblock_duration); log += write_yaml_form(log, 1, "subblocks:"); - for (uint64_t i = 0; i < para->nb_segments; ++i) { - if (para->type == IAMF_PARAMETER_TYPE_MIX_GAIN) { - MixGainSegment* mg = (MixGainSegment*)para->segments[i]; - log += write_yaml_form(log, 1, "- mix_gain_parameter_data:"); - log += write_yaml_form(log, 3, "subblock_duration: %llu", - mg->seg.segment_interval); - log += write_yaml_form(log, 3, "animation_type: %llu", - mg->mix_gain.animated_type); - log += write_yaml_form(log, 3, "param_data:"); - if (mg->mix_gain.animated_type == PARAMETER_ANIMATED_TYPE_STEP) { - log += write_yaml_form(log, 4, "step:"); - log += write_yaml_form(log, 5, "start_point_value: %d", - mg->mix_gain.start); - } else if (mg->mix_gain.animated_type == PARAMETER_ANIMATED_TYPE_LINEAR) { - log += write_yaml_form(log, 4, "linear:"); - log += write_yaml_form(log, 5, "start_point_value: %d", - mg->mix_gain.start); - log += write_yaml_form(log, 5, "end_point_value: %d", mg->mix_gain.end); - } else if (mg->mix_gain.animated_type == PARAMETER_ANIMATED_TYPE_BEZIER) { - log += write_yaml_form(log, 4, "bezier:"); - log += write_yaml_form(log, 5, "start_point_value: %d", - mg->mix_gain.start); - log += write_yaml_form(log, 5, "end_point_value: %d", mg->mix_gain.end); - log += write_yaml_form(log, 5, "control_point_value: %d", - mg->mix_gain.control); - log += write_yaml_form(log, 5, "control_point_relative_time: %u", - mg->mix_gain.control_relative_time & 0xFF); - } - } else if (para->type == IAMF_PARAMETER_TYPE_DEMIXING) { - DemixingSegment* mode = (DemixingSegment*)para->segments[i]; - log += write_yaml_form(log, 1, "- demixing_info_parameter_data:"); - log += write_yaml_form(log, 3, "subblock_duration: %llu", - mode->seg.segment_interval); - log += write_yaml_form(log, 3, "dmixp_mode: %lu", mode->demixing_mode); - } else if (para->type == IAMF_PARAMETER_TYPE_RECON_GAIN) { - ReconGainSegment* mode = (ReconGainSegment*)para->segments[i]; - log += write_yaml_form(log, 1, "- recon_gain_info_parameter_data:"); - for (uint64_t j = 0; j < mode->list.count; ++j) { - log += write_yaml_form(log, 3, "recon_gains_for_layer:"); - ReconGain recon_gain = mode->list.recon[j]; - int channels = bit1_count(recon_gain.flags); - if (channels > 0) { - // leb128 - // read 2 bytes - uint8_t cur_channel = 0; - - uint32_t recon_channel = recon_gain.flags & 0xFFFF; - if (recon_channel & 0x8000) { - uint32_t ch = ((recon_channel & 0xFF00) >> 8); - for (uint8_t k = 0; k < 7; ++k) { - if (ch & 0x01) { - log += write_yaml_form(log, 4, "recon_gain:"); - log += write_yaml_form(log, 5, "key: %u", k); - log += write_yaml_form(log, 5, "value: %d", - recon_gain.recon_gain[cur_channel++]); - } - ch >>= 1; - } - - ch = (recon_channel & 0x00FF); - for (uint8_t k = 7; k < 12; ++k) { - if (ch & 0x01) { - log += write_yaml_form(log, 4, "recon_gain:"); - log += write_yaml_form(log, 5, "key: %u", k); - log += write_yaml_form(log, 5, "value: %d", - recon_gain.recon_gain[cur_channel++]); - } - ch >>= 1; - } - } else { - uint32_t ch = recon_channel & 0xFF; - for (uint8_t k = 0; k < 7; ++k) { - if (ch & 0x01) { - log += write_yaml_form(log, 4, "recon_gain:"); - log += write_yaml_form(log, 5, "key: %u", k); - log += write_yaml_form(log, 5, "value: %d", - recon_gain.recon_gain[cur_channel++]); + if (param_block->subblocks) { + int32_t subblock_count = array_size(param_block->subblocks); + for (int32_t i = 0; i < subblock_count; ++i) { + if (param_block->base->type == ck_iamf_parameter_type_mix_gain) { + mix_gain_parameter_subblock_t* mg_subblock = + (mix_gain_parameter_subblock_t*)def_value_wrap_ptr( + array_at(param_block->subblocks, i)); + log += write_yaml_form(log, 1, "- mix_gain_parameter_data:"); + log += write_yaml_form(log, 3, "subblock_duration: %u", + mg_subblock->base.subblock_duration); + log += write_yaml_form(log, 3, "animation_type: %u", + mg_subblock->gain.animation_type); + log += write_yaml_form(log, 3, "param_data:"); + if (mg_subblock->gain.animation_type == ck_iamf_animation_type_step) { + log += write_yaml_form(log, 4, "step:"); + log += write_yaml_form(log, 5, "start_point_value: %d", + mg_subblock->gain.data.start); + } else if (mg_subblock->gain.animation_type == + ck_iamf_animation_type_linear) { + log += write_yaml_form(log, 4, "linear:"); + log += write_yaml_form(log, 5, "start_point_value: %d", + mg_subblock->gain.data.start); + log += write_yaml_form(log, 5, "end_point_value: %d", + mg_subblock->gain.data.end); + } else if (mg_subblock->gain.animation_type == + ck_iamf_animation_type_bezier) { + log += write_yaml_form(log, 4, "bezier:"); + log += write_yaml_form(log, 5, "start_point_value: %d", + mg_subblock->gain.data.start); + log += write_yaml_form(log, 5, "end_point_value: %d", + mg_subblock->gain.data.end); + log += write_yaml_form(log, 5, "control_point_value: %d", + mg_subblock->gain.data.control); + log += write_yaml_form( + log, 5, "control_point_relative_time: %u", + mg_subblock->gain.data.control_relative_time & 0xFF); + } + } else if (param_block->base->type == ck_iamf_parameter_type_demixing) { + demixing_info_parameter_subblock_t* dmix_subblock = + (demixing_info_parameter_subblock_t*)def_value_wrap_ptr( + array_at(param_block->subblocks, i)); + log += write_yaml_form(log, 1, "- demixing_info_parameter_data:"); + log += write_yaml_form(log, 3, "subblock_duration: %u", + dmix_subblock->base.subblock_duration); + log += write_yaml_form(log, 3, "dmixp_mode: %lu", + dmix_subblock->demixing_mode); + } else if (param_block->base->type == ck_iamf_parameter_type_recon_gain) { + recon_gain_parameter_subblock_t* recon_subblock = + (recon_gain_parameter_subblock_t*)def_value_wrap_ptr( + array_at(param_block->subblocks, i)); + log += write_yaml_form(log, 1, "- recon_gain_info_parameter_data:"); + if (recon_subblock->recon_gains) { + int32_t recon_gain_count = array_size(recon_subblock->recon_gains); + for (int32_t j = 0; j < recon_gain_count; ++j) { + log += write_yaml_form(log, 3, "recon_gains_for_layer:"); + recon_gain_t* recon_gain = (recon_gain_t*)def_value_wrap_ptr( + array_at(recon_subblock->recon_gains, j)); + if (!recon_gain) continue; + int channels = bit1_count(recon_gain->recon_gain_flags); + if (channels > 0) { + uint8_t cur_channel = 0; + uint32_t recon_channel = recon_gain->recon_gain_flags & 0xFFFF; + if (recon_channel & 0x8000) { + uint32_t ch = ((recon_channel & 0xFF00) >> 8); + for (uint8_t k = 0; k < 7; ++k) { + if (ch & 0x01) { + log += write_yaml_form(log, 4, "recon_gain:"); + log += write_yaml_form(log, 5, "key: %u", k); + log += write_yaml_form( + log, 5, "value: %d", + def_value_wrap_i32( + array_at(recon_gain->recon_gain, cur_channel++))); + } + ch >>= 1; + } + ch = (recon_channel & 0x00FF); + for (uint8_t k = 7; k < 12; ++k) { + if (ch & 0x01) { + log += write_yaml_form(log, 4, "recon_gain:"); + log += write_yaml_form(log, 5, "key: %u", k); + log += write_yaml_form( + log, 5, "value: %d", + def_value_wrap_i32( + array_at(recon_gain->recon_gain, cur_channel++))); + } + ch >>= 1; + } + } else { + uint32_t ch = recon_channel & 0xFF; + for (uint8_t k = 0; k < 7; ++k) { + if (ch & 0x01) { + log += write_yaml_form(log, 4, "recon_gain:"); + log += write_yaml_form(log, 5, "key: %u", k); + log += write_yaml_form( + log, 5, "value: %d", + def_value_wrap_i32( + array_at(recon_gain->recon_gain, cur_channel++))); + } + ch >>= 1; + } } - ch >>= 1; } } } @@ -894,101 +1366,214 @@ static void write_parameter_block_log(uint64_t idx, void* obu, char* log) { write_postfix(LOG_OBU, log); } +/** + * @brief Writes IAMF audio frame OBU information to log + * + * This function logs the audio frame OBU data including substream ID, trim + * information, and audio frame size in YAML format. + * + * @param idx The index/ID of the OBU being logged + * @param obu Pointer to the IAMF audio frame OBU data + * @param log Buffer to write the log output to + * @param num_samples_to_trim_at_start Number of samples to trim from the start + * @param num_samples_to_trim_at_end Number of samples to trim from the end + * + * @note This function performs input validation and will handle NULL pointers + * gracefully by writing an error message to the log. + */ static void write_audio_frame_log(uint64_t idx, void* obu, char* log, uint64_t num_samples_to_trim_at_start, uint64_t num_samples_to_trim_at_end) { - IAMF_Frame* af_obu = (IAMF_Frame*)obu; + // Input validation + if (!obu) { + log += write_prefix(LOG_OBU, log); + log += write_yaml_form(log, 0, "AudioFrameOBU_%u:", idx); + log += write_yaml_form(log, 0, "- error: \"NULL OBU pointer\""); + write_postfix(LOG_OBU, log); + return; + } + if (!log) { + return; // Cannot log if buffer is NULL + } + + // Cast to the correct structure type + iamf_audio_frame_obu_t* audio_frame = (iamf_audio_frame_obu_t*)obu; + + // Write log header log += write_prefix(LOG_OBU, log); - log += write_yaml_form(log, 0, "AudioFrameOBU_%llu:", idx); - log += write_yaml_form(log, 0, "- audio_substream_id: %llu", af_obu->id); - log += write_yaml_form(log, 1, "num_samples_to_trim_at_start: %llu", + log += write_yaml_form(log, 0, "AudioFrameOBU_%u:", idx); + + // Write basic audio frame information + log += write_yaml_form(log, 0, "- audio_substream_id: %u", + audio_frame->audio_substream_id); + log += write_yaml_form(log, 1, "num_samples_to_trim_at_start: %u", num_samples_to_trim_at_start); - log += write_yaml_form(log, 1, "num_samples_to_trim_at_end: %llu", + log += write_yaml_form(log, 1, "num_samples_to_trim_at_end: %u", num_samples_to_trim_at_end); - log += write_yaml_form(log, 1, "size_of_audio_frame: %u", af_obu->size); + + // Write audio frame size information + if (audio_frame->audio_frame && audio_frame->audio_frame->data) { + log += write_yaml_form(log, 1, "size_of_audio_frame: %u", + audio_frame->audio_frame->size); + } else { + log += write_yaml_form(log, 1, "size_of_audio_frame: 0"); + } + + // Write log footer write_postfix(LOG_OBU, log); } static void write_temporal_delimiter_block_log(uint64_t idx, void* obu, char* log) { log += write_prefix(LOG_OBU, log); - log += write_yaml_form(log, 0, "TemporalDelimiterOBU_%llu:", idx); + log += write_yaml_form(log, 0, "TemporalDelimiterOBU_%u:", idx); write_postfix(LOG_OBU, log); } -#ifdef SYNC_OBU -static void write_sync_log(uint64_t idx, void* obu, char* log) { - IAMF_Sync* sc_obu = (IAMF_Sync*)obu; +static void write_metadata_log(uint64_t idx, void* obu, char* log) { + // Input validation + if (!obu) { + log += write_prefix(LOG_OBU, log); + log += write_yaml_form(log, 0, "MetadataOBU_%u:", idx); + log += write_yaml_form(log, 0, "- error: \"NULL OBU pointer\""); + write_postfix(LOG_OBU, log); + return; + } + if (!log) return; + + iamf_metadata_obu_t* metadata = (iamf_metadata_obu_t*)obu; log += write_prefix(LOG_OBU, log); - log += write_yaml_form(log, 0, "SyncOBU_%llu:", idx); + log += write_yaml_form(log, 0, "MetadataObuOBU_%u:", idx); log += - write_yaml_form(log, 0, "- global_offset: %llu", sc_obu->global_offset); - log += write_yaml_form(log, 1, "num_obu_ids: %llu", sc_obu->nb_obu_ids); - - log += write_yaml_form(log, 1, "sync_array:"); - for (uint64_t i = 0; i < sc_obu->nb_obu_ids; ++i) { - log += write_yaml_form(log, 1, "- obu_id: %llu", sc_obu->objs[i].obu_id); - log += write_yaml_form(log, 2, "obu_data_type: %u", - sc_obu->objs[i].obu_data_type); - log += write_yaml_form(log, 2, "reinitialize_decoder: %u", - sc_obu->objs[i].reinitialize_decoder); - log += write_yaml_form(log, 2, "relative_offset: %d", - sc_obu->objs[i].relative_offset); + write_yaml_form(log, 0, "- metadata type: %u", metadata->metadata_type); + + switch (metadata->metadata_type) { + case ck_iamf_metadata_type_itut_t35: { + metadata_itut_t35_t* itu_t35_metadata = (metadata_itut_t35_t*)metadata; + log += write_yaml_form(log, 1, "metadata_itu_t_t35:"); + log += write_yaml_form(log, 2, "itu_t_t35_country_code: 0x%02X", + itu_t35_metadata->itu_t_t35_country_code); + if (itu_t35_metadata->itu_t_t35_country_code == 0xFF) { + log += write_yaml_form( + log, 2, "itu_t_t35_country_code_extension_byte: %u", + itu_t35_metadata->itu_t_t35_country_code_extension_byte); + } + break; + } + case ck_iamf_metadata_type_iamf_tags: { + metadata_iamf_tags* tags_metadata = (metadata_iamf_tags*)metadata; + log += write_yaml_form(log, 1, "metadata_iamf_tags:"); + if (tags_metadata->tags) { + log += write_yaml_form(log, 2, "tags:"); + int32_t tag_count = array_size(tags_metadata->tags); + for (int32_t i = 0; i < tag_count; ++i) { + value_wrap_t* v = array_at(tags_metadata->tags, i); + iamf_tag_t* tag = (iamf_tag_t*)v->ptr; + if (tag) { + log += write_yaml_form(log, 2, "- name: %s", tag->name); + log += write_yaml_form(log, 3, "value: %s", tag->value); + } + } + } + break; + } + default: + log += write_yaml_form(log, 1, "error: \"Unsupported metadata type: %u\"", + metadata->metadata_type); + break; } + write_postfix(LOG_OBU, log); } -#endif +/** + * @brief Main OBU logging function that dispatches to specific OBU type + * handlers + * + * This function serves as the main entry point for logging IAMF OBU data. It + * validates the log file state, determines the OBU type, and dispatches to the + * appropriate specific logging function. It handles all supported OBU types + * including sequence headers, codec configs, audio elements, mix presentations, + * parameter blocks, and audio frames. + * + * @param obu_type The type of OBU to log (using iamf_obu_type_t enum values) + * @param obu Pointer to the OBU data structure + * @param num_samples_to_trim_at_start Number of samples to trim from start (for + * audio frames) + * @param num_samples_to_trim_at_end Number of samples to trim from end (for + * audio frames) + * + * @return int Returns 0 on success, -1 if log file is not open or on error + * + * @note This function performs input validation and will handle unknown OBU + * types gracefully by logging an appropriate message. + */ int vlog_obu(uint32_t obu_type, void* obu, uint64_t num_samples_to_trim_at_start, uint64_t num_samples_to_trim_at_end) { - if (!is_vlog_file_open()) return -1; + // Validate log file state + if (!is_vlog_file_open()) { + return -1; + } static uint64_t obu_count = 0; static char log[LOG_BUFFER_SIZE]; uint64_t key; + // Initialize log buffer log[0] = 0; key = obu_count; + // Dispatch to appropriate logging function based on OBU type switch (obu_type) { - case IAMF_OBU_CODEC_CONFIG: + case ck_iamf_obu_codec_config: write_codec_config_log(obu_count++, obu, log); break; - case IAMF_OBU_AUDIO_ELEMENT: + + case ck_iamf_obu_audio_element: write_audio_element_log(obu_count++, obu, log); break; - case IAMF_OBU_MIX_PRESENTATION: + + case ck_iamf_obu_mix_presentation: write_mix_presentation_log(obu_count++, obu, log); break; - case IAMF_OBU_PARAMETER_BLOCK: + + case ck_iamf_obu_parameter_block: write_parameter_block_log(obu_count++, obu, log); break; - case IAMF_OBU_TEMPORAL_DELIMITER: + + case ck_iamf_obu_temporal_delimiter: write_temporal_delimiter_block_log(obu_count++, obu, log); break; -#ifdef SYNC_OBU - case IAMF_OBU_SYNC: - write_sync_log(obu_count++, obu, log); + + case ck_iamf_obu_metadata: + write_metadata_log(obu_count++, obu, log); break; -#endif - case IAMF_OBU_SEQUENCE_HEADER: + + case ck_iamf_obu_sequence_header: write_sequence_header_log(obu_count++, obu, log); break; + default: - if (obu_type >= IAMF_OBU_AUDIO_FRAME && - obu_type <= IAMF_OBU_AUDIO_FRAME_ID17) { + // Handle audio frame OBU types (frame ID0-ID17) + if (obu_type >= ck_iamf_obu_audio_frame && + obu_type <= ck_iamf_obu_audio_frame_id17) { write_audio_frame_log(obu_count++, obu, log, num_samples_to_trim_at_start, num_samples_to_trim_at_end); + } else { + // Handle unknown OBU types + write_temporal_delimiter_block_log(obu_count++, obu, log); + // Could add specific logging for unknown types here } break; } return vlog_print(LOG_OBU, key, log); } +#endif // SUPPORT_VERIFIER int vlog_decop(char* decop_text) { if (!is_vlog_file_open()) return -1; @@ -999,7 +1584,7 @@ int vlog_decop(char* decop_text) { uint64_t key = decop_log_count++; log += write_prefix(LOG_DECOP, log); - log += write_yaml_form(log, 0, "DECOP_%llu:", decop_log_count); + log += write_yaml_form(log, 0, "DECOP_%u:", decop_log_count); log += write_yaml_form(log, 0, "- text: %s", decop_text); write_postfix(LOG_DECOP, log); diff --git a/code/test/tools/iamfdec/CMakeLists.txt b/code/test/tools/iamfdec/CMakeLists.txt index 8bf04c4c..c0b17c39 100755 --- a/code/test/tools/iamfdec/CMakeLists.txt +++ b/code/test/tools/iamfdec/CMakeLists.txt @@ -1,34 +1,18 @@ -cmake_minimum_required(VERSION 3.6) +cmake_minimum_required(VERSION 3.28) project (iamfdec) -message(status,"+++++++++++iamfdec+++++++++++++") +message(STATUS "+++++++++++iamfdec+++++++++++++") -option(MULTICHANNEL_BINAURALIZER "Enable multichannel binaural rendering" OFF) -option(HOA_BINAURALIZER "Enable HOA binaural rendering" OFF) option(SUPPORT_VERIFIER "Output vlogging file" OFF) -include_directories (include) -aux_source_directory (src DIR_IAMFDEC_SRC) - -set(LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") -set(INCLUDE_IAMF_DIR "${CMAKE_INSTALL_PREFIX}/include/iamf") -set(INCLUDE_DEP_EXTERNAL_WAV_DIR "../../../dep_external/include/wav") -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=unused-variable") -if((CMAKE_SYSTEM_NAME MATCHES "Darwin") OR (CMAKE_SYSTEM_NAME MATCHES "Android")) -else() -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--no-as-need") -endif() - -if(MULTICHANNEL_BINAURALIZER) - message(STATUS "Enable multichannel binaural rendering") - add_definitions(-DENABLE_MULTICHANNEL_TO_BINAURAL=1) +if(NOT MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=unused-variable") endif() -if(HOA_BINAURALIZER) - message(STATUS "Enable HOA binaural rendering") - add_definitions(-DENABLE_HOA_TO_BINAURAL=1) -endif() +set(LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") +set(IAMF_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include/iamf") +set(EXTERNAL_WAV_INCLUDE_DIR "../../../dep_external/include/wav") if(SUPPORT_VERIFIER) message(STATUS "Output vlogging file") @@ -36,33 +20,22 @@ if(SUPPORT_VERIFIER) endif() -message(status,${INCLUDE_IAMF_DIR}) +file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c") + include_directories( - ${INCLUDE_IAMF_DIR} - ${INCLUDE_DEP_EXTERNAL_WAV_DIR} + include + ${IAMF_INCLUDE_DIR} + ${EXTERNAL_WAV_INCLUDE_DIR} ) -if(MULTICHANNEL_BINAURALIZER OR HOA_BINAURALIZER) link_directories( - ${LIB_DIR}/binaural ${LIB_DIR} ) -else() -link_directories( - ${LIB_DIR} -) -endif() + +add_executable (iamfdec ${sources}) -add_executable (iamfdec ${DIR_IAMFDEC_SRC}) - -if(MULTICHANNEL_BINAURALIZER OR HOA_BINAURALIZER) - if(MULTICHANNEL_BINAURALIZER) - target_link_libraries (iamfdec iamf m iamf2bear efl objectmodel panning pml rbbl rcl rrl visr) - endif() - if(HOA_BINAURALIZER) - target_link_libraries (iamfdec iamf m iamf2resonance) - endif() -else() - target_link_libraries (iamfdec iamf m) +target_link_libraries (iamfdec iamf) +if(NOT MSVC) + target_link_libraries (iamfdec m) endif() - diff --git a/code/test/tools/iamfdec/include/iamfdec_private.h b/code/test/tools/iamfdec/include/iamfdec_private.h new file mode 100755 index 00000000..3933d324 --- /dev/null +++ b/code/test/tools/iamfdec/include/iamfdec_private.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 3-Clause Clear License + * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear + * License was not distributed with this source code in the LICENSE file, you + * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the + * Alliance for Open Media Patent License 1.0 was not distributed with this + * source code in the PATENTS file, you can obtain it at + * www.aomedia.org/license/patent. + */ + +/** + * @file iamfdec_private.h + * @brief IAMF decoder header file. + * @version 2.0.0 + * @date Created 12/11/2025 + **/ + +#ifndef __IAMFDEC_PRIVATE_H__ +#define __IAMFDEC_PRIVATE_H__ + +#include "IAMF_defines.h" + +#if SUPPORT_VERIFIER +#define def_flag_vlog 0x2 +#endif + +#define def_flag_disable_limiter 0x4 +#define def_flag_enable_head_tracking 0x8 + + +#define def_default_sampling_rate 48000 +#define def_default_profile IA_PROFILE_ADVANCED_2 +#define def_default_mix_presentation_id -1LL +#define def_block_size 960 * 6 * 2 * 16 + + +typedef struct Layout { + int type; + union { + IAMF_SoundSystem ss; + }; +} layout_t; + +#define def_max_element_gain_offsets 28 + +typedef struct { + uint32_t element_id; + float gain_offset; +} element_gain_offset_t; + +typedef struct DecoderArgs { + const char *path; + const char *output_path; + layout_t *layout; + float peak; + float loudness; + uint32_t flags; + uint32_t st; + uint32_t rate; + uint32_t bit_depth; + int64_t mix_presentation_id; + IA_Profile profile; + element_gain_offset_t element_gain_offsets[def_max_element_gain_offsets]; + uint32_t element_gain_count; + float head_rotation_w; + float head_rotation_x; + float head_rotation_y; + float head_rotation_z; +} decoder_args_t; + +#endif // __IAMFDEC_PRIVATE_H__ diff --git a/code/test/tools/iamfdec/include/mp4demux.h b/code/test/tools/iamfdec/include/mp4demux.h index c4761e8b..b7217135 100755 --- a/code/test/tools/iamfdec/include/mp4demux.h +++ b/code/test/tools/iamfdec/include/mp4demux.h @@ -13,7 +13,7 @@ /** * @file mp4demux.h * @brief MP4 and fMP4 demux. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ @@ -65,13 +65,16 @@ typedef struct { uint32_t sample_size; // samples per packet (varable mode = 0, constant mode // = size > 0) uint32_t sample_duration; + uint32_t default_sample_flags; struct { chunkinfo *chunks; uint32_t chunk_count; - uint32_t *offs; // sample offs array(stco) - uint32_t *sizes; // sample size array(stsz) - uint32_t *deltas; // sample count array(stts) + uint32_t *offs; // sample offs array(stco) + uint32_t *sizes; // sample size array(stsz) + uint32_t *deltas; // sample count array(stts) + uint32_t *syncs; // sync sample array(stss) + uint32_t sync_count; // number of sync samples uint32_t bufsize; uint32_t ents; uint32_t ents_offset; @@ -165,7 +168,6 @@ enum { ERR_OK = 0, ERR_FAIL = -1, ERR_UNSUPPORTED = -2 }; #endif mp4r_t *mp4demux_open(const char *name, FILE *logger); -int mp4demux_getframenum(mp4r_t *mp4r, int trak, uint32_t offs); int mp4demux_seek(mp4r_t *mp4r, int trak, int framenum); int mp4demux_audio(mp4r_t *mp4r, int trak, int *delta); int mp4demux_parse(mp4r_t *mp4r, int trak); diff --git a/code/test/tools/iamfdec/include/mp4iamfpar.h b/code/test/tools/iamfdec/include/mp4iamfpar.h index 65e31673..db908f1e 100755 --- a/code/test/tools/iamfdec/include/mp4iamfpar.h +++ b/code/test/tools/iamfdec/include/mp4iamfpar.h @@ -13,7 +13,7 @@ /** * @file mp4iamfpar.h * @brief MP4 and fMP4 file parser. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ diff --git a/code/test/tools/iamfdec/include/vlogging_iamfmp4_sr.h b/code/test/tools/iamfdec/include/vlogging_iamfmp4_sr.h index 64e1fdb5..5e4d3f31 100755 --- a/code/test/tools/iamfdec/include/vlogging_iamfmp4_sr.h +++ b/code/test/tools/iamfdec/include/vlogging_iamfmp4_sr.h @@ -48,6 +48,7 @@ enum _mp4box_type { MP4BOX_MINF = atom_type('m', 'i', 'n', 'f'), MP4BOX_STBL = atom_type('s', 't', 'b', 'l'), MP4BOX_STTS = atom_type('s', 't', 't', 's'), + MP4BOX_STSS = atom_type('s', 't', 's', 's'), MP4BOX_STSC = atom_type('s', 't', 's', 'c'), MP4BOX_STSZ = atom_type('s', 't', 's', 'z'), MP4BOX_STCO = atom_type('s', 't', 'c', 'o'), diff --git a/code/test/tools/iamfdec/src/mp4demux.c b/code/test/tools/iamfdec/src/mp4demux.c index da23b1d1..a0df61fb 100755 --- a/code/test/tools/iamfdec/src/mp4demux.c +++ b/code/test/tools/iamfdec/src/mp4demux.c @@ -74,6 +74,7 @@ static int mov_read_stts(mp4r_t *mp4r, int size); static int mov_read_stsc(mp4r_t *mp4r, int size); static int mov_read_stsz(mp4r_t *mp4r, int size); static int mov_read_stco(mp4r_t *mp4r, int size); +static int mov_read_stss(mp4r_t *mp4r, int size); #if SUPPORT_VERIFIER static int mov_read_sgpd(mp4r_t *mp4r, int size); #endif @@ -104,6 +105,8 @@ static avio_context atoms_stsz[] = { {MOV_ATOM_NAME, "stsz"}, {MOV_ATOM_DATA, mov_read_stsz}, {0}}; static avio_context atoms_stco[] = { {MOV_ATOM_NAME, "stco"}, {MOV_ATOM_DATA, mov_read_stco}, {0}}; +static avio_context atoms_stss[] = { + {MOV_ATOM_NAME, "stss"}, {MOV_ATOM_DATA, mov_read_stss}, {0}}; #if SUPPORT_VERIFIER static avio_context atoms_sgpd[] = { {MOV_ATOM_NAME, "sgpd"}, {MOV_ATOM_DATA, mov_read_sgpd}, {0}}; @@ -232,23 +235,6 @@ static int mov_read_ftyp(mp4r_t *mp4r, int size) { return size; } -enum { SECSINDAY = 24 * 60 * 60 }; - -#if 0 -static char *mp4time(time_t t) { - int y; - - // subtract some seconds from the start of 1904 to the start of 1970 - for (y = 1904; y < 1970; y++) { - t -= 365 * SECSINDAY; - if (!(y & 3)) { - t -= SECSINDAY; - } - } - return ctime(&t); -} -#endif - static int mov_read_mvhd(mp4r_t *mp4r, int size) { #if SUPPORT_VERIFIER char *atom_d = (char *)malloc(size); @@ -418,14 +404,14 @@ int mov_read_stbl(mp4r_t *mp4r, int size) { #endif int64_t apos = ftell(mp4r->fin); - avio_context *list[] = { - atoms_stts, - atoms_stsc, - atoms_stsz, - atoms_stco + avio_context *list[] = {atoms_stts, + atoms_stsc, + atoms_stsz, + atoms_stco, + atoms_stss #if SUPPORT_VERIFIER - , - atoms_sgpd + , + atoms_sgpd #endif }; @@ -889,6 +875,50 @@ int mov_read_stsz(mp4r_t *mp4r, int size) { return size; } +int mov_read_stss(mp4r_t *mp4r, int size) { +#if SUPPORT_VERIFIER + char *atom_d = (char *)malloc(size); + int fpos; + fpos = ftell(mp4r->fin); + avio_rdata(mp4r->fin, atom_d, size); + fseek(mp4r->fin, fpos, SEEK_SET); + vlog_atom(MP4BOX_STSS, atom_d, size, fpos - 8); + free(atom_d); +#endif + + uint32_t entry_count; + int sel_a_trak; + sel_a_trak = mp4r->sel_a_trak; + audio_rtr_t *atr = mp4r->a_trak; + + // version/flags + avio_rb32(); + // entry count + entry_count = avio_rb32(); + // fprintf(stderr, "stssin: entry_count %d\n", entry_count); + if (!entry_count) return size; + + // Allocate memory for sync sample array + atr[sel_a_trak].frame.syncs = (uint32_t *)_dcalloc( + entry_count + 1, sizeof(*atr[sel_a_trak].frame.syncs), __FILE__, + __LINE__); + if (!atr[sel_a_trak].frame.syncs) { + return ERR_FAIL; + } + + // Store the number of sync samples + atr[sel_a_trak].frame.sync_count = entry_count; + + // Read sync sample numbers + for (int i = 0; i < entry_count; i++) { + atr[sel_a_trak].frame.syncs[i] = avio_rb32(); + // fprintf(stderr, "stssin: index %d, sync_sample %u\n", i, + // atr[sel_a_trak].frame.syncs[i]); + } + + return size; +} + int mov_read_stco(mp4r_t *mp4r, int size) { #if SUPPORT_VERIFIER char *atom_d = (char *)malloc(size); @@ -981,6 +1011,7 @@ static int mov_read_moof(mp4r_t *mp4r, int size) { atr[i].frame.ents_offset += atr[i].frame.ents; FREE(atr[i].frame.sizes); FREE(atr[i].frame.offs); + FREE(atr[i].frame.syncs); atr[i].frame.ents = 0; header = (IAMFHeader *)atr[i].csc; @@ -1031,9 +1062,9 @@ static int mov_read_tfhd(mp4r_t *mp4r, int size) { } /* base_data_offset */ - mp4r->base_data_offset = - vf & 0x01 ? avio_rb64() - : vf & 0x02 ? mp4r->moof_position : mp4r->implicit_offset; + mp4r->base_data_offset = vf & 0x01 ? avio_rb64() + : vf & 0x02 ? mp4r->moof_position + : mp4r->implicit_offset; // sample_description_index if (vf & 0x2) { @@ -1054,7 +1085,8 @@ static int mov_read_tfhd(mp4r_t *mp4r, int size) { // default_sample_size if (vf & 0x10) mp4r->a_trak[mp4r->sel_a_trak].sample_size = avio_rb32(); // default_sample_flags - /* if (vf & 0x20) avio_rb32(); */ + if (vf & 0x20) + mp4r->a_trak[mp4r->sel_a_trak].default_sample_flags = avio_rb32(); return size; } @@ -1073,6 +1105,8 @@ static int mov_read_trun(mp4r_t *mp4r, int size) { uint32_t vf; uint32_t sample_count; uint32_t offset = 0; + uint32_t first_sample_flags = 0; + uint32_t *sample_flags = NULL; int sel_a_trak; sel_a_trak = mp4r->sel_a_trak; @@ -1106,14 +1140,30 @@ static int mov_read_trun(mp4r_t *mp4r, int size) { if (vf & 0x1) offset = avio_rb32(); /* fprintf(stderr, "offset %u\n", offset); */ - if (vf & 0x04) avio_rb32(); + // first_sample_flags_present flag + if (vf & 0x04) { + first_sample_flags = avio_rb32(); + } uint32_t fsize = mp4r->a_trak[mp4r->sel_a_trak].sample_size; if (fsize) atr[sel_a_trak].frame.maxsize = fsize; offset += mp4r->base_data_offset; + + // Allocate memory for sample flags if sample_flags_present flag is set + // or if first_sample_flags_present flag is set (to handle key frame + // detection) + if ((vf & 0x400) || (vf & 0x04)) { + sample_flags = (uint32_t *)_dmalloc( + sizeof(uint32_t) * atr[sel_a_trak].frame.ents, __FILE__, __LINE__); + } + for (cnt = 0; cnt < atr[sel_a_trak].frame.ents; cnt++) { + uint32_t current_sample_flags = 0; + + // sample_duration_present flag if (vf & 0x100) avio_rb32(); + // sample_size_present flag if (vf & 0x200) fsize = avio_rb32(); if (atr[sel_a_trak].frame.maxsize < fsize) { atr[sel_a_trak].frame.maxsize = fsize; @@ -1123,9 +1173,68 @@ static int mov_read_trun(mp4r_t *mp4r, int size) { // fprintf(stderr, "entry %d : size %d, offset %u\n", cnt, fsize, offset); offset += fsize; - if (vf & 0x400) avio_rb32(); + // sample_flags_present flag + if (vf & 0x400) { + current_sample_flags = avio_rb32(); + if (sample_flags) { + sample_flags[cnt] = current_sample_flags; + } + } else if (vf & 0x04) { + // Use first_sample_flags for the first sample, and default_sample_flags + // for others + if (sample_flags) { + if (cnt == 0) { + sample_flags[cnt] = first_sample_flags; + } else { + sample_flags[cnt] = atr[sel_a_trak].default_sample_flags; + } + } + } + + // sample_composition_time_offsets_present flag if (vf & 0x800) avio_rb32(); } + + // Process sample flags to identify key frames + if (sample_flags) { + // Count key frames + uint32_t key_frame_count = 0; + for (cnt = 0; cnt < atr[sel_a_trak].frame.ents; cnt++) { + // Check if sample_is_non_sync_sample is 0 (sync sample = key frame) + // sample_is_non_sync_sample is bit 16 in sample flags: + uint32_t sample_is_non_sync_sample = (sample_flags[cnt] >> 16) & 0x1; + if (sample_is_non_sync_sample == 0) { + key_frame_count++; + } + } + + // fprintf(stderr, "key frame count %d\n", key_frame_count); + + // If we found key frames and don't already have sync samples from stss, + // create sync sample array from sample flags + if (key_frame_count > 0 && !atr[sel_a_trak].frame.syncs) { + atr[sel_a_trak].frame.syncs = (uint32_t *)_dmalloc( + sizeof(uint32_t) * key_frame_count, __FILE__, __LINE__); + if (atr[sel_a_trak].frame.syncs) { + atr[sel_a_trak].frame.sync_count = key_frame_count; + uint32_t sync_index = 0; + for (cnt = 0; cnt < atr[sel_a_trak].frame.ents; cnt++) { + // Check if sample_is_non_sync_sample is 0 (sync sample = key frame) + // sample_is_non_sync_sample is bit 16 in sample flags + uint32_t sample_is_non_sync_sample = (sample_flags[cnt] >> 16) & 0x1; + if (sample_is_non_sync_sample == 0) { + // Store 1-based index (as used in stss atom) + atr[sel_a_trak].frame.syncs[sync_index] = cnt + 1; + sync_index++; + // fprintf(stderr, "key frame index %d\n", cnt + 1); + } + } + } + } + + FREE(sample_flags); + } + mp4r->implicit_offset = offset; return size; @@ -1465,27 +1574,6 @@ int mp4demux_seek(mp4r_t *mp4r, int trakn, int framenum) { return ERR_OK; } -#if 0 -void mp4demux_info(mp4r_t *mp4r, int trakn, int print) { - audio_rtr_t *atr = mp4r->a_trak; - fprintf(stderr, "Modification Time:\t\t%s\n", mp4time(mp4r->mtime)); - if (trakn < mp4r->num_a_trak) { - int s = (trakn < 0) ? 0 : trakn; - int e = (trakn < 0) ? mp4r->num_a_trak - 1 : trakn; - for (int i = s; i <= e; i++) { - if (print) { - fprintf(stderr, "Audio track#%d -------------\n", i); - fprintf(stderr, "Samplerate:\t\t%u\n", atr[i].samplerate); - fprintf(stderr, "Total samples:\t\t%d\n", atr[i].samples); - fprintf(stderr, "Total channels:\t\t%d\n", atr[i].channels); - fprintf(stderr, "Bits per sample:\t%d\n", atr[i].bits); - fprintf(stderr, "Frames:\t\t\t%d\n", atr[i].frame.ents); - } - } - } -} -#endif - #define FREE_FUN(x, f, c) \ if (x) { \ f(x, c); \ @@ -1499,6 +1587,7 @@ int mp4demux_clean_tracks(mp4r_t *mp4r) { FREE(atr[i].frame.offs); FREE(atr[i].frame.sizes); FREE(atr[i].frame.deltas); + FREE(atr[i].frame.syncs); FREE(atr[i].bitbuf.data); FREE_FUN(atr[i].csc, iamf_header_free, atr[i].csc_count); } @@ -1596,13 +1685,10 @@ mp4r_t *mp4demux_open(const char *name, FILE *logger) { ////////////////////////// - // mp4demux_info(mp4r, -1, 1); - return mp4r; err: - if (mp4r != NULL) { - mp4demux_close(mp4r); - } + if (mp4r) mp4demux_close(mp4r); + return NULL; } diff --git a/code/test/tools/iamfdec/src/mp4iamfpar.c b/code/test/tools/iamfdec/src/mp4iamfpar.c index 1db0aa86..793ea70f 100755 --- a/code/test/tools/iamfdec/src/mp4iamfpar.c +++ b/code/test/tools/iamfdec/src/mp4iamfpar.c @@ -13,7 +13,7 @@ /** * @file mp4iamfpar.c * @brief MP4 and fMP4 file parser. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ @@ -58,7 +58,7 @@ int mp4_iamf_parser_get_audio_track_header(MP4IAMFParser *ths, } iamf_header = (IAMFHeader *)atr->csc; - if (iamf_header == NULL || atr == NULL) { + if (!iamf_header) { fprintf(stderr, "MP4 file does not have audio track.\n"); return -1; } diff --git a/code/test/tools/iamfdec/src/test_iamfdec.c b/code/test/tools/iamfdec/src/test_iamfdec.c index 872407d0..8cde1f9d 100755 --- a/code/test/tools/iamfdec/src/test_iamfdec.c +++ b/code/test/tools/iamfdec/src/test_iamfdec.c @@ -18,19 +18,20 @@ This software module is out of scope and not part of the IAMF Final Deliverable. /** * @file test_iamfdec.c * @brief IAMF decode test. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ #include #include -#include +#include #include +#include #include "IAMF_decoder.h" #include "dep_wavwriter.h" +#include "iamfdec_private.h" #include "mp4iamfpar.h" -#include "string.h" #ifndef SUPPORT_VERIFIER #define SUPPORT_VERIFIER 0 @@ -39,32 +40,129 @@ This software module is out of scope and not part of the IAMF Final Deliverable. #include "vlogging_tool_sr.h" #endif -#define FLAG_METADATA 0x1 -#if SUPPORT_VERIFIER -#define FLAG_VLOG 0x2 -#endif -#define FLAG_DISABLE_LIMITER 0x4 -#define SAMPLING_RATE 48000 +typedef struct Decoder { + FILE *f; + FILE *wav_f; -typedef struct Layout { - int type; - union { - IAMF_SoundSystem ss; - }; -} Layout; - -typedef struct PlayerArgs { - const char *input_path; - const char *ouput_path; - Layout *layout; - float peak; - float loudness; - uint32_t flags; - uint32_t st; + IAMF_DecoderHandle dec; + + int channels; uint32_t rate; - uint32_t bit_depth; - uint64_t mix_presentation_id; -} PlayerArgs; + IA_Profile profile; +} decoder_t; + +static int parse_element_gain_offsets(const char *ego_str, + decoder_args_t *das) { +#if defined(_WIN32) + char *str_copy = _strdup(ego_str); +#else + char *str_copy = strdup(ego_str); +#endif + char *token = NULL, *saveptr = NULL; + char *colon_pos = NULL; + + if (!str_copy || !das) return -1; + + das->element_gain_count = 0; +#if defined(_WIN32) + token = strtok_s(str_copy, ",", &saveptr); +#else + token = strtok_r(str_copy, ",", &saveptr); +#endif + while (token != NULL && + das->element_gain_count < def_max_element_gain_offsets) { + colon_pos = strchr(token, ':'); + if (!colon_pos) { + fprintf(stderr, + "Error: Invalid format in -ego parameter. Expected id:gain " + "format.\n"); + free(str_copy); + return -1; + } + + *colon_pos = '\0'; + colon_pos++; + + das->element_gain_offsets[das->element_gain_count].element_id = + strtoul(token, NULL, 10); + das->element_gain_offsets[das->element_gain_count].gain_offset = + strtof(colon_pos, 0); + das->element_gain_count++; + + fprintf(stdout, "Element gain offset: id=%u, gain=%.1f dB\n", + das->element_gain_offsets[das->element_gain_count - 1].element_id, + das->element_gain_offsets[das->element_gain_count - 1].gain_offset); +#if defined(_WIN32) + token = strtok_s(NULL, ",", &saveptr); +#else + token = strtok_r(NULL, ",", &saveptr); +#endif + } + + free(str_copy); + return 0; +} + +static int apply_element_gain_offset(IAMF_DecoderHandle handle, + IAMF_StreamInfo *info, + decoder_args_t *das) { + if (!handle || !info || !das || das->element_gain_count == 0) { + return 0; + } + + for (uint32_t idx = 0; idx < das->element_gain_count; idx++) { + uint32_t element_id = das->element_gain_offsets[idx].element_id; + float gain_offset = das->element_gain_offsets[idx].gain_offset; + iamf_element_presentation_info_t *element = NULL; + int element_found = 0; + + for (uint32_t i = 0; i < info->iamf_stream_info.mix_presentation_count; + i++) { + iamf_mix_presentation_info_t *mix = + &info->iamf_stream_info.mix_presentations[i]; + for (uint32_t j = 0; j < mix->num_audio_elements; j++) { + if (mix->elements[j].eid == element_id) { + element = &mix->elements[j]; + element_found = 1; + break; + } + } + if (element_found) break; + } + + if (!element_found) { + fprintf(stderr, "Element ID %u not found in stream\n", element_id); + continue; + } + + if (!element->gain_offset_range) { + fprintf(stderr, "Element ID %u does not support gain offset adjustment\n", + element_id); + continue; + } + + if (gain_offset < element->gain_offset_range->min || + gain_offset > element->gain_offset_range->max) { + fprintf(stderr, + "Element gain offset %.1f dB is out of range [%.1f, %.1f] dB for " + "element %u\n", + gain_offset, element->gain_offset_range->min, + element->gain_offset_range->max, element_id); + continue; + } + + IAMF_decoder_set_audio_element_gain_offset(handle, element_id, gain_offset); + + fprintf(stdout, "Successfully set element %u gain offset to %.1f dB\n", + element_id, gain_offset); + } + + return 0; +} + +static void iamf_decoder_output_info(IAMF_DecoderHandle handle, + decoder_args_t *das, + IAMF_StreamInfo *stream_info); static void print_usage(char *argv[]) { fprintf(stderr, "Usage:\n"); @@ -72,8 +170,9 @@ static void print_usage(char *argv[]) { fprintf(stderr, "options:\n"); fprintf(stderr, "-i[0-1] 0 : IAMF bitstream input.(default)\n"); fprintf(stderr, " 1 : MP4 input.\n"); + fprintf(stderr, "-o[1-3] 1 : Output IAMF stream info.\n"); fprintf(stderr, - "-o[2-3] 2 : WAVE output, same path as binary.(default)\n"); + " 2 : WAVE output, same path as binary.(default)\n"); fprintf(stderr, " 3 [path]\n" " : WAVE output, user setting path.\n"); @@ -84,7 +183,7 @@ static void print_usage(char *argv[]) { fprintf(stderr, "-v : verification log generation.\n"); #endif fprintf(stderr, - "-s[0~11,b] : Output layout, the sound system A~J and extensions " + "-s[0~14,b] : Output layout, the sound system A~J and extensions " "(Upper + Middle + Bottom).\n"); fprintf(stderr, " 0 : Sound system A (0+2+0)\n"); fprintf(stderr, " 1 : Sound system B (0+5+0)\n"); @@ -100,355 +199,243 @@ static void print_usage(char *argv[]) { fprintf(stderr, " 11 : Sound system extension 312 (2+3+0)\n"); fprintf(stderr, " 12 : Sound system mono (0+1+0)\n"); fprintf(stderr, " 13 : Sound system extension 916 (6+9+0)\n"); + fprintf(stderr, " 14 : Sound system extension 7154 (5+7+4)\n"); fprintf(stderr, " b : Binaural.\n"); fprintf(stderr, "-p [dB] : Peak threshold in dB.\n"); fprintf(stderr, "-l [LKFS] : Normalization loudness(<0) in LKFS.\n"); - fprintf(stderr, "-d [bit] : Bit depth of WAVE output.\n"); + fprintf(stderr, "-d [bits] : Bit depth of pcm output.\n"); fprintf(stderr, "-mp [id] : Set mix presentation id.\n"); - fprintf(stderr, - "-m : Generate a metadata file with the suffix .met .\n"); fprintf(stderr, "-disable_limiter\n : Disable peak limiter.\n"); + fprintf(stderr, + "-profile [n] : Set IAMF profile (0=SIMPLE, 1=BASE, 2=BASE_ENHANCED, " + "3=BASE_ADVANCED, 4=ADVANCED_1, 5=ADVANCED_2).\n"); + fprintf(stderr, + "-ego id1:gain1,id2:gain2,...\n : Set element gain " + "offsets in dB for multiple audio elements.\n"); + fprintf(stderr, "-ht : Enable head tracking.\n"); + fprintf(stderr, "-hr w,x,y,z : Set head rotation quaternion.\n"); } -static uint32_t valid_sound_system_layout(uint32_t ss) { - return ss < SOUND_SYSTEM_END ? 1 : 0; +static uint32_t sound_system_layout_check(uint32_t ss) { + return ss < SOUND_SYSTEM_END; } -typedef struct extradata_header { - uint32_t nSize; - uint32_t nVersion; - uint32_t nPortIndex; - uint32_t nType; - uint32_t nDataSize; -} extradata_header; - -static int extradata_layout2stream(uint8_t *buf, IAMF_Layout *layout) { - int s = sizeof(IAMF_Layout); - memcpy(buf, layout, s); - return s; -} +static int build_file_name(const char *path, layout_t *layout, char *n, + uint32_t size) { + int ret = 0; + const char *s = 0, *d; -static int extradata_loudness2stream(uint8_t *buf, - IAMF_LoudnessInfo *loudness) { - uint32_t offset = 0; - memcpy(buf + offset, &loudness->info_type, 1); - offset += 1; - memcpy(buf + offset, &loudness->integrated_loudness, 2); - offset += 2; - memcpy(buf + offset, &loudness->digital_peak, 2); - offset += 2; - - if (loudness->info_type & 1) { - memcpy(buf + offset, &loudness->true_peak, 2); - offset += 2; - } - - if (loudness->info_type & 2) { - memcpy(buf + offset, &loudness->num_anchor_loudness, 1); - offset += 1; - - for (int i = 0; i < loudness->num_anchor_loudness; ++i) { - memcpy(buf + offset, &loudness->anchor_loudness[i].anchor_element, 1); - offset += 1; - memcpy(buf + offset, &loudness->anchor_loudness[i].anchored_loudness, 2); - offset += 2; - } + if (layout->type == 2) { + snprintf(n, size, "ss%d_", layout->ss); + ret = strlen(n); + } else if (layout->type == 3) { + snprintf(n, size, "binaural_"); + ret = strlen(n); + } else { + fprintf(stdout, "Invalid output layout type %d.\n", layout->type); + return -1; } - return offset; -} +#if defined(_WIN32) + s = strrchr(path, '\\'); +#else + s = strrchr(path, '/'); +#endif + if (!s) + s = path; + else + ++s; -static int extradata_iamf_loudness_size(IAMF_LoudnessInfo *loudness) { - int ret = 5; - if (loudness->info_type & 1) ret += 2; - if (loudness->info_type & 2) { - ret += (1 + loudness->num_anchor_loudness * sizeof(anchor_loudness_t)); + d = strrchr(path, '.'); + if (d) { + int nn = d - s < size - ret - 1 ? d - s : size - ret - 1; + strncpy(n + ret, s, nn); + ret += nn; } - return ret; -} + n[ret] = 0; -static int extradata_iamf_size(IAMF_extradata *meta) { - int ret = 24; - for (int i = 0; i < meta->num_loudness_layouts; ++i) { - ret += sizeof(IAMF_Layout); - ret += extradata_iamf_loudness_size(&meta->loudness[i]); - } - ret += 4; - if (meta->num_parameters) { - ret += sizeof(IAMF_Param) * meta->num_parameters; - } - /* printf("iamf extradata size %d\n", ret); */ return ret; } -/** - * [0..7] PTS #8 bytes // ex) PTS = 90000 * [sample start clock] / 48000 - * [8..n] - * struct extradata_type { - * u32 nSize; - * u32 nVersion; // 1 - * u32 nPortIndex; // 0 - * u32 nType; // Extra Data type, 0x7f000001 : raw data, - * // 0x7f000005 : info data - * u32 nDataSize; // Size of the supporting data to follow - * u8 data[1]; // Supporting data hint ===> iamf_extradata - * } extradata_type; - * - * struct iamf_extradata { - * IAMF_SoundSystem output_sound_system; // sound system (5.1.2 -> -s2): 0~11 - * // in 4.2.5. Layout Syntax and - * // Semantics <--- renamed target - * // layout to output_sound_system - * uint32_t number_of_samples; - * uint32_t bitdepth; // 16 bits per sample - * uint32_t sampling_rate; // 48000 - * int output_sound_mode; // n/a(-1), stereo(0), multichannel(1) and - * // binaural(2). - * int num_loudness_layouts; - * for (i = 0; i < num_loudness_layouts; i++) { - * layout loudness_layout; // stereo, 5.1., 7.1.4, etc - * loudness_info loudness; - * } - * uint32_t num_parameters; // 1 - * for (i = 0; i < num_parameters; i++) { - * int parameter_length; // 8 bytes - * uint32_t parameter_definition_type; // PARAMETER_DEFINITION_DEMIXING(1) - * uint32_t dmixp_mode; - * } - * } - * - * */ -static int extradata_write(FILE *f, int64_t pts, IAMF_extradata *meta) { - extradata_header h; - uint8_t *buf; - uint32_t offset = 0; - uint32_t size = 0; - - h.nVersion = 1; - h.nPortIndex = 0; - h.nType = 0x7f000005; - - h.nDataSize = extradata_iamf_size(meta); - h.nSize = sizeof(extradata_header) + h.nDataSize; - - size = h.nSize + 8 + 3 & ~3; - /* printf ("the extradata size is %d\n", size); */ - - buf = (uint8_t *)malloc(size); - if (!buf) return -1; - memset(buf, 0, size); - - memcpy(buf + offset, &pts, 8); - offset += 8; - - memcpy(buf + offset, &h, sizeof(extradata_header)); - offset += sizeof(extradata_header); - - memcpy(buf + offset, &meta->output_sound_system, sizeof(uint32_t)); - offset += 4; - memcpy(buf + offset, &meta->number_of_samples, sizeof(uint32_t)); - offset += 4; - memcpy(buf + offset, &meta->bitdepth, sizeof(uint32_t)); - offset += 4; - memcpy(buf + offset, &meta->sampling_rate, sizeof(uint32_t)); - offset += 4; - memcpy(buf + offset, &meta->output_sound_mode, sizeof(int)); - offset += 4; - memcpy(buf + offset, &meta->num_loudness_layouts, sizeof(uint32_t)); - offset += 4; - - for (int i = 0; i < meta->num_loudness_layouts; ++i) { - offset += extradata_layout2stream(buf + offset, &meta->loudness_layout[i]); - offset += extradata_loudness2stream(buf + offset, &meta->loudness[i]); - } - - memcpy(buf + offset, &meta->num_parameters, sizeof(uint32_t)); - offset += 4; - if (meta->num_parameters) { - for (int i = 0; i < meta->num_parameters; ++i) { - memcpy(buf + offset, &meta->param[i], sizeof(IAMF_Param)); - offset += sizeof(IAMF_Param); - } - } - - fwrite(buf, 1, size, f); - - if (buf) free(buf); - return size; -} - -static void extradata_iamf_clean(IAMF_extradata *data) { - if (data) { - if (data->loudness_layout) free(data->loudness_layout); +static const char *sound_system_string(IAMF_SoundSystem ss) { + static const char *sss[] = { + "sound system A", "sound system B", "sound system C", + "sound system D", "sound system E", "sound system F", + "sound system G", "sound system H", "sound system I", + "sound system J", "sound system EXT 712", "sound system EXT 312", + "sound system MONO", "sound system EXT 916", "sound system EXT 7154", + }; - if (data->loudness) { - if (data->loudness->anchor_loudness) - free(data->loudness->anchor_loudness); - free(data->loudness); - } - if (data->param) free(data->param); - memset(data, 0, sizeof(IAMF_extradata)); - } + if (sound_system_layout_check(ss)) return sss[ss]; + return "Invalid sound system."; } -#define BLOCK_SIZE 960 * 6 * 2 * 16 -#define NAME_LENGTH 256 -#define FCLOSE(f) \ - if (f) { \ - fclose(f); \ - f = 0; \ +#define def_path_length 128 +#define def_fclose(f) \ + if (f) { \ + fclose(f); \ + f = 0; \ } -static int bs_input_wav_output(PlayerArgs *pas) { - FILE *f = 0; - FILE *wav_f = 0, *meta_f = 0; - uint8_t block[BLOCK_SIZE]; - char out[NAME_LENGTH] = {0}; - char meta_n[NAME_LENGTH] = {0}; - int used = 0, end = 0; +static int decoder_init(decoder_t *decoder, decoder_args_t *das) { int ret = 0; - int state = 0; - uint32_t rsize = 0; - void *pcm = NULL; - IAMF_DecoderHandle dec; - int channels = 0; - int count = 0, samples = 0; - uint64_t frsize = 0, fsize = 0; - uint32_t size; - const char *s = 0, *d; - const char *input_path = pas->input_path; - Layout *layout = pas->layout; - float db = pas->peak; - float loudness = pas->loudness; - uint32_t r = pas->rate; - uint32_t bit_depth = pas->bit_depth; - - if (!input_path) return -1; - if (pas->ouput_path) { - snprintf(out, NAME_LENGTH, "%s", pas->ouput_path); - } else { - if (layout->type == 2) { - snprintf(out, NAME_LENGTH, "ss%d_", layout->ss); - ret = strlen(out); - } else if (layout->type == 3) { - snprintf(out, NAME_LENGTH, "binaural_"); - ret = strlen(out); - } else { - fprintf(stdout, "Invalid output layout type %d.\n", layout->type); - return -1; - } -#if defined(_WIN32) - s = strrchr(input_path, '\\'); -#else - s = strrchr(input_path, '/'); -#endif - if (!s) { - s = input_path; - } else { - ++s; - } - d = strrchr(input_path, '.'); - if (d) { - strncpy(out + ret, s, - d - s < NAME_LENGTH - 5 - ret ? d - s : NAME_LENGTH - 5 - ret); - ret = strlen(out); - } - snprintf(out + ret, NAME_LENGTH - ret, "%s", ".wav"); - } - if (pas->flags & FLAG_METADATA) { - strcpy(meta_n, out); - snprintf(meta_n + ret, NAME_LENGTH - ret, "%s", ".met"); - meta_f = fopen(meta_n, "w+"); - if (!meta_f) { - fprintf(stderr, "%s can't opened.\n", out); - } + char out[def_path_length]; + + memset(decoder, 0, sizeof(decoder_t)); + + decoder->rate = das->rate; + if (das->output_path) { + ret = strlen(das->output_path); + strncpy(out, das->output_path, def_path_length); + } else { + ret = build_file_name(das->path, das->layout, out, def_path_length - 4); + if (ret < 0) return ret; + snprintf(out + ret, def_path_length - ret, "%s", ".wav"); } - dec = IAMF_decoder_open(); - if (!dec) { + decoder->dec = IAMF_decoder_open(); + if (!decoder->dec) { fprintf(stderr, "IAMF decoder can't created.\n"); - goto end; + return -1; + } + + if (IAMF_decoder_set_profile(decoder->dec, das->profile) != IAMF_OK) { + fprintf(stderr, "Failed to set profile %d, use default profile %d\n", + das->profile, def_default_profile); + IAMF_decoder_set_profile(decoder->dec, def_default_profile); + das->profile = def_default_profile; } - float limiter_threshold = IAMF_decoder_peak_limiter_get_threshold(dec); - fprintf(stderr, "The default threshold of limiter: %f db\n", - limiter_threshold); - if (pas->flags & FLAG_DISABLE_LIMITER) - IAMF_decoder_peak_limiter_enable(dec, 0); + if (das->flags & def_flag_disable_limiter) + IAMF_decoder_peak_limiter_enable(decoder->dec, 0); else - IAMF_decoder_peak_limiter_set_threshold(dec, db); - IAMF_decoder_set_normalization_loudness(dec, loudness); - IAMF_decoder_set_bit_depth(dec, bit_depth); + IAMF_decoder_peak_limiter_set_threshold(decoder->dec, das->peak); + IAMF_decoder_set_normalization_loudness(decoder->dec, das->loudness); + IAMF_decoder_set_bit_depth(decoder->dec, das->bit_depth); - if (r > 0 && IAMF_decoder_set_sampling_rate(dec, r) != IAMF_OK) { - fprintf(stderr, "Invalid sampling rate %u\n", r); - goto end; + if (decoder->rate > 0 && + IAMF_decoder_set_sampling_rate(decoder->dec, decoder->rate) != IAMF_OK) { + fprintf(stderr, "Invalid sampling rate %u\n", decoder->rate); + return -1; } - if (layout->type == 2) { - IAMF_decoder_output_layout_set_sound_system(dec, layout->ss); - channels = IAMF_layout_sound_system_channels_count(layout->ss); - const char *letter[] = {"A", "B", "C", "D", "E", - "F", "G", "H", "I", "J", - "EXT 712", "EXT 312", "MONO", "EXT 916"}; - - fprintf(stdout, "Sound system %s has %d channels\n", letter[layout->ss], - channels); + if (das->layout->type == 2) { + IAMF_decoder_output_layout_set_sound_system(decoder->dec, das->layout->ss); + decoder->channels = + IAMF_layout_sound_system_channels_count(das->layout->ss); + fprintf(stdout, "%s has %d channels\n", + sound_system_string(das->layout->ss), decoder->channels); } else { - IAMF_decoder_output_layout_set_binaural(dec); - channels = IAMF_layout_binaural_channels_count(); - fprintf(stdout, "Binaural has %d channels\n", channels); + IAMF_decoder_output_layout_set_binaural(decoder->dec); + decoder->channels = IAMF_layout_binaural_channels_count(); + fprintf(stdout, "Binaural has %d channels\n", decoder->channels); + + // Apply head tracking settings for binaural output + if (das->flags & def_flag_enable_head_tracking) { + IAMF_decoder_enable_head_tracking(decoder->dec, 1); + fprintf(stdout, "Head tracking enabled for binaural output\n"); + + // Set head rotation if provided (only effective when head tracking is + // enabled) + if (das->head_rotation_w != 0.0f || das->head_rotation_x != 0.0f || + das->head_rotation_y != 0.0f || das->head_rotation_z != 0.0f) { + IAMF_decoder_set_head_rotation( + decoder->dec, das->head_rotation_w, das->head_rotation_x, + das->head_rotation_y, das->head_rotation_z); + fprintf(stdout, "Head rotation set for binaural output\n"); + } + } } - f = fopen(input_path, "rb"); - if (!f) { - fprintf(stderr, "%s can't opened.\n", input_path); + decoder->f = fopen(das->path, "rb"); + if (!decoder->f) { + fprintf(stderr, "%s can't opened.\n", das->path); return -1; } - fseek(f, 0L, SEEK_END); - fsize = ftell(f); - fseek(f, 0L, SEEK_SET); - - if (!r) r = SAMPLING_RATE; - wav_f = (FILE *)dep_wav_write_open(out, r, bit_depth, channels); - if (!wav_f) { + if (!decoder->rate) decoder->rate = def_default_sampling_rate; + decoder->wav_f = (FILE *)dep_wav_write_open( + out, decoder->rate, das->bit_depth, decoder->channels); + if (!decoder->wav_f) { fprintf(stderr, "%s can't opened.\n", out); - goto end; + return -1; } + return 0; +} + +static void decoder_cleanup(decoder_t *decoder) { + def_fclose(decoder->f); + + if (decoder->wav_f) dep_wav_write_close(decoder->wav_f); + if (decoder->dec) IAMF_decoder_close(decoder->dec); +} + +static int bs_input_wav_output(decoder_args_t *das) { + decoder_t decoder; + uint8_t block[def_block_size]; + int used = 0, end = 0; + int ret = 0; + int state = 0; + uint32_t rsize = 0; + void *pcm = NULL; + int count = 0, samples = 0; + uint64_t frsize = 0, fsize = 0; + uint32_t size; + + if (!das->path) return -1; + + ret = decoder_init(&decoder, das); + if (ret < 0) goto end; + + fseek(decoder.f, 0L, SEEK_END); + fsize = ftell(decoder.f); + fseek(decoder.f, 0L, SEEK_SET); + do { ret = 0; - if (BLOCK_SIZE != used) { - ret = fread(block + used, 1, BLOCK_SIZE - used, f); + if (def_block_size != used) { + ret = fread(block + used, 1, def_block_size - used, decoder.f); if (ret < 0) { fprintf(stderr, "file read error : %d (%s).\n", ret, strerror(ret)); break; } - if (!ret) { - end = 1; - } + if (!ret) end = 1; } frsize += ret; - /* fprintf(stdout, "Read FILE ========== read %d and count %" PRIu64"\n", - * ret, */ - /* frsize); */ + // fprintf(stdout, "Read FILE ========== read %d and count %" PRIu64"\n", + // ret, frsize); size = used + ret; used = 0; if (state <= 0) { if (end) break; rsize = 0; - if (!state) IAMF_decoder_set_pts(dec, 0, 90000); - if (pas->mix_presentation_id != UINT64_MAX) - IAMF_decoder_set_mix_presentation_id(dec, pas->mix_presentation_id); - ret = IAMF_decoder_configure(dec, block + used, size - used, &rsize); + if (das->mix_presentation_id != def_default_mix_presentation_id) + IAMF_decoder_set_mix_presentation_id(decoder.dec, + das->mix_presentation_id); + ret = IAMF_decoder_configure(decoder.dec, block + used, size - used, + &rsize); if (ret == IAMF_OK) { state = 1; - IAMF_StreamInfo *info = IAMF_decoder_get_stream_info(dec); + IAMF_StreamInfo *info = IAMF_decoder_get_stream_info(decoder.dec); + if (apply_element_gain_offset(decoder.dec, info, das) != 0) { + fprintf(stderr, "Failed to apply element gain offset\n"); + if (info) IAMF_decoder_free_stream_info(info); + ret = -1; + break; + } + + iamf_decoder_output_info(decoder.dec, das, info); + if (!pcm) - pcm = (void *)malloc(bit_depth / 8 * info->max_frame_size * channels); + pcm = (void *)malloc(das->bit_depth / 8 * info->max_frame_size * + decoder.channels); + if (info) { + IAMF_decoder_free_stream_info(info); + info = 0; + } } else if (ret != IAMF_ERR_BUFFER_TOO_SMALL) { fprintf(stderr, "errno: %d, fail to configure decoder.\n", ret); break; @@ -460,15 +447,14 @@ static int bs_input_wav_output(PlayerArgs *pas) { used += rsize; } if (state > 0) { - IAMF_extradata meta; - int64_t pts; while (1) { rsize = 0; if (!end) - ret = - IAMF_decoder_decode(dec, block + used, size - used, &rsize, pcm); + ret = IAMF_decoder_decode(decoder.dec, block + used, size - used, + &rsize, pcm); else - ret = IAMF_decoder_decode(dec, (const uint8_t *)NULL, 0, &rsize, pcm); + ret = IAMF_decoder_decode(decoder.dec, (const uint8_t *)NULL, 0, + &rsize, pcm); /* fprintf(stdout, "read packet size %d\n", rsize); */ if (ret > 0) { @@ -476,14 +462,8 @@ static int bs_input_wav_output(PlayerArgs *pas) { samples += ret; /* fprintf(stderr, "===================== Get %d frame and size %d\n", * count, ret); */ - dep_wav_write_data(wav_f, (unsigned char *)pcm, - (bit_depth / 8) * ret * channels); - - if (pas->flags & FLAG_METADATA) { - IAMF_decoder_get_last_metadata(dec, &pts, &meta); - if (meta_f) extradata_write(meta_f, pts, &meta); - extradata_iamf_clean(&meta); - } + dep_wav_write_data(decoder.wav_f, (unsigned char *)pcm, + (das->bit_depth / 8) * ret * decoder.channels); } if (end) break; @@ -505,7 +485,10 @@ static int bs_input_wav_output(PlayerArgs *pas) { memmove(block, block + used, size - used); used = size - used; + } while (1); + +end: fprintf(stderr, "===================== Get %d frames\n", count); fprintf(stderr, "===================== Get %d samples\n", samples); @@ -515,173 +498,367 @@ static int bs_input_wav_output(PlayerArgs *pas) { "), not completely. return value %d\n", frsize, fsize, ret); -end: if (pcm) free(pcm); + decoder_cleanup(&decoder); - FCLOSE(f); - FCLOSE(meta_f); - - if (wav_f) dep_wav_write_close(wav_f); - if (dec) IAMF_decoder_close(dec); return ret; } -static int mp4_input_wav_output2(PlayerArgs *pas) { - MP4IAMFParser mp4par; - IAMFHeader *header = 0; - FILE *f = 0; - FILE *wav_f = 0, *meta_f = 0; - uint8_t *block = 0; - uint32_t size = 0; - char out[NAME_LENGTH] = {0}; - char meta_n[NAME_LENGTH] = {0}; - int end = 0; - int ret = 0; - void *pcm = NULL; - IAMF_DecoderHandle dec; - int channels; - int count = 0, samples = 0; - const char *s = 0, *d; - int entno = 0; - int64_t sample_offs; - const char *input_path = pas->input_path; - Layout *layout = pas->layout; - float db = pas->peak; - float loudness = pas->loudness; - uint32_t bit_depth = pas->bit_depth; - uint32_t r = pas->rate; - int64_t st = 0; +static const char *profile_string(IA_Profile profile) { + switch (profile) { + case IA_PROFILE_SIMPLE: + return "SIMPLE"; + case IA_PROFILE_BASE: + return "BASE"; + case IA_PROFILE_BASE_ENHANCED: + return "BASE_ENHANCED"; + case IA_PROFILE_BASE_ADVANCED: + return "BASE_ADVANCED"; + case IA_PROFILE_ADVANCED_1: + return "ADVANCED_1"; + case IA_PROFILE_ADVANCED_2: + return "ADVANCED_2"; + default: + return "UNKNOWN"; + } +} - if (!input_path) return -1; +static const char *codec_string(IAMF_CodecID codec_id) { + switch (codec_id) { + case IAMF_CODEC_OPUS: + return "Opus"; + case IAMF_CODEC_AAC: + return "AAC"; + case IAMF_CODEC_FLAC: + return "FLAC"; + case IAMF_CODEC_PCM: + return "PCM"; + default: + return "UNKNOWN"; + } +} - memset(&mp4par, 0, sizeof(mp4par)); - if (pas->ouput_path) { - snprintf(out, NAME_LENGTH, "%s", pas->ouput_path); +static const char *headphones_rendering_mode_string( + IAMF_HeadphonesRenderingMode mode) { + switch (mode) { + case HEADPHONES_RENDERING_MODE_WORLD_LOCKED_RESTRICTED: + return "WORLD_LOCKED_RESTRICTED"; + case HEADPHONES_RENDERING_MODE_WORLD_LOCKED: + return "WORLD_LOCKED"; + case HEADPHONES_RENDERING_MODE_HEAD_LOCKED: + return "HEAD_LOCKED"; + case HEADPHONES_RENDERING_MODE_RESERVED: + return "RESERVED"; + default: + return "UNKNOWN"; + } +} + +static const char *binaural_filter_profile_string( + IAMF_BinauralFilterProfile profile) { + switch (profile) { + case BINAURAL_FILTER_PROFILE_AMBIENT: + return "AMBIENT"; + case BINAURAL_FILTER_PROFILE_DIRECT: + return "DIRECT"; + case BINAURAL_FILTER_PROFILE_REVERBERANT: + return "REVERBERANT"; + case BINAURAL_FILTER_PROFILE_RESERVED: + return "RESERVED"; + default: + return "UNKNOWN"; + } +} + +void iamf_decoder_output_info(IAMF_DecoderHandle handle, decoder_args_t *das, + IAMF_StreamInfo *stream_info) { + if (!handle) { + fprintf(stdout, "Invalid decoder handle.\n"); + return; + } + + IA_Profile current_profile = IAMF_decoder_get_profile(handle); + fprintf(stdout, "Current IAMF Profile: %d (%s)\n", current_profile, + profile_string(current_profile)); + + int64_t mix_presentation_id = IAMF_decoder_get_mix_presentation_id(handle); + if (mix_presentation_id >= 0) { + fprintf(stdout, "Selected Mix Presentation ID: %" PRId64 "\n", + mix_presentation_id); } else { - if (layout->type == 2) { - snprintf(out, NAME_LENGTH, "ss%d_", layout->ss); - ret = strlen(out); - } else if (layout->type == 3) { - snprintf(out, NAME_LENGTH, "binaural_"); - ret = strlen(out); - } else { - fprintf(stdout, "Invalid output layout type %d.\n", layout->type); - return -1; - } + fprintf(stdout, "Selected Mix Presentation ID: None (default)\n"); + } -#if defined(_WIN32) - s = strrchr(input_path, '\\'); -#else - s = strrchr(input_path, '/'); -#endif - if (!s) { - s = input_path; - } else { - ++s; + if (!(das->flags & def_flag_disable_limiter)) { + float limiter_threshold = IAMF_decoder_peak_limiter_get_threshold(handle); + fprintf(stdout, "Peak Limiter Threshold: %.2f dB\n", limiter_threshold); + } + + if (stream_info && mix_presentation_id >= 0) { + iamf_mix_presentation_info_t *target_mix = NULL; + for (uint32_t i = 0; + i < stream_info->iamf_stream_info.mix_presentation_count; i++) { + if (stream_info->iamf_stream_info.mix_presentations[i].id == + (uint32_t)mix_presentation_id) { + target_mix = &stream_info->iamf_stream_info.mix_presentations[i]; + break; + } } - d = strrchr(input_path, '.'); - if (d) { - strncpy(out + ret, s, - d - s < NAME_LENGTH - 5 - ret ? d - s : NAME_LENGTH - 5 - ret); - ret = strlen(out); + + if (target_mix) { + for (uint32_t j = 0; j < target_mix->num_audio_elements; j++) { + iamf_element_presentation_info_t *element = &target_mix->elements[j]; + float current_gain = 0.0f; + + if (!element->gain_offset_range) continue; + if (IAMF_decoder_get_audio_element_gain_offset( + handle, element->eid, ¤t_gain) == IAMF_OK) { + fprintf(stdout, " Element %u: Current gain offset = %.2f dB", + element->eid, current_gain); + + if (element->gain_offset_range) { + fprintf(stdout, " (range: %.1f to %.1f dB)", + element->gain_offset_range->min, + element->gain_offset_range->max); + } + fprintf(stdout, "\n"); + } + } } - snprintf(out + ret, NAME_LENGTH - ret, "%s", ".wav"); + } +} + +static void print_complete_stream_info(IAMF_StreamInfo *info) { + if (!info) { + fprintf(stdout, "No stream information available.\n"); + return; + } + + fprintf(stdout, "\n=== IAMF Stream Information ===\n"); + fprintf(stdout, "Maximum frame size: %u samples\n", info->max_frame_size); + + fprintf(stdout, "\n--- Profile Information ---\n"); + fprintf(stdout, "Primary profile: %d (%s)\n", + info->iamf_stream_info.primary_profile, + profile_string(info->iamf_stream_info.primary_profile)); + fprintf(stdout, "Additional profile: %d (%s)\n", + info->iamf_stream_info.additional_profile, + profile_string(info->iamf_stream_info.additional_profile)); + + fprintf(stdout, "\n--- Codec Information ---\n"); + for (int i = 0; + i < IAMF_MAX_CODECS && info->iamf_stream_info.codec_ids[i] != 0; i++) { + fprintf(stdout, "Codec %d: %d (%s)\n", i, + info->iamf_stream_info.codec_ids[i], + codec_string(info->iamf_stream_info.codec_ids[i])); } - if (pas->flags & FLAG_METADATA) { - strcpy(meta_n, out); - snprintf(meta_n + ret, NAME_LENGTH - ret, "%s", ".met"); - meta_f = fopen(meta_n, "w+"); - if (!meta_f) { - fprintf(stderr, "%s can't opened.\n", out); + fprintf(stdout, "\n--- Audio Parameters ---\n"); + fprintf(stdout, "Sampling rate: %u Hz\n", + info->iamf_stream_info.sampling_rate); + fprintf(stdout, "Samples per channel per frame: %u\n", + info->iamf_stream_info.samples_per_channel_in_frame); + + fprintf(stdout, "\n--- Mix Presentations ---\n"); + fprintf(stdout, "Number of mix presentations: %u\n", + info->iamf_stream_info.mix_presentation_count); + + if (info->iamf_stream_info.mix_presentations) { + for (uint32_t i = 0; i < info->iamf_stream_info.mix_presentation_count; + i++) { + iamf_mix_presentation_info_t *mix = + &info->iamf_stream_info.mix_presentations[i]; + fprintf(stdout, "\n Mix Presentation %u:\n", mix->id); + fprintf(stdout, " Number of audio elements: %u\n", + mix->num_audio_elements); + + if (mix->elements) { + for (uint32_t j = 0; j < mix->num_audio_elements; j++) { + iamf_element_presentation_info_t *elem = &mix->elements[j]; + fprintf(stdout, " Audio Element %u:\n", elem->eid); + fprintf(stdout, " Headphones rendering mode: %d (%s)\n", + elem->mode, headphones_rendering_mode_string(elem->mode)); + fprintf(stdout, " Binaural filter profile: %d (%s)\n", + elem->profile, binaural_filter_profile_string(elem->profile)); + if (elem->gain_offset_range) { + fprintf(stdout, " Gain offset range: %.1f dB to %.1f dB\n", + elem->gain_offset_range->min, elem->gain_offset_range->max); + } + } + } } } + fprintf(stdout, "=== End of Stream Information ===\n\n"); +} + +static int stream_info_output(decoder_args_t *das, int input_mode) { + IAMF_DecoderHandle dec; + IAMF_StreamInfo *info = NULL; + int ret = 0; + + // Initialize decoder and set profile dec = IAMF_decoder_open(); if (!dec) { fprintf(stderr, "IAMF decoder can't created.\n"); return -1; } - float limiter_threshold = IAMF_decoder_peak_limiter_get_threshold(dec); - fprintf(stderr, "The default threshold of limiter: %f db\n", - limiter_threshold); - if (pas->flags & FLAG_DISABLE_LIMITER) - IAMF_decoder_peak_limiter_enable(dec, 0); - else - IAMF_decoder_peak_limiter_set_threshold(dec, db); - IAMF_decoder_set_normalization_loudness(dec, loudness); - IAMF_decoder_set_bit_depth(dec, bit_depth); + IAMF_decoder_output_layout_set_sound_system(dec, SOUND_SYSTEM_A); - if (r > 0 && IAMF_decoder_set_sampling_rate(dec, r) != IAMF_OK) { - fprintf(stderr, "Invalid sampling rate %u\n", r); - goto end; - } + if (input_mode == 0) { + decoder_t decoder; + uint8_t block[def_block_size]; + int used = 0, end = 0, state = 0; + uint32_t rsize = 0, size; - if (layout->type == 2) { - IAMF_decoder_output_layout_set_sound_system(dec, layout->ss); - channels = IAMF_layout_sound_system_channels_count(layout->ss); - const char *letter[] = {"A", "B", "C", "D", "E", - "F", "G", "H", "I", "J", - "EXT 712", "EXT 312", "MONO", "EXT 916"}; - - fprintf(stdout, "Sound system %s has %d channels\n", letter[layout->ss], - channels); - } else if (layout->type == 3) { - IAMF_decoder_output_layout_set_binaural(dec); - channels = IAMF_layout_binaural_channels_count(); - fprintf(stdout, "Binaural has %d channels\n", channels); + memset(&decoder, 0, sizeof(decoder_t)); + decoder.dec = dec; + decoder.f = fopen(das->path, "rb"); + if (!decoder.f) { + fprintf(stderr, "%s can't opened.\n", das->path); + IAMF_decoder_close(dec); + return -1; + } + + do { + ret = 0; + if (def_block_size != used) { + ret = fread(block + used, 1, def_block_size - used, decoder.f); + if (ret < 0) { + fprintf(stderr, "file read error : %d (%s).\n", ret, strerror(ret)); + break; + } + if (!ret) end = 1; + } + + size = used + ret; + used = 0; + if (state <= 0) { + if (end) break; + rsize = 0; + ret = IAMF_decoder_configure(dec, block + used, size - used, &rsize); + if (ret == IAMF_OK) { + info = IAMF_decoder_get_stream_info(dec); + break; + } else if (ret != IAMF_ERR_BUFFER_TOO_SMALL) { + fprintf(stderr, "errno: %d, fail to configure decoder.\n", ret); + break; + } else if (!rsize) { + fprintf(stderr, "errno: %d, buffer is too small.\n", ret); + break; + } + used += rsize; + } + + if (end) break; + memmove(block, block + used, size - used); + used = size - used; + } while (1); + + fclose(decoder.f); } else { - fprintf(stderr, "Invalid layout"); - ret = -1; - goto end; - } + // MP4 input + MP4IAMFParser mp4par; + IAMFHeader *header = 0; + uint8_t *block = 0; + uint32_t size = 0; + + memset(&mp4par, 0, sizeof(mp4par)); + mp4_iamf_parser_init(&mp4par); + mp4_iamf_parser_set_logger(&mp4par, 0); + ret = mp4_iamf_parser_open_audio_track(&mp4par, das->path, &header); + + if (ret <= 0) { + fprintf(stderr, "mp4iamfpar can not open mp4 file(%s)\n", das->path); + goto mp4_end; + } - f = fopen(input_path, "rb"); - if (!f) { - fprintf(stderr, "%s can't opened.\n", input_path); - ret = errno; - goto end; + ret = iamf_header_read_description_OBUs(header, &block, &size); + if (!ret) { + fprintf(stderr, "fail to copy description obu.\n"); + goto mp4_end; + } + + ret = IAMF_decoder_configure(dec, block, ret, 0); + if (ret != IAMF_OK) { + fprintf(stderr, "fail to configure.\n"); + goto mp4_end; + } + + info = IAMF_decoder_get_stream_info(dec); + + mp4_end: + if (block) free(block); + mp4_iamf_parser_close(&mp4par); } - if (!r) r = SAMPLING_RATE; - wav_f = (FILE *)dep_wav_write_open(out, r, bit_depth, channels); - if (!wav_f) { - fprintf(stderr, "%s can't opened.\n", out); - ret = errno; - goto end; + if (info) { + print_complete_stream_info(info); + IAMF_decoder_free_stream_info(info); + } else { + fprintf(stderr, "Failed to get stream info.\n"); } + IAMF_decoder_close(dec); + return ret; +} + +static int mp4_input_wav_output2(decoder_args_t *das) { + MP4IAMFParser mp4par; + IAMFHeader *header = 0; + decoder_t decoder; + uint8_t *block = 0; + uint32_t size = 0; + int end = 0; + int ret = 0; + void *pcm = NULL; + int count = 0, samples = 0; + int entno = 0; + int64_t sample_offs; + + if (!das->path) return -1; + + memset(&mp4par, 0, sizeof(mp4par)); + + ret = decoder_init(&decoder, das); + if (ret < 0) goto end; + mp4_iamf_parser_init(&mp4par); mp4_iamf_parser_set_logger(&mp4par, 0); - ret = mp4_iamf_parser_open_audio_track(&mp4par, input_path, &header); + ret = mp4_iamf_parser_open_audio_track(&mp4par, das->path, &header); if (ret <= 0) { - fprintf(stderr, "mp4opusdemuxer can not open mp4 file(%s)\n", input_path); + fprintf(stderr, "mp4opusdemuxer can not open mp4 file(%s)\n", das->path); goto end; } - if (pas->st) - st = pas->st * 90000; - else { - double r = header->skip * 90000; - st = r / header->timescale + 0.5f; - printf("skip %d/%d pts is %" PRId64 "/90000\n", header->skip, - header->timescale, st); - } - IAMF_decoder_set_pts(dec, st * -1, 90000); - ret = iamf_header_read_description_OBUs(header, &block, &size); if (!ret) { fprintf(stderr, "fail to copy description obu.\n"); goto end; } - if (pas->mix_presentation_id != UINT64_MAX) - IAMF_decoder_set_mix_presentation_id(dec, pas->mix_presentation_id); - ret = IAMF_decoder_configure(dec, block, ret, 0); - IAMF_StreamInfo *info = IAMF_decoder_get_stream_info(dec); - pcm = (void *)malloc(bit_depth / 8 * info->max_frame_size * channels); + if (das->mix_presentation_id != def_default_mix_presentation_id) + IAMF_decoder_set_mix_presentation_id(decoder.dec, das->mix_presentation_id); + ret = IAMF_decoder_configure(decoder.dec, block, ret, 0); + if (ret != IAMF_OK) { + fprintf(stderr, "fail to configure.\n"); + goto end; + } + + IAMF_StreamInfo *info = IAMF_decoder_get_stream_info(decoder.dec); + if (apply_element_gain_offset(decoder.dec, info, das) != 0) { + fprintf(stderr, "Failed to apply element gain offset\n"); + if (info) IAMF_decoder_free_stream_info(info); + ret = -1; + goto end; + } + + iamf_decoder_output_info(decoder.dec, das, info); + + pcm = (void *)malloc(das->bit_depth / 8 * info->max_frame_size * + decoder.channels); if (!pcm) { ret = errno; fprintf(stderr, "error no(%d):fail to malloc memory for pcm.", ret); @@ -693,18 +870,21 @@ static int mp4_input_wav_output2(PlayerArgs *pas) { goto end; } + if (info) { + IAMF_decoder_free_stream_info(info); + info = 0; + } + do { - IAMF_extradata meta; - int64_t pts; if (mp4_iamf_parser_read_packet(&mp4par, 0, &block, &size, &sample_offs, &entno) < 0) { end = 1; } if (!end) - ret = IAMF_decoder_decode(dec, block, size, 0, pcm); + ret = IAMF_decoder_decode(decoder.dec, block, size, 0, pcm); else - ret = IAMF_decoder_decode(dec, (const uint8_t *)NULL, 0, 0, pcm); + ret = IAMF_decoder_decode(decoder.dec, (const uint8_t *)NULL, 0, 0, pcm); if (block) free(block); block = 0; @@ -715,26 +895,19 @@ static int mp4_input_wav_output2(PlayerArgs *pas) { /* "===================== Get %d frame and size %d, offset %" PRId64"\n", */ /* count, ret, sample_offs); */ - dep_wav_write_data(wav_f, (unsigned char *)pcm, - (bit_depth / 8) * ret * channels); - - if (pas->flags & FLAG_METADATA) { - IAMF_decoder_get_last_metadata(dec, &pts, &meta); - if (meta_f) extradata_write(meta_f, pts, &meta); - extradata_iamf_clean(&meta); - } + dep_wav_write_data(decoder.wav_f, (unsigned char *)pcm, + (das->bit_depth / 8) * ret * decoder.channels); } if (end) break; } while (1); end: fprintf(stderr, "===================== Get %d frames\n", count); fprintf(stderr, "===================== Get %d samples\n", samples); + + if (block) free(block); if (pcm) free(pcm); - FCLOSE(f) - FCLOSE(meta_f) - if (wav_f) dep_wav_write_close(wav_f); - if (dec) IAMF_decoder_close(dec); mp4_iamf_parser_close(&mp4par); + decoder_cleanup(&decoder); return ret; } @@ -745,15 +918,17 @@ int main(int argc, char *argv[]) { int input_mode = 0; int sound_system = -1; char *f = 0; - Layout target; - PlayerArgs pas; - - memset(&pas, 0, sizeof(pas)); - pas.layout = ⌖ - pas.peak = -1.f; - pas.loudness = .0f; - pas.bit_depth = 16; - pas.mix_presentation_id = UINT64_MAX; + layout_t target; + decoder_args_t das; + + memset(&das, 0, sizeof(das)); + das.layout = ⌖ + das.peak = -1.f; + das.loudness = .0f; + das.bit_depth = 16; + das.mix_presentation_id = -1; + das.rate = def_default_sampling_rate; + das.profile = def_default_profile; if (argc < 2) { print_usage(argv); @@ -764,7 +939,7 @@ int main(int argc, char *argv[]) { char *vlog_file = 0; #endif - memset(&target, 0, sizeof(Layout)); + memset(&target, 0, sizeof(layout_t)); args = 1; fprintf(stdout, "IN ARGS:\n"); while (args < argc) { @@ -773,7 +948,7 @@ int main(int argc, char *argv[]) { output_mode = atoi(argv[args] + 2); fprintf(stdout, "Output mode %d\n", output_mode); if (output_mode == 3) { - pas.ouput_path = argv[++args]; + das.output_path = argv[++args]; } } else if (argv[args][1] == 'i') { input_mode = atoi(argv[args] + 2); @@ -785,7 +960,7 @@ int main(int argc, char *argv[]) { } else { sound_system = atoi(argv[args] + 2); fprintf(stdout, "Output sound system %d\n", sound_system); - if (valid_sound_system_layout(sound_system)) { + if (sound_system_layout_check(sound_system)) { target.type = 2; target.ss = sound_system; } else { @@ -794,88 +969,116 @@ int main(int argc, char *argv[]) { } } } else if (!strcmp(argv[args], "-p")) { - pas.peak = strtof(argv[++args], 0); - fprintf(stdout, "Peak threshold value : %g db\n", pas.peak); + das.peak = strtof(argv[++args], 0); + fprintf(stdout, "Peak threshold value : %g db\n", das.peak); } else if (!strcmp(argv[args], "-l")) { - pas.loudness = strtof(argv[++args], 0); + das.loudness = strtof(argv[++args], 0); fprintf(stdout, "Normalization loudness value : %g LKFS\n", - pas.loudness); + das.loudness); } else if (!strcmp(argv[args], "-d")) { - pas.bit_depth = strtof(argv[++args], 0); - fprintf(stdout, "Bit depth of pcm output : %u bit\n", pas.bit_depth); - } else if (!strcmp(argv[args], "-m")) { - pas.flags |= FLAG_METADATA; - fprintf(stdout, "Generate metadata file"); + das.bit_depth = strtof(argv[++args], 0); + fprintf(stdout, "Bit depth of pcm output : %u bit\n", das.bit_depth); } else if (argv[args][1] == 'v') { #if SUPPORT_VERIFIER - pas.flags |= FLAG_VLOG; + das.flags |= def_flag_vlog; vlog_file = argv[++args]; fprintf(stdout, "Verification log file : %s\n", vlog_file); #endif - } else if (argv[args][1] == 'h') { + } else if (!strcmp(argv[args], "-h")) { print_usage(argv); return 0; - } else if (argv[args][1] == 't') { - if (!strcmp(argv[args], "-ts")) { - pas.st = strtoul(argv[++args], NULL, 10); - fprintf(stdout, "Start time : %us\n", pas.st); - } + } else if (!strcmp(argv[args], "-ht")) { + das.flags |= def_flag_enable_head_tracking; + fprintf(stdout, "Head tracking enabled\n"); } else if (!strcmp(argv[args], "-r")) { - pas.rate = strtoul(argv[++args], NULL, 10); - fprintf(stdout, "sampling rate : %u\n", pas.rate); + das.rate = strtoul(argv[++args], NULL, 10); + fprintf(stdout, "sampling rate : %u\n", das.rate); } else if (!strcmp(argv[args], "-mp")) { - pas.mix_presentation_id = strtoull(argv[++args], NULL, 10); + das.mix_presentation_id = strtoull(argv[++args], NULL, 10); fprintf(stdout, "select mix presentation id %" PRId64 "\n", - pas.mix_presentation_id); + das.mix_presentation_id); } else if (!strcmp(argv[args], "-disable_limiter")) { - pas.flags |= FLAG_DISABLE_LIMITER; + das.flags |= def_flag_disable_limiter; fprintf(stdout, "Disable peak limiter\n"); + } else if (!strcmp(argv[args], "-ego")) { + parse_element_gain_offsets(argv[++args], &das); + } else if (!strcmp(argv[args], "-hr")) { + char *rotation_str = argv[++args]; + sscanf(rotation_str, "%f,%f,%f,%f", &das.head_rotation_w, + &das.head_rotation_x, &das.head_rotation_y, + &das.head_rotation_z); + fprintf(stdout, "Head rotation: w=%f, x=%f, y=%f, z=%f\n", + das.head_rotation_w, das.head_rotation_x, das.head_rotation_y, + das.head_rotation_z); + } else if (!strcmp(argv[args], "-profile")) { + int profile_val = atoi(argv[++args]); + if (profile_val > IA_PROFILE_NONE && + profile_val <= IA_PROFILE_ADVANCED_2) { + das.profile = (IA_Profile)profile_val; + fprintf(stdout, "Profile set to %d\n", profile_val); + } else { + fprintf(stderr, "Invalid profile value %d\n", profile_val); + } } } else { f = argv[args]; - if (!f) { - fprintf(stderr, "Input file path.\n"); - return 0; - } - fprintf(stdout, "Input file : %s\n", f); - pas.input_path = f; } args++; } - if (input_mode != 1 && pas.st) { + if (!f) { + fprintf(stderr, "Please input file.\n"); + print_usage(argv); + return -1; + } else { + fprintf(stdout, "file : %s\n", f); + das.path = f; + } + + if (input_mode != 1 && das.st) { fprintf(stderr, "ERROR: -st is valid when mp4 file is used as input.\n"); print_usage(argv); return -1; } - if (output_mode != 2 && output_mode != 3) { - fprintf(stderr, "invalid output mode\n"); + if (!output_mode || output_mode > 3) { + fprintf(stderr, "invalid output mode %d\n", output_mode); print_usage(argv); return -1; } char *supported_codecs = IAMF_decoder_get_codec_capability(); - if (supported_codecs) free(supported_codecs); + if (supported_codecs) { + fprintf(stdout, "codec capability: %s\n", supported_codecs); + free(supported_codecs); + } + + if (output_mode == 1 && input_mode > 1) { + fprintf(stderr, "ERROR: -o1 is only valid when input mode is 0 or 1.\n"); + return -1; + } - if (target.type) { #if SUPPORT_VERIFIER - if (pas.flags & FLAG_VLOG) vlog_file_open(vlog_file); + if (das.flags & def_flag_vlog) vlog_file_open(vlog_file); #endif + + if (output_mode == 1) { + stream_info_output(&das, input_mode); + } else if (target.type) { + // WAVE output modes (2 and 3) if (!input_mode) { - bs_input_wav_output(&pas); + bs_input_wav_output(&das); } else if (input_mode == 1) { - mp4_input_wav_output2(&pas); + mp4_input_wav_output2(&das); } else { fprintf(stderr, "invalid input mode %d\n", input_mode); } -#if SUPPORT_VERIFIER - if (pas.flags & FLAG_VLOG) vlog_file_close(); -#endif } else { print_usage(argv); fprintf(stderr, "invalid output sound system %d\n", sound_system); } - +#if SUPPORT_VERIFIER + if (das.flags & def_flag_vlog) vlog_file_close(); +#endif return 0; } diff --git a/code/test/tools/iamfdec/src/vlogging_iamfmp4_sr.c b/code/test/tools/iamfdec/src/vlogging_iamfmp4_sr.c index 8246bdd7..eca33312 100755 --- a/code/test/tools/iamfdec/src/vlogging_iamfmp4_sr.c +++ b/code/test/tools/iamfdec/src/vlogging_iamfmp4_sr.c @@ -98,7 +98,8 @@ int utc2rstring(uint64_t utc, char* txt, int sizemax) { enum { BUFSIZE = 40 }; char buf[BUFSIZE]; int j; - if (utc >= 208284480) utc -= 2082844800; + uint64_t tmp = 2082844800; + if (utc >= tmp) utc -= tmp; new_tm = gmtime(&utc); sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d UTC", new_tm->tm_year + 1900, // years since 1900 @@ -1392,6 +1393,57 @@ static void write_stts_atom_log(char** log, void* atom_d, int size, write_postfix(LOG_MP4BOX, *log + len); } +static void write_stss_atom_log(char** log, void* atom_d, int size, + uint64_t atom_addr) { + /* + + + + + + + + + + */ + uint32_t val; + int index = 0; + int entry_count = 0; + int cnt; + + int len = write_prefix(LOG_MP4BOX, *log); + len += write_yaml_form(*log + len, 0, "stss_%016x:", atom_addr); + + // version/flags + val = queue_rb32(index, atom_d, size - index); + index += 4; + len += write_yaml_form(*log + len, 0, "- Version: %u", (val >> 24) & 0xff); + len += write_yaml_form(*log + len, 0, "- Flags: %u", val & 0xffffff); + + // entry count + val = queue_rb32(index, atom_d, size - index); + index += 4; + len += write_yaml_form(*log + len, 0, "- EntryCount: %u", val); + if (val > 0) { + char* tmp = *log; + *log = + (char*)realloc(*log, sizeof(char) * (LOG_BUFFER_SIZE - len + 50 * val)); + if (NULL == *log) { + *log = tmp; + return; + } + + entry_count = val; + for (cnt = 0; cnt < entry_count; cnt++) { + val = queue_rb32(index, atom_d, size - index); + index += 4; + len += write_yaml_form(*log + len, 0, "- SampleNumber_%d: %u", cnt, val); + } + } + + write_postfix(LOG_MP4BOX, *log + len); +} + static void write_stsc_atom_log(char** log, void* atom_d, int size, uint64_t atom_addr) { /* @@ -1754,6 +1806,9 @@ int vlog_atom(uint32_t atom_type, void* atom_d, int size, uint64_t atom_addr) { case MP4BOX_STTS: write_stts_atom_log(&log, atom_d, size, atom_addr); break; + case MP4BOX_STSS: + write_stss_atom_log(&log, atom_d, size, atom_addr); + break; case MP4BOX_STSC: write_stsc_atom_log(&log, atom_d, size, atom_addr); break; diff --git a/code/win64/VS2022/iamf.sln b/code/win64/VS2022/iamf.sln deleted file mode 100755 index 22980d05..00000000 --- a/code/win64/VS2022/iamf.sln +++ /dev/null @@ -1,41 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.3.32901.215 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iamf", "iamf\iamf.vcxproj", "{8E84EEFB-BAD7-4D3D-B6D4-A2340CA616A5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iamfdec", "iamfdec\iamfdec.vcxproj", "{87B309F3-FD93-462A-A18B-250EB410506E}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8E84EEFB-BAD7-4D3D-B6D4-A2340CA616A5}.Debug|x64.ActiveCfg = Debug|x64 - {8E84EEFB-BAD7-4D3D-B6D4-A2340CA616A5}.Debug|x64.Build.0 = Debug|x64 - {8E84EEFB-BAD7-4D3D-B6D4-A2340CA616A5}.Debug|x86.ActiveCfg = Debug|Win32 - {8E84EEFB-BAD7-4D3D-B6D4-A2340CA616A5}.Debug|x86.Build.0 = Debug|Win32 - {8E84EEFB-BAD7-4D3D-B6D4-A2340CA616A5}.Release|x64.ActiveCfg = Release|x64 - {8E84EEFB-BAD7-4D3D-B6D4-A2340CA616A5}.Release|x64.Build.0 = Release|x64 - {8E84EEFB-BAD7-4D3D-B6D4-A2340CA616A5}.Release|x86.ActiveCfg = Release|Win32 - {8E84EEFB-BAD7-4D3D-B6D4-A2340CA616A5}.Release|x86.Build.0 = Release|Win32 - {87B309F3-FD93-462A-A18B-250EB410506E}.Debug|x64.ActiveCfg = Debug|x64 - {87B309F3-FD93-462A-A18B-250EB410506E}.Debug|x64.Build.0 = Debug|x64 - {87B309F3-FD93-462A-A18B-250EB410506E}.Debug|x86.ActiveCfg = Debug|Win32 - {87B309F3-FD93-462A-A18B-250EB410506E}.Debug|x86.Build.0 = Debug|Win32 - {87B309F3-FD93-462A-A18B-250EB410506E}.Release|x64.ActiveCfg = Release|x64 - {87B309F3-FD93-462A-A18B-250EB410506E}.Release|x64.Build.0 = Release|x64 - {87B309F3-FD93-462A-A18B-250EB410506E}.Release|x86.ActiveCfg = Release|Win32 - {87B309F3-FD93-462A-A18B-250EB410506E}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {C492D50D-70C8-4E71-8488-634AE1095782} - EndGlobalSection -EndGlobal diff --git a/code/win64/VS2022/iamf/iamf.vcxproj b/code/win64/VS2022/iamf/iamf.vcxproj deleted file mode 100755 index 8bb25f7e..00000000 --- a/code/win64/VS2022/iamf/iamf.vcxproj +++ /dev/null @@ -1,203 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {8e84eefb-bad7-4d3d-b6d4-a2340ca616a5} - iamf - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - Level3 - true - WIN32;_CRT_SECURE_NO_WARNINGS;CONFIG_OPUS_CODEC;CONFIG_AAC_CODEC;CONFIG_FLAC_CODEC;FLAC__NO_DLL - true - ..\..\..\include\;..\..\..\src\common\;..\..\..\dep_codecs\include\;..\..\..\src\iamf_enc\dmpd\asc\include\;..\..\..\src\iamf_enc\dmpd\heq\include\;..\..\..\src\iamf_dec\;..\..\..\src\iamf_enc\;..\..\..\dep_external\include\ - - - Console - true - - - - - Level3 - true - true - true - WIN32;_CRT_SECURE_NO_WARNINGS;CONFIG_OPUS_CODEC;CONFIG_AAC_CODEC;CONFIG_FLAC_CODEC;FLAC__NO_DLL - true - ..\..\..\include\;..\..\..\src\common\;..\..\..\dep_codecs\include\;..\..\..\src\iamf_enc\dmpd\asc\include\;..\..\..\src\iamf_enc\dmpd\heq\include\;..\..\..\src\iamf_dec\;..\..\..\src\iamf_enc\;..\..\..\dep_external\include\ - - - Console - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/code/win64/VS2022/iamf/iamf.vcxproj.filters b/code/win64/VS2022/iamf/iamf.vcxproj.filters deleted file mode 100755 index 114158d0..00000000 --- a/code/win64/VS2022/iamf/iamf.vcxproj.filters +++ /dev/null @@ -1,216 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/code/win64/VS2022/iamfdec/iamfdec.vcxproj b/code/win64/VS2022/iamfdec/iamfdec.vcxproj deleted file mode 100755 index ca533bc6..00000000 --- a/code/win64/VS2022/iamfdec/iamfdec.vcxproj +++ /dev/null @@ -1,161 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {87b309f3-fd93-462a-a18b-250eb410506e} - iamfdec - 10.0 - iamfdec - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - Level3 - true - WIN32;_CRT_SECURE_NO_WARNINGS - true - ..\..\..\include\;..\..\..\test\tools\iamfdec\include\;..\..\..\dep_external\include\wav\ - - - Console - true - ..\..\..\dep_codecs\lib\;..\..\..\dep_external\lib\ - opus.lib;fdk-aac.lib;FLAC.lib;%(AdditionalDependencies) - - - - - Level3 - true - true - true - WIN32;_CRT_SECURE_NO_WARNINGS - true - ..\..\..\include\;..\..\..\test\tools\iamfdec\include\;..\..\..\dep_external\include\wav\ - - - Console - true - true - true - ..\..\..\dep_codecs\lib\;..\..\..\dep_external\lib\ - opus.lib;fdk-aac.lib;FLAC.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - {8e84eefb-bad7-4d3d-b6d4-a2340ca616a5} - - - - - - \ No newline at end of file diff --git a/code/win64/VS2022/iamfdec/iamfdec.vcxproj.filters b/code/win64/VS2022/iamfdec/iamfdec.vcxproj.filters deleted file mode 100755 index 8548f473..00000000 --- a/code/win64/VS2022/iamfdec/iamfdec.vcxproj.filters +++ /dev/null @@ -1,60 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file