From 617c8582b4307be7749bd4905d7bd04c8aa6a047 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 10 Feb 2018 16:42:45 -0800 Subject: [PATCH] Fix crash on MediaTek PAL Android TVs --- app/src/main/java/com/limelight/Game.java | 20 +++++++++++++------ .../video/MediaCodecDecoderRenderer.java | 12 ++++++++++- .../binding/video/MediaCodecHelper.java | 18 ++++++++++++++++- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index b3573c01..5c49d476 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -329,13 +329,21 @@ public class Game extends Activity implements SurfaceHolder.Callback, // Hopefully, we can get rid of this once someone comes up with a better way // to track the state of the pipeline and time frames. int roundedRefreshRate = Math.round(displayRefreshRate); - if (roundedRefreshRate <= 49) { - // Let's avoid clearly bogus refresh rates - roundedRefreshRate = 60; - } if (!prefConfig.disableFrameDrop && prefConfig.fps >= roundedRefreshRate) { - prefConfig.fps = roundedRefreshRate - 1; - LimeLog.info("Adjusting FPS target for screen to "+prefConfig.fps); + if (roundedRefreshRate <= 49) { + // Let's avoid clearly bogus refresh rates and fall back to legacy rendering + decoderRenderer.enableLegacyFrameDropRendering(); + LimeLog.info("Bogus refresh rate: "+roundedRefreshRate); + } + // HACK: Avoid crashing on some MTK devices + else if (roundedRefreshRate == 50 && decoderRenderer.is49FpsBlacklisted()) { + // Use the old rendering strategy on these broken devices + decoderRenderer.enableLegacyFrameDropRendering(); + } + else { + prefConfig.fps = roundedRefreshRate - 1; + LimeLog.info("Adjusting FPS target for screen to "+prefConfig.fps); + } } StreamConfiguration config = new StreamConfiguration.Builder() diff --git a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java index 9ba65a09..972233ee 100644 --- a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java +++ b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java @@ -56,6 +56,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer { private int consecutiveCrashCount; private String glRenderer; private boolean foreground = true; + private boolean legacyFrameDropRendering = false; private boolean needsBaselineSpsHack; private SeqParameterSet savedSps; @@ -191,6 +192,15 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer { return avcDecoder != null; } + public boolean is49FpsBlacklisted() { + return avcDecoder != null && MediaCodecHelper.decoderBlacklistedFor49Fps(avcDecoder.getName()); + } + + public void enableLegacyFrameDropRendering() { + LimeLog.info("Legacy frame drop rendering enabled"); + legacyFrameDropRendering = true; + } + public boolean isHevcMain10Hdr10Supported() { if (hevcDecoder == null) { return false; @@ -410,7 +420,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer { } // Render the last buffer - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !legacyFrameDropRendering) { // Use a PTS that will cause this frame to never be dropped if frame dropping // is disabled videoDecoder.releaseOutputBuffer(lastIndex, 0); diff --git a/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java b/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java index 8c2cbc6e..c77a8db8 100644 --- a/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java +++ b/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java @@ -36,6 +36,7 @@ public class MediaCodecHelper { private static final List whitelistedHevcDecoders; private static final List refFrameInvalidationAvcPrefixes; private static final List refFrameInvalidationHevcPrefixes; + private static final List blacklisted49FpsDecoderPrefixes; private static boolean isLowEndSnapdragon = false; private static boolean initialized = false; @@ -153,6 +154,17 @@ public class MediaCodecHelper { // Qualcomm is currently the only decoders in this group. } + static { + blacklisted49FpsDecoderPrefixes = new LinkedList<>(); + + // We see a bunch of crashes on MediaTek Android TVs running + // at 49 FPS (PAL 50 Hz - 1). Blacklist this frame rate for + // these devices and hope they fix it in Oreo. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + blacklisted49FpsDecoderPrefixes.add("omx.mtk"); + } + } + private static String getAdrenoVersionString(String glRenderer) { glRenderer = glRenderer.toLowerCase().trim(); @@ -271,7 +283,7 @@ public class MediaCodecHelper { public static long getMonotonicMillis() { return System.nanoTime() / 1000000L; } - + public static boolean decoderSupportsAdaptivePlayback(MediaCodecInfo decoderInfo) { // Possibly enable adaptive playback on KitKat and above if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { @@ -312,6 +324,10 @@ public class MediaCodecHelper { return isDecoderInList(baselineProfileHackPrefixes, decoderName); } + public static boolean decoderBlacklistedFor49Fps(String decoderName) { + return isDecoderInList(blacklisted49FpsDecoderPrefixes, decoderName); + } + public static boolean decoderSupportsRefFrameInvalidationAvc(String decoderName, int videoHeight) { // Reference frame invalidation is broken on low-end Snapdragon SoCs at 1080p. if (videoHeight > 720 && isLowEndSnapdragon) {