media: Use qcom hardware video decoders if opted in

The H.264/AVC and MPEG2 Qualcomm hardware video decoders are currently
not fully compliant with CTS/GTS requirements and therefore disabled by
default. Allow enabling them if requested by conditionally loading a
media codec xml that declares Qualcomm hardware instead of Google
software decoders for those formats.

The new library gets loaded by the Android mediacodec service and
customizes the codec registration.

Issue: FP2P-529
Change-Id: I0f6c080ec6ffd4f4e2d6ed5f2a5ff3aae2e4dd69
diff --git a/media/Android.mk b/media/Android.mk
new file mode 100644
index 0000000..7a16792
--- /dev/null
+++ b/media/Android.mk
@@ -0,0 +1,3 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/media_codecs_8974_hwdec.xml b/media/media_codecs_8974_hwdec.xml
new file mode 100644
index 0000000..262921d
--- /dev/null
+++ b/media/media_codecs_8974_hwdec.xml
@@ -0,0 +1,254 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012-2013 The Android Open Source Project
+     Copyright (C) 2014 The Linux Foundation. All rights reserved.
+     Not a contribution.
+     Copyright 2018-2021 Fairphone B.V.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+8974 Encoder capabilities
+ ______________________________________________________
+ | Codec    | W       H       fps     Mbps    MB/s    |
+ |__________|_________________________________________|
+ | h264     | 3840    2160    30      100     972000  |
+ |          | 4096    2160    24      100     829440  |
+ | mpeg4    | 1920    1088    30      40      244800  |
+ | vp8      | 1920    1088    30      20      244800  |
+ | h263     | 864     480     30      2       48600   |
+ |__________|_________________________________________|
+
+ 8974 Decoder capabilities
+ ______________________________________________________
+ | Codec    | W       H       fps     Mbps    MB/s    |
+ |__________|_________________________________________|
+ | h264     | 3840    2160    30      100     972000  |
+ |          | 4096    2160    24      100     829440  |
+ | hevc     | 1280    720     30      2       108000  |
+ | hevchybd | 1920    1088    30      6       244800  |
+ | mpeg4    | 1920    1088    60      60      489600  |
+ | vc1      | 1920    1088    60      60      489600  |
+ | vp8      | 3820    2160    30      20      972000  |
+ | divx3    | 720     480     30      2       40500   |
+ | div4/5/6 | 1920    1088    30      10      244800  |
+ | h263     | 864     480     30      2       48600   |
+ | mpeg2    | 1920    1088    30      40      244800  |
+ |__________|_________________________________________|
+
+-->
+
+<MediaCodecs>
+    <Include href="media_codecs_google_audio.xml" />
+    <Include href="media_codecs_google_telephony.xml" />
+    <Settings>
+        <Setting name="max-video-encoder-input-buffers" value="9" />
+    </Settings>
+    <Encoders>
+        <!-- Video Hardware  -->
+        <MediaCodec name="OMX.qcom.video.encoder.avc" type="video/avc" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Quirk name="requires-loaded-to-idle-after-allocation" />
+            <Limit name="size" min="96x64" max="4096x2160" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="972000" />
+            <Limit name="bitrate" range="1-100000000" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.encoder.mpeg4" type="video/mp4v-es" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Quirk name="requires-loaded-to-idle-after-allocation"/>
+            <Limit name="size" min="96x64" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="244800" />
+            <Limit name="bitrate" range="1-40000000" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.encoder.h263" type="video/3gpp" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Quirk name="requires-loaded-to-idle-after-allocation" />
+            <Limit name="size" min="96x64" max="864x480" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="48600" />
+            <Limit name="bitrate" range="1-2000000" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.encoder.vp8" type="video/x-vnd.on2.vp8" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Quirk name="requires-loaded-to-idle-after-allocation" />
+            <Limit name="size" min="96x64" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="244800" />
+            <Limit name="bitrate" range="1-20000000" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+    </Encoders>
+
+    <Decoders>
+        <!-- Video Hardware  -->
+        <MediaCodec name="OMX.qcom.video.decoder.avc" type="video/avc" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="64x64" max="4096x2160" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="972000" />
+            <Limit name="bitrate" range="1-100000000" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <!-- <MediaCodec name="OMX.qcom.video.decoder.avc.secure" type="video/avc" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="64x64" max="4096x2160" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="972000" />
+            <Limit name="bitrate" range="1-100000000" />
+            <Feature name="adaptive-playback" />
+            <Feature name="secure-playback" required="true" />
+            <Limit name="concurrent-instances" max="4" />
+        </MediaCodec> -->
+        <MediaCodec name="OMX.qcom.video.decoder.mpeg2" type="video/mpeg2" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x64" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="244800" />
+            <Limit name="bitrate" range="1-40000000" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.mpeg2.secure" type="video/mpeg2" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="96x64" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="244800" />
+            <Limit name="bitrate" range="1-40000000" />
+            <Feature name="adaptive-playback" />
+            <Feature name="secure-playback" required="true" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.mpeg4" type="video/mp4v-es" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="64x64" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="489600" />
+            <Limit name="bitrate" range="1-60000000" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.h263" type="video/3gpp" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="64x64" max="864x480" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="48600" />
+            <Limit name="bitrate" range="1-2000000" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.vc1" type="video/x-ms-wmv" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="64x64" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="489600" />
+            <Limit name="bitrate" range="1-60000000" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.divx" type="video/divx" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="64x64" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="244800" />
+            <Limit name="bitrate" range="1-10000000" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.divx311" type="video/divx311" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="64x64" max="720x480" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="40500" />
+            <Limit name="bitrate" range="1-2000000" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.divx4" type="video/divx4" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="64x64" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="244800" />
+            <Limit name="bitrate" range="1-10000000" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <MediaCodec name="OMX.qcom.video.decoder.vp8" type="video/x-vnd.on2.vp8" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="64x64" max="3840x2160" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="972000" />
+            <Limit name="bitrate" range="1-20000000" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="13" />
+        </MediaCodec>
+        <!-- <MediaCodec name="OMX.qcom.video.decoder.hevc" type="video/hevc" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="64x64" max="1280x720" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="108000" />
+            <Limit name="bitrate" range="1-2000000" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="3" />
+        </MediaCodec> -->
+        <!-- <MediaCodec name="OMX.qcom.video.decoder.hevchybrid" type="video/hevc" >
+            <Quirk name="requires-allocate-on-input-ports" />
+            <Quirk name="requires-allocate-on-output-ports" />
+            <Limit name="size" min="64x64" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="1" max="244800" />
+            <Limit name="bitrate" range="1-6000000" />
+            <Feature name="adaptive-playback" />
+            <Limit name="concurrent-instances" max="2" />
+        </MediaCodec> -->
+    </Decoders>
+    <Include href="media_codecs_google_video_8974.xml" />
+</MediaCodecs>
diff --git a/media/registrant/Android.mk b/media/registrant/Android.mk
new file mode 100644
index 0000000..d1af2e2
--- /dev/null
+++ b/media/registrant/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libmedia_codecserviceregistrant
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := CodecServiceRegistrant.cpp
+LOCAL_SHARED_LIBRARIES := \
+	libbase \
+	liblog \
+	libutils \
+	libstagefright_omx \
+	libstagefright_xmlparser \
+	android.hardware.media.omx@1.0
+
+LOCAL_VENDOR_MODULE := true
+LOCAL_CFLAGS := -Wall -Werror
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/registrant/CodecServiceRegistrant.cpp b/media/registrant/CodecServiceRegistrant.cpp
new file mode 100644
index 0000000..705ed33
--- /dev/null
+++ b/media/registrant/CodecServiceRegistrant.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016-2018, The Android Open Source Project
+ * Copyright (c) 2021 Fairphone B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "FP2_CodecServiceRegistrant"
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <media/stagefright/omx/1.0/Omx.h>
+#include <media/stagefright/omx/1.0/OmxStore.h>
+
+using namespace android;
+using namespace ::android::hardware::media::omx::V1_0;
+
+static constexpr char const *hwDecProperty = "persist.fp2.use_qcom_hw_vdec";
+static constexpr char const* hwDecMainXmlName = "media_codecs_8974_hwdec.xml";
+
+// Called by frameworks/av/services/mediacodec/main_codecservice.cpp
+extern "C" void RegisterCodecServices() {
+    // Default to software video decoders; only use (legacy) hardware decoders if opted-in.
+    const bool use_qcom_hw_vdec = base::GetBoolProperty(hwDecProperty, false);
+    const char* mainXmlName = use_qcom_hw_vdec
+        ? hwDecMainXmlName
+        : MediaCodecsXmlParser::defaultMainXmlName;
+
+    LOG(INFO) << "FP2: Using Qualcomm hardware video decoders: "
+        << (use_qcom_hw_vdec ? "yes" : "no");
+
+    sp<IOmxStore> omxStore = new implementation::OmxStore(
+            "default",                                  // default parameter value
+            MediaCodecsXmlParser::defaultSearchDirs,    // default parameter value
+            mainXmlName);
+
+    // Everything below comes from main_codecservice.cpp
+    if (omxStore == nullptr) {
+        LOG(ERROR) << "Cannot create IOmxStore HAL service.";
+    } else if (omxStore->registerAsService() != OK) {
+        LOG(ERROR) << "Cannot register IOmxStore HAL service.";
+    }
+    sp<IOmx> omx = new implementation::Omx();
+    if (omx == nullptr) {
+        LOG(ERROR) << "Cannot create IOmx HAL service.";
+    } else if (omx->registerAsService() != OK) {
+        LOG(ERROR) << "Cannot register IOmx HAL service.";
+    } else {
+        LOG(INFO) << "IOmx HAL service created.";
+    }
+}
diff --git a/sepolicy/mediacodec.te b/sepolicy/mediacodec.te
new file mode 100644
index 0000000..8e3dc00
--- /dev/null
+++ b/sepolicy/mediacodec.te
@@ -0,0 +1 @@
+get_prop(mediacodec, fp_misc_settings_prop)
diff --git a/sepolicy/property.te b/sepolicy/property.te
index fee9c77..2cc8974 100644
--- a/sepolicy/property.te
+++ b/sepolicy/property.te
@@ -1 +1,2 @@
+type fp_misc_settings_prop, property_type;
 type shutdown_reason_prop, property_type;
