summaryrefslogtreecommitdiffstats
path: root/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/DefaultRenderersFactory.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/DefaultRenderersFactory.java')
-rw-r--r--mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/DefaultRenderersFactory.java580
1 files changed, 580 insertions, 0 deletions
diff --git a/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/DefaultRenderersFactory.java b/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/DefaultRenderersFactory.java
new file mode 100644
index 0000000000..95fe509ee9
--- /dev/null
+++ b/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/DefaultRenderersFactory.java
@@ -0,0 +1,580 @@
+/*
+ * Copyright (C) 2017 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 org.mozilla.thirdparty.com.google.android.exoplayer2;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.os.Handler;
+import android.os.Looper;
+import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.audio.AudioCapabilities;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.audio.AudioProcessor;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.audio.AudioRendererEventListener;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.audio.DefaultAudioSink;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.audio.MediaCodecAudioRenderer;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.drm.DrmSessionManager;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.metadata.MetadataOutput;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.metadata.MetadataRenderer;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.text.TextOutput;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.text.TextRenderer;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.trackselection.TrackSelector;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.util.Log;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.video.VideoRendererEventListener;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.video.spherical.CameraMotionRenderer;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+
+/**
+ * Default {@link RenderersFactory} implementation.
+ */
+public class DefaultRenderersFactory implements RenderersFactory {
+
+ /**
+ * The default maximum duration for which a video renderer can attempt to seamlessly join an
+ * ongoing playback.
+ */
+ public static final long DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS = 5000;
+
+ /**
+ * Modes for using extension renderers. One of {@link #EXTENSION_RENDERER_MODE_OFF}, {@link
+ * #EXTENSION_RENDERER_MODE_ON} or {@link #EXTENSION_RENDERER_MODE_PREFER}.
+ */
+ @Documented
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({EXTENSION_RENDERER_MODE_OFF, EXTENSION_RENDERER_MODE_ON, EXTENSION_RENDERER_MODE_PREFER})
+ public @interface ExtensionRendererMode {}
+ /**
+ * Do not allow use of extension renderers.
+ */
+ public static final int EXTENSION_RENDERER_MODE_OFF = 0;
+ /**
+ * Allow use of extension renderers. Extension renderers are indexed after core renderers of the
+ * same type. A {@link TrackSelector} that prefers the first suitable renderer will therefore
+ * prefer to use a core renderer to an extension renderer in the case that both are able to play
+ * a given track.
+ */
+ public static final int EXTENSION_RENDERER_MODE_ON = 1;
+ /**
+ * Allow use of extension renderers. Extension renderers are indexed before core renderers of the
+ * same type. A {@link TrackSelector} that prefers the first suitable renderer will therefore
+ * prefer to use an extension renderer to a core renderer in the case that both are able to play
+ * a given track.
+ */
+ public static final int EXTENSION_RENDERER_MODE_PREFER = 2;
+
+ private static final String TAG = "DefaultRenderersFactory";
+
+ protected static final int MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY = 50;
+
+ private final Context context;
+ @Nullable private DrmSessionManager<FrameworkMediaCrypto> drmSessionManager;
+ @ExtensionRendererMode private int extensionRendererMode;
+ private long allowedVideoJoiningTimeMs;
+ private boolean playClearSamplesWithoutKeys;
+ private boolean enableDecoderFallback;
+ private MediaCodecSelector mediaCodecSelector;
+
+ /** @param context A {@link Context}. */
+ public DefaultRenderersFactory(Context context) {
+ this.context = context;
+ extensionRendererMode = EXTENSION_RENDERER_MODE_OFF;
+ allowedVideoJoiningTimeMs = DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS;
+ mediaCodecSelector = MediaCodecSelector.DEFAULT;
+ }
+
+ /**
+ * @deprecated Use {@link #DefaultRenderersFactory(Context)} and pass {@link DrmSessionManager}
+ * directly to {@link SimpleExoPlayer.Builder}.
+ */
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ public DefaultRenderersFactory(
+ Context context, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
+ this(context, drmSessionManager, EXTENSION_RENDERER_MODE_OFF);
+ }
+
+ /**
+ * @deprecated Use {@link #DefaultRenderersFactory(Context)} and {@link
+ * #setExtensionRendererMode(int)}.
+ */
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ public DefaultRenderersFactory(
+ Context context, @ExtensionRendererMode int extensionRendererMode) {
+ this(context, extensionRendererMode, DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS);
+ }
+
+ /**
+ * @deprecated Use {@link #DefaultRenderersFactory(Context)} and {@link
+ * #setExtensionRendererMode(int)}, and pass {@link DrmSessionManager} directly to {@link
+ * SimpleExoPlayer.Builder}.
+ */
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ public DefaultRenderersFactory(
+ Context context,
+ @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
+ @ExtensionRendererMode int extensionRendererMode) {
+ this(context, drmSessionManager, extensionRendererMode, DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS);
+ }
+
+ /**
+ * @deprecated Use {@link #DefaultRenderersFactory(Context)}, {@link
+ * #setExtensionRendererMode(int)} and {@link #setAllowedVideoJoiningTimeMs(long)}.
+ */
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ public DefaultRenderersFactory(
+ Context context,
+ @ExtensionRendererMode int extensionRendererMode,
+ long allowedVideoJoiningTimeMs) {
+ this(context, null, extensionRendererMode, allowedVideoJoiningTimeMs);
+ }
+
+ /**
+ * @deprecated Use {@link #DefaultRenderersFactory(Context)}, {@link
+ * #setExtensionRendererMode(int)} and {@link #setAllowedVideoJoiningTimeMs(long)}, and pass
+ * {@link DrmSessionManager} directly to {@link SimpleExoPlayer.Builder}.
+ */
+ @Deprecated
+ public DefaultRenderersFactory(
+ Context context,
+ @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
+ @ExtensionRendererMode int extensionRendererMode,
+ long allowedVideoJoiningTimeMs) {
+ this.context = context;
+ this.extensionRendererMode = extensionRendererMode;
+ this.allowedVideoJoiningTimeMs = allowedVideoJoiningTimeMs;
+ this.drmSessionManager = drmSessionManager;
+ mediaCodecSelector = MediaCodecSelector.DEFAULT;
+ }
+
+ /**
+ * Sets the extension renderer mode, which determines if and how available extension renderers are
+ * used. Note that extensions must be included in the application build for them to be considered
+ * available.
+ *
+ * <p>The default value is {@link #EXTENSION_RENDERER_MODE_OFF}.
+ *
+ * @param extensionRendererMode The extension renderer mode.
+ * @return This factory, for convenience.
+ */
+ public DefaultRenderersFactory setExtensionRendererMode(
+ @ExtensionRendererMode int extensionRendererMode) {
+ this.extensionRendererMode = extensionRendererMode;
+ return this;
+ }
+
+ /**
+ * Sets whether renderers are permitted to play clear regions of encrypted media prior to having
+ * obtained the keys necessary to decrypt encrypted regions of the media. For encrypted media that
+ * starts with a short clear region, this allows playback to begin in parallel with key
+ * acquisition, which can reduce startup latency.
+ *
+ * <p>The default value is {@code false}.
+ *
+ * @param playClearSamplesWithoutKeys Whether renderers are permitted to play clear regions of
+ * encrypted media prior to having obtained the keys necessary to decrypt encrypted regions of
+ * the media.
+ * @return This factory, for convenience.
+ */
+ public DefaultRenderersFactory setPlayClearSamplesWithoutKeys(
+ boolean playClearSamplesWithoutKeys) {
+ this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
+ return this;
+ }
+
+ /**
+ * Sets whether to enable fallback to lower-priority decoders if decoder initialization fails.
+ * This may result in using a decoder that is less efficient or slower than the primary decoder.
+ *
+ * @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder
+ * initialization fails.
+ * @return This factory, for convenience.
+ */
+ public DefaultRenderersFactory setEnableDecoderFallback(boolean enableDecoderFallback) {
+ this.enableDecoderFallback = enableDecoderFallback;
+ return this;
+ }
+
+ /**
+ * Sets a {@link MediaCodecSelector} for use by {@link MediaCodec} based renderers.
+ *
+ * <p>The default value is {@link MediaCodecSelector#DEFAULT}.
+ *
+ * @param mediaCodecSelector The {@link MediaCodecSelector}.
+ * @return This factory, for convenience.
+ */
+ public DefaultRenderersFactory setMediaCodecSelector(MediaCodecSelector mediaCodecSelector) {
+ this.mediaCodecSelector = mediaCodecSelector;
+ return this;
+ }
+
+ /**
+ * Sets the maximum duration for which video renderers can attempt to seamlessly join an ongoing
+ * playback.
+ *
+ * <p>The default value is {@link #DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS}.
+ *
+ * @param allowedVideoJoiningTimeMs The maximum duration for which video renderers can attempt to
+ * seamlessly join an ongoing playback, in milliseconds.
+ * @return This factory, for convenience.
+ */
+ public DefaultRenderersFactory setAllowedVideoJoiningTimeMs(long allowedVideoJoiningTimeMs) {
+ this.allowedVideoJoiningTimeMs = allowedVideoJoiningTimeMs;
+ return this;
+ }
+
+ @Override
+ public Renderer[] createRenderers(
+ Handler eventHandler,
+ VideoRendererEventListener videoRendererEventListener,
+ AudioRendererEventListener audioRendererEventListener,
+ TextOutput textRendererOutput,
+ MetadataOutput metadataRendererOutput,
+ @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
+ if (drmSessionManager == null) {
+ drmSessionManager = this.drmSessionManager;
+ }
+ ArrayList<Renderer> renderersList = new ArrayList<>();
+ buildVideoRenderers(
+ context,
+ extensionRendererMode,
+ mediaCodecSelector,
+ drmSessionManager,
+ playClearSamplesWithoutKeys,
+ enableDecoderFallback,
+ eventHandler,
+ videoRendererEventListener,
+ allowedVideoJoiningTimeMs,
+ renderersList);
+ buildAudioRenderers(
+ context,
+ extensionRendererMode,
+ mediaCodecSelector,
+ drmSessionManager,
+ playClearSamplesWithoutKeys,
+ enableDecoderFallback,
+ buildAudioProcessors(),
+ eventHandler,
+ audioRendererEventListener,
+ renderersList);
+ buildTextRenderers(context, textRendererOutput, eventHandler.getLooper(),
+ extensionRendererMode, renderersList);
+ buildMetadataRenderers(context, metadataRendererOutput, eventHandler.getLooper(),
+ extensionRendererMode, renderersList);
+ buildCameraMotionRenderers(context, extensionRendererMode, renderersList);
+ buildMiscellaneousRenderers(context, eventHandler, extensionRendererMode, renderersList);
+ return renderersList.toArray(new Renderer[0]);
+ }
+
+ /**
+ * Builds video renderers for use by the player.
+ *
+ * @param context The {@link Context} associated with the player.
+ * @param extensionRendererMode The extension renderer mode.
+ * @param mediaCodecSelector A decoder selector.
+ * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the player will
+ * not be used for DRM protected playbacks.
+ * @param playClearSamplesWithoutKeys Whether renderers are permitted to play clear regions of
+ * encrypted media prior to having obtained the keys necessary to decrypt encrypted regions of
+ * the media.
+ * @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder
+ * initialization fails. This may result in using a decoder that is slower/less efficient than
+ * the primary decoder.
+ * @param eventHandler A handler associated with the main thread's looper.
+ * @param eventListener An event listener.
+ * @param allowedVideoJoiningTimeMs The maximum duration for which video renderers can attempt to
+ * seamlessly join an ongoing playback, in milliseconds.
+ * @param out An array to which the built renderers should be appended.
+ */
+ protected void buildVideoRenderers(
+ Context context,
+ @ExtensionRendererMode int extensionRendererMode,
+ MediaCodecSelector mediaCodecSelector,
+ @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
+ boolean playClearSamplesWithoutKeys,
+ boolean enableDecoderFallback,
+ Handler eventHandler,
+ VideoRendererEventListener eventListener,
+ long allowedVideoJoiningTimeMs,
+ ArrayList<Renderer> out) {
+ out.add(
+ new MediaCodecVideoRenderer(
+ context,
+ mediaCodecSelector,
+ allowedVideoJoiningTimeMs,
+ drmSessionManager,
+ playClearSamplesWithoutKeys,
+ enableDecoderFallback,
+ eventHandler,
+ eventListener,
+ MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY));
+
+ if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) {
+ return;
+ }
+ int extensionRendererIndex = out.size();
+ if (extensionRendererMode == EXTENSION_RENDERER_MODE_PREFER) {
+ extensionRendererIndex--;
+ }
+
+ try {
+ // Full class names used for constructor args so the LINT rule triggers if any of them move.
+ // LINT.IfChange
+ Class<?> clazz = Class.forName("org.mozilla.thirdparty.com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer");
+ Constructor<?> constructor =
+ clazz.getConstructor(
+ long.class,
+ android.os.Handler.class,
+ org.mozilla.thirdparty.com.google.android.exoplayer2.video.VideoRendererEventListener.class,
+ int.class);
+ // LINT.ThenChange(../../../../../../../proguard-rules.txt)
+ Renderer renderer =
+ (Renderer)
+ constructor.newInstance(
+ allowedVideoJoiningTimeMs,
+ eventHandler,
+ eventListener,
+ MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
+ out.add(extensionRendererIndex++, renderer);
+ Log.i(TAG, "Loaded LibvpxVideoRenderer.");
+ } catch (ClassNotFoundException e) {
+ // Expected if the app was built without the extension.
+ } catch (Exception e) {
+ // The extension is present, but instantiation failed.
+ throw new RuntimeException("Error instantiating VP9 extension", e);
+ }
+
+ try {
+ // Full class names used for constructor args so the LINT rule triggers if any of them move.
+ // LINT.IfChange
+ Class<?> clazz = Class.forName("org.mozilla.thirdparty.com.google.android.exoplayer2.ext.av1.Libgav1VideoRenderer");
+ Constructor<?> constructor =
+ clazz.getConstructor(
+ long.class,
+ android.os.Handler.class,
+ org.mozilla.thirdparty.com.google.android.exoplayer2.video.VideoRendererEventListener.class,
+ int.class);
+ // LINT.ThenChange(../../../../../../../proguard-rules.txt)
+ Renderer renderer =
+ (Renderer)
+ constructor.newInstance(
+ allowedVideoJoiningTimeMs,
+ eventHandler,
+ eventListener,
+ MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
+ out.add(extensionRendererIndex++, renderer);
+ Log.i(TAG, "Loaded Libgav1VideoRenderer.");
+ } catch (ClassNotFoundException e) {
+ // Expected if the app was built without the extension.
+ } catch (Exception e) {
+ // The extension is present, but instantiation failed.
+ throw new RuntimeException("Error instantiating AV1 extension", e);
+ }
+ }
+
+ /**
+ * Builds audio renderers for use by the player.
+ *
+ * @param context The {@link Context} associated with the player.
+ * @param extensionRendererMode The extension renderer mode.
+ * @param mediaCodecSelector A decoder selector.
+ * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the player will
+ * not be used for DRM protected playbacks.
+ * @param playClearSamplesWithoutKeys Whether renderers are permitted to play clear regions of
+ * encrypted media prior to having obtained the keys necessary to decrypt encrypted regions of
+ * the media.
+ * @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder
+ * initialization fails. This may result in using a decoder that is slower/less efficient than
+ * the primary decoder.
+ * @param audioProcessors An array of {@link AudioProcessor}s that will process PCM audio buffers
+ * before output. May be empty.
+ * @param eventHandler A handler to use when invoking event listeners and outputs.
+ * @param eventListener An event listener.
+ * @param out An array to which the built renderers should be appended.
+ */
+ protected void buildAudioRenderers(
+ Context context,
+ @ExtensionRendererMode int extensionRendererMode,
+ MediaCodecSelector mediaCodecSelector,
+ @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
+ boolean playClearSamplesWithoutKeys,
+ boolean enableDecoderFallback,
+ AudioProcessor[] audioProcessors,
+ Handler eventHandler,
+ AudioRendererEventListener eventListener,
+ ArrayList<Renderer> out) {
+ out.add(
+ new MediaCodecAudioRenderer(
+ context,
+ mediaCodecSelector,
+ drmSessionManager,
+ playClearSamplesWithoutKeys,
+ enableDecoderFallback,
+ eventHandler,
+ eventListener,
+ new DefaultAudioSink(AudioCapabilities.getCapabilities(context), audioProcessors)));
+
+ if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) {
+ return;
+ }
+ int extensionRendererIndex = out.size();
+ if (extensionRendererMode == EXTENSION_RENDERER_MODE_PREFER) {
+ extensionRendererIndex--;
+ }
+
+ try {
+ // Full class names used for constructor args so the LINT rule triggers if any of them move.
+ // LINT.IfChange
+ Class<?> clazz = Class.forName("org.mozilla.thirdparty.com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer");
+ Constructor<?> constructor =
+ clazz.getConstructor(
+ android.os.Handler.class,
+ org.mozilla.thirdparty.com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
+ org.mozilla.thirdparty.com.google.android.exoplayer2.audio.AudioProcessor[].class);
+ // LINT.ThenChange(../../../../../../../proguard-rules.txt)
+ Renderer renderer =
+ (Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors);
+ out.add(extensionRendererIndex++, renderer);
+ Log.i(TAG, "Loaded LibopusAudioRenderer.");
+ } catch (ClassNotFoundException e) {
+ // Expected if the app was built without the extension.
+ } catch (Exception e) {
+ // The extension is present, but instantiation failed.
+ throw new RuntimeException("Error instantiating Opus extension", e);
+ }
+
+ try {
+ // Full class names used for constructor args so the LINT rule triggers if any of them move.
+ // LINT.IfChange
+ Class<?> clazz = Class.forName("org.mozilla.thirdparty.com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer");
+ Constructor<?> constructor =
+ clazz.getConstructor(
+ android.os.Handler.class,
+ org.mozilla.thirdparty.com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
+ org.mozilla.thirdparty.com.google.android.exoplayer2.audio.AudioProcessor[].class);
+ // LINT.ThenChange(../../../../../../../proguard-rules.txt)
+ Renderer renderer =
+ (Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors);
+ out.add(extensionRendererIndex++, renderer);
+ Log.i(TAG, "Loaded LibflacAudioRenderer.");
+ } catch (ClassNotFoundException e) {
+ // Expected if the app was built without the extension.
+ } catch (Exception e) {
+ // The extension is present, but instantiation failed.
+ throw new RuntimeException("Error instantiating FLAC extension", e);
+ }
+
+ try {
+ // Full class names used for constructor args so the LINT rule triggers if any of them move.
+ // LINT.IfChange
+ Class<?> clazz =
+ Class.forName("org.mozilla.thirdparty.com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer");
+ Constructor<?> constructor =
+ clazz.getConstructor(
+ android.os.Handler.class,
+ org.mozilla.thirdparty.com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
+ org.mozilla.thirdparty.com.google.android.exoplayer2.audio.AudioProcessor[].class);
+ // LINT.ThenChange(../../../../../../../proguard-rules.txt)
+ Renderer renderer =
+ (Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors);
+ out.add(extensionRendererIndex++, renderer);
+ Log.i(TAG, "Loaded FfmpegAudioRenderer.");
+ } catch (ClassNotFoundException e) {
+ // Expected if the app was built without the extension.
+ } catch (Exception e) {
+ // The extension is present, but instantiation failed.
+ throw new RuntimeException("Error instantiating FFmpeg extension", e);
+ }
+ }
+
+ /**
+ * Builds text renderers for use by the player.
+ *
+ * @param context The {@link Context} associated with the player.
+ * @param output An output for the renderers.
+ * @param outputLooper The looper associated with the thread on which the output should be called.
+ * @param extensionRendererMode The extension renderer mode.
+ * @param out An array to which the built renderers should be appended.
+ */
+ protected void buildTextRenderers(
+ Context context,
+ TextOutput output,
+ Looper outputLooper,
+ @ExtensionRendererMode int extensionRendererMode,
+ ArrayList<Renderer> out) {
+ out.add(new TextRenderer(output, outputLooper));
+ }
+
+ /**
+ * Builds metadata renderers for use by the player.
+ *
+ * @param context The {@link Context} associated with the player.
+ * @param output An output for the renderers.
+ * @param outputLooper The looper associated with the thread on which the output should be called.
+ * @param extensionRendererMode The extension renderer mode.
+ * @param out An array to which the built renderers should be appended.
+ */
+ protected void buildMetadataRenderers(
+ Context context,
+ MetadataOutput output,
+ Looper outputLooper,
+ @ExtensionRendererMode int extensionRendererMode,
+ ArrayList<Renderer> out) {
+ out.add(new MetadataRenderer(output, outputLooper));
+ }
+
+ /**
+ * Builds camera motion renderers for use by the player.
+ *
+ * @param context The {@link Context} associated with the player.
+ * @param extensionRendererMode The extension renderer mode.
+ * @param out An array to which the built renderers should be appended.
+ */
+ protected void buildCameraMotionRenderers(
+ Context context, @ExtensionRendererMode int extensionRendererMode, ArrayList<Renderer> out) {
+ out.add(new CameraMotionRenderer());
+ }
+
+ /**
+ * Builds any miscellaneous renderers used by the player.
+ *
+ * @param context The {@link Context} associated with the player.
+ * @param eventHandler A handler to use when invoking event listeners and outputs.
+ * @param extensionRendererMode The extension renderer mode.
+ * @param out An array to which the built renderers should be appended.
+ */
+ protected void buildMiscellaneousRenderers(Context context, Handler eventHandler,
+ @ExtensionRendererMode int extensionRendererMode, ArrayList<Renderer> out) {
+ // Do nothing.
+ }
+
+ /**
+ * Builds an array of {@link AudioProcessor}s that will process PCM audio before output.
+ */
+ protected AudioProcessor[] buildAudioProcessors() {
+ return new AudioProcessor[0];
+ }
+
+}