diff --git a/c2_components/include/mfx_c2_component.h b/c2_components/include/mfx_c2_component.h index 8a2e10ca..ad7cd7b4 100755 --- a/c2_components/include/mfx_c2_component.h +++ b/c2_components/include/mfx_c2_component.h @@ -37,6 +37,7 @@ class MfxC2Component : public C2ComponentInterface, { int flags{0}; bool dump_output{false}; + uint32_t concurrent_instances{0}; }; protected: /* State diagram: diff --git a/c2_components/src/mfx_c2_component.cpp b/c2_components/src/mfx_c2_component.cpp index e2ad95eb..36f8dd90 100755 --- a/c2_components/src/mfx_c2_component.cpp +++ b/c2_components/src/mfx_c2_component.cpp @@ -22,6 +22,7 @@ #include "mfx_debug.h" #include "mfx_c2_debug.h" #include "mfx_c2_components_registry.h" +#include "mfx_c2_components_monitor.h" using namespace android; @@ -303,6 +304,17 @@ c2_status_t MfxC2Component::start() MFX_DEBUG_TRACE_FUNC; c2_status_t res = C2_OK; + + MfxC2ComponentsMonitor::getInstance().increase(m_name.c_str()); + + // The creating component instances of the same type can't exceece the configured the number of maximum concurrent instances + // And must ensure that C2_NO_MEMORY is returned by start() which because the reclaimResource calling happens in + // MediaCodec::start() in libstagefright + MFX_DEBUG_TRACE_I32(m_createConfig.concurrent_instances); + if (MfxC2ComponentsMonitor::getInstance().get(m_name.c_str()) > m_createConfig.concurrent_instances) { + MFX_DEBUG_TRACE_MSG("Cannot create component, the number of created components has exceeded maximum instance limit."); + return C2_NO_MEMORY; + } // work to be done for state change std::function action = [] () { return C2_CORRUPTED; }; @@ -339,6 +351,8 @@ c2_status_t MfxC2Component::start() } m_condStateStable.notify_all(); } + } else { + MfxC2ComponentsMonitor::getInstance().decrease(m_name.c_str()); } MFX_DEBUG_TRACE__android_c2_status_t(res); @@ -449,6 +463,9 @@ c2_status_t MfxC2Component::release() } } + if (C2_OK == res) { + MfxC2ComponentsMonitor::getInstance().decrease(m_name.c_str()); + } MFX_DEBUG_TRACE__android_c2_status_t(res); return res; } diff --git a/c2_store/src/mfx_c2_store.cpp b/c2_store/src/mfx_c2_store.cpp index fca86e4c..7b642d37 100755 --- a/c2_store/src/mfx_c2_store.cpp +++ b/c2_store/src/mfx_c2_store.cpp @@ -314,6 +314,7 @@ c2_status_t MfxC2ComponentStore::readConfigFile() MfxC2Component::CreateConfig config; config.flags = flags; config.dump_output = m_xmlParser.dumpOutputEnabled(name.c_str()); + config.concurrent_instances = m_xmlParser.getConcurrentInstances(name.c_str()); m_componentsRegistry_.emplace(name, ComponentDesc(module.c_str(), media_type.c_str(), kind, config)); } diff --git a/c2_utils/include/mfx_c2_components_monitor.h b/c2_utils/include/mfx_c2_components_monitor.h new file mode 100644 index 00000000..9536ebed --- /dev/null +++ b/c2_utils/include/mfx_c2_components_monitor.h @@ -0,0 +1,48 @@ +// Copyright (c) 2017-2023 Intel Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include "mfx_defs.h" + +class MfxC2ComponentsMonitor +{ +private: + MfxC2ComponentsMonitor() {} +public: + MFX_CLASS_NO_COPY(MfxC2ComponentsMonitor); + + static MfxC2ComponentsMonitor& getInstance() + { + static MfxC2ComponentsMonitor m_pInstance; + return m_pInstance; + } + + unsigned int get(std::string name); + void increase(std::string name); + void decrease(std::string name); + +private: + std::map m_monitor; + std::mutex m_mutex; +}; diff --git a/c2_utils/include/mfx_c2_xml_parser.h b/c2_utils/include/mfx_c2_xml_parser.h index 97febd41..9949cefd 100755 --- a/c2_utils/include/mfx_c2_xml_parser.h +++ b/c2_utils/include/mfx_c2_xml_parser.h @@ -49,6 +49,7 @@ class MfxXmlParser c2_status_t parseConfig(const char *path); C2Component::kind_t getKind(const char *name); C2String getMediaType(const char *name); + uint32_t getConcurrentInstances(const char *name); bool dumpOutputEnabled(const char *name); private: @@ -60,6 +61,7 @@ class MfxXmlParser size_t order; // order of appearance in the file (starting from 0) std::map typeMap; // map of types supported by this codec bool dump_output{false}; + uint32_t concurrentInstance{0}; }; enum Section { @@ -79,6 +81,8 @@ class MfxXmlParser c2_status_t addDiagnostics(const char **attrs); + c2_status_t addLimits(const char **attrs); + void startElementHandler(const char *name, const char **attrs); void endElementHandler(const char *name); diff --git a/c2_utils/include/mfx_defs.h b/c2_utils/include/mfx_defs.h index cd695802..d933740a 100755 --- a/c2_utils/include/mfx_defs.h +++ b/c2_utils/include/mfx_defs.h @@ -59,6 +59,8 @@ extern mfxVersion g_required_mfx_version; #include #endif // #ifdef LIBVA_SUPPORT +constexpr uint32_t DEFAULT_MAX_INSTANCES = 32; + #define MFX_MAX_PATH 260 #define WIDTH_16K 16384 diff --git a/c2_utils/src/mfx_c2_components_monitor.cpp b/c2_utils/src/mfx_c2_components_monitor.cpp new file mode 100644 index 00000000..2d1460c6 --- /dev/null +++ b/c2_utils/src/mfx_c2_components_monitor.cpp @@ -0,0 +1,78 @@ +// Copyright (c) 2017-2023 Intel Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "mfx_c2_components_monitor.h" +#include "mfx_c2_debug.h" + +#undef MFX_DEBUG_MODULE_NAME +#define MFX_DEBUG_MODULE_NAME "mfx_c2_components_monitor" + +uint32_t MfxC2ComponentsMonitor::get(std::string name) +{ + MFX_DEBUG_TRACE_FUNC; + + std::unique_lock lock(m_mutex); + auto obj = m_monitor.find(name); + if (m_monitor.end() != obj) + { + MFX_DEBUG_TRACE_I32(obj->second); + return obj->second; + } + return 0; +} + +void MfxC2ComponentsMonitor::increase(std::string name) +{ + MFX_DEBUG_TRACE_FUNC; + + std::unique_lock lock(m_mutex); + auto obj = m_monitor.find(name); + if (m_monitor.end() == obj) + { + MFX_DEBUG_TRACE_STREAM("increase " << name << ", instances 0 + 1"); + m_monitor.insert(std::pair(name, 1)); + } + else + { + MFX_DEBUG_TRACE_STREAM("increase " << name << ", instances " << obj->second << " + 1"); + obj->second++; + } +} + +void MfxC2ComponentsMonitor::decrease(std::string name) +{ + MFX_DEBUG_TRACE_FUNC; + + std::unique_lock lock(m_mutex); + auto obj = m_monitor.find(name); + if (m_monitor.end() == obj) // impossible + { + MFX_DEBUG_TRACE_MSG("can't find the record!"); + m_monitor.insert(std::pair(name, 0)); + } + else + { + MFX_DEBUG_TRACE_STREAM("decrease " << name << ", instances " << obj->second << " - 1"); + if (0 == obj->second) + obj->second = 0; + else + obj->second--; + } +} diff --git a/c2_utils/src/mfx_c2_xml_parser.cpp b/c2_utils/src/mfx_c2_xml_parser.cpp index 89655aae..7b80541d 100755 --- a/c2_utils/src/mfx_c2_xml_parser.cpp +++ b/c2_utils/src/mfx_c2_xml_parser.cpp @@ -36,6 +36,7 @@ */ #include "mfx_c2_xml_parser.h" +#include "mfx_defs.h" #include "mfx_c2_debug.h" #include @@ -81,6 +82,18 @@ C2Component::kind_t MfxXmlParser::getKind(const char *name) { return codec->second.isEncoder ? KIND_ENCODER : KIND_DECODER; } +uint32_t MfxXmlParser::getConcurrentInstances(const char *name) { + MFX_DEBUG_TRACE_FUNC; + + auto codec = m_codecMap.find(name); + if (codec == m_codecMap.end() || 0 == codec->second.concurrentInstance) { + MFX_DEBUG_TRACE_STREAM("concurrent-instances wasn't found, using default value " << DEFAULT_MAX_INSTANCES); + return DEFAULT_MAX_INSTANCES; + } + + return codec->second.concurrentInstance; +} + bool MfxXmlParser::dumpOutputEnabled(const char *name) { MFX_DEBUG_TRACE_FUNC; @@ -177,6 +190,25 @@ c2_status_t MfxXmlParser::addDiagnostics(const char **attrs) { return C2_OK; } +c2_status_t MfxXmlParser::addLimits(const char **attrs) { + MFX_DEBUG_TRACE_FUNC; + size_t i = 0; + while (attrs[i] != nullptr) { + if (strcmp(attrs[i], "concurrent-instances") == 0) { + if (strcmp(attrs[++i], "max") == 0) { + m_currentCodec->second.concurrentInstance = std::atoi(attrs[++i]); + MFX_DEBUG_TRACE_STREAM("m_currentCodec->second.concurrentInstance = %d", m_currentCodec->second.concurrentInstance); + } else { + MFX_DEBUG_TRACE_MSG("concurrent-instances is null"); + return C2_BAD_VALUE; + } + } + i++; + } + + return C2_OK; +} + void MfxXmlParser::startElementHandler(const char* name, const char** attrs) { MFX_DEBUG_TRACE_FUNC; @@ -233,6 +265,8 @@ void MfxXmlParser::startElementHandler(const char* name, const char** attrs) { if (strcmp(name, "Diagnostics") == 0) { m_parsingStatus = addDiagnostics(attrs); + } else if (strcmp(name, "Limit") == 0) { + addLimits(attrs); } break; }