From 2cb7d31e226dacc7a89d91b241e2a0b07f7b6ba1 Mon Sep 17 00:00:00 2001 From: zhangyihui1 Date: Sat, 12 Oct 2019 17:39:13 +0800 Subject: [PATCH] Add extra config for white list codec. --- sdk/android/BUILD.gn | 1 + .../webrtc/HardwareVideoDecoderFactory.java | 15 ++-- .../webrtc/HardwareVideoEncoderFactory.java | 22 +++-- .../api/org/webrtc/VideoCapabilityParser.java | 84 +++++++++++++++++++ 4 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 sdk/android/api/org/webrtc/VideoCapabilityParser.java diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index a59b98882ed..f3ab027ae2c 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -383,6 +383,7 @@ if (is_android) { rtc_android_library("hwcodecs_java") { java_files = [ + "api/org/webrtc/VideoCapabilityParser.java", "api/org/webrtc/HardwareVideoDecoderFactory.java", "api/org/webrtc/HardwareVideoEncoderFactory.java", "src/java/org/webrtc/BaseBitrateAdjuster.java", diff --git a/sdk/android/api/org/webrtc/HardwareVideoDecoderFactory.java b/sdk/android/api/org/webrtc/HardwareVideoDecoderFactory.java index 8f88a912e6b..d1ac626d1fe 100644 --- a/sdk/android/api/org/webrtc/HardwareVideoDecoderFactory.java +++ b/sdk/android/api/org/webrtc/HardwareVideoDecoderFactory.java @@ -28,7 +28,8 @@ @SuppressWarnings("deprecation") // API level 16 requires use of deprecated methods. public class HardwareVideoDecoderFactory implements VideoDecoderFactory { private static final String TAG = "HardwareVideoDecoderFactory"; - + private final VideoCapabilityParser vcp = new VideoCapabilityParser(); + private final String extraMediaCodecFile = "sdcard/mediaCodec.xml"; private final EglBase.Context sharedContext; /** Creates a HardwareVideoDecoderFactory that does not use surface textures. */ @@ -132,21 +133,25 @@ private boolean isHardwareSupported(MediaCodecInfo info, VideoCodecType type) { return name.startsWith(QCOM_PREFIX) || name.startsWith(INTEL_PREFIX) || name.startsWith(EXYNOS_PREFIX) || name.startsWith(NVIDIA_PREFIX) // Hisi seems to support VP8. - || name.startsWith(HISI_PREFIX); + || name.startsWith(HISI_PREFIX) + || vcp.isExtraHardwareSupported(name, "video/x-vnd.on2.vp8", vcp.parseWithTag(vcp.loadWithDom(extraMediaCodecFile), "Decoders")); case VP9: // QCOM and Exynos supported for VP9. return name.startsWith(QCOM_PREFIX) || name.startsWith(EXYNOS_PREFIX) // Hisi seems to support VP9. - || name.startsWith(HISI_PREFIX); + || name.startsWith(HISI_PREFIX) + || vcp.isExtraHardwareSupported(name, "video/x-vnd.on2.vp9", vcp.parseWithTag(vcp.loadWithDom(extraMediaCodecFile), "Decoders")); case H264: // QCOM, Intel, and Exynos supported for H264. return name.startsWith(QCOM_PREFIX) || name.startsWith(INTEL_PREFIX) // Hisi seems to support H264. - || name.startsWith(EXYNOS_PREFIX) || name.startsWith(HISI_PREFIX); + || name.startsWith(EXYNOS_PREFIX) || name.startsWith(HISI_PREFIX) + || vcp.isExtraHardwareSupported(name, "video/avc", vcp.parseWithTag(vcp.loadWithDom(extraMediaCodecFile), "Decoders")); case H265: // H265 is copied from H264. More testing is needed. return name.startsWith(QCOM_PREFIX) || name.startsWith(INTEL_PREFIX) - || name.startsWith(EXYNOS_PREFIX) || name.startsWith(HISI_PREFIX); + || name.startsWith(EXYNOS_PREFIX) || name.startsWith(HISI_PREFIX) + || vcp.isExtraHardwareSupported(name, "video/hevc", vcp.parseWithTag(vcp.loadWithDom(extraMediaCodecFile), "Decoders")); default: return false; } diff --git a/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java b/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java index ef4f2b9c7b8..7021516efc7 100644 --- a/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java +++ b/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java @@ -43,6 +43,8 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory { @Nullable private final EglBase14.Context sharedContext; private final boolean enableIntelVp8Encoder; private final boolean enableH264HighProfile; + private final String extraMediaCodecFile = "sdcard/mediaCodec.xml"; + private final VideoCapabilityParser vcp = new VideoCapabilityParser(); public HardwareVideoEncoderFactory( EglBase.Context sharedContext, boolean enableIntelVp8Encoder, boolean enableH264HighProfile) { @@ -185,12 +187,14 @@ private boolean isHardwareSupportedInCurrentSdkVp8(MediaCodecInfo info) { || (name.startsWith(INTEL_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && enableIntelVp8Encoder) // Hisi Vp8 encoder seems to be supported. Needs more testing. - || (name.startsWith(HISI_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT); + || (name.startsWith(HISI_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) + || (vcp.isExtraHardwareSupported(name, "video/x-vnd.on2.vp8", vcp.parseWithTag(vcp.loadWithDom(extraMediaCodecFile), "Encoders")) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT); } private boolean isHardwareSupportedInCurrentSdkVp9(MediaCodecInfo info) { String name = info.getName(); - return (name.startsWith(QCOM_PREFIX) || name.startsWith(EXYNOS_PREFIX) || name.startsWith(HISI_PREFIX)) + return (name.startsWith(QCOM_PREFIX) || name.startsWith(EXYNOS_PREFIX) || name.startsWith(HISI_PREFIX) || vcp.isExtraHardwareSupported(name, "video/x-vnd.on2.vp9", vcp.parseWithTag(vcp.loadWithDom(extraMediaCodecFile), "Encoders"))) + // Just redo an old change on MediaCodecVideoEncoder. Needs more testing. // Both QCOM and Exynos VP9 encoders are supported in N or later. && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; @@ -208,12 +212,20 @@ private boolean isHardwareSupportedInCurrentSdkH264(MediaCodecInfo info) { || (name.startsWith(EXYNOS_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) // Hisi H264 encoder seems to be supported. Needs more testing. - || (name.startsWith(HISI_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT); + || (name.startsWith(HISI_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) + || (vcp.isExtraHardwareSupported(name, "video/avc", vcp.parseWithTag(vcp.loadWithDom(extraMediaCodecFile), "Encoders")) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT); } private boolean isHardwareSupportedInCurrentSdkH265(MediaCodecInfo info) { - // We don't have too much data for H.265. Just use the same configuration for H.264. - return isHardwareSupportedInCurrentSdkH264(info); + String name = info.getName(); + // QCOM H265 encoder is supported in KITKAT or later. + return (name.startsWith(QCOM_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) + // Exynos H265 encoder is supported in LOLLIPOP or later. + || (name.startsWith(EXYNOS_PREFIX) + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) + // Hisi H265 encoder seems to be supported. Needs more testing. + || (name.startsWith(HISI_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) + || (vcp.isExtraHardwareSupported(name, "video/hevc", vcp.parseWithTag(vcp.loadWithDom(extraMediaCodecFile), "Encoders")) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT); } private int getKeyFrameIntervalSec(VideoCodecType type) { diff --git a/sdk/android/api/org/webrtc/VideoCapabilityParser.java b/sdk/android/api/org/webrtc/VideoCapabilityParser.java new file mode 100644 index 00000000000..b749e3c73a1 --- /dev/null +++ b/sdk/android/api/org/webrtc/VideoCapabilityParser.java @@ -0,0 +1,84 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.webrtc.Logging; +import org.xml.sax.SAXException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +public class VideoCapabilityParser { + + public Document loadWithDom(String xmlFilePath) { + Document document = null; + File file = new File(xmlFilePath); + if (file.exists()) { + try { + InputStream inputStream = new FileInputStream(file); + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + document = documentBuilder.parse(inputStream); + } catch (FileNotFoundException e) { + } catch (ParserConfigurationException e) { + } catch (IOException e) { + } catch (SAXException e) { + } + } + return document; + } + + public ArrayList> parseWithTag(Document document, String tag) { + if (document == null) { + return null; + } + ArrayList> extraMediaCodecList = new ArrayList<>(); + NodeList sList = document.getElementsByTagName(tag); + for (int i = 0; i < sList.getLength(); i++) { + Element encoded = (Element) sList.item(i); + NodeList nodeList = encoded.getElementsByTagName("MediaCodec"); + for (i = 0; i < nodeList.getLength(); i++) { + HashMap map = new HashMap<>(); + Node node = nodeList.item(i); + map.put("name", node.getAttributes().getNamedItem("name").getNodeValue()); + map.put("type", node.getAttributes().getNamedItem("type").getNodeValue()); + extraMediaCodecList.add(map); + } + } + return extraMediaCodecList; + } + + public boolean isExtraHardwareSupported(String name , String type, ArrayList> extraMediaCodecMap){ + boolean result = false; + if (extraMediaCodecMap != null) { + for (HashMap item : extraMediaCodecMap){ + if (name.startsWith(item.get("name")) && type.startsWith(item.get("type"))){ + result=true; + break; + } + } + } + return result; + } +}