From b1127ed73537d08e0ba5b2e25a03e17eec7d936e Mon Sep 17 00:00:00 2001 From: claincly Date: Thu, 11 Apr 2024 12:16:42 -0700 Subject: [PATCH] Add support for codec importance Set an importance value when configuring the codec in `Codec.Factory`, PiperOrigin-RevId: 623902251 --- .../transformer/DefaultDecoderFactory.java | 103 ++++++++++++++++-- .../transformer/DefaultEncoderFactory.java | 61 ++++++++--- 2 files changed, 140 insertions(+), 24 deletions(-) diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java index 180664bb2f..37910003f0 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultDecoderFactory.java @@ -27,6 +27,7 @@ import android.media.MediaFormat; import android.os.Build; import android.util.Pair; import android.view.Surface; +import androidx.annotation.IntRange; import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.ColorInfo; @@ -40,6 +41,7 @@ import androidx.media3.exoplayer.mediacodec.MediaCodecInfo; import androidx.media3.exoplayer.mediacodec.MediaCodecSelector; import androidx.media3.exoplayer.mediacodec.MediaCodecUtil; import com.google.common.collect.ImmutableList; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.ArrayList; import java.util.List; @@ -51,9 +53,8 @@ public final class DefaultDecoderFactory implements Codec.DecoderFactory { private static final String TAG = "DefaultDecoderFactory"; - private final Context context; - private final boolean enableDecoderFallback; - private final Listener listener; + /** The platform's default value of {@code MediaFormat#KEY_IMPORTANCE}. */ + private static final int DEFAULT_CODEC_IMPORTANCE = 0; /** Listener for decoder factory events. */ public interface Listener { @@ -70,12 +71,78 @@ public final class DefaultDecoderFactory implements Codec.DecoderFactory { void onCodecInitialized(String codecName, List codecInitializationExceptions); } - /** Creates a new factory that selects the most preferred decoder for the format. */ + /** A builder for {@link DefaultDecoderFactory} instances. */ + public static final class Builder { + private final Context context; + private Listener listener; + private boolean enableDecoderFallback; + private int codecImportance; + + /** Creates a new {@link Builder}. */ + public Builder(Context context) { + this.context = context.getApplicationContext(); + listener = (codecName, codecInitializationExceptions) -> {}; + codecImportance = DEFAULT_CODEC_IMPORTANCE; + } + + /** Sets the {@link Listener}. */ + @CanIgnoreReturnValue + public Builder setListener(Listener listener) { + this.listener = listener; + return this; + } + + /** + * Sets whether the decoder can fallback. + * + *

This decides 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. + * + *

The default value is {@code false}. + */ + @CanIgnoreReturnValue + public Builder setEnableDecoderFallback(boolean enableDecoderFallback) { + this.enableDecoderFallback = enableDecoderFallback; + return this; + } + + /** + * Sets the codec importance value. + * + *

Specifying codec importance allows the resource manager in the platform to reclaim less + * important codecs (higher importance values) before more important codecs. For example, codecs + * used for background operations should have higher importance values so they are reclaimed if + * required for foreground operations. + * + *

This method is a no-op on API versions before 35. + * + *

The default value is {@code 0}. + */ + // TODO: b/333552477 - Link documentation after API35 is released. + @CanIgnoreReturnValue + public Builder setCodecImportance(@IntRange(from = 0) int codecImportance) { + this.codecImportance = codecImportance; + return this; + } + + /** Creates an instance of {@link DefaultDecoderFactory}, using defaults if values are unset. */ + public DefaultDecoderFactory build() { + return new DefaultDecoderFactory(this); + } + } + + private final Context context; + private final boolean enableDecoderFallback; + private final Listener listener; + private final int codecImportance; + + /** + * @deprecated Use {@link Builder} instead. + */ + @Deprecated public DefaultDecoderFactory(Context context) { - this( - context, - /* enableDecoderFallback= */ false, - (codecName, codecInitializationExceptions) -> {}); + this(new Builder(context)); } /** @@ -87,11 +154,19 @@ public final class DefaultDecoderFactory implements Codec.DecoderFactory { * initialization fails. This may result in using a decoder that is less efficient or slower * than the primary decoder. * @param listener Listener for codec initialization errors. + * @deprecated Use {@link Builder} instead. */ + @Deprecated public DefaultDecoderFactory(Context context, boolean enableDecoderFallback, Listener listener) { - this.context = context.getApplicationContext(); - this.enableDecoderFallback = enableDecoderFallback; - this.listener = listener; + this( + new Builder(context).setEnableDecoderFallback(enableDecoderFallback).setListener(listener)); + } + + private DefaultDecoderFactory(Builder builder) { + this.context = builder.context; + this.enableDecoderFallback = builder.enableDecoderFallback; + this.listener = builder.listener; + this.codecImportance = builder.codecImportance; } @Override @@ -146,6 +221,12 @@ public final class DefaultDecoderFactory implements Codec.DecoderFactory { mediaFormat, MediaFormat.KEY_LEVEL, codecProfileAndLevel.second); } + if (SDK_INT >= 35) { + // TODO: b/333552477 - Redefinition of MediaFormat.KEY_IMPORTANCE, remove after API35 is + // released. + mediaFormat.setInteger("importance", codecImportance); + } + return createCodecForMediaFormat(mediaFormat, format, outputSurface); } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java index c5bd75d23a..b7497ffa03 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java @@ -32,6 +32,7 @@ import android.media.MediaFormat; import android.os.Build; import android.util.Pair; import android.util.Size; +import androidx.annotation.IntRange; import androidx.annotation.Nullable; import androidx.media3.common.ColorInfo; import androidx.media3.common.Format; @@ -54,18 +55,25 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { /** Best effort, or as-fast-as-possible priority setting for {@link MediaFormat#KEY_PRIORITY}. */ private static final int PRIORITY_BEST_EFFORT = 1; + /** The platform's default value of {@code MediaFormat#KEY_IMPORTANCE}. */ + private static final int DEFAULT_CODEC_IMPORTANCE = 0; + /** A builder for {@link DefaultEncoderFactory} instances. */ public static final class Builder { private final Context context; - @Nullable private EncoderSelector videoEncoderSelector; - @Nullable private VideoEncoderSettings requestedVideoEncoderSettings; + private EncoderSelector videoEncoderSelector; + private VideoEncoderSettings requestedVideoEncoderSettings; private boolean enableFallback; + private int codecImportance; /** Creates a new {@link Builder}. */ public Builder(Context context) { - this.context = context; - this.enableFallback = true; + this.context = context.getApplicationContext(); + videoEncoderSelector = EncoderSelector.DEFAULT; + requestedVideoEncoderSettings = VideoEncoderSettings.DEFAULT; + enableFallback = true; + codecImportance = DEFAULT_CODEC_IMPORTANCE; } /** @@ -120,17 +128,28 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { return this; } + /** + * Sets the codec importance value. + * + *

Specifying codec importance allows the resource manager in the platform to reclaim less + * important codecs (higher importance values) before more important codecs. For example, codecs + * used for background operations should have higher importance values so they are reclaimed if + * required for foreground operations. + * + *

This method is a no-op on API versions before 35. + * + *

The default value is {@code 0}. + */ + // TODO: b/333552477 - Link documentation after API35 is released. + @CanIgnoreReturnValue + public Builder setCodecImportance(@IntRange(from = 0) int codecImportance) { + this.codecImportance = codecImportance; + return this; + } + /** Creates an instance of {@link DefaultEncoderFactory}, using defaults if values are unset. */ - @SuppressWarnings("deprecation") public DefaultEncoderFactory build() { - if (videoEncoderSelector == null) { - videoEncoderSelector = EncoderSelector.DEFAULT; - } - if (requestedVideoEncoderSettings == null) { - requestedVideoEncoderSettings = VideoEncoderSettings.DEFAULT; - } - return new DefaultEncoderFactory( - context, videoEncoderSelector, requestedVideoEncoderSettings, enableFallback); + return new DefaultEncoderFactory(this); } } @@ -138,6 +157,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { private final EncoderSelector videoEncoderSelector; private final VideoEncoderSettings requestedVideoEncoderSettings; private final boolean enableFallback; + private final int codecImportance; /** * @deprecated Use {@link Builder} instead. @@ -171,6 +191,15 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { this.videoEncoderSelector = videoEncoderSelector; this.requestedVideoEncoderSettings = requestedVideoEncoderSettings; this.enableFallback = enableFallback; + this.codecImportance = DEFAULT_CODEC_IMPORTANCE; + } + + private DefaultEncoderFactory(Builder builder) { + this.context = builder.context; + this.videoEncoderSelector = builder.videoEncoderSelector; + this.requestedVideoEncoderSettings = builder.requestedVideoEncoderSettings; + this.enableFallback = builder.enableFallback; + this.codecImportance = builder.codecImportance; } @Override @@ -326,6 +355,12 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { } } + if (Util.SDK_INT >= 35) { + // TODO: b/333552477 - Redefinition of MediaFormat.KEY_IMPORTANCE, remove after API35 is + // released. + mediaFormat.setInteger("importance", codecImportance); + } + return new DefaultCodec( context, encoderSupportedFormat,