From a60e5f597bd632c59f65408cafaa3e53e56eef1e Mon Sep 17 00:00:00 2001 From: samrobinson Date: Mon, 21 Mar 2022 12:16:50 +0000 Subject: [PATCH] Force video encoding if VideoEncoderSettings are not default. Add a MH test exercising this behaviour. PiperOrigin-RevId: 436177198 --- .../transformer/mh/TransformationTest.java | 24 +++++++++++++ .../transformer/DefaultEncoderFactory.java | 7 +++- .../transformer/VideoEncoderSettings.java | 35 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TransformationTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TransformationTest.java index b403b0ec47..08411354b4 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TransformationTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TransformationTest.java @@ -25,10 +25,13 @@ import androidx.media3.common.Format; import androidx.media3.common.util.Log; import androidx.media3.common.util.Util; import androidx.media3.transformer.Codec; +import androidx.media3.transformer.DefaultEncoderFactory; +import androidx.media3.transformer.EncoderSelector; import androidx.media3.transformer.TransformationException; import androidx.media3.transformer.TransformationRequest; import androidx.media3.transformer.Transformer; import androidx.media3.transformer.TransformerAndroidTestRunner; +import androidx.media3.transformer.VideoEncoderSettings; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.List; @@ -97,6 +100,27 @@ public class TransformationTest { .run(testId, MP4_ASSET_WITH_INCREASING_TIMESTAMPS_URI_STRING); } + @Test + public void transformToSpecificBitrate() throws Exception { + final String testId = TAG + "_transformWithSpecificBitrate"; + Context context = ApplicationProvider.getApplicationContext(); + Transformer transformer = + new Transformer.Builder(context) + .setRemoveAudio(true) + .setEncoderFactory( + new DefaultEncoderFactory( + EncoderSelector.DEFAULT, + new VideoEncoderSettings.Builder().setBitrate(5_000_000).build(), + /* enableFallback= */ true)) + .build(); + // TODO(b/223381524): Remove analysis failure suppression after ssim calculation doesn't fail. + new TransformerAndroidTestRunner.Builder(context, transformer) + .setCalculateSsim(true) + .setSuppressAnalysisExceptions(true) + .build() + .run(testId, MP4_ASSET_WITH_INCREASING_TIMESTAMPS_URI_STRING); + } + @Test public void transform4K60() throws Exception { final String testId = TAG + "_transform4K60"; 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 1beaeaeea1..b59f6ca2bb 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java @@ -59,7 +59,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { /** Creates a new instance using a default {@link VideoEncoderSettings}. */ public DefaultEncoderFactory(EncoderSelector videoEncoderSelector, boolean enableFallback) { - this(videoEncoderSelector, new VideoEncoderSettings.Builder().build(), enableFallback); + this(videoEncoderSelector, VideoEncoderSettings.DEFAULT, enableFallback); } /** @@ -193,6 +193,11 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { /* outputSurface= */ null); } + @Override + public boolean videoNeedsEncoding() { + return !requestedVideoEncoderSettings.equals(VideoEncoderSettings.DEFAULT); + } + /** * Finds an {@link MediaCodecInfo encoder} that supports the requested format most closely. * diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/VideoEncoderSettings.java b/libraries/transformer/src/main/java/androidx/media3/transformer/VideoEncoderSettings.java index 2b7335fc4c..f00fc7f433 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/VideoEncoderSettings.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/VideoEncoderSettings.java @@ -19,8 +19,10 @@ package androidx.media3.transformer; import static androidx.media3.common.util.Assertions.checkArgument; import static java.lang.annotation.ElementType.TYPE_USE; +import android.annotation.SuppressLint; import android.media.MediaCodecInfo; import androidx.annotation.IntDef; +import androidx.annotation.Nullable; import androidx.media3.common.Format; import androidx.media3.common.util.UnstableApi; import java.lang.annotation.Documented; @@ -40,6 +42,9 @@ public final class VideoEncoderSettings { /** The default I-frame interval in seconds. */ public static final float DEFAULT_I_FRAME_INTERVAL_SECONDS = 1.0f; + /** A default {@link VideoEncoderSettings}. */ + public static final VideoEncoderSettings DEFAULT = new Builder().build(); + /** * The allowed values for {@code bitrateMode}, one of * @@ -51,6 +56,7 @@ public final class VideoEncoderSettings { * MediaCodecInfo.EncoderCapabilities#BITRATE_MODE_CBR_FD}, available from API31. * */ + @SuppressLint("InlinedApi") @Documented @Retention(RetentionPolicy.SOURCE) @Target(TYPE_USE) @@ -207,4 +213,33 @@ public final class VideoEncoderSettings { public Builder buildUpon() { return new Builder(this); } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (!(o instanceof VideoEncoderSettings)) { + return false; + } + VideoEncoderSettings that = (VideoEncoderSettings) o; + return bitrate == that.bitrate + && bitrateMode == that.bitrateMode + && profile == that.profile + && level == that.level + && colorProfile == that.colorProfile + && iFrameIntervalSeconds == that.iFrameIntervalSeconds; + } + + @Override + public int hashCode() { + int result = 7; + result = 31 * result + bitrate; + result = 31 * result + bitrateMode; + result = 31 * result + profile; + result = 31 * result + level; + result = 31 * result + colorProfile; + result = 31 * result + Float.floatToIntBits(iFrameIntervalSeconds); + return result; + } }