From 104fcc1c76e3e2b8012ce74b2797253482932cca Mon Sep 17 00:00:00 2001 From: ktrajkovski Date: Tue, 16 Jul 2024 02:51:49 -0700 Subject: [PATCH] Add skeleton of the IAMF JNI wrapper for the native decoder in libiamf. PiperOrigin-RevId: 652761237 --- libraries/decoder_iamf/src/README.md | 5 ++ .../src/androidTest/AndroidManifest.xml | 33 ++++++++++ .../media3/decoder/iamf/IamfDecoderTest.java | 39 +++++++++++ .../media3/decoder/iamf/IamfDecoder.java | 65 +++++++++++++++++++ .../decoder/iamf/IamfDecoderException.java | 30 +++++++++ .../media3/decoder/iamf/IamfLibrary.java | 59 +++++++++++++++++ .../decoder/iamf/LibiamfAudioRenderer.java | 48 ++++++++++++++ .../media3/decoder/iamf/package-info.java | 19 ++++++ .../decoder_iamf/src/main/jni/iamf_jni.cc | 55 ++++++++++++++++ .../decoder_iamf/src/main/proguard-rules.txt | 6 ++ 10 files changed, 359 insertions(+) create mode 100644 libraries/decoder_iamf/src/README.md create mode 100644 libraries/decoder_iamf/src/androidTest/AndroidManifest.xml create mode 100644 libraries/decoder_iamf/src/androidTest/java/androidx/media3/decoder/iamf/IamfDecoderTest.java create mode 100644 libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfDecoder.java create mode 100644 libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfDecoderException.java create mode 100644 libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfLibrary.java create mode 100644 libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/LibiamfAudioRenderer.java create mode 100644 libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/package-info.java create mode 100644 libraries/decoder_iamf/src/main/jni/iamf_jni.cc create mode 100755 libraries/decoder_iamf/src/main/proguard-rules.txt diff --git a/libraries/decoder_iamf/src/README.md b/libraries/decoder_iamf/src/README.md new file mode 100644 index 0000000000..1521829a01 --- /dev/null +++ b/libraries/decoder_iamf/src/README.md @@ -0,0 +1,5 @@ +# 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/androidTest/AndroidManifest.xml b/libraries/decoder_iamf/src/androidTest/AndroidManifest.xml new file mode 100644 index 0000000000..6ce4dad5d8 --- /dev/null +++ b/libraries/decoder_iamf/src/androidTest/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + diff --git a/libraries/decoder_iamf/src/androidTest/java/androidx/media3/decoder/iamf/IamfDecoderTest.java b/libraries/decoder_iamf/src/androidTest/java/androidx/media3/decoder/iamf/IamfDecoderTest.java new file mode 100644 index 0000000000..6fe1ffcd19 --- /dev/null +++ b/libraries/decoder_iamf/src/androidTest/java/androidx/media3/decoder/iamf/IamfDecoderTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 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. + */ +package androidx.media3.decoder.iamf; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Test IAMF native functions. */ +@RunWith(AndroidJUnit4.class) +public final class IamfDecoderTest { + + @Before + public void setUp() { + assertThat(IamfLibrary.isAvailable()).isTrue(); + } + + @Test + public void iamfLayoutBinauralChannelsCountTest() { + IamfDecoder iamf = new IamfDecoder(); + assertThat(iamf.getBinauralLayoutChannelCount()).isEqualTo(2); + } +} 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 new file mode 100644 index 0000000000..cbea45637c --- /dev/null +++ b/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfDecoder.java @@ -0,0 +1,65 @@ +/* + * Copyright 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. + */ +package androidx.media3.decoder.iamf; + +import static android.support.annotation.VisibleForTesting.PACKAGE_PRIVATE; + +import androidx.annotation.VisibleForTesting; +import androidx.media3.decoder.DecoderInputBuffer; +import androidx.media3.decoder.SimpleDecoder; +import androidx.media3.decoder.SimpleDecoderOutputBuffer; + +/** IAMF decoder. */ +@VisibleForTesting(otherwise = PACKAGE_PRIVATE) +public final class IamfDecoder + extends SimpleDecoder { + + public IamfDecoder() { + super(new DecoderInputBuffer[0], new SimpleDecoderOutputBuffer[0]); + } + + public int getBinauralLayoutChannelCount() { + return iamfLayoutBinauralChannelsCount(); + } + + @Override + public String getName() { + return "libiamf"; + } + + @Override + protected DecoderInputBuffer createInputBuffer() { + throw new UnsupportedOperationException(); + } + + @Override + protected SimpleDecoderOutputBuffer createOutputBuffer() { + throw new UnsupportedOperationException(); + } + + @Override + protected IamfDecoderException createUnexpectedDecodeException(Throwable error) { + throw new UnsupportedOperationException(); + } + + @Override + protected IamfDecoderException decode( + DecoderInputBuffer inputBuffer, SimpleDecoderOutputBuffer outputBuffer, boolean reset) { + throw new UnsupportedOperationException(); + } + + private native int iamfLayoutBinauralChannelsCount(); +} diff --git a/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfDecoderException.java b/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfDecoderException.java new file mode 100644 index 0000000000..18c25601d1 --- /dev/null +++ b/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfDecoderException.java @@ -0,0 +1,30 @@ +/* + * Copyright 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. + */ +package androidx.media3.decoder.iamf; + +import androidx.media3.decoder.DecoderException; + +/** Thrown when an IAMF decoder error occurs. */ +final class IamfDecoderException extends DecoderException { + + /* package */ IamfDecoderException(String message) { + super(message); + } + + /* package */ IamfDecoderException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfLibrary.java b/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfLibrary.java new file mode 100644 index 0000000000..41a6c75959 --- /dev/null +++ b/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/IamfLibrary.java @@ -0,0 +1,59 @@ +/* + * Copyright 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. + */ +package androidx.media3.decoder.iamf; + +import androidx.media3.common.C; +import androidx.media3.common.MediaLibraryInfo; +import androidx.media3.common.util.LibraryLoader; +import androidx.media3.common.util.UnstableApi; + +/** Configures and queries the underlying native library. */ +@UnstableApi +public final class IamfLibrary { + + static { + MediaLibraryInfo.registerModule("media3.decoder.iamf"); + } + + private static final LibraryLoader LOADER = + new LibraryLoader("iamfJNI") { + @Override + protected void loadLibrary(String name) { + System.loadLibrary(name); + } + }; + + private IamfLibrary() {} + + /** + * Override the names of the IAMF native libraries. If an application wishes to call this method, + * it must do so before calling any other method defined by this class, and before instantiating a + * {@link LibiamfAudioRenderer} instance. + * + * @param cryptoType The {@link C.CryptoType} for which the decoder library supports decrypting + * protected content, or {@link C#CRYPTO_TYPE_UNSUPPORTED} if the library does not support + * decryption. + * @param libraries The names of the IAMF native libraries. + */ + public static void setLibraries(@C.CryptoType int cryptoType, String... libraries) { + LOADER.setLibraries(libraries); + } + + /** Returns whether the underlying library is available, loading it if necessary. */ + public static boolean isAvailable() { + return LOADER.isAvailable(); + } +} diff --git a/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/LibiamfAudioRenderer.java b/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/LibiamfAudioRenderer.java new file mode 100644 index 0000000000..18c0abf511 --- /dev/null +++ b/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/LibiamfAudioRenderer.java @@ -0,0 +1,48 @@ +/* + * Copyright 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. + */ +package androidx.media3.decoder.iamf; + +import androidx.annotation.Nullable; +import androidx.media3.common.Format; +import androidx.media3.decoder.CryptoConfig; +import androidx.media3.decoder.DecoderException; +import androidx.media3.exoplayer.audio.DecoderAudioRenderer; + +/** Decodes and renders audio using the native IAMF decoder. */ +public class LibiamfAudioRenderer extends DecoderAudioRenderer { + public LibiamfAudioRenderer() {} + + @Override + protected int supportsFormatInternal(Format format) { + throw new UnsupportedOperationException(); + } + + @Override + protected IamfDecoder createDecoder(Format format, @Nullable CryptoConfig cryptoConfig) + throws DecoderException { + throw new UnsupportedOperationException(); + } + + @Override + protected Format getOutputFormat(IamfDecoder decoder) { + throw new UnsupportedOperationException(); + } + + @Override + public String getName() { + throw new UnsupportedOperationException(); + } +} diff --git a/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/package-info.java b/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/package-info.java new file mode 100644 index 0000000000..036d745506 --- /dev/null +++ b/libraries/decoder_iamf/src/main/java/androidx/media3/decoder/iamf/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 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. + */ +@NonNullApi +package androidx.media3.decoder.iamf; + +import androidx.media3.common.util.NonNullApi; diff --git a/libraries/decoder_iamf/src/main/jni/iamf_jni.cc b/libraries/decoder_iamf/src/main/jni/iamf_jni.cc new file mode 100644 index 0000000000..fbd7f2fda5 --- /dev/null +++ b/libraries/decoder_iamf/src/main/jni/iamf_jni.cc @@ -0,0 +1,55 @@ +/* + * Copyright 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. + */ + +#ifdef __ANDROID__ +#include +#endif +#include + +#include +#include + +#include "IAMF_decoder.h" +#include "IAMF_defines.h" + +#ifdef __ANDROID__ +#define LOG_TAG "iamf_jni" +#define LOGE(...) \ + ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) +#else // __ANDROID__ +#define LOGE(...) \ + do { \ + } while (0) +#endif // __ANDROID__ + +#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \ + extern "C" { \ + JNIEXPORT RETURN_TYPE Java_androidx_media3_decoder_iamf_IamfDecoder_##NAME( \ + JNIEnv* env, jobject thiz, ##__VA_ARGS__); \ + } \ + JNIEXPORT RETURN_TYPE Java_androidx_media3_decoder_iamf_IamfDecoder_##NAME( \ + JNIEnv* env, jobject thiz, ##__VA_ARGS__) + +jint JNI_OnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + return -1; + } + return JNI_VERSION_1_6; +} +DECODER_FUNC(jint, iamfLayoutBinauralChannelsCount) { + return IAMF_layout_binaural_channels_count(); +} diff --git a/libraries/decoder_iamf/src/main/proguard-rules.txt b/libraries/decoder_iamf/src/main/proguard-rules.txt new file mode 100755 index 0000000000..7b4eaa0243 --- /dev/null +++ b/libraries/decoder_iamf/src/main/proguard-rules.txt @@ -0,0 +1,6 @@ +# Proguard rules specific to the IAMF extension. + +# This prevents the names of native methods from being obfuscated. +-keepclasseswithmembernames class * { + native ; +}