From 3b7ebecf165981245694dbe6b0cd51956ab20b65 Mon Sep 17 00:00:00 2001 From: claincly Date: Fri, 3 Feb 2023 13:44:11 +0000 Subject: [PATCH] Prefer hardware encoders in EncoderSelector. In encoding small and odd-numbered resolutions, like `316x61` ([this image](https://upload.wikimedia.org/wikipedia/commons/6/65/100winners.png)), the current fallback logic prefers a software encoder to hardware ones. The assumption was, the encoder factory applies the encoder size alignment and changes the resolution to `316x60` for SW encoders and `316x64` for HW ones. SW encoders is selected because the supported resolution 60 is closer to requested 61, than the hardware supported 64. This change changes the default encoder selection process to only expose hardware encoders if there is any. PiperOrigin-RevId: 506879983 --- .../transformer/DefaultEncoderFactory.java | 13 +++++++------ .../media3/transformer/EncoderSelector.java | 18 ++++++++++++++++-- 2 files changed, 23 insertions(+), 8 deletions(-) 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 b51fc60f7b..2be9af522c 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultEncoderFactory.java @@ -58,7 +58,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { public static final class Builder { private final Context context; - @Nullable private EncoderSelector encoderSelector; + @Nullable private EncoderSelector videoEncoderSelector; @Nullable private VideoEncoderSettings requestedVideoEncoderSettings; private boolean enableFallback; @@ -74,8 +74,8 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { *

The default value is {@link EncoderSelector#DEFAULT}. */ @CanIgnoreReturnValue - public Builder setVideoEncoderSelector(EncoderSelector encoderSelector) { - this.encoderSelector = encoderSelector; + public Builder setVideoEncoderSelector(EncoderSelector videoEncoderSelector) { + this.videoEncoderSelector = videoEncoderSelector; return this; } @@ -123,14 +123,14 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { /** Creates an instance of {@link DefaultEncoderFactory}, using defaults if values are unset. */ @SuppressWarnings("deprecation") public DefaultEncoderFactory build() { - if (encoderSelector == null) { - encoderSelector = EncoderSelector.DEFAULT; + if (videoEncoderSelector == null) { + videoEncoderSelector = EncoderSelector.DEFAULT; } if (requestedVideoEncoderSettings == null) { requestedVideoEncoderSettings = VideoEncoderSettings.DEFAULT; } return new DefaultEncoderFactory( - context, encoderSelector, requestedVideoEncoderSettings, enableFallback); + context, videoEncoderSelector, requestedVideoEncoderSettings, enableFallback); } } @@ -452,6 +452,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory { /** Returns a list of encoders that support the requested resolution most closely. */ private static ImmutableList filterEncodersByResolution( List encoders, String mimeType, int requestedWidth, int requestedHeight) { + // TODO(b/267740292): Investigate the fallback logic that might prefer software encoders. return filterEncoders( encoders, /* cost= */ (encoderInfo) -> { diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/EncoderSelector.java b/libraries/transformer/src/main/java/androidx/media3/transformer/EncoderSelector.java index 0f1c7b445d..52bd57b69b 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/EncoderSelector.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/EncoderSelector.java @@ -21,16 +21,30 @@ import android.media.MediaCodecInfo; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.UnstableApi; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; /** Selector of {@link MediaCodec} encoder instances. */ @UnstableApi public interface EncoderSelector { /** - * Default implementation of {@link EncoderSelector}, which returns the preferred encoders for the + * Default implementation of {@code EncoderSelector}, which returns the preferred encoders for the * given {@link MimeTypes MIME type}. + * + *

The {@code EncoderSelector} selection result contains only hardware encoders if they exist, + * or only software encoders otherwise. */ - EncoderSelector DEFAULT = EncoderUtil::getSupportedEncoders; + EncoderSelector DEFAULT = + mimeType -> { + ImmutableList supportedEncoders = + EncoderUtil.getSupportedEncoders(mimeType); + ImmutableList supportedHardwareEncoders = + ImmutableList.copyOf( + Iterables.filter( + supportedEncoders, + encoderInfo -> EncoderUtil.isHardwareAccelerated(encoderInfo, mimeType))); + return supportedHardwareEncoders.isEmpty() ? supportedEncoders : supportedHardwareEncoders; + }; /** * Returns a list of encoders that can encode media in the specified {@code mimeType}, in priority