diff --git a/modules/gapi/CMakeLists.txt b/modules/gapi/CMakeLists.txt index 69c0aaaae8..08dee2f9af 100644 --- a/modules/gapi/CMakeLists.txt +++ b/modules/gapi/CMakeLists.txt @@ -164,8 +164,11 @@ set(gapi_srcs src/backends/python/gpythonbackend.cpp # Streaming source - src/streaming/onevpl/onevpl_source.cpp - src/streaming/onevpl/onevpl_source_priv.cpp + src/streaming/onevpl/source.cpp + src/streaming/onevpl/source_priv.cpp + src/streaming/onevpl/file_data_provider.cpp + src/streaming/onevpl/cfg_params.cpp + src/streaming/onevpl/data_provider_interface_exception.cpp # Utils (ITT tracing) src/utils/itt.cpp diff --git a/modules/gapi/include/opencv2/gapi/streaming/onevpl/cfg_params.hpp b/modules/gapi/include/opencv2/gapi/streaming/onevpl/cfg_params.hpp new file mode 100644 index 0000000000..9dc5ead7d7 --- /dev/null +++ b/modules/gapi/include/opencv2/gapi/streaming/onevpl/cfg_params.hpp @@ -0,0 +1,88 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2021 Intel Corporation + +#ifndef OPENCV_GAPI_STREAMING_ONEVPL_CFG_PARAMS_HPP +#define OPENCV_GAPI_STREAMING_ONEVPL_CFG_PARAMS_HPP + +#include +#include +#include + +#include +#include + +namespace cv { +namespace gapi { +namespace wip { +namespace onevpl { + +/** + * @brief Public class is using for creation of onevpl::GSource instances. + * + * Class members availaible through methods @ref CfgParam::get_name() and @ref CfgParam::get_value() are used by + * onevpl::GSource inner logic to create or find oneVPL particular implementation + * (software/hardware, specific API version and etc.). + * + * @note Because oneVPL may provide several implementations which are satisfying with multiple (or single one) @ref CfgParam + * criteria therefore it is possible to configure `preferred` parameters. This kind of CfgParams are created + * using `is_major = false` argument in @ref CfgParam::create method and are not used by creating oneVPL particular implementations. + * Instead they fill out a "score table" to select preferrable implementation from available list. Implementation are satisfying + * with most of these optional params would be chosen. + * If no one optional CfgParam params were present then first of available oneVPL implementation would be applied. + * Please get on https://spec.oneapi.io/versions/latest/elements/oneVPL/source/API_ref/VPL_disp_api_func.html?highlight=mfxcreateconfig#mfxsetconfigfilterproperty + * for using OneVPL configuration. In this schema `mfxU8 *name` represents @ref CfgParam::get_name() and + * `mfxVariant value` is @ref CfgParam::get_value() + */ +struct GAPI_EXPORTS CfgParam { + using name_t = std::string; + using value_t = cv::util::variant; + + /** + * Create onevp::GSource configuration parameter. + * + *@param name name of parameter. + *@param value value of parameter. + *@param is_major TRUE if parameter MUST be provided by OneVPL inner implementation, FALSE for optional (for resolve multiple available implementations). + * + */ + template + static CfgParam create(const std::string& name, ValueType&& value, bool is_major = true) { + CfgParam param(name, CfgParam::value_t(std::forward(value)), is_major); + return param; + } + + struct Priv; + + const name_t& get_name() const; + const value_t& get_value() const; + bool is_major() const; + bool operator==(const CfgParam& rhs) const; + bool operator< (const CfgParam& rhs) const; + bool operator!=(const CfgParam& rhs) const; + + CfgParam& operator=(const CfgParam& src); + CfgParam& operator=(CfgParam&& src); + CfgParam(const CfgParam& src); + CfgParam(CfgParam&& src); + ~CfgParam(); +private: + CfgParam(const std::string& param_name, value_t&& param_value, bool is_major_param); + std::shared_ptr m_priv; +}; + +} //namespace onevpl +} // namespace wip +} // namespace gapi +} // namespace cv + +#endif // OPENCV_GAPI_STREAMING_ONEVPL_CFG_PARAMS_HPP diff --git a/modules/gapi/include/opencv2/gapi/streaming/onevpl/data_provider_interface.hpp b/modules/gapi/include/opencv2/gapi/streaming/onevpl/data_provider_interface.hpp new file mode 100644 index 0000000000..2c299520f7 --- /dev/null +++ b/modules/gapi/include/opencv2/gapi/streaming/onevpl/data_provider_interface.hpp @@ -0,0 +1,74 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2021 Intel Corporation + +#ifndef GAPI_STREAMING_ONEVPL_ONEVPL_DATA_PROVIDER_INTERFACE_HPP +#define GAPI_STREAMING_ONEVPL_ONEVPL_DATA_PROVIDER_INTERFACE_HPP +#include +#include + +#include // GAPI_EXPORTS + +namespace cv { +namespace gapi { +namespace wip { +namespace onevpl { + +struct GAPI_EXPORTS DataProviderException : public std::exception { + virtual ~DataProviderException() {}; +}; + +struct GAPI_EXPORTS DataProviderSystemErrorException : public DataProviderException { + DataProviderSystemErrorException(int error_code, const std::string& desription = std::string()); + virtual ~DataProviderSystemErrorException(); + virtual const char* what() const noexcept override; + +private: + std::string reason; +}; + +/** + * @brief Public interface allows to customize extraction of video stream data + * used by onevpl::GSource instead of reading stream from file (by default). + * + * Interface implementation constructor MUST provide consistency and creates fully operable object. + * If error happened implementation MUST throw `DataProviderException` kind exceptions + * + * @note Interface implementation MUST manage stream and other constructed resources by itself to avoid any kind of leak. + * For simple interface implementation example please see `StreamDataProvider` in `tests/streaming/gapi_streaming_tests.cpp` + */ +struct GAPI_EXPORTS IDataProvider { + using Ptr = std::shared_ptr; + + virtual ~IDataProvider() {}; + + /** + * The function is used by onevpl::GSource to extract binary data stream from @ref IDataProvider + * implementation. + * + * It MUST throw `DataProviderException` kind exceptions in fail cases. + * It MUST return 0 in EOF which considered as not-fail case. + * + * @param out_data_bytes_size the available capacity of out_data buffer. + * @param out_data the output consumer buffer with capacity out_data_bytes_size. + * @return fetched bytes count. + */ + virtual size_t fetch_data(size_t out_data_bytes_size, void* out_data) = 0; + + /** + * The function is used by onevpl::GSource to check more binary data availability. + * + * It MUST return TRUE in case of EOF and NO_THROW exceptions. + * + * @return boolean value which detects end of stream + */ + virtual bool empty() const = 0; +}; +} // namespace onevpl +} // namespace wip +} // namespace gapi +} // namespace cv + +#endif // GAPI_STREAMING_ONEVPL_ONEVPL_DATA_PROVIDER_INTERFACE_HPP diff --git a/modules/gapi/include/opencv2/gapi/streaming/onevpl/onevpl_source.hpp b/modules/gapi/include/opencv2/gapi/streaming/onevpl/onevpl_source.hpp deleted file mode 100644 index fec8c73dff..0000000000 --- a/modules/gapi/include/opencv2/gapi/streaming/onevpl/onevpl_source.hpp +++ /dev/null @@ -1,44 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// Copyright (C) 2021 Intel Corporation - -#ifndef OPENCV_GAPI_STREAMING_ONEVPL_ONEVPL_SOURCE_HPP -#define OPENCV_GAPI_STREAMING_ONEVPL_ONEVPL_SOURCE_HPP - -#include -#include -#include - -namespace cv { -namespace gapi { -namespace wip { - -class GAPI_EXPORTS OneVPLSource : public IStreamSource -{ -public: - struct Priv; - - explicit OneVPLSource(const std::string& filePath); - ~OneVPLSource() override; - - bool pull(cv::gapi::wip::Data& data) override; - GMetaArg descr_of() const override; - -private: - explicit OneVPLSource(std::unique_ptr&& impl); - std::unique_ptr m_priv; -}; - -template -GAPI_EXPORTS_W cv::Ptr inline make_vpl_src(const std::string& filePath, Args&&... args) -{ - return make_src(filePath, std::forward(args)...); -} - -} // namespace wip -} // namespace gapi -} // namespace cv - -#endif // OPENCV_GAPI_STREAMING_ONEVPL_ONEVPL_SOURCE_HPP diff --git a/modules/gapi/include/opencv2/gapi/streaming/onevpl/source.hpp b/modules/gapi/include/opencv2/gapi/streaming/onevpl/source.hpp new file mode 100644 index 0000000000..b7bf4f2ffb --- /dev/null +++ b/modules/gapi/include/opencv2/gapi/streaming/onevpl/source.hpp @@ -0,0 +1,64 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2021 Intel Corporation + +#ifndef OPENCV_GAPI_STREAMING_ONEVPL_ONEVPL_SOURCE_HPP +#define OPENCV_GAPI_STREAMING_ONEVPL_ONEVPL_SOURCE_HPP + +#include +#include +#include +#include +#include + +namespace cv { +namespace gapi { +namespace wip { +namespace onevpl { +using CfgParams = std::vector; + +/** + * @brief G-API streaming source based on OneVPL implementation. + * + * This class implements IStreamSource interface. + * Its constructor takes source file path (in usual way) or @ref onevpl::IDataProvider + * interface implementation (for not file-based sources). It also allows to pass-through + * oneVPL configuration parameters by using several @ref onevpl::CfgParam. + * + * @note stream sources are passed to G-API via shared pointers, so + * please gapi::make_onevpl_src<> to create objects and ptr() to pass a + * GSource to cv::gin(). + */ +class GAPI_EXPORTS GSource : public IStreamSource +{ +public: + struct Priv; + + GSource(const std::string& filePath, + const CfgParams& cfg_params = CfgParams{}); + GSource(std::shared_ptr source, + const CfgParams& cfg_params = CfgParams{}); + ~GSource() override; + + bool pull(cv::gapi::wip::Data& data) override; + GMetaArg descr_of() const override; + +private: + explicit GSource(std::unique_ptr&& impl); + std::unique_ptr m_priv; +}; +} // namespace onevpl + +template +GAPI_EXPORTS_W cv::Ptr inline make_onevpl_src(Args&&... args) +{ + return make_src(std::forward(args)...); +} + +} // namespace wip +} // namespace gapi +} // namespace cv + +#endif // OPENCV_GAPI_STREAMING_ONEVPL_ONEVPL_SOURCE_HPP diff --git a/modules/gapi/samples/onevpl_infer_single_roi.cpp b/modules/gapi/samples/onevpl_infer_single_roi.cpp index 8a7efafabf..9a3abdf392 100644 --- a/modules/gapi/samples/onevpl_infer_single_roi.cpp +++ b/modules/gapi/samples/onevpl_infer_single_roi.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include // CommandLineParser const std::string about = @@ -19,7 +19,8 @@ const std::string keys = "{ input | | Path to the input demultiplexed video file }" "{ output | | Path to the output RAW video file. Use .avi extension }" "{ facem | face-detection-adas-0001.xml | Path to OpenVINO IE face detection model (.xml) }" - "{ faced | CPU | Target device for face detection model (e.g. CPU, GPU, VPU, ...) }"; + "{ cfg_params | :;: | Semicolon separated list of oneVPL mfxVariants which is used for configuring source (see `MFXSetConfigFilterProperty` by https://spec.oneapi.io/versions/latest/elements/oneVPL/source/index.html) }"; + namespace { std::string get_weights_path(const std::string &model_path) { @@ -155,6 +156,10 @@ GAPI_OCV_KERNEL(OCVBBoxes, BBoxes) { } // namespace custom +namespace cfg { +typename cv::gapi::wip::onevpl::CfgParam create_from_string(const std::string &line); +} + int main(int argc, char *argv[]) { cv::CommandLineParser cmd(argc, argv, keys); @@ -178,10 +183,22 @@ int main(int argc, char *argv[]) { } } + // get oneVPL cfg params from cmd + std::stringstream params_list(cmd.get("cfg_params")); + std::vector source_cfgs; + try { + std::string line; + while (std::getline(params_list, line, ';')) { + source_cfgs.push_back(cfg::create_from_string(line)); + } + } catch (const std::exception& ex) { + std::cerr << "Invalid cfg parameter: " << ex.what() << std::endl; + return -1; + } + auto face_net = cv::gapi::ie::Params { face_model_path, // path to topology IR - get_weights_path(face_model_path), // path to weights - cmd.get("faced"), // device specifier + get_weights_path(face_model_path) // path to weights }; auto kernels = cv::gapi::kernels < custom::OCVLocateROI @@ -192,7 +209,7 @@ int main(int argc, char *argv[]) { // Create source cv::Ptr cap; try { - cap = cv::gapi::wip::make_vpl_src(file_path); + cap = cv::gapi::wip::make_onevpl_src(file_path, source_cfgs); std::cout << "oneVPL source desription: " << cap->descr_of() << std::endl; } catch (const std::exception& ex) { std::cerr << "Cannot create source: " << ex.what() << std::endl; @@ -213,7 +230,7 @@ int main(int argc, char *argv[]) { cv::GStreamingCompiled pipeline; try { - pipeline = cv::GComputation(cv::GIn(in), cv::GOut(out)) + pipeline = cv::GComputation(cv::GIn(in), cv::GOut(out)) .compileStreaming(cv::compile_args(kernels, networks)); } catch (const std::exception& ex) { std::cerr << "Exception occured during pipeline construction: " << ex.what() << std::endl; @@ -252,3 +269,25 @@ int main(int argc, char *argv[]) { return 0; } + + +namespace cfg { +typename cv::gapi::wip::onevpl::CfgParam create_from_string(const std::string &line) { + using namespace cv::gapi::wip; + + if (line.empty()) { + throw std::runtime_error("Cannot parse CfgParam from emply line"); + } + + std::string::size_type name_endline_pos = line.find(':'); + if (name_endline_pos == std::string::npos) { + throw std::runtime_error("Cannot parse CfgParam from: " + line + + "\nExpected separator \":\""); + } + + std::string name = line.substr(0, name_endline_pos); + std::string value = line.substr(name_endline_pos + 1); + + return cv::gapi::wip::onevpl::CfgParam::create(name, value); +} +} diff --git a/modules/gapi/src/streaming/onevpl/cfg_params.cpp b/modules/gapi/src/streaming/onevpl/cfg_params.cpp new file mode 100644 index 0000000000..456725508f --- /dev/null +++ b/modules/gapi/src/streaming/onevpl/cfg_params.cpp @@ -0,0 +1,137 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2021 Intel Corporation + +#include + +#include + +namespace cv { +namespace gapi { +namespace wip { +namespace onevpl { + +namespace util { +struct variant_comparator : cv::util::static_visitor { + variant_comparator(const CfgParam::value_t& rhs_value) : + rhs(rhs_value) {} + + template + bool visit(const ValueType& lhs) const { + return lhs < cv::util::get(rhs); + } +private: + const CfgParam::value_t& rhs; +}; +} // namespace util + +struct CfgParam::Priv { + Priv(const std::string& param_name, CfgParam::value_t&& param_value, bool is_major_param) : + name(param_name), value(std::forward(param_value)), major_flag(is_major_param) { + } + + const CfgParam::name_t& get_name_impl() const { + return name; + } + + const CfgParam::value_t& get_value_impl() const { + return value; + } + + bool is_major_impl() const { + return major_flag; + } + + // comparison implementation + bool operator< (const Priv& rhs) const { + // implement default pair comparison + if (get_name_impl() < rhs.get_name_impl()) { + return true; + } else if (get_name_impl() > rhs.get_name_impl()) { + return false; + } + + //TODO implement operator < for cv::util::variant + const CfgParam::value_t& lvar = get_value_impl(); + const CfgParam::value_t& rvar = rhs.get_value_impl(); + if (lvar.index() < rvar.index()) { + return true; + } else if (lvar.index() > rvar.index()) { + return false; + } + + util::variant_comparator comp(rvar); + return cv::util::visit(comp, lvar); + } + + bool operator==(const Priv& rhs) const { + return (get_name_impl() == rhs.get_name_impl()) + && (get_value_impl() == rhs.get_value_impl()); + } + + bool operator!=(const Priv& rhs) const { + return !(*this == rhs); + } + + CfgParam::name_t name; + CfgParam::value_t value; + bool major_flag; +}; + +CfgParam::CfgParam (const std::string& param_name, value_t&& param_value, bool is_major_param) : + m_priv(new Priv(param_name, std::move(param_value), is_major_param)) { +} + +CfgParam::~CfgParam() = default; + +CfgParam& CfgParam::operator=(const CfgParam& src) { + if (this != &src) { + m_priv = src.m_priv; + } + return *this; +} + +CfgParam& CfgParam::operator=(CfgParam&& src) { + if (this != &src) { + m_priv = std::move(src.m_priv); + } + return *this; +} + +CfgParam::CfgParam(const CfgParam& src) : + m_priv(src.m_priv) { +} + +CfgParam::CfgParam(CfgParam&& src) : + m_priv(std::move(src.m_priv)) { +} + +const CfgParam::name_t& CfgParam::get_name() const { + return m_priv->get_name_impl(); +} + +const CfgParam::value_t& CfgParam::get_value() const { + return m_priv->get_value_impl(); +} + +bool CfgParam::is_major() const { + return m_priv->is_major_impl(); +} + +bool CfgParam::operator< (const CfgParam& rhs) const { + return *m_priv < *rhs.m_priv; +} + +bool CfgParam::operator==(const CfgParam& rhs) const { + return *m_priv == *rhs.m_priv; +} + +bool CfgParam::operator!=(const CfgParam& rhs) const { + return *m_priv != *rhs.m_priv; +} +} // namespace onevpl +} // namespace wip +} // namespace gapi +} // namespace cv diff --git a/modules/gapi/src/streaming/onevpl/data_provider_interface_exception.cpp b/modules/gapi/src/streaming/onevpl/data_provider_interface_exception.cpp new file mode 100644 index 0000000000..feaae7a727 --- /dev/null +++ b/modules/gapi/src/streaming/onevpl/data_provider_interface_exception.cpp @@ -0,0 +1,22 @@ +#include +#include + +#include + +namespace cv { +namespace gapi { +namespace wip { +namespace onevpl { +DataProviderSystemErrorException::DataProviderSystemErrorException(int error_code, const std::string& desription) { + reason = desription + ", error: " + std::to_string(error_code) + ", desctiption: " + strerror(error_code); +} + +DataProviderSystemErrorException::~DataProviderSystemErrorException() = default; + +const char* DataProviderSystemErrorException::what() const noexcept { + return reason.c_str(); +} +} // namespace onevpl +} // namespace wip +} // namespace gapi +} // namespace cv diff --git a/modules/gapi/src/streaming/onevpl/file_data_provider.cpp b/modules/gapi/src/streaming/onevpl/file_data_provider.cpp new file mode 100644 index 0000000000..2a3df07c51 --- /dev/null +++ b/modules/gapi/src/streaming/onevpl/file_data_provider.cpp @@ -0,0 +1,47 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2021 Intel Corporation +#include + +#include "streaming/onevpl/file_data_provider.hpp" + +namespace cv { +namespace gapi { +namespace wip { +namespace onevpl { + +FileDataProvider::FileDataProvider(const std::string& file_path) : + source_handle(fopen(file_path.c_str(), "rb"), &fclose) { + if (!source_handle) { + throw DataProviderSystemErrorException(errno, + "FileDataProvider: cannot open source file: " + file_path); + } +} + +FileDataProvider::~FileDataProvider() = default; + +size_t FileDataProvider::fetch_data(size_t out_data_bytes_size, void* out_data) { + if (empty()) { + return 0; + } + + size_t ret = fread(out_data, 1, out_data_bytes_size, source_handle.get()); + if (ret == 0) { + if (feof(source_handle.get())) { + source_handle.reset(); + } else { + throw DataProviderSystemErrorException (errno, "FileDataProvider::fetch_data error read"); + } + } + return ret; +} + +bool FileDataProvider::empty() const { + return !source_handle; +} +} // namespace onevpl +} // namespace wip +} // namespace gapi +} // namespace cv diff --git a/modules/gapi/src/streaming/onevpl/file_data_provider.hpp b/modules/gapi/src/streaming/onevpl/file_data_provider.hpp new file mode 100644 index 0000000000..22348290be --- /dev/null +++ b/modules/gapi/src/streaming/onevpl/file_data_provider.hpp @@ -0,0 +1,33 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2021 Intel Corporation + +#ifndef GAPI_STREAMING_ONEVPL_ONEVPL_FILE_DATA_PROVIDER_HPP +#define GAPI_STREAMING_ONEVPL_ONEVPL_FILE_DATA_PROVIDER_HPP +#include + +#include + +namespace cv { +namespace gapi { +namespace wip { +namespace onevpl { +struct FileDataProvider : public IDataProvider { + + using file_ptr = std::unique_ptr; + FileDataProvider(const std::string& file_path); + ~FileDataProvider(); + + size_t fetch_data(size_t out_data_bytes_size, void* out_data) override; + bool empty() const override; +private: + file_ptr source_handle; +}; +} // namespace onevpl +} // namespace wip +} // namespace gapi +} // namespace cv + +#endif // GAPI_STREAMING_ONEVPL_ONEVPL_FILE_DATA_PROVIDER_HPP diff --git a/modules/gapi/src/streaming/onevpl/onevpl_source.cpp b/modules/gapi/src/streaming/onevpl/onevpl_source.cpp deleted file mode 100644 index 988986f6d9..0000000000 --- a/modules/gapi/src/streaming/onevpl/onevpl_source.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// Copyright (C) 2021 Intel Corporation - -#include - -#include "streaming/onevpl/onevpl_source_priv.hpp" - -namespace cv { -namespace gapi { -namespace wip { - -#ifdef HAVE_ONEVPL -OneVPLSource::OneVPLSource(const std::string& filePath) : - OneVPLSource(std::unique_ptr(new OneVPLSource::Priv(filePath))) { - - if (filePath.empty()) { - util::throw_error(std::logic_error("Cannot create 'OneVPLSource' on empty source file name")); - } -} -#else -OneVPLSource::OneVPLSource(const std::string&) { - GAPI_Assert(false && "Unsupported: G-API compiled without `WITH_GAPI_ONEVPL=ON`"); -} -#endif - -OneVPLSource::OneVPLSource(std::unique_ptr&& impl) : - IStreamSource(), - m_priv(std::move(impl)) { -} - -OneVPLSource::~OneVPLSource() { -} - -bool OneVPLSource::pull(cv::gapi::wip::Data& data) -{ - return m_priv->pull(data); -} - -GMetaArg OneVPLSource::descr_of() const -{ - return m_priv->descr_of(); -} -} // namespace wip -} // namespace gapi -} // namespace cv diff --git a/modules/gapi/src/streaming/onevpl/source.cpp b/modules/gapi/src/streaming/onevpl/source.cpp new file mode 100644 index 0000000000..0decb1358b --- /dev/null +++ b/modules/gapi/src/streaming/onevpl/source.cpp @@ -0,0 +1,58 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2021 Intel Corporation + +#include + +#include "streaming/onevpl/source_priv.hpp" +#include "streaming/onevpl/file_data_provider.hpp" +namespace cv { +namespace gapi { +namespace wip { +namespace onevpl { + +#ifdef HAVE_ONEVPL +GSource::GSource(const std::string& filePath, const CfgParams& cfg_params) : + GSource(std::unique_ptr(new GSource::Priv(std::make_shared(filePath), + cfg_params))) { + + if (filePath.empty()) { + util::throw_error(std::logic_error("Cannot create 'GSource' on empty source file name")); + } +} + +GSource::GSource(std::shared_ptr source, const CfgParams& cfg_params) : + GSource(std::unique_ptr(new GSource::Priv(source, cfg_params))) { +} +#else +GSource::GSource(const std::string&, const CfgParams&) { + GAPI_Assert(false && "Unsupported: G-API compiled without `WITH_GAPI_ONEVPL=ON`"); +} + +GSource::GSource(std::shared_ptr, const CfgParams&) { + GAPI_Assert(false && "Unsupported: G-API compiled without `WITH_GAPI_ONEVPL=ON`"); +} +#endif + +GSource::GSource(std::unique_ptr&& impl) : + IStreamSource(), + m_priv(std::move(impl)) { +} + +GSource::~GSource() = default; + +bool GSource::pull(cv::gapi::wip::Data& data) +{ + return m_priv->pull(data); +} + +GMetaArg GSource::descr_of() const +{ + return m_priv->descr_of(); +} +} // namespace onevpl +} // namespace wip +} // namespace gapi +} // namespace cv diff --git a/modules/gapi/src/streaming/onevpl/onevpl_source_priv.cpp b/modules/gapi/src/streaming/onevpl/source_priv.cpp similarity index 66% rename from modules/gapi/src/streaming/onevpl/onevpl_source_priv.cpp rename to modules/gapi/src/streaming/onevpl/source_priv.cpp index 5c4e8e6941..ed838d6adc 100644 --- a/modules/gapi/src/streaming/onevpl/onevpl_source_priv.cpp +++ b/modules/gapi/src/streaming/onevpl/source_priv.cpp @@ -7,19 +7,21 @@ #include #include -#include "streaming/onevpl/onevpl_source_priv.hpp" +#include "streaming/onevpl/source_priv.hpp" #include "logger.hpp" #ifndef HAVE_ONEVPL namespace cv { namespace gapi { namespace wip { -bool OneVPLSource::Priv::pull(cv::gapi::wip::Data&) { +namespace onevpl { +bool GSource::Priv::pull(cv::gapi::wip::Data&) { return true; } -GMetaArg OneVPLSource::Priv::descr_of() const { +GMetaArg GSource::Priv::descr_of() const { return {}; } +} // namespace onevpl } // namespace wip } // namespace gapi } // namespace cv @@ -29,33 +31,35 @@ GMetaArg OneVPLSource::Priv::descr_of() const { namespace cv { namespace gapi { namespace wip { -OneVPLSource::Priv::Priv() : +namespace onevpl { +GSource::Priv::Priv() : mfx_handle(MFXLoad()) { GAPI_LOG_INFO(nullptr, "Initialized MFX handle: " << mfx_handle); description_is_valid = false; } -OneVPLSource::Priv::Priv(const std::string&) : - OneVPLSource::Priv() +GSource::Priv::Priv(std::shared_ptr, const std::vector&) : + GSource::Priv() { } -OneVPLSource::Priv::~Priv() +GSource::Priv::~Priv() { GAPI_LOG_INFO(nullptr, "Unload MFX handle: " << mfx_handle); MFXUnload(mfx_handle); } -bool OneVPLSource::Priv::pull(cv::gapi::wip::Data&) +bool GSource::Priv::pull(cv::gapi::wip::Data&) { return false; } -GMetaArg OneVPLSource::Priv::descr_of() const +GMetaArg GSource::Priv::descr_of() const { return {}; } +} // namespace onevpl } // namespace wip } // namespace gapi } // namespace cv diff --git a/modules/gapi/src/streaming/onevpl/onevpl_source_priv.hpp b/modules/gapi/src/streaming/onevpl/source_priv.hpp similarity index 80% rename from modules/gapi/src/streaming/onevpl/onevpl_source_priv.hpp rename to modules/gapi/src/streaming/onevpl/source_priv.hpp index b139add993..c278934253 100644 --- a/modules/gapi/src/streaming/onevpl/onevpl_source_priv.hpp +++ b/modules/gapi/src/streaming/onevpl/source_priv.hpp @@ -14,7 +14,7 @@ #include #include -#include +#include #ifdef HAVE_ONEVPL #if (MFX_VERSION >= 2000) @@ -28,10 +28,12 @@ namespace cv { namespace gapi { namespace wip { +namespace onevpl { -struct OneVPLSource::Priv +struct GSource::Priv { - explicit Priv(const std::string& file_path); + explicit Priv(std::shared_ptr provider, + const std::vector& params); ~Priv(); bool pull(cv::gapi::wip::Data& data); @@ -41,6 +43,7 @@ private: mfxLoader mfx_handle; bool description_is_valid; }; +} // namespace onevpl } // namespace wip } // namespace gapi } // namespace cv @@ -50,11 +53,13 @@ private: namespace cv { namespace gapi { namespace wip { -struct OneVPLSource::Priv final +namespace onevpl { +struct GSource::Priv final { bool pull(cv::gapi::wip::Data&); GMetaArg descr_of() const; }; +} // namespace onevpl } // namespace wip } // namespace gapi } // namespace cv diff --git a/modules/gapi/test/streaming/gapi_streaming_tests.cpp b/modules/gapi/test/streaming/gapi_streaming_tests.cpp index 5386d1736f..76027a56c6 100644 --- a/modules/gapi/test/streaming/gapi_streaming_tests.cpp +++ b/modules/gapi/test/streaming/gapi_streaming_tests.cpp @@ -25,6 +25,17 @@ #include #include +#include + +#ifdef HAVE_ONEVPL + +#if (MFX_VERSION >= 2000) +#include +#endif + +#include +#endif // HAVE_ONEVPL + namespace opencv_test { namespace @@ -273,6 +284,22 @@ void checkPullOverload(const cv::Mat& ref, EXPECT_EQ(0., cv::norm(ref, out_mat, cv::NORM_INF)); } +struct StreamDataProvider : public cv::gapi::wip::onevpl::IDataProvider { + + StreamDataProvider(std::istream& in) : data_stream (in) { + EXPECT_TRUE(in); + } + + size_t fetch_data(size_t out_data_size, void* out_data_buf) override { + data_stream.read(reinterpret_cast(out_data_buf), out_data_size); + return data_stream.gcount(); + } + bool empty() const override { + return data_stream.eof() || data_stream.bad(); + } +private: + std::istream& data_stream; +}; } // anonymous namespace TEST_P(GAPI_Streaming, SmokeTest_ConstInput_GMat) @@ -2214,4 +2241,47 @@ TEST(GAPI_Streaming, TestPythonAPI) cc.stop(); } +#ifdef HAVE_ONEVPL +const unsigned char hevc_header[] = { + 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0C, 0x06, 0xFF, 0xFF, 0x01, 0x40, 0x00, + 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x00, + 0x00, 0x04, 0x02, 0x10, 0x30, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03, + 0x01, 0xE5, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x06, 0x01, 0x40, 0x00, 0x00, + 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x00, 0x00, + 0xA0, 0x10, 0x20, 0x61, 0x63, 0x41, 0x00, 0x86, 0x49, 0x1B, 0x2B, 0x20, 0x00, + 0x00, 0x00, 0x01, 0x44, 0x01, 0xC0, 0x71, 0xC0, 0xD9, 0x20, 0x00, 0x00, 0x00, + 0x01, 0x26, 0x01, 0xAF, 0x0C +}; +TEST(OneVPL_Source, Init) +{ + using CfgParam = cv::gapi::wip::onevpl::CfgParam; + + std::vector src_params; + src_params.push_back(CfgParam::create("mfxImplDescription.Impl", + MFX_IMPL_TYPE_HARDWARE)); + src_params.push_back(CfgParam::create("mfxImplDescription.AccelerationMode", + MFX_ACCEL_MODE_VIA_D3D11, false)); + src_params.push_back(CfgParam::create("mfxImplDescription.mfxDecoderDescription.decoder.CodecID", + MFX_CODEC_HEVC)); + std::stringstream stream(std::ios_base::in | std::ios_base::out | std::ios_base::binary); + EXPECT_TRUE(stream.write(reinterpret_cast(const_cast(hevc_header)), + sizeof(hevc_header))); + std::shared_ptr stream_data_provider = std::make_shared(stream); + + cv::Ptr cap; + bool cap_created = false; + try { + cap = cv::gapi::wip::make_onevpl_src(stream_data_provider, src_params); + cap_created = true; + } catch (const std::exception&) { + } + ASSERT_TRUE(cap_created); + + cv::gapi::wip::Data out; + while (cap->pull(out)) { + (void)out; + } + EXPECT_TRUE(stream_data_provider->empty()); +} +#endif } // namespace opencv_test