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 {
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);
}
/**
......
......@@ -20,6 +20,7 @@ import static com.google.android.exoplayer2.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;
......@@ -64,24 +65,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;
}
/**
......@@ -140,35 +144,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);
}
......@@ -181,7 +185,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;
}
/**
......
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