From f903e4a9f8d431e7e3c65a0afdd320e966469db8 Mon Sep 17 00:00:00 2001 From: claincly Date: Wed, 20 Apr 2022 15:57:14 +0100 Subject: [PATCH] Apply resolution fix. Some devices under report their resolution support, like 2144 for 2160 in H265, 1072 for 1080 in H264. This CL only takes care of these two cases, - reporting 1920x1080 is supported when the device reports 1920x1072, and - reporting 3840x2160 is supported when the device reports 3840x2144 PiperOrigin-RevId: 443095042 --- .../media3/transformer/AndroidTestUtil.java | 7 +-- .../media3/transformer/EncoderUtil.java | 48 ++++++++++--------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java index a392263e02..08e9e31041 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java @@ -256,8 +256,9 @@ public final class AndroidTestUtil { if (decoderInfo == null) { return false; } + // Use Format.NO_VALUE for frame rate to only check whether size is supported. return decoderInfo.isVideoSizeAndRateSupportedV21( - format.width, format.height, format.frameRate); + format.width, format.height, /* frameRate= */ Format.NO_VALUE); } private static boolean canEncode(Format format) { @@ -267,8 +268,8 @@ public final class AndroidTestUtil { if (supportedEncoders.isEmpty()) { return false; } - return EncoderUtil.areSizeAndRateSupported( - supportedEncoders.get(0), mimeType, format.width, format.height, format.frameRate); + return EncoderUtil.isSizeSupported( + supportedEncoders.get(0), mimeType, format.width, format.height); } /** diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/EncoderUtil.java b/libraries/transformer/src/main/java/androidx/media3/transformer/EncoderUtil.java index 99c88a1b38..a312d8e75a 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/EncoderUtil.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/EncoderUtil.java @@ -20,6 +20,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull; import static java.lang.Math.max; import static java.lang.Math.round; +import android.media.CamcorderProfile; import android.media.MediaCodec; import android.media.MediaCodecInfo; import android.media.MediaCodecList; @@ -66,24 +67,27 @@ public final class EncoderUtil { return checkNotNull(MIME_TYPE_TO_ENCODERS.get()).keySet(); } - /** - * Returns whether the {@linkplain MediaCodecInfo encoder} supports the given resolution and frame - * rate. - */ - public static boolean areSizeAndRateSupported( - MediaCodecInfo encoderInfo, String mimeType, int width, int height, double frameRate) { - // VideoCapabilities.areSizeAndRateSupported incorrectly returns false if frameRate < 1 on all - // current versions of Android, so only checks the width and height in this case [b/153940404]. - if (frameRate == Format.NO_VALUE || frameRate < 1) { - return encoderInfo - .getCapabilitiesForType(mimeType) - .getVideoCapabilities() - .isSizeSupported(width, height); - } - return encoderInfo + /** Returns whether the {@linkplain MediaCodecInfo encoder} supports the given resolution. */ + public static boolean isSizeSupported( + MediaCodecInfo encoderInfo, String mimeType, int width, int height) { + if (encoderInfo .getCapabilitiesForType(mimeType) .getVideoCapabilities() - .areSizeAndRateSupported(width, height, frameRate); + .isSizeSupported(width, height)) { + return true; + } + + // Some devices (Samsung, Huawei, and Pixel 6. See b/222095724) under-report their encoding + // capabilities. The supported height reported for H265@3840x2160 is 2144, and + // H264@1920x1080 is 1072. See b/229825948. + // Cross reference with CamcorderProfile to ensure a resolution is supported. + if (width == 1920 && height == 1080) { + return CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P); + } + if (width == 3840 && height == 2160) { + return CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2160P); + } + return false; } /** @@ -142,35 +146,35 @@ public final class EncoderUtil { // Fix size alignment. width = alignResolution(width, widthAlignment); height = alignResolution(height, heightAlignment); - if (videoEncoderCapabilities.isSizeSupported(width, height)) { + if (isSizeSupported(encoderInfo, mimeType, width, height)) { return new Size(width, height); } // Try three-fourths (e.g. 1440 -> 1080). int newWidth = alignResolution(width * 3 / 4, widthAlignment); int newHeight = alignResolution(height * 3 / 4, heightAlignment); - if (videoEncoderCapabilities.isSizeSupported(newWidth, newHeight)) { + if (isSizeSupported(encoderInfo, mimeType, newWidth, newHeight)) { return new Size(newWidth, newHeight); } // Try two-thirds (e.g. 4k -> 1440). newWidth = alignResolution(width * 2 / 3, widthAlignment); newHeight = alignResolution(height * 2 / 3, heightAlignment); - if (videoEncoderCapabilities.isSizeSupported(newWidth, newHeight)) { + if (isSizeSupported(encoderInfo, mimeType, width, height)) { return new Size(newWidth, newHeight); } // Try half (e.g. 4k -> 1080). newWidth = alignResolution(width / 2, widthAlignment); newHeight = alignResolution(height / 2, heightAlignment); - if (videoEncoderCapabilities.isSizeSupported(newWidth, newHeight)) { + if (isSizeSupported(encoderInfo, mimeType, newWidth, newHeight)) { return new Size(newWidth, newHeight); } // Try one-third (e.g. 4k -> 720). newWidth = alignResolution(width / 3, widthAlignment); newHeight = alignResolution(height / 3, heightAlignment); - if (videoEncoderCapabilities.isSizeSupported(newWidth, newHeight)) { + if (isSizeSupported(encoderInfo, mimeType, newWidth, newHeight)) { return new Size(newWidth, newHeight); } @@ -183,7 +187,7 @@ public final class EncoderUtil { height = alignResolution(adjustedHeight, heightAlignment); } - return videoEncoderCapabilities.isSizeSupported(width, height) ? new Size(width, height) : null; + return isSizeSupported(encoderInfo, mimeType, width, height) ? new Size(width, height) : null; } /**