19e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu/*
29e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu * Copyright 2015 The Android Open Source Project
39e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu *
49e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu * Licensed under the Apache License, Version 2.0 (the "License");
59e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu * you may not use this file except in compliance with the License.
69e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu * You may obtain a copy of the License at
79e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu *
89e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu *      http://www.apache.org/licenses/LICENSE-2.0
99e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu *
109e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu * Unless required by applicable law or agreed to in writing, software
119e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu * distributed under the License is distributed on an "AS IS" BASIS,
129e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu * See the License for the specific language governing permissions and
149e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu * limitations under the License.
159e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu */
169e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
179e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu//#define LOG_NDEBUG 0
189e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu#define LOG_TAG "MediaCodecListOverrides"
199e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu#include <utils/Log.h>
209e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
219e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu#include "MediaCodecListOverrides.h"
229e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
2319352b3287480394aa9963276305d5168a7adf85Ronghua Wu#include <cutils/properties.h>
249e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu#include <gui/Surface.h>
259e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu#include <media/ICrypto.h>
269e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu#include <media/IMediaCodecList.h>
279e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu#include <media/MediaCodecInfo.h>
289ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu#include <media/MediaResourcePolicy.h>
2979608158c2254fe1357959157f2d0c1560a8a6c6Chong Zhang#include <media/openmax/OMX_IVCommon.h>
309e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu#include <media/stagefright/foundation/AMessage.h>
319e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu#include <media/stagefright/MediaCodec.h>
3279608158c2254fe1357959157f2d0c1560a8a6c6Chong Zhang#include <media/stagefright/MediaCodecList.h>
339e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
349e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wunamespace android {
359e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
3665c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wuconst char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml";
3765c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu
3819352b3287480394aa9963276305d5168a7adf85Ronghua WuAString getProfilingVersionString() {
3919352b3287480394aa9963276305d5168a7adf85Ronghua Wu    char val[PROPERTY_VALUE_MAX];
4019352b3287480394aa9963276305d5168a7adf85Ronghua Wu    if (property_get("ro.build.display.id", val, NULL) && (strlen(val) > 0)) {
4119352b3287480394aa9963276305d5168a7adf85Ronghua Wu        return AStringPrintf("<!-- Profiled-with: %s -->", val);
4219352b3287480394aa9963276305d5168a7adf85Ronghua Wu    }
4319352b3287480394aa9963276305d5168a7adf85Ronghua Wu
4419352b3287480394aa9963276305d5168a7adf85Ronghua Wu    return "<!-- Profiled-with: UNKNOWN_BUILD_ID -->";
4519352b3287480394aa9963276305d5168a7adf85Ronghua Wu}
4619352b3287480394aa9963276305d5168a7adf85Ronghua Wu
479e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu// a limit to avoid allocating unreasonable number of codec instances in the measurement.
489e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu// this should be in sync with the MAX_SUPPORTED_INSTANCES defined in MediaCodecInfo.java.
499e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wustatic const int kMaxInstances = 32;
509e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
519e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu// TODO: move MediaCodecInfo to C++. Until then, some temp methods to parse out info.
5240d8899f60c5212af9d727ba0ffaaecf676ebd1dChih-Hung Hsiehstatic bool getMeasureSize(const sp<MediaCodecInfo::Capabilities> &caps, int32_t *width, int32_t *height) {
539e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    AString sizeRange;
549e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (!caps->getDetails()->findString("size-range", &sizeRange)) {
559e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        return false;
569e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
579e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    AString minSize;
589e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    AString maxSize;
599e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (!splitString(sizeRange, "-", &minSize, &maxSize)) {
609e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        return false;
619e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
629e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    AString sWidth;
639e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    AString sHeight;
649e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (!splitString(minSize, "x", &sWidth, &sHeight)) {
659e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        if (!splitString(minSize, "*", &sWidth, &sHeight)) {
669e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            return false;
679e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        }
689e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
699e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
709e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    *width = strtol(sWidth.c_str(), NULL, 10);
719e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    *height = strtol(sHeight.c_str(), NULL, 10);
729e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    return (*width > 0) && (*height > 0);
739e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu}
749e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
7540d8899f60c5212af9d727ba0ffaaecf676ebd1dChih-Hung Hsiehstatic void getMeasureBitrate(const sp<MediaCodecInfo::Capabilities> &caps, int32_t *bitrate) {
769e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    // Until have native MediaCodecInfo, we cannot get bitrates based on profile/levels.
779e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    // We use 200000 as default value for our measurement.
789e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    *bitrate = 200000;
799e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    AString bitrateRange;
809e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (!caps->getDetails()->findString("bitrate-range", &bitrateRange)) {
819e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        return;
829e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
839e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    AString minBitrate;
849e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    AString maxBitrate;
859e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (!splitString(bitrateRange, "-", &minBitrate, &maxBitrate)) {
869e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        return;
879e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
889e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
899e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    *bitrate = strtol(minBitrate.c_str(), NULL, 10);
909e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu}
919e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
929e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wustatic sp<AMessage> getMeasureFormat(
9340d8899f60c5212af9d727ba0ffaaecf676ebd1dChih-Hung Hsieh        bool isEncoder, const AString &mime, const sp<MediaCodecInfo::Capabilities> &caps) {
949e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    sp<AMessage> format = new AMessage();
959e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    format->setString("mime", mime);
969e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
979e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (isEncoder) {
989e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        int32_t bitrate = 0;
999e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        getMeasureBitrate(caps, &bitrate);
1009e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        format->setInt32("bitrate", bitrate);
10179608158c2254fe1357959157f2d0c1560a8a6c6Chong Zhang        format->setInt32("encoder", 1);
1029e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
1039e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
1049e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (mime.startsWith("video/")) {
1059e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        int32_t width = 0;
1069e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        int32_t height = 0;
1079e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        if (!getMeasureSize(caps, &width, &height)) {
1089e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            return NULL;
1099e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        }
1109e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        format->setInt32("width", width);
1119e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        format->setInt32("height", height);
1129e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
1139e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        Vector<uint32_t> colorFormats;
1149e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        caps->getSupportedColorFormats(&colorFormats);
1159e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        if (colorFormats.size() == 0) {
1169e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            return NULL;
1179e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        }
1189e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        format->setInt32("color-format", colorFormats[0]);
1199e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
1209e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        format->setFloat("frame-rate", 10.0);
1219e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        format->setInt32("i-frame-interval", 10);
1229e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    } else {
1239e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        // TODO: profile hw audio
1249e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        return NULL;
1259e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
1269e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
1279e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    return format;
1289e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu}
1299e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
1309e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wustatic size_t doProfileCodecs(
13140d8899f60c5212af9d727ba0ffaaecf676ebd1dChih-Hung Hsieh        bool isEncoder, const AString &name, const AString &mime, const sp<MediaCodecInfo::Capabilities> &caps) {
1329e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    sp<AMessage> format = getMeasureFormat(isEncoder, mime, caps);
1339e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (format == NULL) {
1349e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        return 0;
1359e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
1369e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    ALOGV("doProfileCodecs %s %s %s %s",
1379e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            name.c_str(), mime.c_str(), isEncoder ? "encoder" : "decoder",
1389e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            format->debugString().c_str());
1399e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
1409e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    status_t err = OK;
1419e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    Vector<sp<MediaCodec>> codecs;
1429e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    while (err == OK && codecs.size() < kMaxInstances) {
1439e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        sp<ALooper> looper = new ALooper;
1449e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        looper->setName("MediaCodec_looper");
145ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar        ALOGV("doProfileCodecs for codec #%zu", codecs.size());
1469e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        ALOGV("doProfileCodecs start looper");
1479e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        looper->start(
1489e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                false /* runOnCallingThread */, false /* canCallJava */, ANDROID_PRIORITY_AUDIO);
1499e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        ALOGV("doProfileCodecs CreateByComponentName");
1509e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        sp<MediaCodec> codec = MediaCodec::CreateByComponentName(looper, name.c_str(), &err);
1519e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        if (err != OK) {
1529e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            ALOGV("Failed to create codec: %s", name.c_str());
1539e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            break;
1549e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        }
1559e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        const sp<Surface> nativeWindow;
1569e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        const sp<ICrypto> crypto;
15779608158c2254fe1357959157f2d0c1560a8a6c6Chong Zhang        uint32_t flags = isEncoder ? MediaCodec::CONFIGURE_FLAG_ENCODE : 0;
1589e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        ALOGV("doProfileCodecs configure");
1599e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        err = codec->configure(format, nativeWindow, crypto, flags);
1609e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        if (err != OK) {
1619e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            ALOGV("Failed to configure codec: %s with mime: %s", name.c_str(), mime.c_str());
1629e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            codec->release();
1639e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            break;
1649e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        }
1659e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        ALOGV("doProfileCodecs start");
1669e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        err = codec->start();
1679e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        if (err != OK) {
1689e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            ALOGV("Failed to start codec: %s with mime: %s", name.c_str(), mime.c_str());
1699e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            codec->release();
1709e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            break;
1719e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        }
1729e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        codecs.push_back(codec);
1739e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
1749e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
1759e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    for (size_t i = 0; i < codecs.size(); ++i) {
1769e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        ALOGV("doProfileCodecs release %s", name.c_str());
1779e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        err = codecs[i]->release();
1789e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        if (err != OK) {
1799e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            ALOGE("Failed to release codec: %s with mime: %s", name.c_str(), mime.c_str());
1809e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        }
1819e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
1829e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
1839e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    return codecs.size();
1849e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu}
1859e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
1869e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wubool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2) {
1879e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    ssize_t pos = s.find(delimiter.c_str());
1889e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (pos < 0) {
1899e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        return false;
1909e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
1919e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    *s1 = AString(s, 0, pos);
1929e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    *s2 = AString(s, pos + 1, s.size() - pos - 1);
1939e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    return true;
1949e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu}
1959e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
1969e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wubool splitString(
1979e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        const AString &s, const AString &delimiter, AString *s1, AString *s2, AString *s3) {
1989e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    AString temp;
1999e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (!splitString(s, delimiter, s1, &temp)) {
2009e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        return false;
2019e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
2029e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (!splitString(temp, delimiter, s2, s3)) {
2039e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        return false;
2049e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
2059e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    return true;
2069e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu}
2079e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
20865c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wuvoid profileCodecs(const Vector<sp<MediaCodecInfo>> &infos) {
2099ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu    CodecSettings global_results;
21065c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    KeyedVector<AString, CodecSettings> encoder_results;
21165c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    KeyedVector<AString, CodecSettings> decoder_results;
2129ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu    profileCodecs(infos, &global_results, &encoder_results, &decoder_results);
21365c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    exportResultsToXML(kProfilingResults, global_results, encoder_results, decoder_results);
21465c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu}
21565c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu
2169e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wuvoid profileCodecs(
2179e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        const Vector<sp<MediaCodecInfo>> &infos,
2189ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu        CodecSettings *global_results,
21965c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        KeyedVector<AString, CodecSettings> *encoder_results,
22065c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        KeyedVector<AString, CodecSettings> *decoder_results,
2219e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        bool forceToMeasure) {
2229e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    KeyedVector<AString, sp<MediaCodecInfo::Capabilities>> codecsNeedMeasure;
2239ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu    AString supportMultipleSecureCodecs = "true";
2249e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    for (size_t i = 0; i < infos.size(); ++i) {
2259e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        const sp<MediaCodecInfo> info = infos[i];
2269e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        AString name = info->getCodecName();
2279e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        if (name.startsWith("OMX.google.") ||
2289e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                // TODO: reenable below codecs once fixed
2299e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                name == "OMX.Intel.VideoDecoder.VP9.hybrid") {
2309e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            continue;
2319e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        }
2329e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
2339e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        Vector<AString> mimes;
2349e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        info->getSupportedMimes(&mimes);
2359e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        for (size_t i = 0; i < mimes.size(); ++i) {
2369e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            const sp<MediaCodecInfo::Capabilities> &caps =
2379e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                    info->getCapabilitiesFor(mimes[i].c_str());
2380f29c9d205ff03286da629d30fddd5dd5ca020dbRonghua Wu            if (!forceToMeasure &&
2390f29c9d205ff03286da629d30fddd5dd5ca020dbRonghua Wu                (caps->getDetails()->contains("max-supported-instances") ||
2400f29c9d205ff03286da629d30fddd5dd5ca020dbRonghua Wu                 caps->getDetails()->contains("max-concurrent-instances"))) {
2419e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                continue;
2429e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            }
2439e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
2449e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            size_t max = doProfileCodecs(info->isEncoder(), name, mimes[i], caps);
2459e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            if (max > 0) {
2469e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                CodecSettings settings;
2479e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                char maxStr[32];
248ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar                sprintf(maxStr, "%zu", max);
2499e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                settings.add("max-supported-instances", maxStr);
2509e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
2519e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                AString key = name;
2529e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                key.append(" ");
2539e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                key.append(mimes[i]);
2549e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
25565c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                if (info->isEncoder()) {
25665c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                    encoder_results->add(key, settings);
25765c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                } else {
25865c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                    decoder_results->add(key, settings);
25965c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                }
2609ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu
2619ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu                if (name.endsWith(".secure")) {
2629ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu                    if (max <= 1) {
2639ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu                        supportMultipleSecureCodecs = "false";
2649ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu                    }
2659ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu                }
2669e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            }
2679e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        }
2689e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
2699ba21b9418d10ddcc39f08901e24fbf43d82b2bcRonghua Wu    global_results->add(kPolicySupportsMultipleSecureCodecs, supportMultipleSecureCodecs);
2709e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu}
2719e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
27240d8899f60c5212af9d727ba0ffaaecf676ebd1dChih-Hung Hsiehstatic AString globalResultsToXml(const CodecSettings &results) {
27365c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    AString ret;
2749e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    for (size_t i = 0; i < results.size(); ++i) {
27565c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        AString setting = AStringPrintf(
27665c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                "        <Setting name=\"%s\" value=\"%s\" />\n",
27765c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                results.keyAt(i).c_str(),
27865c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                results.valueAt(i).c_str());
27965c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        ret.append(setting);
2809e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
28165c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    return ret;
28265c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu}
2839e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
28440d8899f60c5212af9d727ba0ffaaecf676ebd1dChih-Hung Hsiehstatic AString codecResultsToXml(const KeyedVector<AString, CodecSettings> &results) {
28565c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    AString ret;
2869e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    for (size_t i = 0; i < results.size(); ++i) {
2879e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        AString name;
2889e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        AString mime;
28965c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        if (!splitString(results.keyAt(i), " ", &name, &mime)) {
2909e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            continue;
2919e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        }
29265c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        AString codec =
29365c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                AStringPrintf("        <MediaCodec name=\"%s\" type=\"%s\" update=\"true\" >\n",
29465c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                              name.c_str(),
29565c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                              mime.c_str());
29665c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        ret.append(codec);
29740d8899f60c5212af9d727ba0ffaaecf676ebd1dChih-Hung Hsieh        const CodecSettings &settings = results.valueAt(i);
2989e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        for (size_t i = 0; i < settings.size(); ++i) {
2999e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            // WARNING: we assume all the settings are "Limit". Currently we have only one type
3009e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu            // of setting in this case, which is "max-supported-instances".
30165c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu            AString setting = AStringPrintf(
30265c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu                    "            <Limit name=\"%s\" value=\"%s\" />\n",
3039e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                    settings.keyAt(i).c_str(),
3049e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu                    settings.valueAt(i).c_str());
30565c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu            ret.append(setting);
3069e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        }
30765c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        ret.append("        </MediaCodec>\n");
30865c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    }
30965c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    return ret;
31065c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu}
31165c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu
31265c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wuvoid exportResultsToXML(
31365c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        const char *fileName,
31440d8899f60c5212af9d727ba0ffaaecf676ebd1dChih-Hung Hsieh        const CodecSettings &global_results,
31540d8899f60c5212af9d727ba0ffaaecf676ebd1dChih-Hung Hsieh        const KeyedVector<AString, CodecSettings> &encoder_results,
31640d8899f60c5212af9d727ba0ffaaecf676ebd1dChih-Hung Hsieh        const KeyedVector<AString, CodecSettings> &decoder_results) {
31765c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    if (global_results.size() == 0 && encoder_results.size() == 0 && decoder_results.size() == 0) {
31865c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        return;
3199e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
3209e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
32165c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    AString overrides;
32219352b3287480394aa9963276305d5168a7adf85Ronghua Wu    overrides.append(getProfilingVersionString());
32319352b3287480394aa9963276305d5168a7adf85Ronghua Wu    overrides.append("\n");
32465c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    overrides.append("<MediaCodecs>\n");
32565c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    if (global_results.size() > 0) {
32665c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        overrides.append("    <Settings>\n");
32765c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        overrides.append(globalResultsToXml(global_results));
32865c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        overrides.append("    </Settings>\n");
32965c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    }
33065c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    if (encoder_results.size() > 0) {
33165c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        overrides.append("    <Encoders>\n");
33265c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        overrides.append(codecResultsToXml(encoder_results));
33365c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        overrides.append("    </Encoders>\n");
33465c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    }
33565c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    if (decoder_results.size() > 0) {
33665c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        overrides.append("    <Decoders>\n");
33765c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        overrides.append(codecResultsToXml(decoder_results));
33865c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu        overrides.append("    </Decoders>\n");
3393b0da19c78f6a61ed343a07f2448b94faafe4c02Lajos Molnar    }
34065c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    overrides.append("</MediaCodecs>\n");
3419e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
34265c8fbcf91f0f0b5f60a45d2777c36d396c4ba16Ronghua Wu    FILE *f = fopen(fileName, "wb");
3439e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (f == NULL) {
3449e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        ALOGE("Failed to open %s for writing.", fileName);
3459e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        return;
3469e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
3479e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    if (fwrite(overrides.c_str(), 1, overrides.size(), f) != overrides.size()) {
3489e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu        ALOGE("Failed to write to %s.", fileName);
3499e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    }
3509e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu    fclose(f);
3519e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu}
3529e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu
3539e6955a19bf77ebf27b770e910efbe1ebf1ceac0Ronghua Wu}  // namespace android
354