From 6f05b2af8a96cdd32044c14efd81d60abb306b19 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Tue, 21 Oct 2014 19:20:54 -0400 Subject: [PATCH] Attempt to detect Exynos 4 to apply the bitstream fixup code --- decoder-errata.txt | 6 +- .../video/MediaCodecDecoderRenderer.java | 18 +++++- .../binding/video/MediaCodecHelper.java | 63 +++++++++++++++++++ 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/decoder-errata.txt b/decoder-errata.txt index a4933c57..d761f161 100644 --- a/decoder-errata.txt +++ b/decoder-errata.txt @@ -1,7 +1,7 @@ This file serves to document some of the decoder errata when using MediaCodec hardware decoders on certain devices. -1. num_ref_frames is set to 16 by NVENC which causes decoders to allocate 16+ buffers. This can cause an error on some devices. - - Affected decoders: TI OMAP4, Exynos 4 +1. num_ref_frames is set to 16 by NVENC which causes decoders to allocate 16+ buffers. This can cause an error or lag on some devices. + - Affected decoders: TI OMAP4, Allwinner A20 2. Some decoders have a huge per-frame latency with the unmodified SPS sent from NVENC. Setting max_dec_frame_buffering fixes this latency issue. - Affected decoders: NVIDIA Tegra 3 and 4 @@ -10,7 +10,7 @@ This file serves to document some of the decoder errata when using MediaCodec ha - Affected decoders: TI OMAP4 4. Some decoders require num_ref_frames=1 and max_dec_frame_buffering=1 to avoid crashing on SPS or first I-frame - - Affected decoders: Qualcomm in GS3 on 4.3+ + - Affected decoders: Qualcomm in GS3 on 4.3+, Exynos 4 at 1080p only 5. Some decoders will hang if max_dec_frame_buffering is not present - Affected decoders: MediaTek decoder in Fire HD 7 (2014) diff --git a/src/com/limelight/binding/video/MediaCodecDecoderRenderer.java b/src/com/limelight/binding/video/MediaCodecDecoderRenderer.java index cf91d802..0ba47678 100644 --- a/src/com/limelight/binding/video/MediaCodecDecoderRenderer.java +++ b/src/com/limelight/binding/video/MediaCodecDecoderRenderer.java @@ -22,12 +22,13 @@ import android.media.MediaCodec.CodecException; import android.os.Build; import android.view.SurfaceHolder; +@SuppressWarnings("unused") public class MediaCodecDecoderRenderer implements VideoDecoderRenderer { private ByteBuffer[] videoDecoderInputBuffers; private MediaCodec videoDecoder; private Thread rendererThread; - private boolean needsSpsBitstreamFixup; + private boolean needsSpsBitstreamFixup, isExynos4; private VideoDepacketizer depacketizer; private boolean adaptivePlayback; private int initialWidth, initialHeight; @@ -65,6 +66,10 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer { if (needsSpsBitstreamFixup) { LimeLog.info("Decoder "+decoderName+" needs SPS bitstream restrictions fixup"); } + isExynos4 = MediaCodecHelper.isExynos4Device(); + if (isExynos4) { + LimeLog.info("Decoder "+decoderName+" is on Exynos 4"); + } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @@ -406,7 +411,7 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer { LimeLog.info("Patching num_ref_frames in SPS"); sps.num_ref_frames = 1; - if (needsSpsBitstreamFixup) { + if (needsSpsBitstreamFixup || isExynos4) { // The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag // or max_dec_frame_buffering which increases decoding latency on Tegra. LimeLog.info("Adding bitstream restrictions"); @@ -512,6 +517,15 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer { str += "Buffer codec flags: "+currentCodecFlags+"\n"; } + str += "Is Exynos 4: "+renderer.isExynos4+"\n"; + + str += "/proc/cpuinfo:\n"; + try { + str += MediaCodecHelper.readCpuinfo(); + } catch (Exception e) { + str += e.getMessage(); + } + str += "Full decoder dump:\n"; try { str += MediaCodecHelper.dumpDecoders(); diff --git a/src/com/limelight/binding/video/MediaCodecHelper.java b/src/com/limelight/binding/video/MediaCodecHelper.java index f26a8be9..1e69c773 100644 --- a/src/com/limelight/binding/video/MediaCodecHelper.java +++ b/src/com/limelight/binding/video/MediaCodecHelper.java @@ -1,7 +1,11 @@ package com.limelight.binding.video; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -233,4 +237,63 @@ public class MediaCodecHelper { return null; } + + public static String readCpuinfo() throws Exception { + StringBuilder cpuInfo = new StringBuilder(); + BufferedReader br = new BufferedReader(new FileReader(new File("/proc/cpuinfo"))); + try { + for (;;) { + int ch = br.read(); + if (ch == -1) + break; + cpuInfo.append((char)ch); + } + + return cpuInfo.toString(); + } finally { + br.close(); + } + } + + private static boolean stringContainsIgnoreCase(String string, String substring) { + return string.toLowerCase(Locale.ENGLISH).contains(substring.toLowerCase(Locale.ENGLISH)); + } + + public static boolean isExynos4Device() { + try { + // Try reading CPU info too look for + String cpuInfo = readCpuinfo(); + + // SMDK4xxx is Exynos 4 + if (stringContainsIgnoreCase(cpuInfo, "SMDK4")) { + LimeLog.info("Found SMDK4 in /proc/cpuinfo"); + return true; + } + + // If we see "Exynos 4" also we'll count it + if (stringContainsIgnoreCase(cpuInfo, "Exynos 4")) { + LimeLog.info("Found Exynos 4 in /proc/cpuinfo"); + return true; + } + } catch (Exception e) { + e.printStackTrace(); + } + + try { + File systemDir = new File("/sys/devices/system"); + File[] files = systemDir.listFiles(); + if (files != null) { + for (File f : files) { + if (stringContainsIgnoreCase(f.getName(), "exynos4")) { + LimeLog.info("Found exynos4 in /sys/devices/system"); + return true; + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + return false; + } }