codec2: add util method to fill Traits from C2ComponentInterface

Bug: 160259947
Test: manual
Change-Id: I630138a1ac193848acd4f933bc571a2ceeaa4f6c
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index 13c90f2..c07c09e 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -982,58 +982,10 @@
 
     std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
     if (traits) {
-        traits->name = intf->getName();
-
-        C2ComponentKindSetting kind;
-        C2ComponentDomainSetting domain;
-        res = intf->query_vb({ &kind, &domain }, {}, C2_MAY_BLOCK, nullptr);
-        bool fixDomain = res != C2_OK;
-        if (res == C2_OK) {
-            traits->kind = kind.value;
-            traits->domain = domain.value;
-        } else {
-            // TODO: remove this fall-back
-            ALOGD("failed to query interface for kind and domain: %d", res);
-
-            traits->kind =
-                (traits->name.find("encoder") != std::string::npos) ? C2Component::KIND_ENCODER :
-                (traits->name.find("decoder") != std::string::npos) ? C2Component::KIND_DECODER :
-                C2Component::KIND_OTHER;
-        }
-
-        uint32_t mediaTypeIndex =
-                traits->kind == C2Component::KIND_ENCODER ? C2PortMediaTypeSetting::output::PARAM_TYPE
-                : C2PortMediaTypeSetting::input::PARAM_TYPE;
-        std::vector<std::unique_ptr<C2Param>> params;
-        res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, &params);
-        if (res != C2_OK) {
-            ALOGD("failed to query interface: %d", res);
+        if (!C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf)) {
+            ALOGD("Failed to fill traits from interface");
             return mInit;
         }
-        if (params.size() != 1u) {
-            ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
-            return mInit;
-        }
-        C2PortMediaTypeSetting *mediaTypeConfig = C2PortMediaTypeSetting::From(params[0].get());
-        if (mediaTypeConfig == nullptr) {
-            ALOGD("failed to query media type");
-            return mInit;
-        }
-        traits->mediaType =
-            std::string(mediaTypeConfig->m.value,
-                        strnlen(mediaTypeConfig->m.value, mediaTypeConfig->flexCount()));
-
-        if (fixDomain) {
-            if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
-                traits->domain = C2Component::DOMAIN_AUDIO;
-            } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
-                traits->domain = C2Component::DOMAIN_VIDEO;
-            } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
-                traits->domain = C2Component::DOMAIN_IMAGE;
-            } else {
-                traits->domain = C2Component::DOMAIN_OTHER;
-            }
-        }
 
         // TODO: get this properly from the store during emplace
         switch (traits->domain) {
@@ -1043,26 +995,6 @@
         default:
             traits->rank = 512;
         }
-
-        params.clear();
-        res = intf->query_vb({}, { C2ComponentAliasesSetting::PARAM_TYPE }, C2_MAY_BLOCK, &params);
-        if (res == C2_OK && params.size() == 1u) {
-            C2ComponentAliasesSetting *aliasesSetting =
-                C2ComponentAliasesSetting::From(params[0].get());
-            if (aliasesSetting) {
-                // Split aliases on ','
-                // This looks simpler in plain C and even std::string would still make a copy.
-                char *aliases = ::strndup(aliasesSetting->m.value, aliasesSetting->flexCount());
-                ALOGD("'%s' has aliases: '%s'", intf->getName().c_str(), aliases);
-
-                for (char *tok, *ptr, *str = aliases; (tok = ::strtok_r(str, ",", &ptr));
-                        str = nullptr) {
-                    traits->aliases.push_back(tok);
-                    ALOGD("adding alias: '%s'", tok);
-                }
-                free(aliases);
-            }
-        }
     }
     mTraits = traits;
 
diff --git a/media/codec2/vndk/include/util/C2InterfaceUtils.h b/media/codec2/vndk/include/util/C2InterfaceUtils.h
index e9037e5..13bdac3 100644
--- a/media/codec2/vndk/include/util/C2InterfaceUtils.h
+++ b/media/codec2/vndk/include/util/C2InterfaceUtils.h
@@ -17,6 +17,7 @@
 #ifndef C2UTILS_INTERFACE_UTILS_H_
 #define C2UTILS_INTERFACE_UTILS_H_
 
+#include <C2Component.h>
 #include <C2Param.h>
 #include <C2Work.h>
 
@@ -1130,6 +1131,19 @@
 
 };
 
