From 1c725b9dac8586992ebd22ec8ffa276846f84633 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 20 Nov 2017 20:56:26 -0800 Subject: [PATCH] Don't use reference picture invalidation on low-end Snapdragon SoCs --- app/src/main/java/com/limelight/Game.java | 37 +++++++++++++++-- .../video/MediaCodecDecoderRenderer.java | 2 +- .../binding/video/MediaCodecHelper.java | 40 ++++++++++++++++--- decoder-errata.txt | 5 ++- 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index b5edf266..175c7136 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -44,6 +44,7 @@ import android.hardware.input.InputManager; import android.media.AudioManager; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; +import android.opengl.GLSurfaceView; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -65,6 +66,9 @@ import android.widget.FrameLayout; import android.view.inputmethod.InputMethodManager; import android.widget.Toast; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + public class Game extends Activity implements SurfaceHolder.Callback, OnGenericMotionListener, OnTouchListener, NvConnectionListener, EvdevListener, @@ -104,6 +108,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, private ShortcutHelper shortcutHelper; private MediaCodecDecoderRenderer decoderRenderer; + private String glRenderer; private WifiManager.WifiLock wifiLock; @@ -135,8 +140,6 @@ public class Game extends Activity implements SurfaceHolder.Callback, protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - shortcutHelper = new ShortcutHelper(this); - UiHelper.setLocale(this); // We don't want a title bar @@ -164,6 +167,33 @@ public class Game extends Activity implements SurfaceHolder.Callback, // Change volume button behavior setVolumeControlStream(AudioManager.STREAM_MUSIC); + // We first construct a GLSurfaceView to probe for GL + // properties to pass to MediaCodecHelper. After this completes, + // we'll construct the activity like normal. + GLSurfaceView surfaceView = new GLSurfaceView(this); + surfaceView.setRenderer(new GLSurfaceView.Renderer() { + @Override + public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) { + glRenderer = gl10.glGetString(GL10.GL_RENDERER); + LimeLog.info("GL Renderer: "+glRenderer); + runOnUiThread(new Runnable() { + @Override + public void run() { + completeOnCreate(); + } + }); + } + + @Override + public void onSurfaceChanged(GL10 gl10, int i, int i1) {} + + @Override + public void onDrawFrame(GL10 gl10) {} + }); + setContentView(surfaceView); + } + + private void completeOnCreate() { // Inflate the content setContentView(R.layout.activity_game); @@ -222,11 +252,12 @@ public class Game extends Activity implements SurfaceHolder.Callback, } // Add a launcher shortcut for this PC (forced, since this is user interaction) + shortcutHelper = new ShortcutHelper(this); shortcutHelper.createAppViewShortcut(uuid, pcName, uuid, true); shortcutHelper.reportShortcutUsed(uuid); // Initialize the MediaCodec helper before creating the decoder - MediaCodecHelper.initializeWithContext(this); + MediaCodecHelper.initialize(this, glRenderer); // Check if the user has enabled HDR if (prefConfig.enableHdr) { 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 6e2c122a..b894498d 100644 --- a/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java +++ b/app/src/main/java/com/limelight/binding/video/MediaCodecDecoderRenderer.java @@ -157,7 +157,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer { if (avcDecoder != null) { directSubmit = MediaCodecHelper.decoderCanDirectSubmit(avcDecoder.getName()); adaptivePlayback = MediaCodecHelper.decoderSupportsAdaptivePlayback(avcDecoder); - refFrameInvalidationAvc = MediaCodecHelper.decoderSupportsRefFrameInvalidationAvc(avcDecoder.getName()); + refFrameInvalidationAvc = MediaCodecHelper.decoderSupportsRefFrameInvalidationAvc(avcDecoder.getName(), prefs.height); refFrameInvalidationHevc = MediaCodecHelper.decoderSupportsRefFrameInvalidationHevc(avcDecoder.getName()); if (directSubmit) { 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 12b53fe6..ba22475c 100644 --- a/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java +++ b/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java @@ -7,9 +7,10 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import android.annotation.SuppressLint; -import android.annotation.TargetApi; import android.app.ActivityManager; import android.content.Context; import android.content.pm.ConfigurationInfo; @@ -36,6 +37,8 @@ public class MediaCodecHelper { private static final List refFrameInvalidationAvcPrefixes; private static final List refFrameInvalidationHevcPrefixes; + private static boolean isLowEndSnapdragon = false; + static { directSubmitPrefixes = new LinkedList<>(); @@ -146,20 +149,43 @@ public class MediaCodecHelper { // Qualcomm is currently the only decoders in this group. } - public static void initializeWithContext(Context context) { + private static boolean isLowEndSnapdragonRenderer(String glRenderer) { + glRenderer = glRenderer.toLowerCase().trim(); + + if (!glRenderer.contains("adreno")) { + return false; + } + + Pattern modelNumberPattern = Pattern.compile("(.*)([0-9]{3})(.*)"); + + Matcher matcher = modelNumberPattern.matcher(glRenderer); + if (!matcher.matches()) { + return false; + } + + String modelNumber = matcher.group(2); + LimeLog.info("Found Adreno GPU: "+modelNumber); + + // The current logic is to identify low-end SoCs based on a zero in the x0x place. + return modelNumber.charAt(1) == '0'; + } + + public static void initialize(Context context, String glRenderer) { ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo(); if (configInfo.reqGlEsVersion != ConfigurationInfo.GL_ES_VERSION_UNDEFINED) { LimeLog.info("OpenGL ES version: "+configInfo.reqGlEsVersion); + isLowEndSnapdragon = isLowEndSnapdragonRenderer(glRenderer); + // Tegra K1 and later can do reference frame invalidation properly if (configInfo.reqGlEsVersion >= 0x30000) { LimeLog.info("Added omx.nvidia to AVC reference frame invalidation support list"); refFrameInvalidationAvcPrefixes.add("omx.nvidia"); - LimeLog.info("Added omx.qcom to AVC reference frame invalidation support list"); - refFrameInvalidationAvcPrefixes.add("omx.qcom"); + LimeLog.info("Added omx.qcom to AVC reference frame invalidation support list"); + refFrameInvalidationAvcPrefixes.add("omx.qcom"); // Prior to M, we were tricking the decoder into using baseline profile, which // won't support RFI properly. @@ -247,7 +273,11 @@ public class MediaCodecHelper { return isDecoderInList(baselineProfileHackPrefixes, decoderName); } - public static boolean decoderSupportsRefFrameInvalidationAvc(String 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) { + return false; + } return isDecoderInList(refFrameInvalidationAvcPrefixes, decoderName); } diff --git a/decoder-errata.txt b/decoder-errata.txt index bf09c560..f2321095 100644 --- a/decoder-errata.txt +++ b/decoder-errata.txt @@ -28,4 +28,7 @@ This file serves to document some of the decoder errata when using MediaCodec ha - Affected decoders: Intel decoder in Nexus Player (after Android 6.0) 10. Some decoders actually suffer increased latency when max_dec_frame_buffering=1 - - Affected decoders: MediaTek decoder in Fire TV 2015 \ No newline at end of file + - Affected decoders: MediaTek decoder in Fire TV 2015 + +11. Attempting to use reference picture invalidation at 1080p causes the decoder to crash on low-end Snapdragon SoCs. 720p is unaffected. + - Affected decoders: Snapdragon 200, 410, 415, 430, 435, 616