From ee3d5a03fee9b4234e707bbb15dc3cd824704bbb Mon Sep 17 00:00:00 2001 From: Pawel Wasowski Date: Tue, 12 Jan 2021 16:38:43 +0100 Subject: [PATCH] [ML][pipeline] Implement Pipeline::getSwitch() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit ACR: TWDAPI-274 [Verification] Code tested in Chrome DevTools with below snippets works fine var pipeline_def = "videotestsrc is-live=true" + " ! videoconvert" + " ! tensor_converter" + " ! output-selector name=outs outs.src_0" + " ! tensor_sink name=sink0 async=false outs.src_1" + " ! tensor_sink name=sink1 async=false" var pipeline = tizen.ml.pipeline.createPipeline(pipeline_def, function(state) {console.log(state);}) pipeline.getSwitch('outs') // Switch {name: "outs", type: "OUTPUT_SELECTOR", _pipeline_id: 3} pipeline.getSwitch('non existent switch') // VM31:1 Uncaught WebAPIException {code: 0, name: "InvalidValuesError" Change-Id: Ia7d6838b5e49072c35f0b796151c436d4a3b60e1 Signed-off-by: Pawel Wasowski --- src/ml/js/ml_pipeline.js | 45 +++++++++++++++++ src/ml/ml.gyp | 2 + src/ml/ml_instance.cc | 28 +++++++++++ src/ml/ml_instance.h | 2 +- src/ml/ml_pipeline.cc | 19 ++++++++ src/ml/ml_pipeline.h | 23 ++++++--- src/ml/ml_pipeline_manager.cc | 12 +++++ src/ml/ml_pipeline_manager.h | 2 +- src/ml/ml_pipeline_switch.cc | 91 +++++++++++++++++++++++++++++++++++ src/ml/ml_pipeline_switch.h | 56 +++++++++++++++++++++ 10 files changed, 271 insertions(+), 9 deletions(-) create mode 100644 src/ml/ml_pipeline_switch.cc create mode 100644 src/ml/ml_pipeline_switch.h diff --git a/src/ml/js/ml_pipeline.js b/src/ml/js/ml_pipeline.js index df2913af..2cfb8bee 100755 --- a/src/ml/js/ml_pipeline.js +++ b/src/ml/js/ml_pipeline.js @@ -212,7 +212,52 @@ Pipeline.prototype.getNodeInfo = function() { //Pipeline::getSource() end //Pipeline::getSwitch() begin +function Switch(name, type, pipeline_id) { + Object.defineProperties(this, { + name: { + enumerable: true, + value: name + }, + type: { + enumerable: true, + value: type + }, + _pipeline_id: { + value: pipeline_id + } + }); +} +var ValidPipelineGetSwitchExceptions = [ + 'InvalidStateError', + 'InvalidValuesError', + 'NotFoundError', + 'NotSupportedError', + 'AbortError' +]; +Pipeline.prototype.getSwitch = function() { + var args = validator_.validateArgs(arguments, [ + { + name: 'name', + type: validator_.Types.STRING + } + ]); + + var nativeArgs = { + name: args.name, + id: this._id + }; + var result = native_.callSync('MLPipelineGetSwitch', nativeArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObjectAndValidate( + result, + ValidPipelineGetSwitchExceptions, + AbortError + ); + } + + return new Switch(nativeArgs.name, result.type, this._id); +}; //Pipeline::getSwitch() end //Pipeline::getValve() begin diff --git a/src/ml/ml.gyp b/src/ml/ml.gyp index c0ab8262..1c60e04d 100644 --- a/src/ml/ml.gyp +++ b/src/ml/ml.gyp @@ -21,6 +21,8 @@ 'ml_pipeline_manager.h', 'ml_pipeline_nodeinfo.cc', 'ml_pipeline_nodeinfo.h', + 'ml_pipeline_switch.cc', + 'ml_pipeline_switch.h', 'ml_utils.cc', 'ml_utils.h', ], diff --git a/src/ml/ml_instance.cc b/src/ml/ml_instance.cc index e9445adb..853dab4c 100644 --- a/src/ml/ml_instance.cc +++ b/src/ml/ml_instance.cc @@ -59,6 +59,7 @@ MlInstance::MlInstance() : pipeline_manager_{this} { REGISTER_METHOD(MLPipelineStart); REGISTER_METHOD(MLPipelineStop); REGISTER_METHOD(MLPipelineGetNodeInfo); + REGISTER_METHOD(MLPipelineGetSwitch); // Pipeline API end #undef REGISTER_METHOD @@ -266,7 +267,34 @@ void MlInstance::MLPipelineGetNodeInfo(const picojson::value& args, picojson::ob // Pipeline::getSource() end // Pipeline::getSwitch() begin +void MlInstance::MLPipelineGetSwitch(const picojson::value& args, picojson::object& out) { + ScopeLogger("args: %s", args.serialize().c_str()); + if (!args.get(kId).is()) { + LoggerD("id is not a number"); + ReportError(PlatformResult{ErrorCode::ABORT_ERR, "Invalid pipeline"}, &out); + return; + } + + if (!args.get(kName).is()) { + LoggerD("name is not a string"); + ReportError(PlatformResult{ErrorCode::ABORT_ERR, "Invalid name"}, &out); + return; + } + + auto name = args.get(kName).get(); + auto pipeline_id = args.get(kId).get(); + std::string type; + + auto ret = pipeline_manager_.GetSwitch(name, pipeline_id, &type); + if (!ret) { + LogAndReportError(ret, &out); + return; + } + + out["type"] = picojson::value{type}; + ReportSuccess(out); +} // Pipeline::getSwitch() end // Pipeline::getValve() begin diff --git a/src/ml/ml_instance.h b/src/ml/ml_instance.h index 47d95671..acb013c1 100644 --- a/src/ml/ml_instance.h +++ b/src/ml/ml_instance.h @@ -73,7 +73,7 @@ class MlInstance : public common::ParsedInstance { // Pipeline::getSource() end // Pipeline::getSwitch() begin - + void MLPipelineGetSwitch(const picojson::value& args, picojson::object& out); // Pipeline::getSwitch() end // Pipeline::getValve() begin diff --git a/src/ml/ml_pipeline.cc b/src/ml/ml_pipeline.cc index c843df35..de5edb1d 100644 --- a/src/ml/ml_pipeline.cc +++ b/src/ml/ml_pipeline.cc @@ -190,6 +190,7 @@ PlatformResult Pipeline::Dispose() { * They have to be released HERE (i.e. BEFORE releasing pipeline_). * If they're released after pipeline_, the app may crash. */ + switches_.clear(); node_info_.clear(); @@ -234,7 +235,25 @@ PlatformResult Pipeline::GetNodeInfo(std::string& name) { // Pipeline::getSource() end // Pipeline::getSwitch() begin +PlatformResult Pipeline::GetSwitch(const std::string& name, std::string* type) { + ScopeLogger("id: [%d], name: [%s]", id_, name.c_str()); + auto switch_it = switches_.find(name); + if (switches_.end() != switch_it) { + LoggerD("Switch [%s] found", name.c_str()); + *type = switch_it->second->GetType(); + return PlatformResult{}; + } + LoggerD("Switch [%s] not found", name.c_str()); + + std::unique_ptr switch_ptr; + auto ret = Switch::CreateSwitch(name, pipeline_, &switch_ptr); + if (ret) { + *type = switch_ptr->GetType(); + switches_.insert({name, std::move(switch_ptr)}); + } + return ret; +} // Pipeline::getSwitch() end // Pipeline::getValve() begin diff --git a/src/ml/ml_pipeline.h b/src/ml/ml_pipeline.h index 80c859ba..9d3df8ca 100644 --- a/src/ml/ml_pipeline.h +++ b/src/ml/ml_pipeline.h @@ -19,6 +19,7 @@ #include #include +#include #include @@ -26,9 +27,10 @@ #include "common/picojson.h" #include "common/platform_result.h" #include "ml_pipeline_nodeinfo.h" +#include "ml_pipeline_switch.h" using common::PlatformResult; -using extension::ml::pipeline::NodeInfo; +using namespace extension::ml::pipeline; namespace extension { namespace ml { @@ -46,7 +48,6 @@ class Pipeline { common::Instance* instance_ptr, std::unique_ptr* out); // PipelineManager::createPipeline() end - Pipeline() = delete; Pipeline(const Pipeline&) = delete; Pipeline& operator=(const Pipeline&) = delete; @@ -78,7 +79,7 @@ class Pipeline { // Pipeline::getSource() end // Pipeline::getSwitch() begin - + PlatformResult GetSwitch(const std::string& name, std::string* type); // Pipeline::getSwitch() end // Pipeline::getValve() begin @@ -127,16 +128,24 @@ class Pipeline { private: Pipeline(int id, const std::string& state_change_listener_name, common::Instance* instance_ptr); + const int id_; + ml_pipeline_h pipeline_; + const std::string state_change_listener_name_; + common::Instance* instance_ptr_; + /* ######### VERY IMPORTANT ######### * All nnstreamer handles to nodes belonging to this Pipeline * object have to be released in Dispose(), before calling * ml_pipeline_destroy(pipeline_) (otherwise, the app may crash). */ - const int id_; - ml_pipeline_h pipeline_; - const std::string state_change_listener_name_; - common::Instance* instance_ptr_; + /* + * As switch controls the flow of the data in the pipeline + * and users could potentially want to access it + * often, we use unordered_map instead of a map for quick + * retrieval. + */ + std::unordered_map> switches_; std::map> node_info_; static void PipelineStateChangeListener(ml_pipeline_state_e state, void* user_data); diff --git a/src/ml/ml_pipeline_manager.cc b/src/ml/ml_pipeline_manager.cc index cadb4d4f..20bae151 100644 --- a/src/ml/ml_pipeline_manager.cc +++ b/src/ml/ml_pipeline_manager.cc @@ -16,6 +16,7 @@ #include "ml_pipeline_manager.h" #include "common/tools.h" +#include "ml_pipeline_switch.h" using common::PlatformResult; using common::ErrorCode; @@ -147,7 +148,18 @@ PlatformResult PipelineManager::GetNodeInfo(int id, std::string& name) { // Pipeline::getSource() end // Pipeline::getSwitch() begin +PlatformResult PipelineManager::GetSwitch(const std::string& name, int pipeline_id, + std::string* type) { + ScopeLogger("name: [%s], pipeline_id: [%d]", name.c_str(), pipeline_id); + auto pipeline_it = pipelines_.find(pipeline_id); + if (pipelines_.end() == pipeline_it) { + LoggerD("Pipeline not found: [%d]", pipeline_id); + return PlatformResult{ErrorCode::NOT_FOUND_ERR, "Pipeline not found"}; + } + + return pipeline_it->second->GetSwitch(name, type); +} // Pipeline::getSwitch() end // Pipeline::getValve() begin diff --git a/src/ml/ml_pipeline_manager.h b/src/ml/ml_pipeline_manager.h index 63ee5aa7..f031fc89 100644 --- a/src/ml/ml_pipeline_manager.h +++ b/src/ml/ml_pipeline_manager.h @@ -68,7 +68,7 @@ class PipelineManager { // Pipeline::getSource() end // Pipeline::getSwitch() begin - + PlatformResult GetSwitch(const std::string& name, int pipeline_id, std::string* type); // Pipeline::getSwitch() end // Pipeline::getValve() begin diff --git a/src/ml/ml_pipeline_switch.cc b/src/ml/ml_pipeline_switch.cc new file mode 100644 index 00000000..43a82205 --- /dev/null +++ b/src/ml/ml_pipeline_switch.cc @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#include "ml_pipeline_switch.h" +#include "ml_utils.h" + +using common::PlatformResult; +using common::ErrorCode; + +namespace { + +std::string TypeToString(ml_pipeline_switch_e type) { + ScopeLogger("type: [%d]", type); + + std::string type_str = + (ML_PIPELINE_SWITCH_INPUT_SELECTOR == type) ? "INPUT_SELECTOR" : "OUTPUT_SELECTOR"; + LoggerD("type_str: [%s]", type_str.c_str()); + return type_str; +} + +} // namespace + +namespace extension { +namespace ml { +namespace pipeline { + +PlatformResult Switch::CreateSwitch(const std::string& name, ml_pipeline_h pipeline, + std::unique_ptr* out) { + ScopeLogger("name: [%s], pipeline: [%p]", name.c_str(), pipeline); + + ml_pipeline_switch_e type = ML_PIPELINE_SWITCH_INPUT_SELECTOR; + ml_pipeline_switch_h switch_handle = nullptr; + auto ret = ml_pipeline_switch_get_handle(pipeline, name.c_str(), &type, &switch_handle); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_switch_get_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + return util::ToPlatformResult(ret, "Could not get switch"); + } + LoggerD("ml_pipeline_switch_get_handle() succeeded"); + + out->reset(new (std::nothrow) Switch{name, TypeToString(type), switch_handle}); + if (!out) { + ret = ml_pipeline_switch_release_handle(switch_handle); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_switch_release_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + } else { + LoggerD("ml_pipeline_switch_release_handle() succeeded"); + } + return LogAndCreateResult(ErrorCode::ABORT_ERR, "Could not get the switch", + ("Could not allocate memory")); + } + + return PlatformResult{}; +} + +Switch::Switch(const std::string& name, const std::string& type, ml_pipeline_switch_h switch_handle) + : name_{name}, type_{type}, switch_{switch_handle} { + ScopeLogger("name: [%s], type: [%s], handle: [%p]", name.c_str(), type.c_str(), switch_handle); +} + +Switch::~Switch() { + ScopeLogger("name: [%s], type: [%s], handle: [%p]", name_.c_str(), type_.c_str(), switch_); + + auto ret = ml_pipeline_switch_release_handle(switch_); + if (ML_ERROR_NONE != ret) { + LoggerE("ml_pipeline_switch_release_handle() failed: [%d] (%s)", ret, get_error_message(ret)); + } else { + LoggerD("ml_pipeline_switch_release_handle() succeeded"); + } +} + +std::string Switch::GetType() const { + ScopeLogger("type: [%s]", type_.c_str()); + return type_; +} + +} // namespace pipeline +} // namespace ml +} // namespace extension \ No newline at end of file diff --git a/src/ml/ml_pipeline_switch.h b/src/ml/ml_pipeline_switch.h new file mode 100644 index 00000000..3175387a --- /dev/null +++ b/src/ml/ml_pipeline_switch.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef ML_ML_PIPELINE_SWITCH_H_ +#define ML_ML_PIPELINE_SWITCH_H_ + +#include +#include + +#include + +#include "common/platform_result.h" + +using common::PlatformResult; + +namespace extension { +namespace ml { +namespace pipeline { + +class Switch { + public: + static PlatformResult CreateSwitch(const std::string& name, ml_pipeline_h pipeline, + std::unique_ptr* out); + + std::string GetType() const; + + ~Switch(); + + Switch(const Switch&) = delete; + Switch& operator=(const Switch&) = delete; + + private: + Switch(const std::string& name, const std::string& type, ml_pipeline_switch_h switch_handle); + const std::string name_; + const std::string type_; + const ml_pipeline_switch_h switch_; +}; + +} // namespace pipeline +} // namespace ml +} // namespace extension + +#endif // ML_ML_PIPELINE_SWITCH_H_ \ No newline at end of file -- 2.34.1