-
Notifications
You must be signed in to change notification settings - Fork 409
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e677c8d
commit 59c1f2b
Showing
18 changed files
with
873 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# MPEG-H decoder module | ||
|
||
The MPEG-H module provides `MpeghAudioRenderer`, which uses [mpeghdec | ||
(the Fraunhofer MPEG-H decoding library)](https://github.com/Fraunhofer-IIS/mpeghdec) to decode MPEG-H audio. | ||
|
||
|
||
## License note | ||
|
||
Please note that whilst this code for extending ExoPlayer for MPEG-H 3D Audio | ||
Decoder functionality is licensed under Apache 2.0, using this extension requires | ||
checkout and compile the [Fraunhofer GitHub MPEG-H decoding library](https://github.com/Fraunhofer-IIS/mpeghdec) | ||
as described below. The [Fraunhofer GitHub MPEG-H decoder](https://github.com/Fraunhofer-IIS/mpeghdec) is not licensed | ||
under Apache 2.0, but under the license of the Fraunhofer GitHub MPEG-H | ||
decoder project. | ||
|
||
[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 fetch mpeghdec library with its | ||
dependencies as follows: | ||
|
||
* Set the following environment variables: | ||
|
||
``` | ||
cd "<path to project checkout>" | ||
MPEGH_MODULE_PATH="$(pwd)/libraries/decoder_mpegh/src/main" | ||
``` | ||
|
||
* Fetch mpeghdec library: | ||
|
||
``` | ||
cd "${MPEGH_MODULE_PATH}/jni" && \ | ||
git clone https://github.com/Fraunhofer-IIS/mpeghdec.git --branch r2.0.0 | ||
``` | ||
|
||
* [Install CMake][]. | ||
|
||
Having followed these steps, gradle will build the module automatically when run | ||
on the command line or via Android Studio, using [CMake][] and [Ninja][] to | ||
configure and build mpeghdec and the module's [JNI wrapper library][]. | ||
|
||
[top level README]: ../../README.md | ||
[Install CMake]: https://developer.android.com/studio/projects/install-ndk | ||
[CMake]: https://cmake.org/ | ||
[Ninja]: https://ninja-build.org | ||
[JNI wrapper library]: src/main/jni/mpeghdec_jni.cc | ||
|
||
## 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 | ||
|
||
## 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 `MpeghAudioRenderer`. | ||
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 `MpeghAudioRenderer` for | ||
playback if `MediaCodecAudioRenderer` doesn't support the input format. Pass | ||
`EXTENSION_RENDERER_MODE_PREFER` to give `MpeghAudioRenderer` priority | ||
over `MediaCodecAudioRenderer`. | ||
* If you've subclassed `DefaultRenderersFactory`, add a `MpeghAudioRenderer` | ||
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 | ||
`MpeghAudioRenderer` 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 `MpeghAudioRenderer` 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 an `MpeghAudioRenderer` 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
apply from: "$gradle.ext.androidxMediaSettingsDir/common_library_config.gradle" | ||
|
||
android.namespace 'androidx.media3.decoder.mpegh' | ||
|
||
// Configure the native build only if ffmpeg is present to avoid gradle sync | ||
// failures if ffmpeg hasn't been built according to the README instructions. | ||
if (project.file('src/main/jni/mpeghdec').exists()) { | ||
android.externalNativeBuild.cmake.path = 'src/main/jni/CMakeLists.txt' | ||
// Should match cmake_minimum_required. | ||
android.externalNativeBuild.cmake.version = '3.21.0+' | ||
} | ||
|
||
dependencies { | ||
implementation project(modulePrefix + 'lib-decoder') | ||
// TODO(b/203752526): Remove this dependency. | ||
implementation project(modulePrefix + 'lib-exoplayer') | ||
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion | ||
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion | ||
compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion | ||
testImplementation project(modulePrefix + 'test-utils') | ||
testImplementation 'org.robolectric:robolectric:' + robolectricVersion | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Proguard rules specific to the MPEG-H extension. | ||
|
||
# This prevents the names of native methods from being obfuscated. | ||
-keepclasseswithmembernames class * { | ||
native <methods>; | ||
} | ||
|
||
# Some members of this class are being accessed from native methods. Keep them unobfuscated. | ||
-keep class androidx.media3.decoder.SimpleDecoderOutputBuffer { | ||
*; | ||
} | ||
|
||
-keep class androidx.media3.decoder.mpegh** { *; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest package="androidx.media3.decoder.mpegh"/> |
102 changes: 102 additions & 0 deletions
102
libraries/decoder_mpegh/src/main/java/androidx/media3/decoder/mpegh/MpeghAudioRenderer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package androidx.media3.decoder.mpegh; | ||
|
||
import android.os.Handler; | ||
import androidx.annotation.NonNull; | ||
import androidx.media3.common.C; | ||
import androidx.media3.common.Format; | ||
import androidx.media3.common.MimeTypes; | ||
import androidx.media3.common.audio.AudioProcessor; | ||
import androidx.media3.common.util.UnstableApi; | ||
import androidx.media3.decoder.CryptoConfig; | ||
import androidx.media3.exoplayer.DecoderReuseEvaluation; | ||
import androidx.media3.exoplayer.audio.AudioRendererEventListener; | ||
import androidx.media3.exoplayer.audio.AudioSink; | ||
import androidx.media3.exoplayer.audio.DecoderAudioRenderer; | ||
|
||
/** | ||
* Decodes and renders audio using the native MPEG-H decoder. | ||
*/ | ||
@UnstableApi | ||
public final class MpeghAudioRenderer extends DecoderAudioRenderer<MpeghDecoder> { | ||
|
||
private static final String TAG = "MpeghAudioRenderer"; | ||
|
||
/** The number of input and output buffers. */ | ||
private static final int NUM_BUFFERS = 16; | ||
|
||
public MpeghAudioRenderer() { | ||
this(null, null); | ||
} | ||
|
||
/** | ||
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be | ||
* null if delivery of events is not required. | ||
* @param eventListener A listener of events. May be null if delivery of events is not required. | ||
* @param audioProcessors Optional {@link AudioProcessor}s that will process audio before output. | ||
*/ | ||
public MpeghAudioRenderer( | ||
Handler eventHandler, AudioRendererEventListener eventListener, | ||
AudioProcessor... audioProcessors) { | ||
super(eventHandler, eventListener, audioProcessors); | ||
} | ||
|
||
/** | ||
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be | ||
* null if delivery of events is not required. | ||
* @param eventListener A listener of events. May be null if delivery of events is not required. | ||
* @param audioSink The sink to which audio will be output. | ||
*/ | ||
public MpeghAudioRenderer( | ||
Handler eventHandler, AudioRendererEventListener eventListener, AudioSink audioSink) { | ||
super(eventHandler, eventListener, audioSink); | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return TAG; | ||
} | ||
|
||
@Override | ||
protected int supportsFormatInternal(Format format) { | ||
// check if JNI library is available | ||
if (!MpeghLibrary.isAvailable()) { | ||
return C.FORMAT_UNSUPPORTED_TYPE; | ||
} | ||
|
||
// check if MIME type is supported | ||
if (!(MimeTypes.AUDIO_MPEGH_MHM1.equalsIgnoreCase(format.sampleMimeType) | ||
|| MimeTypes.AUDIO_MPEGH_MHA1.equalsIgnoreCase(format.sampleMimeType))) { | ||
return C.FORMAT_UNSUPPORTED_TYPE; | ||
} | ||
return C.FORMAT_HANDLED; | ||
} | ||
|
||
@Override | ||
protected DecoderReuseEvaluation canReuseDecoder( | ||
@NonNull String decoderName, Format oldFormat, Format newFormat) { | ||
|
||
if (oldFormat.sampleMimeType.equals(newFormat.sampleMimeType) | ||
&& oldFormat.sampleMimeType.equals(MimeTypes.AUDIO_MPEGH_MHM1)) { | ||
return new DecoderReuseEvaluation( | ||
decoderName, oldFormat, newFormat, | ||
DecoderReuseEvaluation.REUSE_RESULT_YES_WITHOUT_RECONFIGURATION, 0); | ||
} | ||
return super.canReuseDecoder(decoderName, oldFormat, newFormat); | ||
} | ||
|
||
@Override | ||
protected MpeghDecoder createDecoder(@NonNull Format format, CryptoConfig cryptoConfig) | ||
throws MpeghException { | ||
|
||
// initialize the decoder | ||
return new MpeghDecoder(NUM_BUFFERS, NUM_BUFFERS, format); | ||
} | ||
|
||
@Override | ||
protected Format getOutputFormat(MpeghDecoder decoder) { | ||
Format.Builder formatBuilder = new Format.Builder(); | ||
formatBuilder.setChannelCount(decoder.getChannelCount()).setSampleRate(decoder.getSampleRate()); | ||
formatBuilder.setSampleMimeType(MimeTypes.AUDIO_RAW).setPcmEncoding(C.ENCODING_PCM_16BIT); | ||
return formatBuilder.build(); | ||
} | ||
} |
Oops, something went wrong.