From 63b45b75031ffab3bdcbaefdcf870361aefd408d Mon Sep 17 00:00:00 2001 From: ktrajkovski Date: Mon, 19 Aug 2024 09:27:10 -0700 Subject: [PATCH] Build IAMF libraries with `gradle` and `ndk-build`. In order to support building with `gradle` a new `build.gradle` file was added together with `Android.mk`, `Application.mk`, and `libiamf.mk` necessary for local builds with NDK. After this change, IAMF files may also be played in the ExoPlayer demo built locally (without blaze). PiperOrigin-RevId: 664841684 --- core_settings.gradle | 2 + demos/main/build.gradle | 1 + libraries/decoder_iamf/README.md | 120 ++++++++++++++++++ libraries/decoder_iamf/build.gradle | 39 ++++++ libraries/decoder_iamf/src/README.md | 5 - .../media3/decoder/iamf/IamfDecoder.java | 4 +- .../decoder_iamf/src/main/jni/Android.mk | 32 +++++ .../decoder_iamf/src/main/jni/Application.mk | 18 +++ .../decoder_iamf/src/main/jni/libiamf.mk | 35 +++++ 9 files changed, 249 insertions(+), 7 deletions(-) create mode 100644 libraries/decoder_iamf/README.md create mode 100644 libraries/decoder_iamf/build.gradle delete mode 100644 libraries/decoder_iamf/src/README.md create mode 100644 libraries/decoder_iamf/src/main/jni/Android.mk create mode 100644 libraries/decoder_iamf/src/main/jni/Application.mk create mode 100644 libraries/decoder_iamf/src/main/jni/libiamf.mk diff --git a/core_settings.gradle b/core_settings.gradle index e0629d2496..eb976e28cb 100644 --- a/core_settings.gradle +++ b/core_settings.gradle @@ -75,6 +75,8 @@ include modulePrefix + 'lib-decoder-ffmpeg' project(modulePrefix + 'lib-decoder-ffmpeg').projectDir = new File(rootDir, 'libraries/decoder_ffmpeg') include modulePrefix + 'lib-decoder-flac' project(modulePrefix + 'lib-decoder-flac').projectDir = new File(rootDir, 'libraries/decoder_flac') +include modulePrefix + 'lib-decoder-iamf' +project(modulePrefix + 'lib-decoder-iamf').projectDir = new File(rootDir, 'libraries/decoder_iamf') if (gradle.ext.has('androidxMediaEnableMidiModule') && gradle.ext.androidxMediaEnableMidiModule) { include modulePrefix + 'lib-decoder-midi' project(modulePrefix + 'lib-decoder-midi').projectDir = new File(rootDir, 'libraries/decoder_midi') diff --git a/demos/main/build.gradle b/demos/main/build.gradle index a5c3852faa..de97527346 100644 --- a/demos/main/build.gradle +++ b/demos/main/build.gradle @@ -87,6 +87,7 @@ dependencies { withDecoderExtensionsImplementation project(modulePrefix + 'lib-decoder-ffmpeg') withDecoderExtensionsImplementation project(modulePrefix + 'lib-decoder-flac') withDecoderExtensionsImplementation project(modulePrefix + 'lib-decoder-opus') + withDecoderExtensionsImplementation project(modulePrefix + 'lib-decoder-iamf') withDecoderExtensionsImplementation project(modulePrefix + 'lib-decoder-vp9') withDecoderExtensionsImplementation project(modulePrefix + 'lib-decoder-midi') withDecoderExtensionsImplementation project(modulePrefix + 'lib-datasource-rtmp') diff --git a/libraries/decoder_iamf/README.md b/libraries/decoder_iamf/README.md new file mode 100644 index 0000000000..35fe715aa3 --- /dev/null +++ b/libraries/decoder_iamf/README.md @@ -0,0 +1,120 @@ +# IAMF decoder module + +The IAMF module provides `LibiamfAudioRenderer`, which uses libiamf (the IAMF +decoding library) to decode IAMF audio. + +## License note + +Please note that whilst the code in this repository is licensed under +[Apache 2.0][], using this module also requires building and including one or +more external libraries as described below. These are licensed separately. + +[Apache 2.0]: ../../LICENSE + +## Build instructions (Linux, macOS) + +To use the module you need to clone this GitHub project and depend on its +modules locally. Instructions for doing this can be found in the +[top level README][]. + +In addition, it's necessary to build the module's native components as follows: + +* Set the following environment variables: + +``` +cd "" + +IAMF_MODULE_PATH="$(pwd)/libraries/decoder_iamf/src/main" +``` + +* Download the [Android NDK][] and set its location in an environment + variable. This build configuration has been tested on NDK r27. + +``` +NDK_PATH="" +``` + +* Fetch libiamf: + +Clone the repository containing libiamf to a local folder of choice - preferably +outside of the project checkout. Link it to the project's jni folder through +symlink. + +``` +cd + + +git clone https://github.com/AOMediaCodec/libiamf.git libiamf && \ +cd libiamf && \ +LIBIAMF_PATH=$(pwd) +``` + +* Symlink the folder containing libiamf to the project's JNI folder and run + the script to convert libiamf code to NDK compatible format: + +``` +cd "${IAMF_MODULE_PATH}"/jni && \ +ln -s $LIBIAMF_PATH libiamf && \ +cd libiamf/code &&\ +cmake . && \ +make +``` + +* Build the JNI native libraries from the command line: + +``` +cd "${IAMF_MODULE_PATH}"/jni && \ +${NDK_PATH}/ndk-build APP_ABI=all -j4 +``` + +[top level README]: ../../README.md +[Android NDK]: https://developer.android.com/tools/sdk/ndk/index.html + +## Build instructions (Windows) + +We do not provide support for building this module on Windows, however it should +be possible to follow the Linux instructions in [Windows PowerShell][]. + +[Windows PowerShell]: https://docs.microsoft.com/en-us/powershell/scripting/getting-started/getting-started-with-windows-powershell + +## Notes + +* Every time there is a change to the libiamf checkout clean and re-build the + project. +* If you want to use your own version of libiamf, place it in + `${IAMF_MODULE_PATH}/jni/libiamf`. + +## Using the module with ExoPlayer + +Once you've followed the instructions above to check out, build and depend on +the module, the next step is to tell ExoPlayer to use `LibiamfAudioRenderer`. +How you do this depends on which player API you're using: + +* If you're passing a `DefaultRenderersFactory` to `ExoPlayer.Builder`, you + can enable using the module by setting the `extensionRendererMode` parameter + of the `DefaultRenderersFactory` constructor to + `EXTENSION_RENDERER_MODE_ON`. This will use `LibiamfAudioRenderer` for + playback if `MediaCodecAudioRenderer` doesn't support the input format. Pass + `EXTENSION_RENDERER_MODE_PREFER` to give `LibiamfAudioRenderer` priority + over `MediaCodecAudioRenderer`. +* If you've subclassed `DefaultRenderersFactory`, add a `LibiamfAudioRenderer` + to the output list in `buildAudioRenderers`. ExoPlayer will use the first + `Renderer` in the list that supports the input media format. +* If you've implemented your own `RenderersFactory`, return a + `LibiamfAudioRenderer` instance from `createRenderers`. ExoPlayer will use + the first `Renderer` in the returned array that supports the input media + format. +* If you're using `ExoPlayer.Builder`, pass a `LibiamfAudioRenderer` in the + array of `Renderer`s. ExoPlayer will use the first `Renderer` in the list + that supports the input media format. + +Note: These instructions assume you're using `DefaultTrackSelector`. If you have +a custom track selector the choice of `Renderer` is up to your implementation, +so you need to make sure you are passing a `LibiamfAudioRenderer` to the +player, then implement your own logic to use the renderer for a given track. + +## Links + +* [Troubleshooting using decoding extensions][] + +[Troubleshooting using decoding extensions]: https://developer.android.com/media/media3/exoplayer/troubleshooting#how-can-i-get-a-decoding-library-to-load-and-be-used-for-playback diff --git a/libraries/decoder_iamf/build.gradle b/libraries/decoder_iamf/build.gradle new file mode 100644 index 0000000000..f067c1948e --- /dev/null +++ b/libraries/decoder_iamf/build.gradle @@ -0,0 +1,39 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// 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. +apply from: "$gradle.ext.androidxMediaSettingsDir/common_library_config.gradle" + +android { + namespace 'androidx.media3.decoder.iamf' + + sourceSets { + main { + jniLibs.srcDir 'src/main/libs' + jni.srcDirs = [] // Disable the automatic ndk-build call by Android Studio. + } + androidTest.assets.srcDir '../test_data/src/test/assets' + } +} + +dependencies { + implementation project(modulePrefix + 'lib-decoder') + // TODO(b/203752526): Remove this dependency. + implementation project(modulePrefix + 'lib-exoplayer') + implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion + compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion + testImplementation project(modulePrefix + 'test-utils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion + androidTestImplementation project(modulePrefix + 'test-utils') + androidTestImplementation 'androidx.test:runner:' + androidxTestRunnerVersion + androidTestImplementation 'androidx.test.ext:junit:' + androidxTestJUnitVersion +} diff --git a/libraries/decoder_iamf/src/README.md b/libraries/decoder_iamf/src/README.md deleted file mode 100644 index 1521829a01..0000000000 --- a/libraries/decoder_iamf/src/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# IAMF support in ExoPlayer - -This is a Work-In-Progress for an extension which shall provide support for IAMF -in Exoplayer. Please await further announcements via Release Notes for -information on the full integration into the library. diff --git a/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfDecoder.java b/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfDecoder.java index f98c30cb91..e4df135890 100644 --- a/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfDecoder.java +++ b/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfDecoder.java @@ -15,9 +15,10 @@ */ package androidx.media3.decoder.iamf; -import static android.support.annotation.VisibleForTesting.PACKAGE_PRIVATE; +import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE; import android.media.AudioFormat; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.media3.common.C; import androidx.media3.common.util.Util; @@ -26,7 +27,6 @@ import androidx.media3.decoder.SimpleDecoder; import androidx.media3.decoder.SimpleDecoderOutputBuffer; import java.nio.ByteBuffer; import java.util.List; -import javax.annotation.Nullable; /** IAMF decoder. */ @VisibleForTesting(otherwise = PACKAGE_PRIVATE) diff --git a/libraries/decoder_iamf/src/main/jni/Android.mk b/libraries/decoder_iamf/src/main/jni/Android.mk new file mode 100644 index 0000000000..b599550335 --- /dev/null +++ b/libraries/decoder_iamf/src/main/jni/Android.mk @@ -0,0 +1,32 @@ +# +# Copyright (C) 2024 The Android Open Source Project +# +# 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. +# +WORKING_DIR := $(call my-dir) +include $(CLEAR_VARS) + +# build libiamf.a +LOCAL_PATH := $(WORKING_DIR) +include libiamf.mk + +# build libiamfJNI.so +include $(CLEAR_VARS) +LOCAL_PATH := $(WORKING_DIR) +LOCAL_MODULE := libiamfJNI +LOCAL_ARM_MODE := arm +LOCAL_CPP_EXTENSION := .cc +LOCAL_SRC_FILES := iamf_jni.cc +LOCAL_LDLIBS := -llog -lz -lm +LOCAL_STATIC_LIBRARIES := libiamf +include $(BUILD_SHARED_LIBRARY) diff --git a/libraries/decoder_iamf/src/main/jni/Application.mk b/libraries/decoder_iamf/src/main/jni/Application.mk new file mode 100644 index 0000000000..0a5ee4b1e4 --- /dev/null +++ b/libraries/decoder_iamf/src/main/jni/Application.mk @@ -0,0 +1,18 @@ +# +# Copyright (C) 2024 The Android Open Source Project +# +# 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. +# + +APP_ABI := all +APP_PLATFORM := android-21 diff --git a/libraries/decoder_iamf/src/main/jni/libiamf.mk b/libraries/decoder_iamf/src/main/jni/libiamf.mk new file mode 100644 index 0000000000..b27c5f5cad --- /dev/null +++ b/libraries/decoder_iamf/src/main/jni/libiamf.mk @@ -0,0 +1,35 @@ +# +# Copyright (C) 2024 The Android Open Source Project +# +# 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. +# + +LOCAL_PATH := $(WORKING_DIR)/libiamf + +include $(CLEAR_VARS) + +LOCAL_MODULE := libiamf +LOCAL_ARM_MODE := arm +LOCAL_C_INCLUDES := $(LOCAL_PATH)/code/include \ + $(LOCAL_PATH)/code/src/iamf_dec \ + $(LOCAL_PATH)/code/src/common \ + $(LOCAL_PATH)/code/dep_codecs/include \ + $(LOCAL_PATH)/code/dep_external/include +LOCAL_SRC_FILES := $(shell find $(LOCAL_PATH)/code/src -name "*.c") +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/code/include \ + $(LOCAL_PATH)/code/src/iamf_dec \ + $(LOCAL_PATH)/code/src/common \ + $(LOCAL_PATH)/code/dep_codecs/include \ + $(LOCAL_PATH)/code/dep_external/include + +include $(BUILD_STATIC_LIBRARY)