diff --git a/sepolicy/property_contexts b/sepolicy/property_contexts
index eade775..dc298d0 100644
--- a/sepolicy/property_contexts
+++ b/sepolicy/property_contexts
@@ -1,2 +1,4 @@
+persist.fp2.use_qcom_hw_vdec        u:object_r:fp_misc_settings_prop:s0
+
 persist.runtime.shutdown_planned    u:object_r:shutdown_reason_prop:s0
 runtime.last_shutdown_was_clean     u:object_r:shutdown_reason_prop:s0
diff --git a/sepolicy/shell.te b/sepolicy/shell.te
new file mode 100644
index 0000000..8257aff
--- /dev/null
+++ b/sepolicy/shell.te
@@ -0,0 +1,2 @@
+# Allow toggling between software/hardware decoders from the shell
+set_prop(shell, fp_misc_settings_prop)
diff --git a/sepolicy/system_app.te b/sepolicy/system_app.te
index 7bd8cff..ac72cd1 100644
--- a/sepolicy/system_app.te
+++ b/sepolicy/system_app.te
@@ -13,6 +13,7 @@
 allow system_app sensors_persist_file:dir r_dir_perms;
 allow system_app sensors_persist_file:file rw_file_perms;
 
-# Fairphone misc settings files
+# Fairphone misc settings files and properties
 allow system_app fp_misc_settings_file:dir search;
 allow system_app fp_misc_settings_file:file rw_file_perms;
+set_prop(system_app, fp_misc_settings_prop)