From 112d9c41eb92552efa648d8f530f148c27bd32b6 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 19 Feb 2020 23:40:06 -0800 Subject: [PATCH] Use KEY_LOW_LATENCY to request low-latency decoding on Android R --- .../video/MediaCodecDecoderRenderer.java | 14 +++++++++-- .../binding/video/MediaCodecHelper.java | 25 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) 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 4edde1b6..d6bebe62 100644 --- a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java +++ b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java @@ -45,6 +45,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer { private Thread rendererThread; private boolean needsSpsBitstreamFixup, isExynos4; private boolean adaptivePlayback, directSubmit; + private boolean lowLatency; private boolean constrainedHighProfile; private boolean refFrameInvalidationAvc, refFrameInvalidationHevc; private boolean refFrameInvalidationActive; @@ -161,7 +162,6 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer { // shared between AVC and HEVC decoders on the same device. if (avcDecoder != null) { directSubmit = MediaCodecHelper.decoderCanDirectSubmit(avcDecoder.getName()); - adaptivePlayback = MediaCodecHelper.decoderSupportsAdaptivePlayback(avcDecoder); refFrameInvalidationAvc = MediaCodecHelper.decoderSupportsRefFrameInvalidationAvc(avcDecoder.getName(), prefs.height); refFrameInvalidationHevc = MediaCodecHelper.decoderSupportsRefFrameInvalidationHevc(avcDecoder.getName()); @@ -264,6 +264,9 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer { } refFrameInvalidationActive = refFrameInvalidationAvc; + + lowLatency = MediaCodecHelper.decoderSupportsLowLatency(avcDecoder, mimeType); + adaptivePlayback = MediaCodecHelper.decoderSupportsAdaptivePlayback(avcDecoder, mimeType); } else if ((videoFormat & MoonBridge.VIDEO_FORMAT_MASK_H265) != 0) { mimeType = "video/hevc"; @@ -275,6 +278,9 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer { } refFrameInvalidationActive = refFrameInvalidationHevc; + + lowLatency = MediaCodecHelper.decoderSupportsLowLatency(hevcDecoder, mimeType); + adaptivePlayback = MediaCodecHelper.decoderSupportsAdaptivePlayback(hevcDecoder, mimeType); } else { // Unknown format @@ -300,7 +306,10 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer { videoFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, height); } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (lowLatency) { + videoFormat.setInteger(MediaCodecHelper.KEY_LOW_LATENCY, 1); + } + else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Operate at maximum rate to lower latency as much as possible on // some Qualcomm platforms. We could also set KEY_PRIORITY to 0 (realtime) // but that will actually result in the decoder crashing if it can't satisfy @@ -1031,6 +1040,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer { str += "Consecutive crashes: "+renderer.consecutiveCrashCount+"\n"; str += "RFI active: "+renderer.refFrameInvalidationActive+"\n"; str += "Using modern SPS patching: "+(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)+"\n"; + str += "Low latency mode: "+renderer.lowLatency+"\n"; str += "Video dimensions: "+renderer.initialWidth+"x"+renderer.initialHeight+"\n"; str += "FPS target: "+renderer.refreshRate+"\n"; str += "Bitrate: "+renderer.prefs.bitrate+" Kbps \n"; 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 449f4e6b..59b208a4 100644 --- a/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java +++ b/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java @@ -39,6 +39,10 @@ public class MediaCodecHelper { private static final List blacklisted49FpsDecoderPrefixes; private static final List blacklisted59FpsDecoderPrefixes; + // FIXME: Remove when Android R SDK is finalized + public static final String FEATURE_LowLatency = "low-latency"; + public static final String KEY_LOW_LATENCY = "low-latency"; + private static boolean isLowEndSnapdragon = false; private static boolean initialized = false; @@ -330,7 +334,23 @@ public class MediaCodecHelper { return System.nanoTime() / 1000000L; } - public static boolean decoderSupportsAdaptivePlayback(MediaCodecInfo decoderInfo) { + public static boolean decoderSupportsLowLatency(MediaCodecInfo decoderInfo, String mimeType) { + try { + if (decoderInfo.getCapabilitiesForType(mimeType). + isFeatureSupported(FEATURE_LowLatency)) + { + LimeLog.info("Low latency decoding mode supported (FEATURE_LowLatency)"); + return true; + } + } catch (Exception e) { + // Tolerate buggy codecs + e.printStackTrace(); + } + + return false; + } + + public static boolean decoderSupportsAdaptivePlayback(MediaCodecInfo decoderInfo, String mimeType) { // Possibly enable adaptive playback on KitKat and above if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (isDecoderInList(blacklistedAdaptivePlaybackPrefixes, decoderInfo.getName())) { @@ -339,7 +359,7 @@ public class MediaCodecHelper { } try { - if (decoderInfo.getCapabilitiesForType("video/avc"). + if (decoderInfo.getCapabilitiesForType(mimeType). isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback)) { // This will make getCapabilities() return that adaptive playback is supported @@ -348,6 +368,7 @@ public class MediaCodecHelper { } } catch (Exception e) { // Tolerate buggy codecs + e.printStackTrace(); } }