diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index 89d2ee16b2..a68ee5b727 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -18,7 +18,6 @@ package com.google.android.exoplayer2.audio; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; -import android.content.pm.PackageManager; import android.media.MediaCodec; import android.media.MediaCrypto; import android.media.MediaFormat; @@ -707,21 +706,12 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media * be determined. */ private int getCodecMaxInputSize(MediaCodecInfo codecInfo, Format format) { - if (Util.SDK_INT < 24 && "OMX.google.raw.decoder".equals(codecInfo.name)) { - // OMX.google.raw.decoder didn't resize its output buffers correctly prior to N, so there's no - // point requesting a non-default input size. Doing so may cause a native crash, where-as not - // doing so will cause a more controlled failure when attempting to fill an input buffer. See: - // https://github.com/google/ExoPlayer/issues/4057. - boolean needsRawDecoderWorkaround = true; - if (Util.SDK_INT == 23) { - PackageManager packageManager = context.getPackageManager(); - if (packageManager != null - && packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) { - // The workaround is not required for AndroidTV devices running M. - needsRawDecoderWorkaround = false; - } - } - if (needsRawDecoderWorkaround) { + if ("OMX.google.raw.decoder".equals(codecInfo.name)) { + // OMX.google.raw.decoder didn't resize its output buffers correctly prior to N, except on + // Android TV running M, so there's no point requesting a non-default input size. Doing so may + // cause a native crash, whereas not doing so will cause a more controlled failure when + // attempting to fill an input buffer. See: https://github.com/google/ExoPlayer/issues/4057. + if (Util.SDK_INT < 24 && !(Util.SDK_INT == 23 && Util.isAndroidTv(context))) { return Format.NO_VALUE; } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java index eafb05226c..33c8dc5643 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -1728,6 +1728,18 @@ public final class Util { } } + /** + * Returns whether the device is an Android TV. + * + * @param context Any context. + * @return Whether the device is an Android TV. + */ + public static boolean isAndroidTv(Context context) { + PackageManager packageManager = context.getPackageManager(); + return packageManager != null + && packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK); + } + /** * Gets the physical size of the default display, in pixels. * @@ -1747,43 +1759,42 @@ public final class Util { * @return The physical display size, in pixels. */ public static Point getPhysicalDisplaySize(Context context, Display display) { - if (Util.SDK_INT < 25 && display.getDisplayId() == Display.DEFAULT_DISPLAY) { - // Before API 25 the Display object does not provide a working way to identify Android TVs - // that can show 4k resolution in a SurfaceView, so check for supported devices here. - if ("Sony".equals(Util.MANUFACTURER) && Util.MODEL.startsWith("BRAVIA") + if (Util.SDK_INT <= 28 + && display.getDisplayId() == Display.DEFAULT_DISPLAY + && Util.isAndroidTv(context)) { + // On Android TVs it is common for the UI to be configured for a lower resolution than + // SurfaceViews can output. Before API 26 the Display object does not provide a way to + // identify this case, and up to and including API 28 many devices still do not correctly set + // their hardware compositor output size. + + // Sony Android TVs advertise support for 4k output via a system feature. + if ("Sony".equals(Util.MANUFACTURER) + && Util.MODEL.startsWith("BRAVIA") && context.getPackageManager().hasSystemFeature("com.sony.dtv.hardware.panel.qfhd")) { return new Point(3840, 2160); - } else if (("NVIDIA".equals(Util.MANUFACTURER) && Util.MODEL.contains("SHIELD")) - || ("philips".equals(Util.toLowerInvariant(Util.MANUFACTURER)) - && (Util.MODEL.startsWith("QM1") - || Util.MODEL.equals("QV151E") - || Util.MODEL.equals("TPM171E")))) { - // Attempt to read sys.display-size. - String sysDisplaySize = null; + } + + // Otherwise check the system property for display size. From API 28 treble may prevent the + // system from writing sys.display-size so we check vendor.display-size instead. + String displaySize = + Util.SDK_INT < 28 + ? getSystemProperty("sys.display-size") + : getSystemProperty("vendor.display-size"); + // If we managed to read the display size, attempt to parse it. + if (!TextUtils.isEmpty(displaySize)) { try { - @SuppressLint("PrivateApi") - Class systemProperties = Class.forName("android.os.SystemProperties"); - Method getMethod = systemProperties.getMethod("get", String.class); - sysDisplaySize = (String) getMethod.invoke(systemProperties, "sys.display-size"); - } catch (Exception e) { - Log.e(TAG, "Failed to read sys.display-size", e); - } - // If we managed to read sys.display-size, attempt to parse it. - if (!TextUtils.isEmpty(sysDisplaySize)) { - try { - String[] sysDisplaySizeParts = split(sysDisplaySize.trim(), "x"); - if (sysDisplaySizeParts.length == 2) { - int width = Integer.parseInt(sysDisplaySizeParts[0]); - int height = Integer.parseInt(sysDisplaySizeParts[1]); - if (width > 0 && height > 0) { - return new Point(width, height); - } + String[] displaySizeParts = split(displaySize.trim(), "x"); + if (displaySizeParts.length == 2) { + int width = Integer.parseInt(displaySizeParts[0]); + int height = Integer.parseInt(displaySizeParts[1]); + if (width > 0 && height > 0) { + return new Point(width, height); } - } catch (NumberFormatException e) { - // Do nothing. } - Log.e(TAG, "Invalid sys.display-size: " + sysDisplaySize); + } catch (NumberFormatException e) { + // Do nothing. } + Log.e(TAG, "Invalid display size: " + displaySize); } } @@ -1800,6 +1811,19 @@ public final class Util { return displaySize; } + @Nullable + private static String getSystemProperty(String name) { + try { + @SuppressLint("PrivateApi") + Class systemProperties = Class.forName("android.os.SystemProperties"); + Method getMethod = systemProperties.getMethod("get", String.class); + return (String) getMethod.invoke(systemProperties, name); + } catch (Exception e) { + Log.e(TAG, "Failed to read system property " + name, e); + return null; + } + } + @TargetApi(23) private static void getDisplaySizeV23(Display display, Point outSize) { Display.Mode mode = display.getMode();