+/**
+ * Utility class for C2ComponentInterface
+ */
+struct C2InterfaceUtils {
+    /**
+     * Create traits from C2ComponentInterface. Note that rank cannot be queried from interfaces,
+     * so left untouched.
+     */
+    static bool FillTraitsFromInterface(
+            C2Component::Traits *traits,
+            const std::shared_ptr<C2ComponentInterface> &intf);
+};
+
 #include <util/C2Debug-interface.h>
 
 #endif  // C2UTILS_INTERFACE_UTILS_H_
diff --git a/media/codec2/vndk/util/C2InterfaceUtils.cpp b/media/codec2/vndk/util/C2InterfaceUtils.cpp
index 0c1729b..b5bc691 100644
--- a/media/codec2/vndk/util/C2InterfaceUtils.cpp
+++ b/media/codec2/vndk/util/C2InterfaceUtils.cpp
@@ -21,6 +21,7 @@
 
 #define C2_LOG_VERBOSE
 
+#include <C2Config.h>
 #include <C2Debug.h>
 #include <C2Param.h>
 #include <C2ParamDef.h>
@@ -30,6 +31,7 @@
 #include <cmath>
 #include <limits>
 #include <map>
+#include <sstream>
 #include <type_traits>
 
 #include <android-base/stringprintf.h>
@@ -1304,3 +1306,81 @@
     return std::vector<Info>(location.begin(), location.end());
 }
 
+//static
+bool C2InterfaceUtils::FillTraitsFromInterface(
+        C2Component::Traits *traits,
+        const std::shared_ptr<C2ComponentInterface> &intf) {
+    if (!traits) {
+        return false;
+    }
+    traits->name = intf->getName();
+
+    C2ComponentKindSetting kind;
+    C2ComponentDomainSetting domain;
+    c2_status_t res = intf->query_vb({ &kind, &domain }, {}, C2_MAY_BLOCK, nullptr);
+    bool fixDomain = res != C2_OK;
+    if (res == C2_OK) {
+        traits->kind = kind.value;
+        traits->domain = domain.value;
+    } else {
+        // TODO: remove this fall-back
+        C2_LOG(DEBUG) << "failed to query interface for kind and domain: " << res;
+
+        traits->kind =
+            (traits->name.find("encoder") != std::string::npos) ? C2Component::KIND_ENCODER :
+            (traits->name.find("decoder") != std::string::npos) ? C2Component::KIND_DECODER :
+            C2Component::KIND_OTHER;
+    }
+
+    uint32_t mediaTypeIndex = traits->kind == C2Component::KIND_ENCODER
+            ? C2PortMediaTypeSetting::output::PARAM_TYPE
+            : C2PortMediaTypeSetting::input::PARAM_TYPE;
+    std::vector<std::unique_ptr<C2Param>> params;
+    res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, &params);
+    if (res != C2_OK) {
+        C2_LOG(DEBUG) << "failed to query interface: " << res;
+        return false;
+    }
+    if (params.size() != 1u) {
+        C2_LOG(DEBUG) << "failed to query interface: unexpected vector size: " << params.size();
+        return false;
+    }
+    C2PortMediaTypeSetting *mediaTypeConfig = C2PortMediaTypeSetting::From(params[0].get());
+    if (mediaTypeConfig == nullptr) {
+        C2_LOG(DEBUG) << "failed to query media type";
+        return false;
+    }
+    traits->mediaType =
+        std::string(mediaTypeConfig->m.value,
+                    strnlen(mediaTypeConfig->m.value, mediaTypeConfig->flexCount()));
+
+    if (fixDomain) {
+        if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
+            traits->domain = C2Component::DOMAIN_AUDIO;
+        } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
+            traits->domain = C2Component::DOMAIN_VIDEO;
+        } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
+            traits->domain = C2Component::DOMAIN_IMAGE;
+        } else {
+            traits->domain = C2Component::DOMAIN_OTHER;
+        }
+    }
+
+    params.clear();
+    res = intf->query_vb({}, { C2ComponentAliasesSetting::PARAM_TYPE }, C2_MAY_BLOCK, &params);
+    if (res == C2_OK && params.size() == 1u) {
+        C2ComponentAliasesSetting *aliasesSetting =
+            C2ComponentAliasesSetting::From(params[0].get());
+        if (aliasesSetting) {
+            std::istringstream iss(
+                    std::string(aliasesSetting->m.value, aliasesSetting->flexCount()));
+            C2_LOG(DEBUG) << intf->getName() << " has aliases: " << iss.str();
+
+            for (std::string tok; std::getline(iss, tok, ','); ) {
+                traits->aliases.push_back(tok);
+                C2_LOG(DEBUG) << "adding alias: " << tok;
+            }
+        }
+    }
+    return true;
+}