[Android] [RFC PATCH 2/2] Use HW Decoders before 4.3 for a list of known devices

Thomas Guillem thomas.guillem at gmail.com
Tue Oct 7 15:31:00 CEST 2014


Add HWDecoderUtil: Utility class that return the preferred hardware decoder
(none, mediacodec and/or iomx) from a list of known devices. It's only taking
effect before Android 4.3 as MediaCodec will always be preferred after.

That class use the hidden android.os.SystemProperties API to retrieve
properties like "ro.board.platform" in order to know which device we are
running. That API won't be used after 4.3 as we want to limit the usage of
android private API.
---
 .../src/org/videolan/libvlc/HWDecoderUtil.java     | 123 +++++++++++++++++++++
 vlc-android/src/org/videolan/libvlc/LibVLC.java    |  53 +++++++--
 2 files changed, 168 insertions(+), 8 deletions(-)
 create mode 100644 vlc-android/src/org/videolan/libvlc/HWDecoderUtil.java

diff --git a/vlc-android/src/org/videolan/libvlc/HWDecoderUtil.java b/vlc-android/src/org/videolan/libvlc/HWDecoderUtil.java
new file mode 100644
index 0000000..145a587
--- /dev/null
+++ b/vlc-android/src/org/videolan/libvlc/HWDecoderUtil.java
@@ -0,0 +1,123 @@
+/*****************************************************************************
+ * HWDecUtil.java
+ *****************************************************************************
+ * Copyright © 2010-2013 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+package org.videolan.libvlc;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+/**
+ * Utility class that return the preferred hardware decoder from a list of known devices.
+ */
+public class HWDecoderUtil {
+
+    public enum Decoder {
+        UNKNOWN, NONE, OMX, MEDIACODEC, ALL
+    }
+
+    private static class DecoderBySOC {
+        public final String key;
+        public final Decoder dec;
+        public final String[] list;
+        public DecoderBySOC(String key, Decoder dec, String[] list) {
+            this.key = key;
+            this.dec = dec;
+            this.list = list;
+        }
+    }
+
+    private static final DecoderBySOC[] sDecoderBySOCList = new DecoderBySOC[] {
+        /*
+         *  Put first devices you want to blacklist
+         *  because theses devices can match the next rules.
+         */
+        new DecoderBySOC ("ro.product.brand", Decoder.NONE, new  String[] {
+                "SEMC",             // Xperia S
+        }),
+        new DecoderBySOC ("ro.board.platform", Decoder.NONE, new  String[] {
+                "msm7627",          // QCOM S1
+        }),
+        /*
+         * Devices working on OMX
+         */
+        new DecoderBySOC ("ro.board.platform", Decoder.OMX, new  String[] {
+                "omap3",            // Omap 3
+                "rockchip", "rk29", // Rockchip RK29
+                "tegra",            // Tegra 2
+                "msm7630",          // QCOM S2
+                "s5pc",             // Exynos 3
+                "montblanc",        // Montblanc
+                "exdroid",          // Allwinner A31
+        }),
+        new DecoderBySOC ("ro.hardware", Decoder.OMX, new  String[] {
+                "sun6i",            // Allwinner A31
+        }),
+        /*
+         * Devices working on Mediacodec and OMX
+         */
+        new DecoderBySOC ("ro.board.platform", Decoder.ALL, new  String[] {
+                "omap4",            // Omap 4
+                "msm8660",          // QCOM S3
+                "exynos4",          // Exynos 4 (Samsung Galaxy S2/S3)
+                "exynos5",          // Exynos 5 (Samsung Galaxy S4)
+                "rk30", "rk31",     // Rockchip RK3*
+        }),
+        new DecoderBySOC ("ro.hardware", Decoder.ALL, new  String[] {
+                "mt65", "mt83",     // MTK
+        }),
+    };
+
+    private static final HashMap<String, String> sSystemPropertyMap = new HashMap<String, String>();
+
+    /**
+     * @return the hardware decoder known to work for the running device
+     * (Always return Dec.ALL after Android 4.3)
+     */
+    public static Decoder getDecoderFromDevice() {
+        if (LibVlcUtil.isJellyBeanMR2OrLater())
+            return Decoder.ALL;
+        for (DecoderBySOC decBySOC : sDecoderBySOCList) {
+            String prop = sSystemPropertyMap.get(decBySOC.key);
+            if (prop == null) {
+                prop = getSystemProperty(decBySOC.key, "none");
+                sSystemPropertyMap.put(decBySOC.key, prop);
+            }
+            if (prop != null) {
+                for (String decProp: decBySOC.list)
+                    if (prop.contains(decProp))
+                        return decBySOC.dec;
+            }
+        }
+        return Decoder.UNKNOWN;
+    }
+
+    private static String getSystemProperty(String key, String def) {
+        try {
+            final ClassLoader cl = ClassLoader.getSystemClassLoader();
+            final Class<?> SystemProperties = cl.loadClass("android.os.SystemProperties");
+            final Class<?>[] paramTypes = new Class[] { String.class, String.class };
+            final Method get = SystemProperties.getMethod("get", paramTypes);
+            final Object[] params = new Object[] { key, def };
+            return (String) get.invoke(SystemProperties, params);
+        } catch (Exception e){
+            return def;
+        }
+    }
+}
diff --git a/vlc-android/src/org/videolan/libvlc/LibVLC.java b/vlc-android/src/org/videolan/libvlc/LibVLC.java
index 6d9d3e9..62a16a9 100644
--- a/vlc-android/src/org/videolan/libvlc/LibVLC.java
+++ b/vlc-android/src/org/videolan/libvlc/LibVLC.java
@@ -43,6 +43,8 @@ public class LibVLC {
     public static final int HW_ACCELERATION_DECODING = 1;
     public static final int HW_ACCELERATION_FULL = 2;
 
+    private static final String DEFAULT_CODEC_LIST = "mediacodec,iomx,all";
+
     private static LibVLC sInstance;
 
     /** libVLC instance C pointer */
@@ -65,6 +67,7 @@ public class LibVLC {
 
     /** Settings */
     private int hardwareAcceleration = HW_ACCELERATION_AUTOMATIC;
+    private String codecList = DEFAULT_CODEC_LIST;
     private String subtitlesEncoding = "";
     private int aout = LibVlcUtil.isGingerbreadOrLater() ? AOUT_OPENSLES : AOUT_AUDIOTRACK_JAVA;
     private int vout = VOUT_ANDROID_SURFACE;
@@ -245,15 +248,49 @@ public class LibVLC {
     }
 
     public void setHardwareAcceleration(int hardwareAcceleration) {
-        if (hardwareAcceleration < 0) {
-            // Automatic mode: activate MediaCodec opaque direct rendering for 4.3 and above.
-            if (LibVlcUtil.isJellyBeanMR2OrLater())
-                this.hardwareAcceleration = HW_ACCELERATION_FULL;
-            else
+
+        if (hardwareAcceleration == HW_ACCELERATION_DISABLED) {
+            Log.d(TAG, "HWDec disabled: by user");
+            this.hardwareAcceleration = HW_ACCELERATION_DISABLED;
+            this.codecList = "all";
+        } else {
+            // Automatic or forced
+            HWDecoderUtil.Decoder decoder = HWDecoderUtil.getDecoderFromDevice();
+
+            if (decoder == HWDecoderUtil.Decoder.NONE) {
+                // NONE
                 this.hardwareAcceleration = HW_ACCELERATION_DISABLED;
+                this.codecList = "all";
+                Log.d(TAG, "HWDec disabled: device not working with mediacodec,iomx");
+            } else if (decoder == HWDecoderUtil.Decoder.UNKNOWN) {
+                // UNKNOWN
+                if (hardwareAcceleration < 0) {
+                    this.hardwareAcceleration = HW_ACCELERATION_DISABLED;
+                    this.codecList = "all";
+                    Log.d(TAG, "HWDec disabled: automatic and (unknown device or android version < 4.3)");
+                } else {
+                    this.hardwareAcceleration = hardwareAcceleration;
+                    this.codecList = DEFAULT_CODEC_LIST;
+                    Log.d(TAG, "HWDec enabled: forced by user and unknown device");
+                }
+            } else {
+                // OMX, MEDIACODEC or ALL
+                this.hardwareAcceleration = hardwareAcceleration < 0 ?
+                        HW_ACCELERATION_FULL : hardwareAcceleration;
+                if (decoder == HWDecoderUtil.Decoder.ALL)
+                    this.codecList = DEFAULT_CODEC_LIST;
+                else {
+                    final StringBuilder sb = new StringBuilder();
+                    if (decoder == HWDecoderUtil.Decoder.MEDIACODEC)
+                        sb.append("mediacodec,");
+                    else if (decoder == HWDecoderUtil.Decoder.OMX)
+                        sb.append("iomx,");
+                    sb.append("all");
+                    this.codecList = sb.toString();
+                }
+                Log.d(TAG, "HWDec enabled: device working with: " + this.codecList);
+            }
         }
-        else
-            this.hardwareAcceleration = hardwareAcceleration;
     }
 
     public String[] getMediaOptions(boolean noHardwareAcceleration, boolean noVideo) {
@@ -274,7 +311,7 @@ public class LibVLC {
              */
             options.add(":file-caching=1500");
             options.add(":network-caching=1500");
-            options.add(":codec=mediacodec,iomx,all");
+            options.add(":codec="+this.codecList);
         }
         if (noVideo)
             options.add(":no-video");
-- 
2.1.0



More information about the Android mailing list