Commit 34591976 by claincly Committed by Ian Baker

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
parent c1993689
...@@ -256,8 +256,9 @@ public final class AndroidTestUtil { ...@@ -256,8 +256,9 @@ public final class AndroidTestUtil {
if (decoderInfo == null) { if (decoderInfo == null) {
return false; return false;
} }
// Use Format.NO_VALUE for frame rate to only check whether size is supported.
return decoderInfo.isVideoSizeAndRateSupportedV21( return decoderInfo.isVideoSizeAndRateSupportedV21(
format.width, format.height, format.frameRate); format.width, format.height, /* frameRate= */ Format.NO_VALUE);
} }
private static boolean canEncode(Format format) { private static boolean canEncode(Format format) {
...@@ -267,8 +268,8 @@ public final class AndroidTestUtil { ...@@ -267,8 +268,8 @@ public final class AndroidTestUtil {
if (supportedEncoders.isEmpty()) { if (supportedEncoders.isEmpty()) {
return false; return false;
} }
return EncoderUtil.areSizeAndRateSupported( return EncoderUtil.isSizeSupported(
supportedEncoders.get(0), mimeType, format.width, format.height, format.frameRate); supportedEncoders.get(0), mimeType, format.width, format.height);
} }
/** /**
......
...@@ -20,6 +20,7 @@ import static com.google.android.exoplayer2.util.Assertions.checkNotNull; ...@@ -20,6 +20,7 @@ import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.lang.Math.round; import static java.lang.Math.round;
import android.media.CamcorderProfile;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCodecInfo; import android.media.MediaCodecInfo;
import android.media.MediaCodecList; import android.media.MediaCodecList;
...@@ -64,24 +65,27 @@ public final class EncoderUtil { ...@@ -64,24 +65,27 @@ public final class EncoderUtil {
return checkNotNull(MIME_TYPE_TO_ENCODERS.get()).keySet(); return checkNotNull(MIME_TYPE_TO_ENCODERS.get()).keySet();
} }
/** /** Returns whether the {@linkplain MediaCodecInfo encoder} supports the given resolution. */
* Returns whether the {@linkplain MediaCodecInfo encoder} supports the given resolution and frame public static boolean isSizeSupported(
* rate. MediaCodecInfo encoderInfo, String mimeType, int width, int height) {
*/ if (encoderInfo
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
.getCapabilitiesForType(mimeType) .getCapabilitiesForType(mimeType)
.getVideoCapabilities() .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;
} }
/** /**
...@@ -140,35 +144,35 @@ public final class EncoderUtil { ...@@ -140,35 +144,35 @@ public final class EncoderUtil {
// Fix size alignment. // Fix size alignment.
width = alignResolution(width, widthAlignment); width = alignResolution(width, widthAlignment);
height = alignResolution(height, heightAlignment); height = alignResolution(height, heightAlignment);
if (videoEncoderCapabilities.isSizeSupported(width, height)) { if (isSizeSupported(encoderInfo, mimeType, width, height)) {
return new Size(width, height); return new Size(width, height);
} }
// Try three-fourths (e.g. 1440 -> 1080). // Try three-fourths (e.g. 1440 -> 1080).
int newWidth = alignResolution(width * 3 / 4, widthAlignment); int newWidth = alignResolution(width * 3 / 4, widthAlignment);
int newHeight = alignResolution(height * 3 / 4, heightAlignment); int newHeight = alignResolution(height * 3 / 4, heightAlignment);
if (videoEncoderCapabilities.isSizeSupported(newWidth, newHeight)) { if (isSizeSupported(encoderInfo, mimeType, newWidth, newHeight)) {
return new Size(newWidth, newHeight); return new Size(newWidth, newHeight);
} }
// Try two-thirds (e.g. 4k -> 1440). // Try two-thirds (e.g. 4k -> 1440).
newWidth = alignResolution(width * 2 / 3, widthAlignment); newWidth = alignResolution(width * 2 / 3, widthAlignment);
newHeight = alignResolution(height * 2 / 3, heightAlignment); newHeight = alignResolution(height * 2 / 3, heightAlignment);
if (videoEncoderCapabilities.isSizeSupported(newWidth, newHeight)) { if (isSizeSupported(encoderInfo, mimeType, width, height)) {
return new Size(newWidth, newHeight); return new Size(newWidth, newHeight);
} }
// Try half (e.g. 4k -> 1080). // Try half (e.g. 4k -> 1080).
newWidth = alignResolution(width / 2, widthAlignment); newWidth = alignResolution(width / 2, widthAlignment);
newHeight = alignResolution(height / 2, heightAlignment); newHeight = alignResolution(height / 2, heightAlignment);
if (videoEncoderCapabilities.isSizeSupported(newWidth, newHeight)) { if (isSizeSupported(encoderInfo, mimeType, newWidth, newHeight)) {
return new Size(newWidth, newHeight); return new Size(newWidth, newHeight);
} }
// Try one-third (e.g. 4k -> 720). // Try one-third (e.g. 4k -> 720).
newWidth = alignResolution(width / 3, widthAlignment); newWidth = alignResolution(width / 3, widthAlignment);
newHeight = alignResolution(height / 3, heightAlignment); newHeight = alignResolution(height / 3, heightAlignment);
if (videoEncoderCapabilities.isSizeSupported(newWidth, newHeight)) { if (isSizeSupported(encoderInfo, mimeType, newWidth, newHeight)) {
return new Size(newWidth, newHeight); return new Size(newWidth, newHeight);
} }
...@@ -181,7 +185,7 @@ public final class EncoderUtil { ...@@ -181,7 +185,7 @@ public final class EncoderUtil {
height = alignResolution(adjustedHeight, heightAlignment); 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;
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment