CCodec: handle vendor parameters

Bug: 142705928
Test: atest ccodec_unit_test:CCodecConfigTest
Change-Id: Ib3fe12d8e6f6785567c9f0ebd74e8ffce6a84322
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index d2f5ea7..870f8bd 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -20,7 +20,6 @@
 #include <log/log.h>
 
 #include <C2Component.h>
-#include <C2Debug.h>
 #include <C2Param.h>
 #include <util/C2InterfaceHelper.h>
 
@@ -49,6 +48,27 @@
 
 namespace {
 
+void C2ValueToMessageItem(const C2Value &value, AMessage::ItemData &item) {
+    int32_t int32Value;
+    uint32_t uint32Value;
+    int64_t int64Value;
+    uint64_t uint64Value;
+    float floatValue;
+    if (value.get(&int32Value)) {
+        item.set(int32Value);
+    } else if (value.get(&uint32Value) && uint32Value <= uint32_t(INT32_MAX)) {
+        // SDK does not support unsigned values
+        item.set((int32_t)uint32Value);
+    } else if (value.get(&int64Value)) {
+        item.set(int64Value);
+    } else if (value.get(&uint64Value) && uint64Value <= uint64_t(INT64_MAX)) {
+        // SDK does not support unsigned values
+        item.set((int64_t)uint64Value);
+    } else if (value.get(&floatValue)) {
+        item.set(floatValue);
+    }
+}
+
 /**
  * mapping between SDK and Codec 2.0 configurations.
  */
@@ -138,27 +158,10 @@
     /// Maps from a C2Value to an SDK value in an AMessage.
     AMessage::ItemData mapToMessage(C2Value value) const {
         AMessage::ItemData item;
-        int32_t int32Value;
-        uint32_t uint32Value;
-        int64_t int64Value;
-        uint64_t uint64Value;
-        float floatValue;
         if (value.type() != C2Value::NO_INIT && mReverse) {
             value = mReverse(value);
         }
-        if (value.get(&int32Value)) {
-            item.set(int32Value);
-        } else if (value.get(&uint32Value) && uint32Value <= uint32_t(INT32_MAX)) {
-            // SDK does not support unsigned values
-            item.set((int32_t)uint32Value);
-        } else if (value.get(&int64Value)) {
-            item.set(int64Value);
-        } else if (value.get(&uint64Value) && uint64Value <= uint64_t(INT64_MAX)) {
-            // SDK does not support unsigned values
-            item.set((int64_t)uint64Value);
-        } else if (value.get(&floatValue)) {
-            item.set(floatValue);
-        }
+        C2ValueToMessageItem(value, item);
         return item;
     }
 
@@ -179,10 +182,10 @@
 
 template <typename PORT, typename STREAM>
 AString QueryMediaTypeImpl(
-        const std::shared_ptr<Codec2Client::Component> &component) {
+        const std::shared_ptr<Codec2Client::Configurable> &configurable) {
     AString mediaType;
     std::vector<std::unique_ptr<C2Param>> queried;
-    c2_status_t c2err = component->query(
+    c2_status_t c2err = configurable->query(
             {}, { PORT::PARAM_TYPE, STREAM::PARAM_TYPE }, C2_DONT_BLOCK, &queried);
     if (c2err != C2_OK && queried.size() == 0) {
         ALOGD("Query media type failed => %s", asString(c2err));
@@ -207,13 +210,13 @@
 }
 
 AString QueryMediaType(
-        bool input, const std::shared_ptr<Codec2Client::Component> &component) {
+        bool input, const std::shared_ptr<Codec2Client::Configurable> &configurable) {
     typedef C2PortMediaTypeSetting P;
     typedef C2StreamMediaTypeSetting S;
     if (input) {
-        return QueryMediaTypeImpl<P::input, S::input>(component);
+        return QueryMediaTypeImpl<P::input, S::input>(configurable);
     } else {
-        return QueryMediaTypeImpl<P::output, S::output>(component);
+        return QueryMediaTypeImpl<P::output, S::output>(configurable);
     }
 }
 
@@ -825,27 +828,27 @@
 }
 
 status_t CCodecConfig::initialize(
-        const std::shared_ptr<Codec2Client> &client,
-        const std::shared_ptr<Codec2Client::Component> &component) {
+        const std::shared_ptr<C2ParamReflector> &reflector,
+        const std::shared_ptr<Codec2Client::Configurable> &configurable) {
     C2ComponentDomainSetting domain(C2Component::DOMAIN_OTHER);
     C2ComponentKindSetting kind(C2Component::KIND_OTHER);
 
     std::vector<std::unique_ptr<C2Param>> queried;
-    c2_status_t c2err = component->query({ &domain, &kind }, {}, C2_DONT_BLOCK, &queried);
+    c2_status_t c2err = configurable->query({ &domain, &kind }, {}, C2_DONT_BLOCK, &queried);
     if (c2err != C2_OK) {
         ALOGD("Query domain & kind failed => %s", asString(c2err));
         // TEMP: determine kind from component name
         if (kind.value == C2Component::KIND_OTHER) {
-            if (component->getName().find("encoder") != std::string::npos) {
+            if (configurable->getName().find("encoder") != std::string::npos) {
                 kind.value = C2Component::KIND_ENCODER;
-            } else if (component->getName().find("decoder") != std::string::npos) {
+            } else if (configurable->getName().find("decoder") != std::string::npos) {
                 kind.value = C2Component::KIND_DECODER;
             }
         }
 
         // TEMP: determine domain from media type (port (preferred) or stream #0)
         if (domain.value == C2Component::DOMAIN_OTHER) {
-            AString mediaType = QueryMediaType(true /* input */, component);
+            AString mediaType = QueryMediaType(true /* input */, configurable);
             if (mediaType.startsWith("audio/")) {
                 domain.value = C2Component::DOMAIN_AUDIO;
             } else if (mediaType.startsWith("video/")) {
@@ -870,16 +873,16 @@
     std::vector<C2Param::Index> paramIndices;
     switch (kind.value) {
     case C2Component::KIND_DECODER:
-        mCodingMediaType = QueryMediaType(true /* input */, component).c_str();
+        mCodingMediaType = QueryMediaType(true /* input */, configurable).c_str();
         break;
     case C2Component::KIND_ENCODER:
-        mCodingMediaType = QueryMediaType(false /* input */, component).c_str();
+        mCodingMediaType = QueryMediaType(false /* input */, configurable).c_str();
         break;
     default:
         mCodingMediaType = "";
     }
 
-    c2err = component->querySupportedParams(&mParamDescs);
+    c2err = configurable->querySupportedParams(&mParamDescs);
     if (c2err != C2_OK) {
         ALOGD("Query supported params failed after returning %zu values => %s",
                 mParamDescs.size(), asString(c2err));
@@ -889,9 +892,9 @@
         mSupportedIndices.emplace(desc->index());
     }
 
-    mReflector = client->getParamReflector();
+    mReflector = reflector;
     if (mReflector == nullptr) {
-        ALOGE("Failed to get param reflector");
+        ALOGE("Null param reflector");
         return UNKNOWN_ERROR;
     }
 
@@ -945,11 +948,21 @@
     // init data (CSD)
     mSubscribedIndices.emplace(C2StreamInitDataInfo::output::PARAM_TYPE);
 
+    for (const std::shared_ptr<C2ParamDescriptor> &desc : mParamDescs) {
+        if (desc->index().isVendor()) {
+            std::vector<std::string> keys;
+            mParamUpdater->getKeysForParamIndex(desc->index(), &keys);
+            for (const std::string &key : keys) {
+                mVendorParamIndices.insert_or_assign(key, desc->index());
+            }
+        }
+    }
+
     return OK;
 }
 
 status_t CCodecConfig::subscribeToConfigUpdate(
-        const std::shared_ptr<Codec2Client::Component> &component,
+        const std::shared_ptr<Codec2Client::Configurable> &configurable,
         const std::vector<C2Param::Index> &indices,
         c2_blocking_t blocking) {
     mSubscribedIndices.insert(indices.begin(), indices.end());
@@ -962,7 +975,7 @@
         std::unique_ptr<C2SubscribedParamIndicesTuning> subscribeTuning =
             C2SubscribedParamIndicesTuning::AllocUnique(indices);
         std::vector<std::unique_ptr<C2SettingResult>> results;
-        c2_status_t c2Err = component->config({ subscribeTuning.get() }, blocking, &results);
+        c2_status_t c2Err = configurable->config({ subscribeTuning.get() }, blocking, &results);
         if (c2Err != C2_OK && c2Err != C2_BAD_INDEX) {
             ALOGD("Failed to subscribe to parameters => %s", asString(c2Err));
             // TODO: error
@@ -974,11 +987,11 @@
 }
 
 status_t CCodecConfig::queryConfiguration(
-        const std::shared_ptr<Codec2Client::Component> &component) {
+        const std::shared_ptr<Codec2Client::Configurable> &configurable) {
     // query all subscribed parameters
     std::vector<C2Param::Index> indices(mSubscribedIndices.begin(), mSubscribedIndices.end());
     std::vector<std::unique_ptr<C2Param>> queried;
-    c2_status_t c2Err = component->query({}, indices, C2_MAY_BLOCK, &queried);
+    c2_status_t c2Err = configurable->query({}, indices, C2_MAY_BLOCK, &queried);
     if (c2Err != OK) {
         ALOGI("query failed after returning %zu values (%s)", queried.size(), asString(c2Err));
         // TODO: error
@@ -1048,7 +1061,7 @@
     if (domain & mInputDomain) {
         sp<AMessage> oldFormat = mInputFormat;
         mInputFormat = mInputFormat->dup(); // trigger format changed
-        mInputFormat->extend(getSdkFormatForDomain(reflected, mInputDomain));
+        mInputFormat->extend(getFormatForDomain(reflected, mInputDomain));
         if (mInputFormat->countEntries() != oldFormat->countEntries()
                 || mInputFormat->changesFrom(oldFormat)->countEntries() > 0) {
             changed = true;
@@ -1059,7 +1072,7 @@
     if (domain & mOutputDomain) {
         sp<AMessage> oldFormat = mOutputFormat;
         mOutputFormat = mOutputFormat->dup(); // trigger output format changed
-        mOutputFormat->extend(getSdkFormatForDomain(reflected, mOutputDomain));
+        mOutputFormat->extend(getFormatForDomain(reflected, mOutputDomain));
         if (mOutputFormat->countEntries() != oldFormat->countEntries()
                 || mOutputFormat->changesFrom(oldFormat)->countEntries() > 0) {
             changed = true;
@@ -1071,8 +1084,9 @@
     return changed;
 }
 
-sp<AMessage> CCodecConfig::getSdkFormatForDomain(
-        const ReflectedParamUpdater::Dict &reflected, Domain portDomain) const {
+sp<AMessage> CCodecConfig::getFormatForDomain(
+        const ReflectedParamUpdater::Dict &reflected,
+        Domain portDomain) const {
     sp<AMessage> msg = new AMessage;
     for (const std::pair<std::string, std::vector<ConfigMapper>> &el : mStandardParams->getKeys()) {
         for (const ConfigMapper &cm : el.second) {
@@ -1103,6 +1117,39 @@
         }
     }
 
+    bool input = (portDomain & Domain::IS_INPUT);
+    std::vector<std::string> vendorKeys;
+    for (const std::pair<std::string, ReflectedParamUpdater::Value> &entry : reflected) {
+        auto it = mVendorParamIndices.find(entry.first);
+        if (it == mVendorParamIndices.end()) {
+            continue;
+        }
+        if (mSubscribedIndices.count(it->second) == 0) {
+            continue;
+        }
+        // For vendor parameters, we only care about direction
+        if ((input && !it->second.forInput())
+                || (!input && !it->second.forOutput())) {
+            continue;
+        }
+        const ReflectedParamUpdater::Value &value = entry.second;
+        C2Value c2Value;
+        sp<ABuffer> bufValue;
+        AString strValue;
+        AMessage::ItemData item;
+        if (value.find(&c2Value)) {
+            C2ValueToMessageItem(c2Value, item);
+        } else if (value.find(&bufValue)) {
+            item.set(bufValue);
+        } else if (value.find(&strValue)) {
+            item.set(strValue);
+        } else {
+            ALOGD("unexpected untyped query value for key: %s", entry.first.c_str());
+            continue;
+        }
+        msg->setItem(entry.first.c_str(), item);
+    }
+
     { // convert from Codec 2.0 rect to MediaFormat rect and add crop rect if not present
         int32_t left, top, width, height;
         if (msg->findInt32("crop-left", &left) && msg->findInt32("crop-width", &width)
@@ -1510,7 +1557,7 @@
 }
 
 status_t CCodecConfig::getConfigUpdateFromSdkParams(
-        std::shared_ptr<Codec2Client::Component> component,
+        std::shared_ptr<Codec2Client::Configurable> configurable,
         const sp<AMessage> &sdkParams, Domain configDomain,
         c2_blocking_t blocking,
         std::vector<std::unique_ptr<C2Param>> *configUpdate) const {
@@ -1537,7 +1584,7 @@
         }
     }
 
-    c2_status_t err = component->query({ }, supportedIndices, blocking, configUpdate);
+    c2_status_t err = configurable->query({ }, supportedIndices, blocking, configUpdate);
     if (err != C2_OK) {
         ALOGD("query failed after returning %zu params => %s", configUpdate->size(), asString(err));
     }
@@ -1549,7 +1596,7 @@
 }
 
 status_t CCodecConfig::setParameters(
-        std::shared_ptr<Codec2Client::Component> component,
+        std::shared_ptr<Codec2Client::Configurable> configurable,
         std::vector<std::unique_ptr<C2Param>> &configUpdate,
         c2_blocking_t blocking) {
     status_t result = OK;
@@ -1585,10 +1632,10 @@
         }
     }
     // update subscribed param indices
-    subscribeToConfigUpdate(component, indices, blocking);
+    subscribeToConfigUpdate(configurable, indices, blocking);
 
     std::vector<std::unique_ptr<C2SettingResult>> failures;
-    c2_status_t err = component->config(paramVector, blocking, &failures);
+    c2_status_t err = configurable->config(paramVector, blocking, &failures);
     if (err != C2_OK) {
         ALOGD("config failed => %s", asString(err));
         // This is non-fatal.
@@ -1608,7 +1655,7 @@
     // Re-query parameter values in case config could not update them and update the current
     // configuration.
     configUpdate.clear();
-    err = component->query({}, indices, blocking, &configUpdate);
+    err = configurable->query({}, indices, blocking, &configUpdate);
     if (err != C2_OK) {
         ALOGD("query failed after returning %zu params => %s", configUpdate.size(), asString(err));
     }
@@ -1627,4 +1674,13 @@
     }
 }
 
+status_t CCodecConfig::subscribeToAllVendorParams(
+        const std::shared_ptr<Codec2Client::Configurable> &configurable,
+        c2_blocking_t blocking) {
+    for (const std::pair<std::string, C2Param::Index> &entry : mVendorParamIndices) {
+        mSubscribedIndices.insert(entry.second);
+    }
+    return subscribeToConfigUpdate(configurable, {}, blocking);
+}
+
 }  // namespace android