opencv/modules/videoio/src/backend_plugin.cpp

783 lines
28 KiB
C++
Raw Normal View History

// 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.
#include "precomp.hpp"
#include "backend.hpp"
#include "plugin_api.hpp"
#include "plugin_capture_api.hpp"
#include "plugin_writer_api.hpp"
#include "opencv2/core/utils/configuration.private.hpp"
2021-02-04 06:04:35 +08:00
#include "opencv2/core/utils/logger.hpp"
#include "opencv2/core/private.hpp"
#include "videoio_registry.hpp"
//==================================================================================================
// Dynamic backend implementation
2021-02-04 06:04:35 +08:00
#include "opencv2/core/utils/plugin_loader.private.hpp"
#include "backend_plugin_legacy.impl.hpp"
2019-03-03 06:36:18 +08:00
2021-02-04 06:04:35 +08:00
namespace cv { namespace impl {
2019-05-31 21:18:00 +08:00
2021-02-04 06:04:35 +08:00
#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS)
2019-03-03 06:36:18 +08:00
2021-02-04 06:04:35 +08:00
using namespace cv::plugin::impl; // plugin_loader.hpp
2019-05-31 21:18:00 +08:00
2019-03-03 06:36:18 +08:00
static Mutex& getInitializationMutex()
{
static Mutex initializationMutex;
return initializationMutex;
}
2019-03-03 06:36:18 +08:00
class PluginBackend: public IBackend
{
protected:
2019-03-03 06:36:18 +08:00
void initCaptureAPI()
{
const char* init_name = "opencv_videoio_capture_plugin_init_v1";
FN_opencv_videoio_capture_plugin_init_t fn_init = reinterpret_cast<FN_opencv_videoio_capture_plugin_init_t>(lib_->getSymbol(init_name));
2019-03-03 06:36:18 +08:00
if (fn_init)
{
CV_LOG_INFO(NULL, "Found entry: '" << init_name << "'");
for (int supported_api_version = CAPTURE_API_VERSION; supported_api_version >= 0; supported_api_version--)
{
capture_api_ = fn_init(CAPTURE_ABI_VERSION, supported_api_version, NULL);
if (capture_api_)
break;
}
if (!capture_api_)
2019-03-03 06:36:18 +08:00
{
CV_LOG_INFO(NULL, "Video I/O: plugin is incompatible (can't be initialized): " << lib_->getName());
2019-03-03 06:36:18 +08:00
return;
}
if (!checkCompatibility(
capture_api_->api_header, CAPTURE_ABI_VERSION, CAPTURE_API_VERSION,
capture_api_->v0.id != CAP_FFMPEG))
2019-03-05 18:22:52 +08:00
{
capture_api_ = NULL;
return;
}
CV_LOG_INFO(NULL, "Video I/O: plugin is ready to use '" << capture_api_->api_header.api_description << "'");
}
else
{
CV_LOG_INFO(NULL, "Video I/O: missing plugin init function: '" << init_name << "', file: " << lib_->getName());
}
}
void initWriterAPI()
{
const char* init_name = "opencv_videoio_writer_plugin_init_v1";
FN_opencv_videoio_writer_plugin_init_t fn_init = reinterpret_cast<FN_opencv_videoio_writer_plugin_init_t>(lib_->getSymbol(init_name));
if (fn_init)
{
CV_LOG_INFO(NULL, "Found entry: '" << init_name << "'");
for (int supported_api_version = WRITER_API_VERSION; supported_api_version >= 0; supported_api_version--)
{
writer_api_ = fn_init(WRITER_ABI_VERSION, supported_api_version, NULL);
if (writer_api_)
break;
}
if (!writer_api_)
{
CV_LOG_INFO(NULL, "Video I/O: plugin is incompatible (can't be initialized): " << lib_->getName());
2019-03-05 18:22:52 +08:00
return;
}
if (!checkCompatibility(
writer_api_->api_header, WRITER_ABI_VERSION, WRITER_API_VERSION,
writer_api_->v0.id != CAP_FFMPEG))
{
writer_api_ = NULL;
return;
}
CV_LOG_INFO(NULL, "Video I/O: plugin is ready to use '" << writer_api_->api_header.api_description << "'");
}
else
{
CV_LOG_INFO(NULL, "Video I/O: missing plugin init function: '" << init_name << "', file: " << lib_->getName());
}
}
void initPluginLegacyAPI()
{
const char* init_name = "opencv_videoio_plugin_init_v0";
FN_opencv_videoio_plugin_init_t fn_init = reinterpret_cast<FN_opencv_videoio_plugin_init_t>(lib_->getSymbol(init_name));
if (fn_init)
{
CV_LOG_INFO(NULL, "Found entry: '" << init_name << "'");
for (int supported_api_version = API_VERSION; supported_api_version >= 0; supported_api_version--)
{
plugin_api_ = fn_init(ABI_VERSION, supported_api_version, NULL);
if (plugin_api_)
break;
}
if (!plugin_api_)
{
CV_LOG_INFO(NULL, "Video I/O: plugin is incompatible (can't be initialized): " << lib_->getName());
return;
}
if (!checkCompatibility(
plugin_api_->api_header, ABI_VERSION, API_VERSION,
plugin_api_->v0.captureAPI != CAP_FFMPEG))
{
plugin_api_ = NULL;
return;
}
CV_LOG_INFO(NULL, "Video I/O: plugin is ready to use '" << plugin_api_->api_header.api_description << "'");
2019-03-03 06:36:18 +08:00
}
else
{
CV_LOG_INFO(NULL, "Video I/O: plugin is incompatible, missing init function: '" << init_name << "', file: " << lib_->getName());
}
}
bool checkCompatibility(const OpenCV_API_Header& api_header, unsigned int abi_version, unsigned int api_version, bool checkMinorOpenCVVersion)
{
if (api_header.opencv_version_major != CV_VERSION_MAJOR)
{
CV_LOG_ERROR(NULL, "Video I/O: wrong OpenCV major version used by plugin '" << api_header.api_description << "': " <<
cv::format("%d.%d, OpenCV version is '" CV_VERSION "'", api_header.opencv_version_major, api_header.opencv_version_minor))
return false;
}
if (!checkMinorOpenCVVersion)
{
// no checks for OpenCV minor version
}
else if (api_header.opencv_version_minor != CV_VERSION_MINOR)
{
CV_LOG_ERROR(NULL, "Video I/O: wrong OpenCV minor version used by plugin '" << api_header.api_description << "': " <<
cv::format("%d.%d, OpenCV version is '" CV_VERSION "'", api_header.opencv_version_major, api_header.opencv_version_minor))
return false;
}
CV_LOG_INFO(NULL, "Video I/O: initialized '" << api_header.api_description << "': built with "
<< cv::format("OpenCV %d.%d (ABI/API = %d/%d)",
api_header.opencv_version_major, api_header.opencv_version_minor,
api_header.min_api_version, api_header.api_version)
<< ", current OpenCV version is '" CV_VERSION "' (ABI/API = " << abi_version << "/" << api_version << ")"
);
if (api_header.min_api_version != abi_version) // future: range can be here
{
// actually this should never happen due to checks in plugin's init() function
CV_LOG_ERROR(NULL, "Video I/O: plugin is not supported due to incompatible ABI = " << api_header.min_api_version);
return false;
}
if (api_header.api_version != api_version)
{
CV_LOG_INFO(NULL, "Video I/O: NOTE: plugin is supported, but there is API version mismath: "
<< cv::format("plugin API level (%d) != OpenCV API level (%d)", api_header.api_version, api_version));
if (api_header.api_version < api_version)
{
CV_LOG_INFO(NULL, "Video I/O: NOTE: some functionality may be unavailable due to lack of support by plugin implementation");
}
}
return true;
}
public:
2021-02-04 06:04:35 +08:00
Ptr<cv::plugin::impl::DynamicLib> lib_;
const OpenCV_VideoIO_Capture_Plugin_API* capture_api_;
const OpenCV_VideoIO_Writer_Plugin_API* writer_api_;
const OpenCV_VideoIO_Plugin_API_preview* plugin_api_; //!< deprecated
2021-02-04 06:04:35 +08:00
PluginBackend(const Ptr<cv::plugin::impl::DynamicLib>& lib)
: lib_(lib)
, capture_api_(NULL), writer_api_(NULL)
, plugin_api_(NULL)
{
initCaptureAPI();
initWriterAPI();
if (capture_api_ == NULL && writer_api_ == NULL)
{
initPluginLegacyAPI();
2019-03-03 06:36:18 +08:00
}
}
Ptr<IVideoCapture> createCapture(int camera) const;
Ptr<IVideoCapture> createCapture(int camera, const VideoCaptureParameters& params) const CV_OVERRIDE;
Ptr<IVideoCapture> createCapture(const std::string &filename) const;
Ptr<IVideoCapture> createCapture(const std::string &filename, const VideoCaptureParameters& params) const CV_OVERRIDE;
Ptr<IVideoWriter> createWriter(const std::string& filename, int fourcc, double fps,
const cv::Size& sz, const VideoWriterParameters& params) const CV_OVERRIDE;
std::string getCapturePluginVersion(CV_OUT int& version_ABI, CV_OUT int& version_API)
{
CV_Assert(capture_api_ || plugin_api_);
const OpenCV_API_Header& api_header = capture_api_ ? capture_api_->api_header : plugin_api_->api_header;
version_ABI = api_header.min_api_version;
version_API = api_header.api_version;
return api_header.api_description;
}
std::string getWriterPluginVersion(CV_OUT int& version_ABI, CV_OUT int& version_API)
{
CV_Assert(writer_api_ || plugin_api_);
const OpenCV_API_Header& api_header = writer_api_ ? writer_api_->api_header : plugin_api_->api_header;
version_ABI = api_header.min_api_version;
version_API = api_header.api_version;
return api_header.api_description;
}
2019-03-03 06:36:18 +08:00
};
2019-03-03 06:36:18 +08:00
class PluginBackendFactory : public IBackendFactory
{
public:
2019-03-03 06:36:18 +08:00
VideoCaptureAPIs id_;
const char* baseName_;
Ptr<PluginBackend> backend;
bool initialized;
public:
2019-03-03 06:36:18 +08:00
PluginBackendFactory(VideoCaptureAPIs id, const char* baseName) :
id_(id), baseName_(baseName),
initialized(false)
{
2019-03-03 06:36:18 +08:00
// nothing, plugins are loaded on demand
}
2019-03-03 06:36:18 +08:00
Ptr<IBackend> getBackend() const CV_OVERRIDE
{
initBackend();
return backend.staticCast<IBackend>();
}
bool isBuiltIn() const CV_OVERRIDE { return false; }
std::string getCapturePluginVersion(
CV_OUT int& version_ABI,
CV_OUT int& version_API) const
{
initBackend();
if (!backend)
CV_Error_(Error::StsNotImplemented, ("Backend '%s' is not available", baseName_));
return backend->getCapturePluginVersion(version_ABI, version_API);
}
std::string getWriterPluginVersion(
CV_OUT int& version_ABI,
CV_OUT int& version_API) const
{
initBackend();
if (!backend)
CV_Error_(Error::StsNotImplemented, ("Backend '%s' is not available", baseName_));
return backend->getWriterPluginVersion(version_ABI, version_API);
}
protected:
inline void initBackend() const
{
2019-03-03 06:36:18 +08:00
if (!initialized)
{
const_cast<PluginBackendFactory*>(this)->initBackend_();
2019-03-03 06:36:18 +08:00
}
}
void initBackend_()
{
2019-03-03 06:36:18 +08:00
AutoLock lock(getInitializationMutex());
try {
if (!initialized)
loadPlugin();
}
catch (...)
{
CV_LOG_INFO(NULL, "Video I/O: exception during plugin loading: " << baseName_ << ". SKIP");
}
initialized = true;
}
2019-03-03 06:36:18 +08:00
void loadPlugin();
};
2019-03-03 06:36:18 +08:00
static
2019-05-31 21:18:00 +08:00
std::vector<FileSystemPath_t> getPluginCandidates(const std::string& baseName)
{
using namespace cv::utils;
using namespace cv::utils::fs;
2021-02-04 06:04:35 +08:00
const std::string baseName_l = toLowerCase(baseName);
const std::string baseName_u = toUpperCase(baseName);
2019-05-31 21:18:00 +08:00
const FileSystemPath_t baseName_l_fs = toFileSystemPath(baseName_l);
2021-02-04 06:04:35 +08:00
std::vector<FileSystemPath_t> paths;
const std::vector<std::string> paths_ = getConfigurationParameterPaths("OPENCV_VIDEOIO_PLUGIN_PATH", std::vector<std::string>());
2019-05-31 21:18:00 +08:00
if (paths_.size() != 0)
{
for (size_t i = 0; i < paths_.size(); i++)
{
paths.push_back(toFileSystemPath(paths_[i]));
}
}
else
{
FileSystemPath_t binaryLocation;
if (getBinLocation(binaryLocation))
{
binaryLocation = getParent(binaryLocation);
2019-03-03 06:36:18 +08:00
#ifndef CV_VIDEOIO_PLUGIN_SUBDIRECTORY
2019-05-31 21:18:00 +08:00
paths.push_back(binaryLocation);
2019-03-03 06:36:18 +08:00
#else
2019-05-31 21:18:00 +08:00
paths.push_back(binaryLocation + toFileSystemPath("/") + toFileSystemPath(CV_VIDEOIO_PLUGIN_SUBDIRECTORY_STR));
2019-03-03 06:36:18 +08:00
#endif
2019-05-31 21:18:00 +08:00
}
}
2021-02-04 06:04:35 +08:00
const std::string default_expr = libraryPrefix() + "opencv_videoio_" + baseName_l + "*" + librarySuffix();
const std::string plugin_expr = getConfigurationParameterString((std::string("OPENCV_VIDEOIO_PLUGIN_") + baseName_u).c_str(), default_expr.c_str());
std::vector<FileSystemPath_t> results;
2019-05-31 21:18:00 +08:00
#ifdef _WIN32
FileSystemPath_t moduleName = toFileSystemPath(libraryPrefix() + "opencv_videoio_" + baseName_l + librarySuffix());
#ifndef WINRT
if (baseName_u == "FFMPEG") // backward compatibility
{
const wchar_t* ffmpeg_env_path = _wgetenv(L"OPENCV_FFMPEG_DLL_DIR");
if (ffmpeg_env_path)
{
results.push_back(FileSystemPath_t(ffmpeg_env_path) + L"\\" + moduleName);
}
}
#endif
if (plugin_expr != default_expr)
{
moduleName = toFileSystemPath(plugin_expr);
results.push_back(moduleName);
}
for (const FileSystemPath_t& path : paths)
{
results.push_back(path + L"\\" + moduleName);
}
results.push_back(moduleName);
#if defined(_DEBUG) && defined(DEBUG_POSTFIX)
if (baseName_u == "FFMPEG") // backward compatibility
{
const FileSystemPath_t templ = toFileSystemPath(CVAUX_STR(DEBUG_POSTFIX) ".dll");
FileSystemPath_t nonDebugName(moduleName);
size_t suf = nonDebugName.rfind(templ);
if (suf != FileSystemPath_t::npos)
{
nonDebugName.replace(suf, suf + templ.size(), L".dll");
results.push_back(nonDebugName);
}
}
#endif // _DEBUG && DEBUG_POSTFIX
2019-05-31 21:18:00 +08:00
#else
2021-02-04 06:04:35 +08:00
CV_LOG_INFO(NULL, "VideoIO plugin (" << baseName << "): glob is '" << plugin_expr << "', " << paths.size() << " location(s)");
for (const std::string& path : paths)
{
if (path.empty())
continue;
2021-02-04 06:04:35 +08:00
std::vector<std::string> candidates;
2019-05-31 21:18:00 +08:00
cv::glob(utils::fs::join(path, plugin_expr), candidates);
// Prefer candisates with higher versions
// TODO: implemented accurate versions-based comparator
std::sort(candidates.begin(), candidates.end(), std::greater<std::string>());
2019-03-03 06:36:18 +08:00
CV_LOG_INFO(NULL, " - " << path << ": " << candidates.size());
copy(candidates.begin(), candidates.end(), back_inserter(results));
}
2019-05-31 21:18:00 +08:00
#endif
2019-03-03 06:36:18 +08:00
CV_LOG_INFO(NULL, "Found " << results.size() << " plugin(s) for " << baseName);
return results;
}
2019-03-03 06:36:18 +08:00
void PluginBackendFactory::loadPlugin()
{
2019-05-31 21:18:00 +08:00
for (const FileSystemPath_t& plugin : getPluginCandidates(baseName_))
{
2021-02-04 06:04:35 +08:00
auto lib = makePtr<cv::plugin::impl::DynamicLib>(plugin);
2019-03-03 06:36:18 +08:00
if (!lib->isLoaded())
continue;
try
{
Ptr<PluginBackend> pluginBackend = makePtr<PluginBackend>(lib);
if (!pluginBackend)
return;
if (pluginBackend->capture_api_)
{
if (pluginBackend->capture_api_->v0.id != id_)
{
CV_LOG_ERROR(NULL, "Video I/O: plugin '" << pluginBackend->capture_api_->api_header.api_description <<
"': unexpected backend ID: " <<
pluginBackend->capture_api_->v0.id << " vs " << (int)id_ << " (expected)");
return;
}
}
if (pluginBackend->writer_api_)
{
if (pluginBackend->writer_api_->v0.id != id_)
{
CV_LOG_ERROR(NULL, "Video I/O: plugin '" << pluginBackend->writer_api_->api_header.api_description <<
"': unexpected backend ID: " <<
pluginBackend->writer_api_->v0.id << " vs " << (int)id_ << " (expected)");
return;
}
}
if (pluginBackend->plugin_api_)
{
2020-12-04 11:18:16 +08:00
if (pluginBackend->plugin_api_->v0.captureAPI != id_)
2019-03-05 18:22:52 +08:00
{
CV_LOG_ERROR(NULL, "Video I/O: plugin '" << pluginBackend->plugin_api_->api_header.api_description <<
"': unexpected backend ID: " <<
2020-12-04 11:18:16 +08:00
pluginBackend->plugin_api_->v0.captureAPI << " vs " << (int)id_ << " (expected)");
2019-03-05 18:22:52 +08:00
return;
}
}
if (pluginBackend->capture_api_ == NULL && pluginBackend->writer_api_ == NULL
&& pluginBackend->plugin_api_ == NULL)
{
CV_LOG_ERROR(NULL, "Video I/O: no compatible plugin API for backend ID: " << (int)id_);
return;
}
backend = pluginBackend;
return;
2019-03-03 06:36:18 +08:00
}
catch (...)
{
2019-05-31 21:18:00 +08:00
CV_LOG_WARNING(NULL, "Video I/O: exception during plugin initialization: " << toPrintablePath(plugin) << ". SKIP");
}
}
}
2019-03-03 06:36:18 +08:00
//==================================================================================================
2019-03-03 06:36:18 +08:00
class PluginCapture : public cv::IVideoCapture
{
const OpenCV_VideoIO_Capture_Plugin_API* plugin_api_;
2019-03-03 06:36:18 +08:00
CvPluginCapture capture_;
public:
2019-03-03 06:36:18 +08:00
static
Ptr<PluginCapture> create(const OpenCV_VideoIO_Capture_Plugin_API* plugin_api,
const std::string &filename, int camera, const VideoCaptureParameters& params)
{
2019-03-03 06:36:18 +08:00
CV_Assert(plugin_api);
CV_Assert(plugin_api->v0.Capture_release);
2019-03-03 06:36:18 +08:00
CvPluginCapture capture = NULL;
if (plugin_api->api_header.api_version >= 1 && plugin_api->v1.Capture_open_with_params)
{
std::vector<int> vint_params = params.getIntVector();
Merge pull request #19460 from mikhail-nikolskiy:videoio-hw videoio: HW decode/encode in FFMPEG backend; new properties with support in FFMPEG/GST/MSMF * HW acceleration in FFMPEG backend * fixes on Windows, remove D3D9 * HW acceleration in FFMPEG backend * fixes on Windows, remove D3D9 * improve va test * Copyright * check LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 78, 100) // FFMPEG 3.4+ * CAP_MSMF test on .mp4 * .mp4 in test * improve va test * Copyright * check LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 78, 100) // FFMPEG 3.4+ * CAP_MSMF test on .mp4 * .mp4 in test * .avi for GStreamer test * revert changes around seek() * cv_writer_open_with_params * params.warnUnusedParameters * VideoCaptureParameters in GStreamer * open_with_params * params->getUnused * Reduce PSNR threshold 33->32 (other tests use 30) * require FFMPEG 4.0+; PSNR 30 as in other tests * GStreamer AVI-demux plugin not installed in Ubuntu test environment? * fix build on very old ffmpeg * fix build on very old ffmpeg * fix build issues * fix build issues (static_cast) * FFMPEG built on Windows without H264 encoder? * fix for write_nothing test on VAAPI * fix warnings * fix cv_writer_get_prop in plugins * use avcodec_get_hw_frames_parameters; more robust fallback to SW codecs * internal function hw_check_device() for device check/logging * two separate tests for HW read and write * image size 640x480 in encode test * WITH_VA=ON (only .h headers used in OpenCV, no linkage dependency) * exception on VP9 SW encoder? * rebase master; refine info message * videoio: fix FFmpeg standalone plugin build * videoio(ffmpeg): eliminate MSVC build warnings * address review comments * videoio(hw): update videocapture_acceleration.read test - remove parallel decoding by SW code path - check PSNR against the original generated image * videoio: minor fixes * videoio(test): disable unsupported MSMF cases (SW and HW) * videoio(test): update PSNR thresholds for HW acceleration read * videoio(test): update debug messages * "hw_acceleration" whitelisting parameter * little optimization in test * D3D11VA supports decoders, doesn't support encoders * videoio(test): adjust PSNR threshold in write_read_position tests * videoio(ffmpeg): fix rejecting on acceleration device name mismatch * videoio(ffmpeg): fix compilation USE_AV_HW_CODECS=0, add more debug logging * videoio: rework VideoAccelerationType behavior - enum is not a bitset - default value is backend specific - only '_NONE' and '_ANY' may fallback on software processing - specific H/W acceleration doesn't fallback on software processing. It fails if there is no support for specified H/W acceleration. * videoio(test): fix for current FFmpeg wrapper Co-authored-by: Alexander Alekhin <alexander.a.alekhin@gmail.com>
2021-03-01 23:51:04 +08:00
int* c_params = vint_params.data();
unsigned n_params = (unsigned)(vint_params.size() / 2);
if (CV_ERROR_OK == plugin_api->v1.Capture_open_with_params(
filename.empty() ? 0 : filename.c_str(), camera, c_params, n_params, &capture))
2019-03-03 06:36:18 +08:00
{
CV_Assert(capture);
return makePtr<PluginCapture>(plugin_api, capture);
}
}
else if (plugin_api->v0.Capture_open)
{
if (CV_ERROR_OK == plugin_api->v0.Capture_open(filename.empty() ? 0 : filename.c_str(), camera, &capture))
{
CV_Assert(capture);
Ptr<PluginCapture> cap = makePtr<PluginCapture>(plugin_api, capture);
if (cap && !params.empty())
{
applyParametersFallback(cap, params);
}
return cap;
}
}
2019-03-03 06:36:18 +08:00
return Ptr<PluginCapture>();
}
PluginCapture(const OpenCV_VideoIO_Capture_Plugin_API* plugin_api, CvPluginCapture capture)
2019-03-03 06:36:18 +08:00
: plugin_api_(plugin_api), capture_(capture)
{
CV_Assert(plugin_api_); CV_Assert(capture_);
}
~PluginCapture()
{
2020-12-04 11:18:16 +08:00
CV_DbgAssert(plugin_api_->v0.Capture_release);
if (CV_ERROR_OK != plugin_api_->v0.Capture_release(capture_))
2019-03-03 06:36:18 +08:00
CV_LOG_ERROR(NULL, "Video I/O: Can't release capture by plugin '" << plugin_api_->api_header.api_description << "'");
capture_ = NULL;
}
double getProperty(int prop) const CV_OVERRIDE
{
double val = -1;
2020-12-04 11:18:16 +08:00
if (plugin_api_->v0.Capture_getProperty)
if (CV_ERROR_OK != plugin_api_->v0.Capture_getProperty(capture_, prop, &val))
2019-03-03 06:36:18 +08:00
val = -1;
return val;
}
bool setProperty(int prop, double val) CV_OVERRIDE
{
2020-12-04 11:18:16 +08:00
if (plugin_api_->v0.Capture_setProperty)
if (CV_ERROR_OK == plugin_api_->v0.Capture_setProperty(capture_, prop, val))
2019-03-03 06:36:18 +08:00
return true;
return false;
}
bool grabFrame() CV_OVERRIDE
{
2020-12-04 11:18:16 +08:00
if (plugin_api_->v0.Capture_grab)
if (CV_ERROR_OK == plugin_api_->v0.Capture_grab(capture_))
2019-03-03 06:36:18 +08:00
return true;
return false;
}
static CvResult CV_API_CALL retrieve_callback(int stream_idx, const unsigned char* data, int step, int width, int height, int type, void* userdata)
{
2019-03-03 06:36:18 +08:00
CV_UNUSED(stream_idx);
cv::_OutputArray* dst = static_cast<cv::_OutputArray*>(userdata);
if (!dst)
return CV_ERROR_FAIL;
cv::Mat(cv::Size(width, height), type, (void*)data, step).copyTo(*dst);
2019-03-03 06:36:18 +08:00
return CV_ERROR_OK;
}
bool retrieveFrame(int idx, cv::OutputArray img) CV_OVERRIDE
{
2019-03-03 06:36:18 +08:00
bool res = false;
2020-12-04 11:18:16 +08:00
if (plugin_api_->v0.Capture_retreive)
if (CV_ERROR_OK == plugin_api_->v0.Capture_retreive(capture_, idx, retrieve_callback, (cv::_OutputArray*)&img))
2019-03-03 06:36:18 +08:00
res = true;
return res;
}
bool isOpened() const CV_OVERRIDE
{
2019-03-03 06:36:18 +08:00
return capture_ != NULL; // TODO always true
}
int getCaptureDomain() CV_OVERRIDE
{
return plugin_api_->v0.id;
}
};
2019-03-03 06:36:18 +08:00
//==================================================================================================
2019-03-03 06:36:18 +08:00
class PluginWriter : public cv::IVideoWriter
{
const OpenCV_VideoIO_Writer_Plugin_API* plugin_api_;
2019-03-03 06:36:18 +08:00
CvPluginWriter writer_;
public:
2019-03-03 06:36:18 +08:00
static
Ptr<PluginWriter> create(const OpenCV_VideoIO_Writer_Plugin_API* plugin_api,
const std::string& filename, int fourcc, double fps, const cv::Size& sz,
const VideoWriterParameters& params)
{
2019-03-03 06:36:18 +08:00
CV_Assert(plugin_api);
CV_Assert(plugin_api->v0.Writer_release);
CV_Assert(!filename.empty());
2019-03-03 06:36:18 +08:00
CvPluginWriter writer = NULL;
2020-12-04 11:18:16 +08:00
if (plugin_api->api_header.api_version >= 1 && plugin_api->v1.Writer_open_with_params)
{
std::vector<int> vint_params = params.getIntVector();
int* c_params = &vint_params[0];
unsigned n_params = (unsigned)(vint_params.size() / 2);
2020-12-04 11:18:16 +08:00
if (CV_ERROR_OK == plugin_api->v1.Writer_open_with_params(filename.c_str(), fourcc, fps, sz.width, sz.height, c_params, n_params, &writer))
{
CV_Assert(writer);
return makePtr<PluginWriter>(plugin_api, writer);
}
}
2020-12-04 11:18:16 +08:00
else if (plugin_api->v0.Writer_open)
{
const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
const int depth = params.get(VIDEOWRITER_PROP_DEPTH, CV_8U);
if (depth != CV_8U)
{
CV_LOG_WARNING(NULL, "Video I/O plugin doesn't support (due to lower API level) creation of VideoWriter with depth != CV_8U");
return Ptr<PluginWriter>();
}
if (params.warnUnusedParameters())
{
Merge pull request #19460 from mikhail-nikolskiy:videoio-hw videoio: HW decode/encode in FFMPEG backend; new properties with support in FFMPEG/GST/MSMF * HW acceleration in FFMPEG backend * fixes on Windows, remove D3D9 * HW acceleration in FFMPEG backend * fixes on Windows, remove D3D9 * improve va test * Copyright * check LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 78, 100) // FFMPEG 3.4+ * CAP_MSMF test on .mp4 * .mp4 in test * improve va test * Copyright * check LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 78, 100) // FFMPEG 3.4+ * CAP_MSMF test on .mp4 * .mp4 in test * .avi for GStreamer test * revert changes around seek() * cv_writer_open_with_params * params.warnUnusedParameters * VideoCaptureParameters in GStreamer * open_with_params * params->getUnused * Reduce PSNR threshold 33->32 (other tests use 30) * require FFMPEG 4.0+; PSNR 30 as in other tests * GStreamer AVI-demux plugin not installed in Ubuntu test environment? * fix build on very old ffmpeg * fix build on very old ffmpeg * fix build issues * fix build issues (static_cast) * FFMPEG built on Windows without H264 encoder? * fix for write_nothing test on VAAPI * fix warnings * fix cv_writer_get_prop in plugins * use avcodec_get_hw_frames_parameters; more robust fallback to SW codecs * internal function hw_check_device() for device check/logging * two separate tests for HW read and write * image size 640x480 in encode test * WITH_VA=ON (only .h headers used in OpenCV, no linkage dependency) * exception on VP9 SW encoder? * rebase master; refine info message * videoio: fix FFmpeg standalone plugin build * videoio(ffmpeg): eliminate MSVC build warnings * address review comments * videoio(hw): update videocapture_acceleration.read test - remove parallel decoding by SW code path - check PSNR against the original generated image * videoio: minor fixes * videoio(test): disable unsupported MSMF cases (SW and HW) * videoio(test): update PSNR thresholds for HW acceleration read * videoio(test): update debug messages * "hw_acceleration" whitelisting parameter * little optimization in test * D3D11VA supports decoders, doesn't support encoders * videoio(test): adjust PSNR threshold in write_read_position tests * videoio(ffmpeg): fix rejecting on acceleration device name mismatch * videoio(ffmpeg): fix compilation USE_AV_HW_CODECS=0, add more debug logging * videoio: rework VideoAccelerationType behavior - enum is not a bitset - default value is backend specific - only '_NONE' and '_ANY' may fallback on software processing - specific H/W acceleration doesn't fallback on software processing. It fails if there is no support for specified H/W acceleration. * videoio(test): fix for current FFmpeg wrapper Co-authored-by: Alexander Alekhin <alexander.a.alekhin@gmail.com>
2021-03-01 23:51:04 +08:00
CV_LOG_ERROR(NULL, "VIDEOIO: unsupported parameters in VideoWriter, see logger INFO channel for details");
return Ptr<PluginWriter>();
}
2020-12-04 11:18:16 +08:00
if (CV_ERROR_OK == plugin_api->v0.Writer_open(filename.c_str(), fourcc, fps, sz.width, sz.height, isColor, &writer))
2019-03-03 06:36:18 +08:00
{
CV_Assert(writer);
return makePtr<PluginWriter>(plugin_api, writer);
}
}
2019-03-03 06:36:18 +08:00
return Ptr<PluginWriter>();
}
PluginWriter(const OpenCV_VideoIO_Writer_Plugin_API* plugin_api, CvPluginWriter writer)
2019-03-03 06:36:18 +08:00
: plugin_api_(plugin_api), writer_(writer)
{
CV_Assert(plugin_api_); CV_Assert(writer_);
}
~PluginWriter()
{
2020-12-04 11:18:16 +08:00
CV_DbgAssert(plugin_api_->v0.Writer_release);
if (CV_ERROR_OK != plugin_api_->v0.Writer_release(writer_))
2019-03-03 06:36:18 +08:00
CV_LOG_ERROR(NULL, "Video I/O: Can't release writer by plugin '" << plugin_api_->api_header.api_description << "'");
writer_ = NULL;
}
double getProperty(int prop) const CV_OVERRIDE
{
double val = -1;
2020-12-04 11:18:16 +08:00
if (plugin_api_->v0.Writer_getProperty)
if (CV_ERROR_OK != plugin_api_->v0.Writer_getProperty(writer_, prop, &val))
2019-03-03 06:36:18 +08:00
val = -1;
return val;
}
bool setProperty(int prop, double val) CV_OVERRIDE
{
2020-12-04 11:18:16 +08:00
if (plugin_api_->v0.Writer_setProperty)
if (CV_ERROR_OK == plugin_api_->v0.Writer_setProperty(writer_, prop, val))
2019-03-03 06:36:18 +08:00
return true;
return false;
}
bool isOpened() const CV_OVERRIDE
{
2019-03-03 06:36:18 +08:00
return writer_ != NULL; // TODO always true
}
void write(cv::InputArray arr) CV_OVERRIDE
{
cv::Mat img = arr.getMat();
2019-03-03 06:36:18 +08:00
CV_DbgAssert(writer_);
2020-12-04 11:18:16 +08:00
CV_Assert(plugin_api_->v0.Writer_write);
if (CV_ERROR_OK != plugin_api_->v0.Writer_write(writer_, img.data, (int)img.step[0], img.cols, img.rows, img.channels()))
2019-03-03 06:36:18 +08:00
{
CV_LOG_DEBUG(NULL, "Video I/O: Can't write frame by plugin '" << plugin_api_->api_header.api_description << "'");
}
// TODO return bool result?
}
int getCaptureDomain() const CV_OVERRIDE
{
return plugin_api_->v0.id;
}
};
2019-03-03 06:36:18 +08:00
Ptr<IVideoCapture> PluginBackend::createCapture(int camera, const VideoCaptureParameters& params) const
2019-03-03 06:36:18 +08:00
{
try
{
if (capture_api_)
return PluginCapture::create(capture_api_, std::string(), camera, params); //.staticCast<IVideoCapture>();
2019-03-03 06:36:18 +08:00
if (plugin_api_)
{
Ptr<IVideoCapture> cap = legacy::PluginCapture::create(plugin_api_, std::string(), camera); //.staticCast<IVideoCapture>();
if (cap && !params.empty())
{
applyParametersFallback(cap, params);
}
return cap;
}
2019-03-03 06:36:18 +08:00
}
catch (...)
{
CV_LOG_DEBUG(NULL, "Video I/O: can't create camera capture: " << camera);
throw;
2019-03-03 06:36:18 +08:00
}
return Ptr<IVideoCapture>();
}
Ptr<IVideoCapture> PluginBackend::createCapture(const std::string &filename, const VideoCaptureParameters& params) const
2019-03-03 06:36:18 +08:00
{
try
{
if (capture_api_)
return PluginCapture::create(capture_api_, filename, 0, params); //.staticCast<IVideoCapture>();
2019-03-03 06:36:18 +08:00
if (plugin_api_)
{
Ptr<IVideoCapture> cap = legacy::PluginCapture::create(plugin_api_, filename, 0); //.staticCast<IVideoCapture>();
if (cap && !params.empty())
{
applyParametersFallback(cap, params);
}
return cap;
}
2019-03-03 06:36:18 +08:00
}
catch (...)
{
CV_LOG_DEBUG(NULL, "Video I/O: can't open file capture: " << filename);
throw;
2019-03-03 06:36:18 +08:00
}
return Ptr<IVideoCapture>();
}
Ptr<IVideoWriter> PluginBackend::createWriter(const std::string& filename, int fourcc, double fps,
const cv::Size& sz, const VideoWriterParameters& params) const
2019-03-03 06:36:18 +08:00
{
try
{
if (writer_api_)
return PluginWriter::create(writer_api_, filename, fourcc, fps, sz, params); //.staticCast<IVideoWriter>();
2019-03-03 06:36:18 +08:00
if (plugin_api_)
return legacy::PluginWriter::create(plugin_api_, filename, fourcc, fps, sz, params); //.staticCast<IVideoWriter>();
2019-03-03 06:36:18 +08:00
}
catch (...)
{
CV_LOG_DEBUG(NULL, "Video I/O: can't open writer: " << filename);
}
return Ptr<IVideoWriter>();
}
2021-02-04 06:04:35 +08:00
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS)
2019-03-03 06:36:18 +08:00
} // namespace
Ptr<IBackendFactory> createPluginBackendFactory(VideoCaptureAPIs id, const char* baseName)
{
2021-02-04 06:04:35 +08:00
#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS)
2019-03-03 06:36:18 +08:00
return makePtr<impl::PluginBackendFactory>(id, baseName); //.staticCast<IBackendFactory>();
2021-02-04 06:04:35 +08:00
#else
CV_UNUSED(id);
CV_UNUSED(baseName);
2021-02-04 06:04:35 +08:00
return Ptr<IBackendFactory>();
#endif
2019-03-03 06:36:18 +08:00
}
std::string getCapturePluginVersion(
const Ptr<IBackendFactory>& backend_factory,
CV_OUT int& version_ABI,
CV_OUT int& version_API
)
{
#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS)
using namespace impl;
CV_Assert(backend_factory);
PluginBackendFactory* plugin_backend_factory = dynamic_cast<PluginBackendFactory*>(backend_factory.get());
CV_Assert(plugin_backend_factory);
return plugin_backend_factory->getCapturePluginVersion(version_ABI, version_API);
#else
CV_UNUSED(backend_factory);
CV_UNUSED(version_ABI);
CV_UNUSED(version_API);
CV_Error(Error::StsBadFunc, "Plugins are not available in this build");
#endif
}
std::string getWriterPluginVersion(
const Ptr<IBackendFactory>& backend_factory,
CV_OUT int& version_ABI,
CV_OUT int& version_API
)
{
#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS)
using namespace impl;
CV_Assert(backend_factory);
PluginBackendFactory* plugin_backend_factory = dynamic_cast<PluginBackendFactory*>(backend_factory.get());
CV_Assert(plugin_backend_factory);
return plugin_backend_factory->getWriterPluginVersion(version_ABI, version_API);
#else
CV_UNUSED(backend_factory);
CV_UNUSED(version_ABI);
CV_UNUSED(version_API);
CV_Error(Error::StsBadFunc, "Plugins are not available in this build");
#endif
}
2019-03-03 06:36:18 +08:00
} // namespace