mirror of
https://github.com/opencv/opencv.git
synced 2024-11-29 05:29:54 +08:00
Merge pull request #13970 from alalek:videoio_plugins_update
This commit is contained in:
commit
b46fa2e556
@ -92,6 +92,7 @@
|
||||
@{
|
||||
@defgroup core_hal_intrin_impl Private implementation helpers
|
||||
@}
|
||||
@defgroup core_lowlevel_api Low-level API for external libraries / plugins
|
||||
@}
|
||||
@}
|
||||
*/
|
||||
|
94
modules/core/include/opencv2/core/llapi/llapi.h
Normal file
94
modules/core/include/opencv2/core/llapi/llapi.h
Normal file
@ -0,0 +1,94 @@
|
||||
// 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.
|
||||
|
||||
|
||||
#ifndef OPENCV_CORE_LLAPI_LLAPI_H
|
||||
#define OPENCV_CORE_LLAPI_LLAPI_H
|
||||
/**
|
||||
@addtogroup core_lowlevel_api
|
||||
|
||||
API for OpenCV external plugins:
|
||||
- HAL accelerators
|
||||
- VideoIO camera backends / decoders / encoders
|
||||
- Imgcodecs encoders / decoders
|
||||
|
||||
Plugins are usually built separately or before OpenCV (OpenCV can depend on them - like HAL libraries).
|
||||
|
||||
Using this approach OpenCV provides some basic low level functionality for external plugins.
|
||||
|
||||
@note Preview only (no backward compatibility)
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#ifndef CV_API_CALL
|
||||
//! calling convention (including callbacks)
|
||||
#define CV_API_CALL
|
||||
#endif
|
||||
|
||||
typedef enum cvResult
|
||||
{
|
||||
CV_ERROR_FAIL = -1, //!< Some error occured (TODO Require to fill exception information)
|
||||
CV_ERROR_OK = 0 //!< No error
|
||||
} CvResult;
|
||||
|
||||
typedef struct OpenCV_API_Header_t
|
||||
{
|
||||
/** @brief valid size of this structure
|
||||
@details `assert(api.header.valid_size >= sizeof(OpenCV_<Name>_API_v<N>));`
|
||||
*/
|
||||
size_t valid_size;
|
||||
unsigned min_api_version; //!< backward compatible API version
|
||||
unsigned api_version; //!< provided API version (features)
|
||||
unsigned opencv_version_major; //!< compiled OpenCV version
|
||||
unsigned opencv_version_minor; //!< compiled OpenCV version
|
||||
unsigned opencv_version_patch; //!< compiled OpenCV version
|
||||
const char* opencv_version_status; //!< compiled OpenCV version
|
||||
const char* api_description; //!< API description (debug purposes only)
|
||||
} OpenCV_API_Header;
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
typedef int (CV_API_CALL *cv_example_callback1_cb_t)(unsigned const char* cb_result, void* cb_context);
|
||||
|
||||
struct OpenCV_Example_API_v1
|
||||
{
|
||||
OpenCV_API_Header header;
|
||||
|
||||
/** @brief Some API call
|
||||
|
||||
@param param1 description1
|
||||
@param param2 description2
|
||||
|
||||
@note API-CALL 1, API-Version >=1
|
||||
*/
|
||||
CvResult (CV_API_CALL *Request1)(int param1, const char* param2);
|
||||
|
||||
/** @brief Register callback
|
||||
|
||||
@param callback function to handle callback
|
||||
@param cb_context context data passed to callback function
|
||||
@param[out] cb_handle callback id (used to unregister callback)
|
||||
|
||||
@note API-CALL 2, API-Version >=1
|
||||
*/
|
||||
CvResult (CV_API_CALL *RegisterCallback)(cv_example_callback1_cb_t callback, void* cb_context, CV_OUT unsigned* cb_handle);
|
||||
|
||||
/** @brief Unregister callback
|
||||
|
||||
@param cb_handle callback handle
|
||||
|
||||
@note API-CALL 3, API-Version >=1
|
||||
*/
|
||||
CvResult (CV_API_CALL *UnegisterCallback)(unsigned cb_handle);
|
||||
|
||||
...
|
||||
};
|
||||
#endif // 0
|
||||
|
||||
//! @}
|
||||
|
||||
#endif // OPENCV_CORE_LLAPI_LLAPI_H
|
@ -21,7 +21,8 @@ set(videoio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/src/cap_images.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/src/cap_mjpeg_encoder.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/src/cap_mjpeg_decoder.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/src/backend.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/src/backend_plugin.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/src/backend_static.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/src/container_avi.cpp")
|
||||
|
||||
file(GLOB videoio_ext_hdrs
|
||||
|
@ -16,7 +16,7 @@ function(ocv_create_builtin_videoio_plugin name target videoio_src_file)
|
||||
|
||||
add_library(${name} MODULE
|
||||
"${CMAKE_CURRENT_LIST_DIR}/src/${videoio_src_file}"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/src/plugin_api.cpp")
|
||||
)
|
||||
target_include_directories(${name} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
target_compile_definitions(${name} PRIVATE BUILD_PLUGIN)
|
||||
target_link_libraries(${name} PRIVATE ${target})
|
||||
@ -66,7 +66,7 @@ function(ocv_create_videoio_plugin default_name target target_desc videoio_src_f
|
||||
set(imgproc_ROOT "${modules_ROOT}/imgproc")
|
||||
set(imgcodecs_ROOT "${modules_ROOT}/imgcodecs")
|
||||
|
||||
add_library(${OPENCV_PLUGIN_NAME} MODULE "${videoio_ROOT}/src/${videoio_src_file}" "${videoio_ROOT}/src/plugin_api.cpp")
|
||||
add_library(${OPENCV_PLUGIN_NAME} MODULE "${videoio_ROOT}/src/${videoio_src_file}")
|
||||
target_include_directories(${OPENCV_PLUGIN_NAME} PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${videoio_ROOT}/src"
|
||||
|
@ -38,15 +38,8 @@ CV_EXPORTS_W std::vector<VideoCaptureAPIs> getStreamBackends();
|
||||
/** @brief Returns list of available backends which works via `cv::VideoWriter()` */
|
||||
CV_EXPORTS_W std::vector<VideoCaptureAPIs> getWriterBackends();
|
||||
|
||||
enum Capability
|
||||
{
|
||||
Read,
|
||||
Write,
|
||||
ReadWrite
|
||||
};
|
||||
|
||||
/** @brief Returns true if backend is available */
|
||||
CV_EXPORTS bool hasBackend(VideoCaptureAPIs api, Capability cap = ReadWrite);
|
||||
CV_EXPORTS bool hasBackend(VideoCaptureAPIs api);
|
||||
|
||||
//! @}
|
||||
}} // namespace
|
||||
|
@ -1,491 +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.
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include "backend.hpp"
|
||||
#include "plugin_api.hpp"
|
||||
|
||||
#include "opencv2/core/utils/filesystem.hpp"
|
||||
#include "opencv2/core/utils/configuration.private.hpp"
|
||||
#include "opencv2/core/private.hpp"
|
||||
#include "videoio_registry.hpp"
|
||||
|
||||
//==================================================================================================
|
||||
// IBackend implementation
|
||||
|
||||
namespace cv {
|
||||
|
||||
static bool param_VIDEOIO_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOIO_DEBUG", false);
|
||||
static bool param_VIDEOCAPTURE_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOCAPTURE_DEBUG", false);
|
||||
static bool param_VIDEOWRITER_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOWRITER_DEBUG", false);
|
||||
|
||||
Ptr<IVideoCapture> IBackend::tryOpenCapture(const std::string & backendName, const std::string & filename, int cameraNum) const
|
||||
{
|
||||
try
|
||||
{
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", backendName.c_str()));
|
||||
Ptr<IVideoCapture> icap = createCapture(filename, cameraNum);
|
||||
if (param_VIDEOIO_DEBUG ||param_VIDEOCAPTURE_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p isOpened=%d ...\n", backendName.c_str(), icap.empty() ? NULL : icap.get(), icap.empty() ? -1: icap->isOpened()));
|
||||
return icap;
|
||||
}
|
||||
catch(const cv::Exception& e)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", backendName.c_str(), e.what()));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", backendName.c_str(), e.what()));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", backendName.c_str()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Ptr<IVideoWriter> IBackend::tryOpenWriter(const std::string & backendName, const std::string& filename, int _fourcc, double fps, const Size &frameSize, bool isColor) const
|
||||
{
|
||||
try
|
||||
{
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", backendName.c_str()));
|
||||
Ptr<IVideoWriter> iwriter = createWriter(filename, _fourcc, fps, frameSize, isColor);
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p isOpened=%d...\n", backendName.c_str(), iwriter.empty() ? NULL : iwriter.get(), iwriter.empty() ? iwriter->isOpened() : -1));
|
||||
return iwriter;
|
||||
}
|
||||
catch(const cv::Exception& e)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", backendName.c_str(), e.what()));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", backendName.c_str(), e.what()));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", backendName.c_str()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // cv::
|
||||
|
||||
//==================================================================================================
|
||||
// Dynamic backend implementation
|
||||
|
||||
#include "opencv2/core/utils/logger.hpp"
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(__linux__) || defined(__APPLE__)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
inline static void * getSymbol_(void *h, const std::string &symbolName)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return (void*)GetProcAddress(static_cast<HMODULE>(h), symbolName.c_str());
|
||||
#elif defined(__linux__) || defined(__APPLE__)
|
||||
return dlsym(h, symbolName.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static void * libraryLoad_(const std::string &filename)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return static_cast<HMODULE>(LoadLibraryA(filename.c_str()));
|
||||
#elif defined(__linux__) || defined(__APPLE__)
|
||||
return dlopen(filename.c_str(), RTLD_LAZY);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static void libraryRelease_(void *h)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
FreeLibrary(static_cast<HMODULE>(h));
|
||||
#elif defined(__linux__) || defined(__APPLE__)
|
||||
dlclose(h);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static std::string libraryPrefix()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return string();
|
||||
#else
|
||||
return "lib";
|
||||
#endif
|
||||
}
|
||||
inline static std::string librarySuffix()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return "dll";
|
||||
#elif defined(__APPLE__)
|
||||
return "dylib";
|
||||
#else
|
||||
return "so";
|
||||
#endif
|
||||
}
|
||||
|
||||
//============================
|
||||
|
||||
class cv::DynamicBackend::DynamicLib
|
||||
{
|
||||
private:
|
||||
void * handle;
|
||||
const std::string fname;
|
||||
|
||||
public:
|
||||
DynamicLib(const std::string &filename)
|
||||
: handle(0), fname(filename)
|
||||
{
|
||||
libraryLoad(filename);
|
||||
}
|
||||
~DynamicLib()
|
||||
{
|
||||
libraryRelease();
|
||||
}
|
||||
bool isLoaded() const
|
||||
{
|
||||
return handle != NULL;
|
||||
}
|
||||
void* getSymbol(const std::string & symbolName) const
|
||||
{
|
||||
if (!handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void * res = getSymbol_(handle, symbolName);
|
||||
if (!res)
|
||||
CV_LOG_ERROR(NULL, "No symbol '" << symbolName << "' in " << fname);
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
void libraryLoad(const std::string &filename)
|
||||
{
|
||||
handle = libraryLoad_(filename);
|
||||
CV_LOG_INFO(NULL, "load " << filename << " => " << (handle ? "OK" : "FAILED"));
|
||||
}
|
||||
void libraryRelease()
|
||||
{
|
||||
CV_LOG_INFO(NULL, "unload "<< fname);
|
||||
if (handle)
|
||||
{
|
||||
libraryRelease_(handle);
|
||||
handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DynamicLib(const DynamicLib &);
|
||||
DynamicLib &operator=(const DynamicLib &);
|
||||
};
|
||||
|
||||
|
||||
//============================
|
||||
|
||||
// Utility function
|
||||
static bool verifyVersion(cv_get_version_t * fun)
|
||||
{
|
||||
if (!fun)
|
||||
return false;
|
||||
int major, minor, patch, api, abi;
|
||||
fun(major, minor, patch, api, abi);
|
||||
if (api < API_VERSION || abi != ABI_VERSION)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "Bad plugin API/ABI (" << api << "/" << abi << "), expected " << API_VERSION << "/" << ABI_VERSION);
|
||||
return false;
|
||||
}
|
||||
#ifdef STRICT_PLUGIN_CHECK
|
||||
if (major != CV_MAJOR_VERSION || minor != CV_MINOR_VERSION)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "Bad plugin version (" << major << "." << minor << "), expected " << CV_MAJOR_VERSION << "/" << CV_MINOR_VERSION);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
//============================
|
||||
|
||||
class cv::DynamicBackend::CaptureTable
|
||||
{
|
||||
public:
|
||||
cv_get_version_t *cv_get_version;
|
||||
cv_domain_t *cv_domain;
|
||||
cv_open_capture_t *cv_open_capture;
|
||||
cv_get_cap_prop_t *cv_get_cap_prop;
|
||||
cv_set_cap_prop_t *cv_set_cap_prop;
|
||||
cv_grab_t *cv_grab;
|
||||
cv_retrieve_t *cv_retrieve;
|
||||
cv_release_capture_t *cv_release_capture;
|
||||
bool isComplete;
|
||||
public:
|
||||
CaptureTable(const cv::DynamicBackend::DynamicLib & p)
|
||||
: isComplete(true)
|
||||
{
|
||||
#define READ_FUN(name) \
|
||||
name = reinterpret_cast<name##_t*>(p.getSymbol(#name)); \
|
||||
isComplete = isComplete && (name)
|
||||
|
||||
READ_FUN(cv_get_version);
|
||||
READ_FUN(cv_domain);
|
||||
READ_FUN(cv_open_capture);
|
||||
READ_FUN(cv_get_cap_prop);
|
||||
READ_FUN(cv_set_cap_prop);
|
||||
READ_FUN(cv_grab);
|
||||
READ_FUN(cv_retrieve);
|
||||
READ_FUN(cv_release_capture);
|
||||
|
||||
#undef READ_FUN
|
||||
}
|
||||
};
|
||||
|
||||
class cv::DynamicBackend::WriterTable
|
||||
{
|
||||
public:
|
||||
cv_get_version_t *cv_get_version;
|
||||
cv_domain_t *cv_domain;
|
||||
cv_open_writer_t *cv_open_writer;
|
||||
cv_get_wri_prop_t *cv_get_wri_prop;
|
||||
cv_set_wri_prop_t *cv_set_wri_prop;
|
||||
cv_write_t *cv_write;
|
||||
cv_release_writer_t *cv_release_writer;
|
||||
bool isComplete;
|
||||
public:
|
||||
WriterTable(const cv::DynamicBackend::DynamicLib & p)
|
||||
: isComplete(true)
|
||||
{
|
||||
#define READ_FUN(name) \
|
||||
name = reinterpret_cast<name##_t*>(p.getSymbol(#name)); \
|
||||
isComplete = isComplete && (name)
|
||||
|
||||
READ_FUN(cv_get_version);
|
||||
READ_FUN(cv_domain);
|
||||
READ_FUN(cv_open_writer);
|
||||
READ_FUN(cv_get_wri_prop);
|
||||
READ_FUN(cv_set_wri_prop);
|
||||
READ_FUN(cv_write);
|
||||
READ_FUN(cv_release_writer);
|
||||
|
||||
#undef READ_FUN
|
||||
}
|
||||
};
|
||||
|
||||
//============================
|
||||
|
||||
class DynamicCapture;
|
||||
class DynamicWriter;
|
||||
|
||||
cv::DynamicBackend::DynamicBackend(const std::string &filename)
|
||||
: lib(0), cap_tbl(0), wri_tbl(0)
|
||||
{
|
||||
lib = new DynamicLib(filename);
|
||||
if (lib->isLoaded())
|
||||
{
|
||||
cap_tbl = new CaptureTable(*lib);
|
||||
wri_tbl = new WriterTable(*lib);
|
||||
}
|
||||
}
|
||||
|
||||
cv::DynamicBackend::~DynamicBackend()
|
||||
{
|
||||
if (cap_tbl)
|
||||
delete cap_tbl;
|
||||
if (wri_tbl)
|
||||
delete wri_tbl;
|
||||
if (lib)
|
||||
delete lib;
|
||||
}
|
||||
|
||||
bool cv::DynamicBackend::canCreateCapture(VideoCaptureAPIs api) const
|
||||
{
|
||||
return lib && lib->isLoaded() && cap_tbl && cap_tbl->isComplete && verifyVersion(cap_tbl->cv_get_version) && (cap_tbl->cv_domain() == api);
|
||||
}
|
||||
|
||||
bool cv::DynamicBackend::canCreateWriter(VideoCaptureAPIs api) const
|
||||
{
|
||||
return lib && lib->isLoaded() && wri_tbl && wri_tbl->isComplete && verifyVersion(wri_tbl->cv_get_version) && (wri_tbl->cv_domain() == api);
|
||||
}
|
||||
|
||||
cv::Ptr<cv::IVideoCapture> cv::DynamicBackend::createCapture(const std::string & filename, int camera) const
|
||||
{
|
||||
return makePtr<DynamicCapture>(cap_tbl, filename, camera).staticCast<IVideoCapture>();
|
||||
}
|
||||
|
||||
cv::Ptr<cv::IVideoWriter> cv::DynamicBackend::createWriter(const std::string & filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const
|
||||
{
|
||||
return makePtr<DynamicWriter>(wri_tbl, filename, fourcc, fps, sz, isColor).staticCast<IVideoWriter>();
|
||||
}
|
||||
|
||||
inline static std::vector<string> getPluginCandidates()
|
||||
{
|
||||
using namespace cv::utils;
|
||||
using namespace cv::utils::fs;
|
||||
const vector<string> default_paths = { getParent(getBinLocation()) };
|
||||
const vector<string> paths = getConfigurationParameterPaths("OPENCV_VIDEOIO_PLUGIN_PATH", default_paths);
|
||||
const string default_expr = libraryPrefix() + "opencv_videoio_*." + librarySuffix();
|
||||
const string expr = getConfigurationParameterString("OPENCV_VIDEOIO_PLUGIN_NAME", default_expr.c_str());
|
||||
CV_LOG_INFO(NULL, "VideoIO pluigins: glob is '" << expr << "', " << paths.size() << " location(s)");
|
||||
vector<string> results;
|
||||
for(const string & path : paths)
|
||||
{
|
||||
if (path.empty())
|
||||
continue;
|
||||
vector<string> candidates;
|
||||
cv::glob(join(path, expr), candidates);
|
||||
CV_LOG_INFO(NULL, "VideoIO pluigins in " << path << ": " << candidates.size());
|
||||
copy(candidates.begin(), candidates.end(), back_inserter(results));
|
||||
}
|
||||
CV_LOG_INFO(NULL, "Found " << results.size() << " plugin(s)");
|
||||
return results;
|
||||
}
|
||||
|
||||
cv::Ptr<cv::DynamicBackend> cv::DynamicBackend::load(cv::VideoCaptureAPIs api, int mode)
|
||||
{
|
||||
for(const std::string & plugin : getPluginCandidates())
|
||||
{
|
||||
bool res = true;
|
||||
Ptr<DynamicBackend> factory = makePtr<DynamicBackend>(plugin);
|
||||
if (factory)
|
||||
if (mode & cv::MODE_CAPTURE_BY_INDEX || mode & cv::MODE_CAPTURE_BY_FILENAME)
|
||||
{
|
||||
res = res && factory->canCreateCapture(api);
|
||||
}
|
||||
if (mode & cv::MODE_WRITER)
|
||||
{
|
||||
res = res && factory->canCreateWriter(api);
|
||||
}
|
||||
if (res)
|
||||
return factory;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// DynamicCapture
|
||||
|
||||
class DynamicCapture : public cv::IVideoCapture
|
||||
{
|
||||
const cv::DynamicBackend::CaptureTable * tbl;
|
||||
void * capture;
|
||||
public:
|
||||
DynamicCapture(const cv::DynamicBackend::CaptureTable * tbl_, const std::string &filename, int camera)
|
||||
: tbl(tbl_), capture(0)
|
||||
{
|
||||
CV_Assert(!capture);
|
||||
if (tbl->cv_open_capture)
|
||||
tbl->cv_open_capture(filename.empty() ? 0 : filename.c_str(), camera, capture);
|
||||
}
|
||||
~DynamicCapture()
|
||||
{
|
||||
if (capture)
|
||||
{
|
||||
CV_Assert(tbl->cv_release_capture);
|
||||
tbl->cv_release_capture(capture);
|
||||
capture = 0;
|
||||
}
|
||||
}
|
||||
double getProperty(int prop) const CV_OVERRIDE
|
||||
{
|
||||
CV_Assert(capture);
|
||||
double val = -1;
|
||||
tbl->cv_get_cap_prop(capture, prop, val);
|
||||
return val;
|
||||
}
|
||||
bool setProperty(int prop, double val) CV_OVERRIDE
|
||||
{
|
||||
CV_Assert(capture);
|
||||
return tbl->cv_set_cap_prop(capture, prop, val);
|
||||
}
|
||||
bool grabFrame() CV_OVERRIDE
|
||||
{
|
||||
CV_Assert(capture);
|
||||
return tbl->cv_grab(capture);
|
||||
}
|
||||
static bool local_retrieve(unsigned char * data, int step, int width, int height, int cn, void * userdata)
|
||||
{
|
||||
cv::Mat * img = static_cast<cv::Mat*>(userdata);
|
||||
if (!img)
|
||||
return false;
|
||||
cv::Mat(cv::Size(width, height), CV_MAKETYPE(CV_8U, cn), data, step).copyTo(*img);
|
||||
return true;
|
||||
}
|
||||
bool retrieveFrame(int idx, cv::OutputArray img) CV_OVERRIDE
|
||||
{
|
||||
CV_Assert(capture);
|
||||
cv::Mat frame;
|
||||
bool res = tbl->cv_retrieve(capture, idx, &local_retrieve, &frame);
|
||||
if (res)
|
||||
frame.copyTo(img);
|
||||
return res;
|
||||
}
|
||||
bool isOpened() const CV_OVERRIDE
|
||||
{
|
||||
return capture != NULL;
|
||||
}
|
||||
int getCaptureDomain() CV_OVERRIDE
|
||||
{
|
||||
return tbl->cv_domain();
|
||||
}
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
// DynamicWriter
|
||||
|
||||
class DynamicWriter : public cv::IVideoWriter
|
||||
{
|
||||
const cv::DynamicBackend::WriterTable * tbl;
|
||||
void * writer;
|
||||
public:
|
||||
DynamicWriter(const cv::DynamicBackend::WriterTable * tbl_, const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor)
|
||||
: tbl(tbl_), writer(0)
|
||||
{
|
||||
CV_Assert(!writer);
|
||||
if(tbl->cv_open_writer)
|
||||
tbl->cv_open_writer(filename.empty() ? 0 : filename.c_str(), fourcc, fps, sz.width, sz.height, isColor, writer);
|
||||
}
|
||||
~DynamicWriter()
|
||||
{
|
||||
if (writer)
|
||||
{
|
||||
CV_Assert(tbl->cv_release_writer);
|
||||
tbl->cv_release_writer(writer);
|
||||
writer = 0;
|
||||
}
|
||||
}
|
||||
double getProperty(int prop) const CV_OVERRIDE
|
||||
{
|
||||
CV_Assert(writer);
|
||||
double val = -1;
|
||||
tbl->cv_get_wri_prop(writer, prop, val);
|
||||
return val;
|
||||
}
|
||||
bool setProperty(int prop, double val) CV_OVERRIDE
|
||||
{
|
||||
CV_Assert(writer);
|
||||
return tbl->cv_set_wri_prop(writer, prop, val);
|
||||
}
|
||||
bool isOpened() const CV_OVERRIDE
|
||||
{
|
||||
return writer != NULL;
|
||||
}
|
||||
void write(cv::InputArray arr) CV_OVERRIDE
|
||||
{
|
||||
cv::Mat img = arr.getMat();
|
||||
CV_Assert(writer);
|
||||
tbl->cv_write(writer, img.data, (int)img.step[0], img.cols, img.rows, img.channels());
|
||||
}
|
||||
int getCaptureDomain() const CV_OVERRIDE
|
||||
{
|
||||
return tbl->cv_domain();
|
||||
}
|
||||
};
|
@ -15,71 +15,30 @@ namespace cv {
|
||||
class IBackend
|
||||
{
|
||||
public:
|
||||
Ptr<IVideoCapture> tryOpenCapture(const std::string & backendName, const std::string & filename, int cameraNum) const;
|
||||
Ptr<IVideoWriter> tryOpenWriter(const std::string & backendName, const std::string& filename, int _fourcc, double fps, const Size &frameSize, bool isColor) const;
|
||||
protected:
|
||||
virtual Ptr<IVideoCapture> createCapture(const std::string &filename, int camera) const = 0;
|
||||
virtual Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const = 0;
|
||||
virtual ~IBackend() {}
|
||||
virtual Ptr<IVideoCapture> createCapture(int camera) const = 0;
|
||||
virtual Ptr<IVideoCapture> createCapture(const std::string &filename) const = 0;
|
||||
virtual Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const = 0;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
class StaticBackend : public IBackend
|
||||
{
|
||||
typedef Ptr<IVideoCapture> (*OpenFileFun)(const std::string &);
|
||||
typedef Ptr<IVideoCapture> (*OpenCamFun)(int);
|
||||
typedef Ptr<IVideoWriter> (*OpenWriterFun)(const std::string&, int, double, const Size&, bool);
|
||||
private:
|
||||
OpenFileFun FUN_FILE;
|
||||
OpenCamFun FUN_CAM;
|
||||
OpenWriterFun FUN_WRITE;
|
||||
public:
|
||||
StaticBackend(OpenFileFun f1, OpenCamFun f2, OpenWriterFun f3)
|
||||
: FUN_FILE(f1), FUN_CAM(f2), FUN_WRITE(f3)
|
||||
{
|
||||
}
|
||||
protected:
|
||||
Ptr<IVideoCapture> createCapture(const std::string &filename, int camera) const CV_OVERRIDE
|
||||
{
|
||||
if (filename.empty() && FUN_CAM)
|
||||
return FUN_CAM(camera);
|
||||
if (FUN_FILE)
|
||||
return FUN_FILE(filename);
|
||||
return 0;
|
||||
}
|
||||
Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const Size &sz, bool isColor) const CV_OVERRIDE
|
||||
{
|
||||
if (FUN_WRITE)
|
||||
return FUN_WRITE(filename, fourcc, fps, sz, isColor);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
class DynamicBackend : public IBackend
|
||||
class IBackendFactory
|
||||
{
|
||||
public:
|
||||
class CaptureTable;
|
||||
class WriterTable;
|
||||
class DynamicLib;
|
||||
private:
|
||||
DynamicLib * lib;
|
||||
CaptureTable const * cap_tbl;
|
||||
WriterTable const * wri_tbl;
|
||||
public:
|
||||
DynamicBackend(const std::string &filename);
|
||||
~DynamicBackend();
|
||||
static Ptr<DynamicBackend> load(VideoCaptureAPIs api, int mode);
|
||||
protected:
|
||||
bool canCreateCapture(cv::VideoCaptureAPIs api) const;
|
||||
bool canCreateWriter(VideoCaptureAPIs api) const;
|
||||
Ptr<IVideoCapture> createCapture(const std::string &filename, int camera) const CV_OVERRIDE;
|
||||
Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const CV_OVERRIDE;
|
||||
virtual ~IBackendFactory() {}
|
||||
virtual Ptr<IBackend> getBackend() const = 0;
|
||||
};
|
||||
|
||||
} // cv::
|
||||
//=============================================================================
|
||||
|
||||
typedef Ptr<IVideoCapture> (*FN_createCaptureFile)(const std::string & filename);
|
||||
typedef Ptr<IVideoCapture> (*FN_createCaptureCamera)(int camera);
|
||||
typedef Ptr<IVideoWriter> (*FN_createWriter)(const std::string& filename, int fourcc, double fps, const Size& sz, bool isColor);
|
||||
Ptr<IBackendFactory> createBackendFactory(FN_createCaptureFile createCaptureFile,
|
||||
FN_createCaptureCamera createCaptureCamera,
|
||||
FN_createWriter createWriter);
|
||||
|
||||
Ptr<IBackendFactory> createPluginBackendFactory(VideoCaptureAPIs id, const char* baseName);
|
||||
|
||||
} // namespace cv::
|
||||
|
||||
#endif // BACKEND_HPP_DEFINED
|
||||
|
510
modules/videoio/src/backend_plugin.cpp
Normal file
510
modules/videoio/src/backend_plugin.cpp
Normal file
@ -0,0 +1,510 @@
|
||||
// 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 "opencv2/core/utils/filesystem.hpp"
|
||||
#include "opencv2/core/utils/configuration.private.hpp"
|
||||
#include "opencv2/core/private.hpp"
|
||||
#include "videoio_registry.hpp"
|
||||
|
||||
//==================================================================================================
|
||||
// Dynamic backend implementation
|
||||
|
||||
#include "opencv2/core/utils/logger.hpp"
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(__linux__) || defined(__APPLE__)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
namespace cv { namespace impl {
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef HMODULE LibHandle_t;
|
||||
#elif defined(__linux__) || defined(__APPLE__)
|
||||
typedef void* LibHandle_t;
|
||||
#endif
|
||||
|
||||
static Mutex& getInitializationMutex()
|
||||
{
|
||||
static Mutex initializationMutex;
|
||||
return initializationMutex;
|
||||
}
|
||||
|
||||
static inline
|
||||
void* getSymbol_(LibHandle_t h, const char* symbolName)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return (void*)GetProcAddress(h, symbolName);
|
||||
#elif defined(__linux__) || defined(__APPLE__)
|
||||
return dlsym(h, symbolName);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline
|
||||
LibHandle_t libraryLoad_(const char* filename)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return LoadLibraryA(filename);
|
||||
#elif defined(__linux__) || defined(__APPLE__)
|
||||
return dlopen(filename, RTLD_LAZY);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline
|
||||
void libraryRelease_(LibHandle_t h)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
FreeLibrary(h);
|
||||
#elif defined(__linux__) || defined(__APPLE__)
|
||||
dlclose(h);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline
|
||||
std::string libraryPrefix()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return string();
|
||||
#else
|
||||
return "lib";
|
||||
#endif
|
||||
}
|
||||
static inline
|
||||
std::string librarySuffix()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return ".dll";
|
||||
#elif defined(__APPLE__)
|
||||
return ".dylib";
|
||||
#else
|
||||
return ".so";
|
||||
#endif
|
||||
}
|
||||
|
||||
//============================
|
||||
|
||||
class DynamicLib
|
||||
{
|
||||
private:
|
||||
LibHandle_t handle;
|
||||
const std::string fname;
|
||||
|
||||
public:
|
||||
DynamicLib(const std::string &filename)
|
||||
: handle(0), fname(filename)
|
||||
{
|
||||
libraryLoad(filename);
|
||||
}
|
||||
~DynamicLib()
|
||||
{
|
||||
libraryRelease();
|
||||
}
|
||||
bool isLoaded() const
|
||||
{
|
||||
return handle != NULL;
|
||||
}
|
||||
void* getSymbol(const char* symbolName) const
|
||||
{
|
||||
if (!handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void * res = getSymbol_(handle, symbolName);
|
||||
if (!res)
|
||||
CV_LOG_ERROR(NULL, "No symbol '" << symbolName << "' in " << fname);
|
||||
return res;
|
||||
}
|
||||
const std::string& getName() const { return fname; }
|
||||
private:
|
||||
void libraryLoad(const std::string &filename)
|
||||
{
|
||||
handle = libraryLoad_(filename.c_str());
|
||||
CV_LOG_INFO(NULL, "load " << filename << " => " << (handle ? "OK" : "FAILED"));
|
||||
}
|
||||
void libraryRelease()
|
||||
{
|
||||
CV_LOG_INFO(NULL, "unload "<< fname);
|
||||
if (handle)
|
||||
{
|
||||
libraryRelease_(handle);
|
||||
handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DynamicLib(const DynamicLib &);
|
||||
DynamicLib &operator=(const DynamicLib &);
|
||||
};
|
||||
|
||||
|
||||
//============================
|
||||
|
||||
class PluginBackend: public IBackend
|
||||
{
|
||||
public:
|
||||
Ptr<DynamicLib> lib_;
|
||||
const OpenCV_VideoIO_Plugin_API_preview* plugin_api_;
|
||||
|
||||
PluginBackend(const Ptr<DynamicLib>& lib) :
|
||||
lib_(lib), plugin_api_(NULL)
|
||||
{
|
||||
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)
|
||||
{
|
||||
plugin_api_ = fn_init(ABI_VERSION, API_VERSION, NULL);
|
||||
if (!plugin_api_)
|
||||
{
|
||||
CV_LOG_INFO(NULL, "Video I/O: plugin is incompatible: " << lib->getName());
|
||||
return;
|
||||
}
|
||||
if (plugin_api_->api_header.opencv_version_major != CV_VERSION_MAJOR ||
|
||||
plugin_api_->api_header.opencv_version_minor != CV_VERSION_MINOR)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "Video I/O: wrong OpenCV version used by plugin '" << plugin_api_->api_header.api_description << "': " <<
|
||||
cv::format("%d.%d, OpenCV version is '" CV_VERSION "'", plugin_api_->api_header.opencv_version_major, plugin_api_->api_header.opencv_version_minor))
|
||||
plugin_api_ = NULL;
|
||||
return;
|
||||
}
|
||||
// TODO Preview: add compatibility API/ABI checks
|
||||
CV_LOG_INFO(NULL, "Video I/O: loaded plugin '" << plugin_api_->api_header.api_description << "'");
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_LOG_INFO(NULL, "Video I/O: plugin is incompatible, missing init function: '" << init_name << "', file: " << lib->getName());
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<IVideoCapture> createCapture(int camera) const CV_OVERRIDE;
|
||||
Ptr<IVideoCapture> createCapture(const std::string &filename) const CV_OVERRIDE;
|
||||
Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
class PluginBackendFactory : public IBackendFactory
|
||||
{
|
||||
public:
|
||||
VideoCaptureAPIs id_;
|
||||
const char* baseName_;
|
||||
Ptr<PluginBackend> backend;
|
||||
bool initialized;
|
||||
public:
|
||||
PluginBackendFactory(VideoCaptureAPIs id, const char* baseName) :
|
||||
id_(id), baseName_(baseName),
|
||||
initialized(false)
|
||||
{
|
||||
// nothing, plugins are loaded on demand
|
||||
}
|
||||
|
||||
Ptr<IBackend> getBackend() const CV_OVERRIDE
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
const_cast<PluginBackendFactory*>(this)->initBackend();
|
||||
}
|
||||
return backend.staticCast<IBackend>();
|
||||
}
|
||||
protected:
|
||||
void initBackend()
|
||||
{
|
||||
AutoLock lock(getInitializationMutex());
|
||||
try {
|
||||
if (!initialized)
|
||||
loadPlugin();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CV_LOG_INFO(NULL, "Video I/O: exception during plugin loading: " << baseName_ << ". SKIP");
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
void loadPlugin();
|
||||
};
|
||||
|
||||
static
|
||||
std::vector<string> getPluginCandidates(const std::string& baseName)
|
||||
{
|
||||
using namespace cv::utils;
|
||||
using namespace cv::utils::fs;
|
||||
#ifndef CV_VIDEOIO_PLUGIN_SUBDIRECTORY
|
||||
#define CV_VIDEOIO_PLUGIN_SUBDIRECTORY_STR ""
|
||||
#else
|
||||
#define CV_VIDEOIO_PLUGIN_SUBDIRECTORY_STR CVAUX_STR(CV_VIDEOIO_PLUGIN_SUBDIRECTORY)
|
||||
#endif
|
||||
const vector<string> default_paths = { utils::fs::join(getParent(getBinLocation()), CV_VIDEOIO_PLUGIN_SUBDIRECTORY_STR) };
|
||||
const vector<string> paths = getConfigurationParameterPaths("OPENCV_VIDEOIO_PLUGIN_PATH", default_paths);
|
||||
const string baseName_l = toLowerCase(baseName);
|
||||
const string baseName_u = toUpperCase(baseName);
|
||||
const string default_expr = libraryPrefix() + "opencv_videoio_" + baseName_l + "*" + librarySuffix();
|
||||
const string expr = getConfigurationParameterString((std::string("OPENCV_VIDEOIO_PLUGIN_") + baseName_u).c_str(), default_expr.c_str());
|
||||
CV_LOG_INFO(NULL, "VideoIO pluigin (" << baseName << "): glob is '" << expr << "', " << paths.size() << " location(s)");
|
||||
vector<string> results;
|
||||
for(const string & path : paths)
|
||||
{
|
||||
if (path.empty())
|
||||
continue;
|
||||
vector<string> candidates;
|
||||
cv::glob(utils::fs::join(path, expr), candidates);
|
||||
CV_LOG_INFO(NULL, " - " << path << ": " << candidates.size());
|
||||
copy(candidates.begin(), candidates.end(), back_inserter(results));
|
||||
}
|
||||
CV_LOG_INFO(NULL, "Found " << results.size() << " plugin(s) for " << baseName);
|
||||
return results;
|
||||
}
|
||||
|
||||
void PluginBackendFactory::loadPlugin()
|
||||
{
|
||||
for(const std::string & plugin : getPluginCandidates(baseName_))
|
||||
{
|
||||
Ptr<DynamicLib> lib = makePtr<DynamicLib>(plugin);
|
||||
if (!lib->isLoaded())
|
||||
continue;
|
||||
try
|
||||
{
|
||||
Ptr<PluginBackend> pluginBackend = makePtr<PluginBackend>(lib);
|
||||
if (pluginBackend && pluginBackend->plugin_api_)
|
||||
{
|
||||
if (pluginBackend->plugin_api_->captureAPI != id_)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "Video I/O: plugin '" << pluginBackend->plugin_api_->api_header.api_description <<
|
||||
"': unexpected backend ID: " <<
|
||||
pluginBackend->plugin_api_->captureAPI << " vs " << (int)id_ << " (expected)");
|
||||
}
|
||||
else
|
||||
{
|
||||
backend = pluginBackend;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CV_LOG_INFO(NULL, "Video I/O: exception during plugin initialization: " << plugin << ". SKIP");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
class PluginCapture : public cv::IVideoCapture
|
||||
{
|
||||
const OpenCV_VideoIO_Plugin_API_preview* plugin_api_;
|
||||
CvPluginCapture capture_;
|
||||
|
||||
public:
|
||||
static
|
||||
Ptr<PluginCapture> create(const OpenCV_VideoIO_Plugin_API_preview* plugin_api,
|
||||
const std::string &filename, int camera)
|
||||
{
|
||||
CV_Assert(plugin_api);
|
||||
CvPluginCapture capture = NULL;
|
||||
if (plugin_api->Capture_open)
|
||||
{
|
||||
CV_Assert(plugin_api->Capture_release);
|
||||
if (CV_ERROR_OK == plugin_api->Capture_open(filename.empty() ? 0 : filename.c_str(), camera, &capture))
|
||||
{
|
||||
CV_Assert(capture);
|
||||
return makePtr<PluginCapture>(plugin_api, capture);
|
||||
}
|
||||
}
|
||||
return Ptr<PluginCapture>();
|
||||
}
|
||||
|
||||
PluginCapture(const OpenCV_VideoIO_Plugin_API_preview* plugin_api, CvPluginCapture capture)
|
||||
: plugin_api_(plugin_api), capture_(capture)
|
||||
{
|
||||
CV_Assert(plugin_api_); CV_Assert(capture_);
|
||||
}
|
||||
|
||||
~PluginCapture()
|
||||
{
|
||||
CV_DbgAssert(plugin_api_->Capture_release);
|
||||
if (CV_ERROR_OK != plugin_api_->Capture_release(capture_))
|
||||
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;
|
||||
if (plugin_api_->Capture_getProperty)
|
||||
if (CV_ERROR_OK != plugin_api_->Capture_getProperty(capture_, prop, &val))
|
||||
val = -1;
|
||||
return val;
|
||||
}
|
||||
bool setProperty(int prop, double val) CV_OVERRIDE
|
||||
{
|
||||
if (plugin_api_->Capture_setProperty)
|
||||
if (CV_ERROR_OK == plugin_api_->Capture_setProperty(capture_, prop, val))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool grabFrame() CV_OVERRIDE
|
||||
{
|
||||
if (plugin_api_->Capture_grab)
|
||||
if (CV_ERROR_OK == plugin_api_->Capture_grab(capture_))
|
||||
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 cn, void* userdata)
|
||||
{
|
||||
CV_UNUSED(stream_idx);
|
||||
cv::_OutputArray* dst = static_cast<cv::_OutputArray*>(userdata);
|
||||
if (!dst)
|
||||
return CV_ERROR_FAIL;
|
||||
cv::Mat(cv::Size(width, height), CV_MAKETYPE(CV_8U, cn), (void*)data, step).copyTo(*dst);
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
bool retrieveFrame(int idx, cv::OutputArray img) CV_OVERRIDE
|
||||
{
|
||||
bool res = false;
|
||||
if (plugin_api_->Capture_retreive)
|
||||
if (CV_ERROR_OK == plugin_api_->Capture_retreive(capture_, idx, retrieve_callback, (cv::_OutputArray*)&img))
|
||||
res = true;
|
||||
return res;
|
||||
}
|
||||
bool isOpened() const CV_OVERRIDE
|
||||
{
|
||||
return capture_ != NULL; // TODO always true
|
||||
}
|
||||
int getCaptureDomain() CV_OVERRIDE
|
||||
{
|
||||
return plugin_api_->captureAPI;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
class PluginWriter : public cv::IVideoWriter
|
||||
{
|
||||
const OpenCV_VideoIO_Plugin_API_preview* plugin_api_;
|
||||
CvPluginWriter writer_;
|
||||
|
||||
public:
|
||||
static
|
||||
Ptr<PluginWriter> create(const OpenCV_VideoIO_Plugin_API_preview* plugin_api,
|
||||
const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor)
|
||||
{
|
||||
CV_Assert(plugin_api);
|
||||
CvPluginWriter writer = NULL;
|
||||
if (plugin_api->Writer_open)
|
||||
{
|
||||
CV_Assert(plugin_api->Writer_release);
|
||||
if (CV_ERROR_OK == plugin_api->Writer_open(filename.empty() ? 0 : filename.c_str(), fourcc, fps, sz.width, sz.height, isColor, &writer))
|
||||
{
|
||||
CV_Assert(writer);
|
||||
return makePtr<PluginWriter>(plugin_api, writer);
|
||||
}
|
||||
}
|
||||
return Ptr<PluginWriter>();
|
||||
}
|
||||
|
||||
PluginWriter(const OpenCV_VideoIO_Plugin_API_preview* plugin_api, CvPluginWriter writer)
|
||||
: plugin_api_(plugin_api), writer_(writer)
|
||||
{
|
||||
CV_Assert(plugin_api_); CV_Assert(writer_);
|
||||
}
|
||||
|
||||
~PluginWriter()
|
||||
{
|
||||
CV_DbgAssert(plugin_api_->Writer_release);
|
||||
if (CV_ERROR_OK != plugin_api_->Writer_release(writer_))
|
||||
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;
|
||||
if (plugin_api_->Writer_getProperty)
|
||||
if (CV_ERROR_OK != plugin_api_->Writer_getProperty(writer_, prop, &val))
|
||||
val = -1;
|
||||
return val;
|
||||
}
|
||||
bool setProperty(int prop, double val) CV_OVERRIDE
|
||||
{
|
||||
if (plugin_api_->Writer_setProperty)
|
||||
if (CV_ERROR_OK == plugin_api_->Writer_setProperty(writer_, prop, val))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool isOpened() const CV_OVERRIDE
|
||||
{
|
||||
return writer_ != NULL; // TODO always true
|
||||
}
|
||||
void write(cv::InputArray arr) CV_OVERRIDE
|
||||
{
|
||||
cv::Mat img = arr.getMat();
|
||||
CV_DbgAssert(writer_);
|
||||
CV_Assert(plugin_api_->Writer_write);
|
||||
if (CV_ERROR_OK != plugin_api_->Writer_write(writer_, img.data, (int)img.step[0], img.cols, img.rows, img.channels()))
|
||||
{
|
||||
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_->captureAPI;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Ptr<IVideoCapture> PluginBackend::createCapture(int camera) const
|
||||
{
|
||||
try
|
||||
{
|
||||
if (plugin_api_)
|
||||
return PluginCapture::create(plugin_api_, std::string(), camera); //.staticCast<IVideoCapture>();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "Video I/O: can't create camera capture: " << camera);
|
||||
}
|
||||
return Ptr<IVideoCapture>();
|
||||
}
|
||||
|
||||
Ptr<IVideoCapture> PluginBackend::createCapture(const std::string &filename) const
|
||||
{
|
||||
try
|
||||
{
|
||||
if (plugin_api_)
|
||||
return PluginCapture::create(plugin_api_, filename, 0); //.staticCast<IVideoCapture>();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "Video I/O: can't open file capture: " << filename);
|
||||
}
|
||||
return Ptr<IVideoCapture>();
|
||||
}
|
||||
|
||||
Ptr<IVideoWriter> PluginBackend::createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const
|
||||
{
|
||||
try
|
||||
{
|
||||
if (plugin_api_)
|
||||
return PluginWriter::create(plugin_api_, filename, fourcc, fps, sz, isColor); //.staticCast<IVideoWriter>();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "Video I/O: can't open writer: " << filename);
|
||||
}
|
||||
return Ptr<IVideoWriter>();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Ptr<IBackendFactory> createPluginBackendFactory(VideoCaptureAPIs id, const char* baseName)
|
||||
{
|
||||
return makePtr<impl::PluginBackendFactory>(id, baseName); //.staticCast<IBackendFactory>();
|
||||
}
|
||||
|
||||
} // namespace
|
72
modules/videoio/src/backend_static.cpp
Normal file
72
modules/videoio/src/backend_static.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
// 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"
|
||||
|
||||
namespace cv {
|
||||
|
||||
class StaticBackend: public IBackend
|
||||
{
|
||||
public:
|
||||
FN_createCaptureFile fn_createCaptureFile_;
|
||||
FN_createCaptureCamera fn_createCaptureCamera_;
|
||||
FN_createWriter fn_createWriter_;
|
||||
|
||||
StaticBackend(FN_createCaptureFile fn_createCaptureFile, FN_createCaptureCamera fn_createCaptureCamera, FN_createWriter fn_createWriter)
|
||||
: fn_createCaptureFile_(fn_createCaptureFile), fn_createCaptureCamera_(fn_createCaptureCamera), fn_createWriter_(fn_createWriter)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
~StaticBackend() CV_OVERRIDE {}
|
||||
|
||||
Ptr<IVideoCapture> createCapture(int camera) const CV_OVERRIDE
|
||||
{
|
||||
if (fn_createCaptureCamera_)
|
||||
return fn_createCaptureCamera_(camera);
|
||||
return Ptr<IVideoCapture>();
|
||||
}
|
||||
Ptr<IVideoCapture> createCapture(const std::string &filename) const CV_OVERRIDE
|
||||
{
|
||||
if (fn_createCaptureFile_)
|
||||
return fn_createCaptureFile_(filename);
|
||||
return Ptr<IVideoCapture>();
|
||||
}
|
||||
Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const CV_OVERRIDE
|
||||
{
|
||||
if (fn_createWriter_)
|
||||
return fn_createWriter_(filename, fourcc, fps, sz, isColor);
|
||||
return Ptr<IVideoWriter>();
|
||||
}
|
||||
}; // StaticBackend
|
||||
|
||||
class StaticBackendFactory : public IBackendFactory
|
||||
{
|
||||
protected:
|
||||
Ptr<StaticBackend> backend;
|
||||
|
||||
public:
|
||||
StaticBackendFactory(FN_createCaptureFile createCaptureFile, FN_createCaptureCamera createCaptureCamera, FN_createWriter createWriter)
|
||||
: backend(makePtr<StaticBackend>(createCaptureFile, createCaptureCamera, createWriter))
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
~StaticBackendFactory() CV_OVERRIDE {}
|
||||
|
||||
Ptr<IBackend> getBackend() const CV_OVERRIDE
|
||||
{
|
||||
return backend.staticCast<IBackend>();
|
||||
}
|
||||
};
|
||||
|
||||
Ptr<IBackendFactory> createBackendFactory(FN_createCaptureFile createCaptureFile,
|
||||
FN_createCaptureCamera createCaptureCamera,
|
||||
FN_createWriter createWriter)
|
||||
{
|
||||
return makePtr<StaticBackendFactory>(createCaptureFile, createCaptureCamera, createWriter).staticCast<IBackendFactory>();
|
||||
}
|
||||
|
||||
} // namespace
|
@ -46,6 +46,11 @@
|
||||
|
||||
namespace cv {
|
||||
|
||||
static bool param_VIDEOIO_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOIO_DEBUG", false);
|
||||
static bool param_VIDEOCAPTURE_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOCAPTURE_DEBUG", false);
|
||||
static bool param_VIDEOWRITER_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOWRITER_DEBUG", false);
|
||||
|
||||
|
||||
void DefaultDeleter<CvCapture>::operator ()(CvCapture* obj) const { cvReleaseCapture(&obj); }
|
||||
void DefaultDeleter<CvVideoWriter>::operator ()(CvVideoWriter* obj) const { cvReleaseVideoWriter(&obj); }
|
||||
|
||||
@ -77,28 +82,54 @@ bool VideoCapture::open(const String& filename, int apiPreference)
|
||||
|
||||
if (isOpened()) release();
|
||||
|
||||
const std::vector<VideoCaptureAPIs> backends = cv::videoio_registry::getStreamBackends();
|
||||
const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByFilename();
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
{
|
||||
const VideoCaptureAPIs id = backends[i];
|
||||
const std::string backendName = cv::videoio_registry::getBackendName(id);
|
||||
if (apiPreference == CAP_ANY || apiPreference == id)
|
||||
const VideoBackendInfo& info = backends[i];
|
||||
if (apiPreference == CAP_ANY || apiPreference == info.id)
|
||||
{
|
||||
Ptr<IBackend> factory = VideoBackendRegistry::getInstance().getBackend(id);
|
||||
if (factory)
|
||||
icap = factory->tryOpenCapture(backendName, filename, 0);
|
||||
if (!icap.empty())
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying capture filename='%s' ...", info.name, filename.c_str()));
|
||||
CV_Assert(!info.backendFactory.empty());
|
||||
const Ptr<IBackend> backend = info.backendFactory->getBackend();
|
||||
if (!backend.empty())
|
||||
{
|
||||
if (icap->isOpened())
|
||||
return true;
|
||||
icap.release();
|
||||
try
|
||||
{
|
||||
icap = backend->createCapture(filename);
|
||||
if (!icap.empty())
|
||||
{
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): created, isOpened=%d",
|
||||
info.name, icap->isOpened()));
|
||||
if (icap->isOpened())
|
||||
return true;
|
||||
icap.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): can't create capture", info.name));
|
||||
}
|
||||
} catch(const cv::Exception& e) {
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", info.name, e.what()));
|
||||
} catch (const std::exception& e) {
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", info.name, e.what()));
|
||||
} catch(...) {
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", info.name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): backend is not available (plugin is missing, or can't be loaded due dependencies or it is not compatible)", info.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VideoCapture::open(int cameraNum, int apiPreference)
|
||||
bool VideoCapture::open(int cameraNum, int apiPreference)
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
@ -115,21 +146,47 @@ bool VideoCapture::open(int cameraNum, int apiPreference)
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<VideoCaptureAPIs> backends = cv::videoio_registry::getCameraBackends();
|
||||
const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByIndex();
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
{
|
||||
const VideoCaptureAPIs id = backends[i];
|
||||
const std::string backendName = cv::videoio_registry::getBackendName(id);
|
||||
if (apiPreference == CAP_ANY || apiPreference == id)
|
||||
const VideoBackendInfo& info = backends[i];
|
||||
if (apiPreference == CAP_ANY || apiPreference == info.id)
|
||||
{
|
||||
Ptr<IBackend> factory = VideoBackendRegistry::getInstance().getBackend(id);
|
||||
if (factory)
|
||||
icap = factory->tryOpenCapture(backendName, std::string(), cameraNum);
|
||||
if (!icap.empty())
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying capture cameraNum=%d ...", info.name, cameraNum));
|
||||
CV_Assert(!info.backendFactory.empty());
|
||||
const Ptr<IBackend> backend = info.backendFactory->getBackend();
|
||||
if (!backend.empty())
|
||||
{
|
||||
if (icap->isOpened())
|
||||
return true;
|
||||
icap.release();
|
||||
try
|
||||
{
|
||||
icap = backend->createCapture(cameraNum);
|
||||
if (!icap.empty())
|
||||
{
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): created, isOpened=%d",
|
||||
info.name, icap->isOpened()));
|
||||
if (icap->isOpened())
|
||||
return true;
|
||||
icap.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): can't create capture", info.name));
|
||||
}
|
||||
} catch(const cv::Exception& e) {
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", info.name, e.what()));
|
||||
} catch (const std::exception& e) {
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", info.name, e.what()));
|
||||
} catch(...) {
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", info.name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): backend is not available (plugin is missing, or can't be loaded due dependencies or it is not compatible)", info.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -277,21 +334,48 @@ bool VideoWriter::open(const String& filename, int apiPreference, int _fourcc, d
|
||||
|
||||
if (isOpened()) release();
|
||||
|
||||
const std::vector<VideoCaptureAPIs> backends = cv::videoio_registry::getWriterBackends();
|
||||
const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_Writer();
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
{
|
||||
const VideoCaptureAPIs id = backends[i];
|
||||
const std::string backendName = cv::videoio_registry::getBackendName(id);
|
||||
if (apiPreference == CAP_ANY || apiPreference == id)
|
||||
const VideoBackendInfo& info = backends[i];
|
||||
if (apiPreference == CAP_ANY || apiPreference == info.id)
|
||||
{
|
||||
Ptr<IBackend> factory = VideoBackendRegistry::getInstance().getBackend(id);
|
||||
if (factory)
|
||||
iwriter = factory->tryOpenWriter(backendName, filename, _fourcc, fps, frameSize, isColor);
|
||||
if (!iwriter.empty())
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying writer with filename='%s' fourcc=0x%08x fps=%g sz=%dx%d isColor=%d...",
|
||||
info.name, filename.c_str(), (unsigned)_fourcc, fps, frameSize.width, frameSize.height, (int)isColor));
|
||||
CV_Assert(!info.backendFactory.empty());
|
||||
const Ptr<IBackend> backend = info.backendFactory->getBackend();
|
||||
if (!backend.empty())
|
||||
{
|
||||
if (iwriter->isOpened())
|
||||
return true;
|
||||
iwriter.release();
|
||||
try
|
||||
{
|
||||
iwriter = backend->createWriter(filename, _fourcc, fps, frameSize, isColor);
|
||||
if (!iwriter.empty())
|
||||
{
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): created, isOpened=%d",
|
||||
info.name, iwriter->isOpened()));
|
||||
if (iwriter->isOpened())
|
||||
return true;
|
||||
iwriter.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG)
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): can't create writer", info.name));
|
||||
}
|
||||
} catch(const cv::Exception& e) {
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", info.name, e.what()));
|
||||
} catch (const std::exception& e) {
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", info.name, e.what()));
|
||||
} catch(...) {
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", info.name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): backend is not available (plugin is missing, or can't be loaded due dependencies or it is not compatible)", info.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -351,23 +351,25 @@ cv::Ptr<cv::IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const std::string& fi
|
||||
|
||||
#include "plugin_api.hpp"
|
||||
|
||||
CV_EXTERN_C int cv_domain()
|
||||
{
|
||||
return cv::CAP_FFMPEG;
|
||||
}
|
||||
namespace cv {
|
||||
|
||||
CV_EXTERN_C bool cv_open_capture(const char * filename, int, void * &handle)
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_open(const char* filename, int camera_index, CV_OUT CvPluginCapture* handle)
|
||||
{
|
||||
if (!handle)
|
||||
return CV_ERROR_FAIL;
|
||||
*handle = NULL;
|
||||
if (!filename)
|
||||
return false;
|
||||
cv::CvCapture_FFMPEG_proxy *cap = 0;
|
||||
return CV_ERROR_FAIL;
|
||||
CV_UNUSED(camera_index);
|
||||
CvCapture_FFMPEG_proxy *cap = 0;
|
||||
try
|
||||
{
|
||||
cap = new cv::CvCapture_FFMPEG_proxy(filename);
|
||||
cap = new CvCapture_FFMPEG_proxy(filename);
|
||||
if (cap->isOpened())
|
||||
{
|
||||
handle = cap;
|
||||
return true;
|
||||
*handle = (CvPluginCapture)cap;
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
@ -375,94 +377,104 @@ CV_EXTERN_C bool cv_open_capture(const char * filename, int, void * &handle)
|
||||
}
|
||||
if (cap)
|
||||
delete cap;
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_get_cap_prop(void * handle, int prop, double & val)
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_release(CvPluginCapture handle)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
CvCapture_FFMPEG_proxy* instance = (CvCapture_FFMPEG_proxy*)handle;
|
||||
delete instance;
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_get_prop(CvPluginCapture handle, int prop, CV_OUT double* val)
|
||||
{
|
||||
if (!handle)
|
||||
return CV_ERROR_FAIL;
|
||||
if (!val)
|
||||
return CV_ERROR_FAIL;
|
||||
try
|
||||
{
|
||||
cv::CvCapture_FFMPEG_proxy *instance = static_cast<cv::CvCapture_FFMPEG_proxy*>(handle);
|
||||
val = instance->getProperty(prop);
|
||||
return true;
|
||||
CvCapture_FFMPEG_proxy* instance = (CvCapture_FFMPEG_proxy*)handle;
|
||||
*val = instance->getProperty(prop);
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_set_cap_prop(void * handle, int prop, double val)
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_set_prop(CvPluginCapture handle, int prop, double val)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
try
|
||||
{
|
||||
cv::CvCapture_FFMPEG_proxy *instance = static_cast<cv::CvCapture_FFMPEG_proxy*>(handle);
|
||||
return instance->setProperty(prop, val);
|
||||
CvCapture_FFMPEG_proxy* instance = (CvCapture_FFMPEG_proxy*)handle;
|
||||
return instance->setProperty(prop, val) ? CV_ERROR_OK : CV_ERROR_FAIL;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_grab(void * handle)
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_grab(CvPluginCapture handle)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
try
|
||||
{
|
||||
cv::CvCapture_FFMPEG_proxy *instance = static_cast<cv::CvCapture_FFMPEG_proxy*>(handle);
|
||||
return instance->grabFrame();
|
||||
CvCapture_FFMPEG_proxy* instance = (CvCapture_FFMPEG_proxy*)handle;
|
||||
return instance->grabFrame() ? CV_ERROR_OK : CV_ERROR_FAIL;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_retrieve(void * handle, int idx, cv_retrieve_cb_t * callback, void * userdata)
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_retrieve(CvPluginCapture handle, int stream_idx, cv_videoio_retrieve_cb_t callback, void* userdata)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
try
|
||||
{
|
||||
cv::CvCapture_FFMPEG_proxy *instance = static_cast<cv::CvCapture_FFMPEG_proxy*>(handle);
|
||||
cv::Mat img;
|
||||
CvCapture_FFMPEG_proxy* instance = (CvCapture_FFMPEG_proxy*)handle;
|
||||
Mat img;
|
||||
// TODO: avoid unnecessary copying
|
||||
if (instance->retrieveFrame(idx, img))
|
||||
return callback(img.data, img.step, img.cols, img.rows, img.channels(), userdata);
|
||||
return false;
|
||||
if (instance->retrieveFrame(stream_idx, img))
|
||||
return callback(stream_idx, img.data, img.step, img.cols, img.rows, img.channels(), userdata);
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_release_capture(void * handle)
|
||||
static
|
||||
CvResult CV_API_CALL cv_writer_open(const char* filename, int fourcc, double fps, int width, int height, int isColor,
|
||||
CV_OUT CvPluginWriter* handle)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
cv::CvCapture_FFMPEG_proxy *instance = static_cast<cv::CvCapture_FFMPEG_proxy*>(handle);
|
||||
delete instance;
|
||||
return true;
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_open_writer(const char * filename, int fourcc, double fps, int width, int height, int isColor, void * &handle)
|
||||
{
|
||||
cv::Size sz(width, height);
|
||||
cv::CvVideoWriter_FFMPEG_proxy* wrt = 0;
|
||||
Size sz(width, height);
|
||||
CvVideoWriter_FFMPEG_proxy* wrt = 0;
|
||||
try
|
||||
{
|
||||
wrt = new cv::CvVideoWriter_FFMPEG_proxy(filename, fourcc, fps, sz, isColor != 0);
|
||||
wrt = new CvVideoWriter_FFMPEG_proxy(filename, fourcc, fps, sz, isColor != 0);
|
||||
if(wrt && wrt->isOpened())
|
||||
{
|
||||
handle = wrt;
|
||||
return true;
|
||||
*handle = (CvPluginWriter)wrt;
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
@ -470,43 +482,79 @@ CV_EXTERN_C bool cv_open_writer(const char * filename, int fourcc, double fps, i
|
||||
}
|
||||
if (wrt)
|
||||
delete wrt;
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_get_wri_prop(void*, int, double&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_set_wri_prop(void*, int, double)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_write(void * handle, const unsigned char * data, int step, int width, int height, int cn)
|
||||
static
|
||||
CvResult CV_API_CALL cv_writer_release(CvPluginWriter handle)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
CvVideoWriter_FFMPEG_proxy* instance = (CvVideoWriter_FFMPEG_proxy*)handle;
|
||||
delete instance;
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
|
||||
static
|
||||
CvResult CV_API_CALL cv_writer_get_prop(CvPluginWriter /*handle*/, int /*prop*/, CV_OUT double* /*val*/)
|
||||
{
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
|
||||
static
|
||||
CvResult CV_API_CALL cv_writer_set_prop(CvPluginWriter /*handle*/, int /*prop*/, double /*val*/)
|
||||
{
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
|
||||
static
|
||||
CvResult CV_API_CALL cv_writer_write(CvPluginWriter handle, const unsigned char *data, int step, int width, int height, int cn)
|
||||
{
|
||||
if (!handle)
|
||||
return CV_ERROR_FAIL;
|
||||
try
|
||||
{
|
||||
cv::CvVideoWriter_FFMPEG_proxy * instance = static_cast<cv::CvVideoWriter_FFMPEG_proxy*>(handle);
|
||||
cv::Mat img(cv::Size(width, height), CV_MAKETYPE(CV_8U, cn), const_cast<uchar*>(data), step);
|
||||
CvVideoWriter_FFMPEG_proxy* instance = (CvVideoWriter_FFMPEG_proxy*)handle;
|
||||
Mat img(Size(width, height), CV_MAKETYPE(CV_8U, cn), const_cast<uchar*>(data), step);
|
||||
instance->write(img);
|
||||
return true;
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_release_writer(void * handle)
|
||||
static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
cv::CvVideoWriter_FFMPEG_proxy * instance = static_cast<cv::CvVideoWriter_FFMPEG_proxy*>(handle);
|
||||
delete instance;
|
||||
return true;
|
||||
{
|
||||
sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
|
||||
CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
|
||||
"FFmpeg OpenCV Video I/O plugin"
|
||||
},
|
||||
/* 1*/CAP_FFMPEG,
|
||||
/* 2*/cv_capture_open,
|
||||
/* 3*/cv_capture_release,
|
||||
/* 4*/cv_capture_get_prop,
|
||||
/* 5*/cv_capture_set_prop,
|
||||
/* 6*/cv_capture_grab,
|
||||
/* 7*/cv_capture_retrieve,
|
||||
/* 8*/cv_writer_open,
|
||||
/* 9*/cv_writer_release,
|
||||
/* 10*/cv_writer_get_prop,
|
||||
/* 11*/cv_writer_set_prop,
|
||||
/* 12*/cv_writer_write
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
const OpenCV_VideoIO_Plugin_API_preview* opencv_videoio_plugin_init_v0(int requested_abi_version, int requested_api_version, void* /*reserved=NULL*/) CV_NOEXCEPT
|
||||
{
|
||||
if (requested_abi_version != 0)
|
||||
return NULL;
|
||||
if (requested_api_version != 0)
|
||||
return NULL;
|
||||
return &cv::plugin_api_v0;
|
||||
}
|
||||
|
||||
#endif // BUILD_PLUGIN
|
||||
|
@ -6,13 +6,17 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined _WIN32
|
||||
#ifndef OPENCV_FFMPEG_API
|
||||
#if defined(__OPENCV_BUILD) || defined(BUILD_PLUGIN)
|
||||
# define OPENCV_FFMPEG_API
|
||||
#elif defined _WIN32
|
||||
# define OPENCV_FFMPEG_API __declspec(dllexport)
|
||||
#elif defined __GNUC__ && __GNUC__ >= 4
|
||||
# define OPENCV_FFMPEG_API __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
# define OPENCV_FFMPEG_API
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -1629,13 +1629,16 @@ void handleMessage(GstElement * pipeline)
|
||||
|
||||
#include "plugin_api.hpp"
|
||||
|
||||
CV_EXTERN_C int cv_domain()
|
||||
{
|
||||
return cv::CAP_GSTREAMER;
|
||||
}
|
||||
namespace cv {
|
||||
|
||||
CV_EXTERN_C bool cv_open_capture(const char * filename, int camera_index, void * &handle)
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_open(const char* filename, int camera_index, CV_OUT CvPluginCapture* handle)
|
||||
{
|
||||
if (!handle)
|
||||
return CV_ERROR_FAIL;
|
||||
*handle = NULL;
|
||||
if (!filename)
|
||||
return CV_ERROR_FAIL;
|
||||
GStreamerCapture *cap = 0;
|
||||
try
|
||||
{
|
||||
@ -1647,8 +1650,8 @@ CV_EXTERN_C bool cv_open_capture(const char * filename, int camera_index, void *
|
||||
res = cap->open(camera_index);
|
||||
if (res)
|
||||
{
|
||||
handle = cap;
|
||||
return true;
|
||||
*handle = (CvPluginCapture)cap;
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
@ -1656,84 +1659,94 @@ CV_EXTERN_C bool cv_open_capture(const char * filename, int camera_index, void *
|
||||
}
|
||||
if (cap)
|
||||
delete cap;
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_get_cap_prop(void * handle, int prop, double & val)
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_release(CvPluginCapture handle)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
GStreamerCapture* instance = (GStreamerCapture*)handle;
|
||||
delete instance;
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_get_prop(CvPluginCapture handle, int prop, CV_OUT double* val)
|
||||
{
|
||||
if (!handle)
|
||||
return CV_ERROR_FAIL;
|
||||
if (!val)
|
||||
return CV_ERROR_FAIL;
|
||||
try
|
||||
{
|
||||
GStreamerCapture * instance = static_cast<GStreamerCapture*>(handle);
|
||||
val = instance->getProperty(prop);
|
||||
return true;
|
||||
GStreamerCapture* instance = (GStreamerCapture*)handle;
|
||||
*val = instance->getProperty(prop);
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_set_prop(CvPluginCapture handle, int prop, double val)
|
||||
{
|
||||
if (!handle)
|
||||
return CV_ERROR_FAIL;
|
||||
try
|
||||
{
|
||||
GStreamerCapture* instance = (GStreamerCapture*)handle;
|
||||
return instance->setProperty(prop, val) ? CV_ERROR_OK : CV_ERROR_FAIL;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_set_cap_prop(void * handle, int prop, double val)
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_grab(CvPluginCapture handle)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
try
|
||||
{
|
||||
GStreamerCapture * instance = static_cast<GStreamerCapture*>(handle);
|
||||
return instance->setProperty(prop, val);
|
||||
GStreamerCapture* instance = (GStreamerCapture*)handle;
|
||||
return instance->grabFrame() ? CV_ERROR_OK : CV_ERROR_FAIL;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_grab(void * handle)
|
||||
static
|
||||
CvResult CV_API_CALL cv_capture_retrieve(CvPluginCapture handle, int stream_idx, cv_videoio_retrieve_cb_t callback, void* userdata)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
try
|
||||
{
|
||||
GStreamerCapture * instance = static_cast<GStreamerCapture*>(handle);
|
||||
return instance->grabFrame();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_retrieve(void * handle, int idx, cv_retrieve_cb_t * callback, void * userdata)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
GStreamerCapture * instance = static_cast<GStreamerCapture*>(handle);
|
||||
GStreamerCapture* instance = (GStreamerCapture*)handle;
|
||||
Mat img;
|
||||
// TODO: avoid unnecessary copying - implement lower level GStreamerCapture::retrieve
|
||||
if (instance->retrieveFrame(idx, img))
|
||||
return callback(img.data, img.step, img.cols, img.rows, img.channels(), userdata);
|
||||
return false;
|
||||
if (instance->retrieveFrame(stream_idx, img))
|
||||
return callback(stream_idx, img.data, img.step, img.cols, img.rows, img.channels(), userdata);
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_release_capture(void * handle)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
GStreamerCapture * instance = static_cast<GStreamerCapture*>(handle);
|
||||
delete instance;
|
||||
return true;
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_open_writer(const char * filename, int fourcc, double fps, int width, int height, int isColor, void * &handle)
|
||||
static
|
||||
CvResult CV_API_CALL cv_writer_open(const char* filename, int fourcc, double fps, int width, int height, int isColor,
|
||||
CV_OUT CvPluginWriter* handle)
|
||||
{
|
||||
CvVideoWriter_GStreamer* wrt = 0;
|
||||
try
|
||||
@ -1742,8 +1755,8 @@ CV_EXTERN_C bool cv_open_writer(const char * filename, int fourcc, double fps, i
|
||||
CvSize sz = { width, height };
|
||||
if(wrt && wrt->open(filename, fourcc, fps, sz, isColor))
|
||||
{
|
||||
handle = wrt;
|
||||
return true;
|
||||
*handle = (CvPluginWriter)wrt;
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
@ -1751,45 +1764,81 @@ CV_EXTERN_C bool cv_open_writer(const char * filename, int fourcc, double fps, i
|
||||
}
|
||||
if (wrt)
|
||||
delete wrt;
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_get_wri_prop(void*, int, double&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_set_wri_prop(void*, int, double)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_write(void * handle, const unsigned char * data, int step, int width, int height, int cn)
|
||||
static
|
||||
CvResult CV_API_CALL cv_writer_release(CvPluginWriter handle)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
CvVideoWriter_GStreamer* instance = (CvVideoWriter_GStreamer*)handle;
|
||||
delete instance;
|
||||
return CV_ERROR_OK;
|
||||
}
|
||||
|
||||
static
|
||||
CvResult CV_API_CALL cv_writer_get_prop(CvPluginWriter /*handle*/, int /*prop*/, CV_OUT double* /*val*/)
|
||||
{
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
|
||||
static
|
||||
CvResult CV_API_CALL cv_writer_set_prop(CvPluginWriter /*handle*/, int /*prop*/, double /*val*/)
|
||||
{
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
|
||||
static
|
||||
CvResult CV_API_CALL cv_writer_write(CvPluginWriter handle, const unsigned char *data, int step, int width, int height, int cn)
|
||||
{
|
||||
if (!handle)
|
||||
return CV_ERROR_FAIL;
|
||||
try
|
||||
{
|
||||
CvVideoWriter_GStreamer * instance = static_cast<CvVideoWriter_GStreamer*>(handle);
|
||||
CvVideoWriter_GStreamer* instance = (CvVideoWriter_GStreamer*)handle;
|
||||
CvSize sz = { width, height };
|
||||
IplImage img;
|
||||
cvInitImageHeader(&img, sz, IPL_DEPTH_8U, cn);
|
||||
cvSetData(&img, const_cast<unsigned char*>(data), step);
|
||||
return instance->writeFrame(&img);
|
||||
return instance->writeFrame(&img) ? CV_ERROR_OK : CV_ERROR_FAIL;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
return CV_ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
CV_EXTERN_C bool cv_release_writer(void * handle)
|
||||
static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
CvVideoWriter_GStreamer * instance = static_cast<CvVideoWriter_GStreamer*>(handle);
|
||||
delete instance;
|
||||
return true;
|
||||
{
|
||||
sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
|
||||
CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
|
||||
"GStreamer OpenCV Video I/O plugin"
|
||||
},
|
||||
/* 1*/CAP_GSTREAMER,
|
||||
/* 2*/cv_capture_open,
|
||||
/* 3*/cv_capture_release,
|
||||
/* 4*/cv_capture_get_prop,
|
||||
/* 5*/cv_capture_set_prop,
|
||||
/* 6*/cv_capture_grab,
|
||||
/* 7*/cv_capture_retrieve,
|
||||
/* 8*/cv_writer_open,
|
||||
/* 9*/cv_writer_release,
|
||||
/* 10*/cv_writer_get_prop,
|
||||
/* 11*/cv_writer_set_prop,
|
||||
/* 12*/cv_writer_write
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
const OpenCV_VideoIO_Plugin_API_preview* opencv_videoio_plugin_init_v0(int requested_abi_version, int requested_api_version, void* /*reserved=NULL*/) CV_NOEXCEPT
|
||||
{
|
||||
if (requested_abi_version != 0)
|
||||
return NULL;
|
||||
if (requested_api_version != 0)
|
||||
return NULL;
|
||||
return &cv::plugin_api_v0;
|
||||
}
|
||||
|
||||
#endif // BUILD_PLUGIN
|
||||
|
@ -1,19 +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.
|
||||
|
||||
#ifdef BUILD_PLUGIN
|
||||
|
||||
#include "plugin_api.hpp"
|
||||
#include "opencv2/core/version.hpp"
|
||||
|
||||
void cv_get_version(int & major, int & minor, int & patch, int & api, int & abi)
|
||||
{
|
||||
major = CV_VERSION_MAJOR;
|
||||
minor = CV_VERSION_MINOR;
|
||||
patch = CV_VERSION_REVISION;
|
||||
api = API_VERSION;
|
||||
abi = ABI_VERSION;
|
||||
}
|
||||
|
||||
#endif // BUILD_PLUGIN
|
@ -5,64 +5,165 @@
|
||||
#ifndef PLUGIN_API_HPP
|
||||
#define PLUGIN_API_HPP
|
||||
|
||||
#include <opencv2/core/cvdef.h>
|
||||
#include <opencv2/core/llapi/llapi.h>
|
||||
|
||||
// increase for backward-compatible changes, e.g. add new function
|
||||
// Main API <= Plugin API -> plugin is compatible
|
||||
#define API_VERSION 1
|
||||
#define API_VERSION 0 // preview
|
||||
// increase for incompatible changes, e.g. remove function argument
|
||||
// Main ABI == Plugin ABI -> plugin is compatible
|
||||
#define ABI_VERSION 1
|
||||
#define ABI_VERSION 0 // preview
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// common
|
||||
typedef void cv_get_version_t(int & major, int & minor, int & patch, int & api, int & abi);
|
||||
typedef int cv_domain_t();
|
||||
typedef CvResult (CV_API_CALL *cv_videoio_retrieve_cb_t)(int stream_idx, unsigned const char* data, int step, int width, int height, int cn, void* userdata);
|
||||
|
||||
// capture
|
||||
typedef bool cv_open_capture_t(const char * filename, int camera_index, void * &handle);
|
||||
typedef bool cv_get_cap_prop_t(void * handle, int prop, double & val);
|
||||
typedef bool cv_set_cap_prop_t(void * handle, int prop, double val);
|
||||
typedef bool cv_grab_t(void * handle);
|
||||
// callback function type
|
||||
typedef bool cv_retrieve_cb_t(unsigned char * data, int step, int width, int height, int cn, void * userdata);
|
||||
typedef bool cv_retrieve_t(void * handle, int idx, cv_retrieve_cb_t * cb, void * userdata);
|
||||
typedef bool cv_release_capture_t(void * handle);
|
||||
typedef struct CvPluginCapture_t* CvPluginCapture;
|
||||
typedef struct CvPluginWriter_t* CvPluginWriter;
|
||||
|
||||
// writer
|
||||
typedef bool cv_open_writer_t(const char * filename, int fourcc, double fps, int width, int height, int isColor, void * &handle);
|
||||
typedef bool cv_get_wri_prop_t(void * handle, int prop, double & val);
|
||||
typedef bool cv_set_wri_prop_t(void * handle, int prop, double val);
|
||||
typedef bool cv_write_t(void * handle, const unsigned char * data, int step, int width, int height, int cn);
|
||||
typedef bool cv_release_writer_t(void * handle);
|
||||
typedef struct OpenCV_VideoIO_Plugin_API_preview
|
||||
{
|
||||
OpenCV_API_Header api_header;
|
||||
|
||||
/** OpenCV capture ID (VideoCaptureAPIs)
|
||||
@note API-ENTRY 1, API-Version == 0
|
||||
*/
|
||||
int captureAPI;
|
||||
|
||||
/** @brief Open video capture
|
||||
|
||||
@param filename File name or NULL to use camera_index instead
|
||||
@param camera_index Camera index (used if filename == NULL)
|
||||
@param[out] handle pointer on Capture handle
|
||||
|
||||
@note API-CALL 2, API-Version == 0
|
||||
*/
|
||||
CvResult (CV_API_CALL *Capture_open)(const char* filename, int camera_index, CV_OUT CvPluginCapture* handle);
|
||||
|
||||
/** @brief Release Capture handle
|
||||
|
||||
@param handle Capture handle
|
||||
|
||||
@note API-CALL 3, API-Version == 0
|
||||
*/
|
||||
CvResult (CV_API_CALL *Capture_release)(CvPluginCapture handle);
|
||||
|
||||
/** @brief Get property value
|
||||
|
||||
@param handle Capture handle
|
||||
@param prop Property index
|
||||
@param[out] val property value
|
||||
|
||||
@note API-CALL 4, API-Version == 0
|
||||
*/
|
||||
CvResult (CV_API_CALL *Capture_getProperty)(CvPluginCapture handle, int prop, CV_OUT double* val);
|
||||
|
||||
/** @brief Set property value
|
||||
|
||||
@param handle Capture handle
|
||||
@param prop Property index
|
||||
@param val property value
|
||||
|
||||
@note API-CALL 5, API-Version == 0
|
||||
*/
|
||||
CvResult (CV_API_CALL *Capture_setProperty)(CvPluginCapture handle, int prop, double val);
|
||||
|
||||
/** @brief Grab frame
|
||||
|
||||
@param handle Capture handle
|
||||
|
||||
@note API-CALL 6, API-Version == 0
|
||||
*/
|
||||
CvResult (CV_API_CALL *Capture_grab)(CvPluginCapture handle);
|
||||
|
||||
/** @brief Retrieve frame
|
||||
|
||||
@param handle Capture handle
|
||||
@param stream_idx stream index to retrieve (BGR/IR/depth data)
|
||||
@param callback retrieve callback (synchronous)
|
||||
@param userdata callback context data
|
||||
|
||||
@note API-CALL 7, API-Version == 0
|
||||
*/
|
||||
CvResult (CV_API_CALL *Capture_retreive)(CvPluginCapture handle, int stream_idx, cv_videoio_retrieve_cb_t callback, void* userdata);
|
||||
|
||||
|
||||
/** @brief Try to open video writer
|
||||
|
||||
@param filename File name or NULL to use camera_index instead
|
||||
@param camera_index Camera index (used if filename == NULL)
|
||||
@param[out] handle pointer on Writer handle
|
||||
|
||||
@note API-CALL 8, API-Version == 0
|
||||
*/
|
||||
CvResult (CV_API_CALL *Writer_open)(const char* filename, int fourcc, double fps, int width, int height, int isColor,
|
||||
CV_OUT CvPluginWriter* handle);
|
||||
|
||||
/** @brief Release Writer handle
|
||||
|
||||
@param handle Writer handle
|
||||
|
||||
@note API-CALL 9, API-Version == 0
|
||||
*/
|
||||
CvResult (CV_API_CALL *Writer_release)(CvPluginWriter handle);
|
||||
|
||||
/** @brief Get property value
|
||||
|
||||
@param handle Capture handle
|
||||
@param prop Property index
|
||||
@param[out] val property value
|
||||
|
||||
@note API-CALL 10, API-Version == 0
|
||||
*/
|
||||
CvResult (CV_API_CALL *Writer_getProperty)(CvPluginWriter handle, int prop, CV_OUT double* val);
|
||||
|
||||
/** @brief Set property value
|
||||
|
||||
@param handle Capture handle
|
||||
@param prop Property index
|
||||
@param val property value
|
||||
|
||||
@note API-CALL 11, API-Version == 0
|
||||
*/
|
||||
CvResult (CV_API_CALL *Writer_setProperty)(CvPluginWriter handle, int prop, double val);
|
||||
|
||||
/** @brief Write frame
|
||||
|
||||
@param handle Capture handle
|
||||
@param data Capture handle
|
||||
@param step step in bytes
|
||||
@param width frame width in pixels
|
||||
@param height frame height
|
||||
@param cn number of channels per pixel
|
||||
|
||||
@note API-CALL 12, API-Version == 0
|
||||
*/
|
||||
CvResult (CV_API_CALL *Writer_write)(CvPluginWriter handle, const unsigned char *data, int step, int width, int height, int cn);
|
||||
|
||||
} OpenCV_VideoIO_Plugin_API_preview;
|
||||
|
||||
#ifdef BUILD_PLUGIN
|
||||
|
||||
#ifndef CV_PLUGIN_EXPORTS
|
||||
#if (defined _WIN32 || defined WINCE || defined __CYGWIN__)
|
||||
# define CV_PLUGIN_EXPORTS __declspec(dllexport)
|
||||
#elif defined __GNUC__ && __GNUC__ >= 4
|
||||
# define CV_PLUGIN_EXPORTS __attribute__ ((visibility ("default")))
|
||||
#endif
|
||||
|
||||
CV_PLUGIN_EXPORTS cv_get_version_t cv_get_version;
|
||||
CV_PLUGIN_EXPORTS cv_domain_t cv_domain;
|
||||
|
||||
CV_PLUGIN_EXPORTS cv_open_capture_t cv_open_capture;
|
||||
CV_PLUGIN_EXPORTS cv_get_cap_prop_t cv_get_cap_prop;
|
||||
CV_PLUGIN_EXPORTS cv_set_cap_prop_t cv_set_cap_prop;
|
||||
CV_PLUGIN_EXPORTS cv_grab_t cv_grab;
|
||||
CV_PLUGIN_EXPORTS cv_retrieve_t cv_retrieve;
|
||||
CV_PLUGIN_EXPORTS cv_release_capture_t cv_release_capture;
|
||||
|
||||
CV_PLUGIN_EXPORTS cv_open_writer_t cv_open_writer;
|
||||
CV_PLUGIN_EXPORTS cv_get_wri_prop_t cv_get_wri_prop;
|
||||
CV_PLUGIN_EXPORTS cv_set_wri_prop_t cv_set_wri_prop;
|
||||
CV_PLUGIN_EXPORTS cv_write_t cv_write;
|
||||
CV_PLUGIN_EXPORTS cv_release_writer_t cv_release_writer;
|
||||
|
||||
#endif
|
||||
|
||||
CV_PLUGIN_EXPORTS
|
||||
const OpenCV_VideoIO_Plugin_API_preview* CV_API_CALL opencv_videoio_plugin_init_v0
|
||||
(int requested_abi_version, int requested_api_version, void* reserved /*NULL*/) CV_NOEXCEPT;
|
||||
|
||||
#else // BUILD_PLUGIN
|
||||
typedef const OpenCV_VideoIO_Plugin_API_preview* (CV_API_CALL *FN_opencv_videoio_plugin_init_t)
|
||||
(int requested_abi_version, int requested_api_version, void* reserved /*NULL*/);
|
||||
#endif // BUILD_PLUGIN
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -3,14 +3,11 @@
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include <map>
|
||||
|
||||
#include "videoio_registry.hpp"
|
||||
|
||||
#include "opencv2/videoio/registry.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "cap_librealsense.hpp"
|
||||
#include "cap_dshow.hpp"
|
||||
|
||||
@ -33,20 +30,20 @@
|
||||
#pragma warning(disable: 4748)
|
||||
#endif
|
||||
|
||||
//=================================================================
|
||||
// Private interface
|
||||
//=================================================================
|
||||
using namespace cv;
|
||||
|
||||
namespace cv {
|
||||
|
||||
namespace {
|
||||
|
||||
namespace cv
|
||||
{
|
||||
#define DECLARE_DYNAMIC_BACKEND(cap, name, mode) \
|
||||
{ \
|
||||
cap, (BackendMode)(mode | MODE_DYNAMIC), 1000, name "_DYNAMIC", 0 \
|
||||
cap, (BackendMode)(mode), 1000, name, createPluginBackendFactory(cap, name) \
|
||||
}
|
||||
|
||||
#define DECLARE_STATIC_BACKEND(cap, name, mode, f1, f2, f3) \
|
||||
#define DECLARE_STATIC_BACKEND(cap, name, mode, createCaptureFile, createCaptureCamera, createWriter) \
|
||||
{ \
|
||||
cap, (BackendMode)(mode), 1000, name, Ptr<StaticBackend>(new StaticBackend(f1, f2, f3)) \
|
||||
cap, (BackendMode)(mode), 1000, name, createBackendFactory(createCaptureFile, createCaptureCamera, createWriter) \
|
||||
}
|
||||
|
||||
/** Ordering guidelines:
|
||||
@ -133,147 +130,177 @@ static const struct VideoBackendInfo builtin_backends[] =
|
||||
#ifdef HAVE_XINE
|
||||
DECLARE_STATIC_BACKEND(CAP_XINE, "XINE", MODE_CAPTURE_BY_FILENAME, createXINECapture, 0, 0),
|
||||
#endif
|
||||
|
||||
// dropped backends: MIL, TYZX, Android
|
||||
};
|
||||
|
||||
inline static bool sortByPriority(const VideoBackendInfo &lhs, const VideoBackendInfo &rhs)
|
||||
bool sortByPriority(const VideoBackendInfo &lhs, const VideoBackendInfo &rhs)
|
||||
{
|
||||
return lhs.priority > rhs.priority;
|
||||
}
|
||||
|
||||
inline static std::vector<std::string> tokenize_string(const std::string& input, char token = ',')
|
||||
/** @brief Manages list of enabled backends
|
||||
*/
|
||||
class VideoBackendRegistry
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
std::string::size_type prev_pos = 0, pos = 0;
|
||||
while((pos = input.find(token, pos)) != std::string::npos)
|
||||
protected:
|
||||
std::vector<VideoBackendInfo> enabledBackends;
|
||||
VideoBackendRegistry()
|
||||
{
|
||||
result.push_back(input.substr(prev_pos, pos-prev_pos));
|
||||
prev_pos = ++pos;
|
||||
}
|
||||
result.push_back(input.substr(prev_pos));
|
||||
return result;
|
||||
}
|
||||
|
||||
VideoBackendRegistry::VideoBackendRegistry()
|
||||
{
|
||||
typedef std::vector<std::string> PriorityVec;
|
||||
using namespace cv::utils;
|
||||
const std::string backendOrder_str = getConfigurationParameterString("OPENCV_VIDEOIO_PRIORITY_LIST", NULL);
|
||||
const PriorityVec backendOrder = tokenize_string(backendOrder_str);
|
||||
if (!backendOrder.empty())
|
||||
{
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Configured priority list (OPENCV_VIDEOIO_PRIORITY_LIST): " << backendOrder_str);
|
||||
}
|
||||
|
||||
const int N = sizeof(builtin_backends)/sizeof(builtin_backends[0]);
|
||||
for (int i = 0; i < N; ++i)
|
||||
{
|
||||
VideoBackendInfo be = builtin_backends[i];
|
||||
|
||||
// Check if backend needs plugin
|
||||
if (be.mode & MODE_DYNAMIC)
|
||||
const int N = sizeof(builtin_backends)/sizeof(builtin_backends[0]);
|
||||
enabledBackends.assign(builtin_backends, builtin_backends + N);
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
Ptr<DynamicBackend> plugin = DynamicBackend::load(be.id, (int)be.mode);
|
||||
if (!plugin)
|
||||
VideoBackendInfo& info = enabledBackends[i];
|
||||
info.priority = 1000 - i * 10;
|
||||
}
|
||||
CV_LOG_DEBUG(NULL, "VIDEOIO: Builtin backends(" << N << "): " << dumpBackends());
|
||||
if (readPrioritySettings())
|
||||
{
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Updated backends priorities: " << dumpBackends());
|
||||
}
|
||||
int enabled = 0;
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
VideoBackendInfo& info = enabledBackends[enabled];
|
||||
if (enabled != i)
|
||||
info = enabledBackends[i];
|
||||
size_t param_priority = utils::getConfigurationParameterSizeT(cv::format("OPENCV_VIDEOIO_PRIORITY_%s", info.name).c_str(), (size_t)info.priority);
|
||||
CV_Assert(param_priority == (size_t)(int)param_priority); // overflow check
|
||||
if (param_priority > 0)
|
||||
{
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Disable backend: " << be.name << " (no plugin)");
|
||||
continue;
|
||||
info.priority = (int)param_priority;
|
||||
enabled++;
|
||||
}
|
||||
else
|
||||
{
|
||||
be.backendFactory = plugin;
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Disable backend: " << info.name);
|
||||
}
|
||||
}
|
||||
|
||||
// initial priority (e.g. for 4 elems: 1000, 990, 980, 970)
|
||||
be.priority = 1000 - i * 10;
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Init backend priority: " << be.name << " -> " << be.priority);
|
||||
|
||||
// priority from environment list (e.g. for 4 elems: 13000, 12000, 11000, 10000)
|
||||
PriorityVec::const_iterator backendPos = std::find(backendOrder.begin(), backendOrder.end(), be.name);
|
||||
if (backendPos != backendOrder.end())
|
||||
{
|
||||
const int env_priority2 = static_cast<int>(backendOrder.end() - backendPos - 1);
|
||||
be.priority = 10000 + 1000 * env_priority2;
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Update backend priority: " << be.name << " -> " << be.priority);
|
||||
}
|
||||
|
||||
// priority from environment variable
|
||||
const std::string priority_var = std::string("OPENCV_VIDEOIO_PRIORITY_") + be.name;
|
||||
const size_t env_priority2 = getConfigurationParameterSizeT(priority_var.c_str(), (size_t)be.priority);
|
||||
CV_Assert(env_priority2 == (size_t)(int)env_priority2); // overflow check
|
||||
if (env_priority2 == 0)
|
||||
{
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Disable backend: " << be.name << " (user)");
|
||||
continue;
|
||||
}
|
||||
else if (be.priority != (int)env_priority2)
|
||||
{
|
||||
be.priority = (int)env_priority2;
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Update backend priority: " << be.name << " -> " << be.priority);
|
||||
}
|
||||
|
||||
enabledBackends.push_back(be);
|
||||
enabledBackends.resize(enabled);
|
||||
CV_LOG_DEBUG(NULL, "VIDEOIO: Available backends(" << enabled << "): " << dumpBackends());
|
||||
std::sort(enabledBackends.begin(), enabledBackends.end(), sortByPriority);
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Enabled backends(" << enabled << ", sorted by priority): " << dumpBackends());
|
||||
}
|
||||
std::sort(enabledBackends.begin(), enabledBackends.end(), sortByPriority);
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Enabled backends: " << dumpBackends());
|
||||
}
|
||||
|
||||
std::string VideoBackendRegistry::dumpBackends() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
for (size_t i = 0; i < enabledBackends.size(); i++)
|
||||
static std::vector<std::string> tokenize_string(const std::string& input, char token)
|
||||
{
|
||||
if (i > 0) os << "; ";
|
||||
const VideoBackendInfo& info = enabledBackends[i];
|
||||
os << info.name << '(' << info.priority << ')';
|
||||
std::vector<std::string> result;
|
||||
std::string::size_type prev_pos = 0, pos = 0;
|
||||
while((pos = input.find(token, pos)) != std::string::npos)
|
||||
{
|
||||
result.push_back(input.substr(prev_pos, pos-prev_pos));
|
||||
prev_pos = ++pos;
|
||||
}
|
||||
result.push_back(input.substr(prev_pos));
|
||||
return result;
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
VideoBackendRegistry &VideoBackendRegistry::getInstance()
|
||||
{
|
||||
static VideoBackendRegistry g_instance;
|
||||
return g_instance;
|
||||
}
|
||||
|
||||
Ptr<IBackend> VideoBackendRegistry::getBackend(VideoCaptureAPIs api) const
|
||||
{
|
||||
BackendsVec result;
|
||||
for (BackendsVec::const_iterator i = enabledBackends.begin(); i != enabledBackends.end(); i++)
|
||||
if (api == i->id)
|
||||
return i->backendFactory;
|
||||
return Ptr<IBackend>(0);
|
||||
}
|
||||
|
||||
VideoBackendRegistry::BackendsVec VideoBackendRegistry::getBackends(int capabilityMask, VideoCaptureAPIs filter) const
|
||||
{
|
||||
BackendsVec result;
|
||||
for (BackendsVec::const_iterator i = enabledBackends.begin(); i != enabledBackends.end(); i++)
|
||||
bool readPrioritySettings()
|
||||
{
|
||||
if (filter != CAP_ANY && filter != i->id)
|
||||
continue;
|
||||
if (i->mode & capabilityMask)
|
||||
result.push_back(*i);
|
||||
bool hasChanges = false;
|
||||
cv::String prioritized_backends = utils::getConfigurationParameterString("OPENCV_VIDEOIO_PRIORITY_LIST", NULL);
|
||||
if (prioritized_backends.empty())
|
||||
return hasChanges;
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Configured priority list (OPENCV_VIDEOIO_PRIORITY_LIST): " << prioritized_backends);
|
||||
const std::vector<std::string> names = tokenize_string(prioritized_backends, ',');
|
||||
for (size_t i = 0; i < names.size(); i++)
|
||||
{
|
||||
const std::string& name = names[i];
|
||||
bool found = false;
|
||||
for (size_t k = 0; k < enabledBackends.size(); k++)
|
||||
{
|
||||
VideoBackendInfo& info = enabledBackends[k];
|
||||
if (name == info.name)
|
||||
{
|
||||
info.priority = (int)(100000 + (names.size() - i) * 1000);
|
||||
CV_LOG_DEBUG(NULL, "VIDEOIO: New backend priority: '" << name << "' => " << info.priority);
|
||||
found = true;
|
||||
hasChanges = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "VIDEOIO: Can't prioritize unknown/unavailable backend: '" << name << "'");
|
||||
}
|
||||
}
|
||||
return hasChanges;
|
||||
}
|
||||
public:
|
||||
std::string dumpBackends() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
for (size_t i = 0; i < enabledBackends.size(); i++)
|
||||
{
|
||||
if (i > 0) os << "; ";
|
||||
const VideoBackendInfo& info = enabledBackends[i];
|
||||
os << info.name << '(' << info.priority << ')';
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
static VideoBackendRegistry& getInstance()
|
||||
{
|
||||
static VideoBackendRegistry g_instance;
|
||||
return g_instance;
|
||||
}
|
||||
|
||||
inline std::vector<VideoBackendInfo> getEnabledBackends() const { return enabledBackends; }
|
||||
|
||||
inline std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex() const
|
||||
{
|
||||
std::vector<VideoBackendInfo> result;
|
||||
for (size_t i = 0; i < enabledBackends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = enabledBackends[i];
|
||||
if (info.mode & MODE_CAPTURE_BY_INDEX)
|
||||
result.push_back(info);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
inline std::vector<VideoBackendInfo> getAvailableBackends_CaptureByFilename() const
|
||||
{
|
||||
std::vector<VideoBackendInfo> result;
|
||||
for (size_t i = 0; i < enabledBackends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = enabledBackends[i];
|
||||
if (info.mode & MODE_CAPTURE_BY_FILENAME)
|
||||
result.push_back(info);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
inline std::vector<VideoBackendInfo> getAvailableBackends_Writer() const
|
||||
{
|
||||
std::vector<VideoBackendInfo> result;
|
||||
for (size_t i = 0; i < enabledBackends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = enabledBackends[i];
|
||||
if (info.mode & MODE_WRITER)
|
||||
result.push_back(info);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace videoio_registry {
|
||||
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex()
|
||||
{
|
||||
const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByIndex();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VideoBackendRegistry::hasBackend(int mask, VideoCaptureAPIs api) const
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_CaptureByFilename()
|
||||
{
|
||||
for (BackendsVec::const_iterator i = enabledBackends.begin(); i != enabledBackends.end(); i++)
|
||||
if (api == i->id && mask & i->mode)
|
||||
return true;
|
||||
return false;
|
||||
const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename();
|
||||
return result;
|
||||
}
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_Writer()
|
||||
{
|
||||
const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_Writer();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // cv::
|
||||
|
||||
//=================================================================
|
||||
// Public interface
|
||||
//=================================================================
|
||||
|
||||
namespace cv { namespace videoio_registry {
|
||||
|
||||
cv::String getBackendName(VideoCaptureAPIs api)
|
||||
{
|
||||
@ -289,42 +316,59 @@ cv::String getBackendName(VideoCaptureAPIs api)
|
||||
return cv::format("UnknownVideoAPI(%d)", (int)api);
|
||||
}
|
||||
|
||||
bool hasBackend(VideoCaptureAPIs api, Capability cap)
|
||||
{
|
||||
int mask = 0;
|
||||
if (cap == Read || cap == ReadWrite)
|
||||
mask |= MODE_CAPTURE_ALL;
|
||||
if (cap == Write || cap == ReadWrite)
|
||||
mask |= MODE_WRITER;
|
||||
return VideoBackendRegistry::getInstance().hasBackend(mask, api);
|
||||
}
|
||||
|
||||
inline static std::vector<VideoCaptureAPIs> toIDs(const std::vector<VideoBackendInfo> &backends)
|
||||
std::vector<VideoCaptureAPIs> getBackends()
|
||||
{
|
||||
std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getEnabledBackends();
|
||||
std::vector<VideoCaptureAPIs> result;
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
result.push_back((VideoCaptureAPIs)backends[i].id);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<VideoCaptureAPIs> getBackends()
|
||||
{
|
||||
return toIDs(VideoBackendRegistry::getInstance().getBackends(MODE_CAPTURE_ALL + MODE_WRITER));
|
||||
}
|
||||
|
||||
std::vector<VideoCaptureAPIs> getCameraBackends()
|
||||
{
|
||||
return toIDs(VideoBackendRegistry::getInstance().getBackends(MODE_CAPTURE_BY_INDEX));
|
||||
const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByIndex();
|
||||
std::vector<VideoCaptureAPIs> result;
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
result.push_back((VideoCaptureAPIs)backends[i].id);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
std::vector<VideoCaptureAPIs> getStreamBackends()
|
||||
{
|
||||
return toIDs(VideoBackendRegistry::getInstance().getBackends(MODE_CAPTURE_BY_FILENAME));
|
||||
const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename();
|
||||
std::vector<VideoCaptureAPIs> result;
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
result.push_back((VideoCaptureAPIs)backends[i].id);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
std::vector<VideoCaptureAPIs> getWriterBackends()
|
||||
{
|
||||
return toIDs(VideoBackendRegistry::getInstance().getBackends(MODE_WRITER));
|
||||
const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_Writer();
|
||||
std::vector<VideoCaptureAPIs> result;
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
result.push_back((VideoCaptureAPIs)backends[i].id);
|
||||
return result;
|
||||
}
|
||||
|
||||
}} // cv::videoio_registry::
|
||||
bool hasBackend(VideoCaptureAPIs api)
|
||||
{
|
||||
std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getEnabledBackends();
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = backends[i];
|
||||
if (api == info.id)
|
||||
{
|
||||
CV_Assert(!info.backendFactory.empty());
|
||||
return !info.backendFactory->getBackend().empty();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace registry
|
||||
|
||||
} // namespace
|
||||
|
@ -5,8 +5,6 @@
|
||||
#ifndef __OPENCV_VIDEOIO_VIDEOIO_REGISTRY_HPP__
|
||||
#define __OPENCV_VIDEOIO_VIDEOIO_REGISTRY_HPP__
|
||||
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include "opencv2/videoio/registry.hpp"
|
||||
#include "backend.hpp"
|
||||
|
||||
namespace cv
|
||||
@ -17,7 +15,6 @@ enum BackendMode {
|
||||
MODE_CAPTURE_BY_INDEX = 1 << 0, //!< device index
|
||||
MODE_CAPTURE_BY_FILENAME = 1 << 1, //!< filename or device path (v4l2)
|
||||
MODE_WRITER = 1 << 4, //!< writer
|
||||
MODE_DYNAMIC = 1 << 5,
|
||||
|
||||
MODE_CAPTURE_ALL = MODE_CAPTURE_BY_INDEX + MODE_CAPTURE_BY_FILENAME,
|
||||
};
|
||||
@ -29,26 +26,16 @@ struct VideoBackendInfo {
|
||||
// 0 - disabled (OPENCV_VIDEOIO_PRIORITY_<name> = 0)
|
||||
// >10000 - prioritized list (OPENCV_VIDEOIO_PRIORITY_LIST)
|
||||
const char* name;
|
||||
Ptr<IBackend> backendFactory;
|
||||
Ptr<IBackendFactory> backendFactory;
|
||||
};
|
||||
|
||||
/** @brief Manages list of enabled backends
|
||||
*/
|
||||
class VideoBackendRegistry
|
||||
{
|
||||
public:
|
||||
typedef std::vector<VideoBackendInfo> BackendsVec;
|
||||
protected:
|
||||
BackendsVec enabledBackends;
|
||||
VideoBackendRegistry();
|
||||
public:
|
||||
std::string dumpBackends() const;
|
||||
Ptr<IBackend> getBackend(VideoCaptureAPIs api) const;
|
||||
BackendsVec getBackends(int capabilityMask, VideoCaptureAPIs filter = CAP_ANY) const;
|
||||
bool hasBackend(int mask, VideoCaptureAPIs api) const;
|
||||
namespace videoio_registry {
|
||||
|
||||
static VideoBackendRegistry& getInstance();
|
||||
};
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex();
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_CaptureByFilename();
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_Writer();
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace
|
||||
#endif // __OPENCV_VIDEOIO_VIDEOIO_REGISTRY_HPP__
|
||||
|
@ -20,7 +20,7 @@ TEST(videoio_dynamic, basic_write)
|
||||
const Size FRAME_SIZE(640, 480);
|
||||
const double FPS = 100;
|
||||
const String filename = cv::tempfile(".avi");
|
||||
const int fourcc = VideoWriter::fourcc('H', '2', '6', '4');
|
||||
const int fourcc = VideoWriter::fourcc('M', 'J', 'P', 'G');
|
||||
|
||||
bool fileExists = false;
|
||||
{
|
||||
|
@ -82,7 +82,7 @@ protected:
|
||||
public:
|
||||
void doTest()
|
||||
{
|
||||
if (!videoio_registry::hasBackend(apiPref, videoio_registry::Read))
|
||||
if (!videoio_registry::hasBackend(apiPref))
|
||||
throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
|
||||
writeVideo();
|
||||
VideoCapture cap;
|
||||
@ -168,7 +168,7 @@ public:
|
||||
}
|
||||
void doFrameCountTest()
|
||||
{
|
||||
if (!videoio_registry::hasBackend(apiPref, videoio_registry::Read))
|
||||
if (!videoio_registry::hasBackend(apiPref))
|
||||
throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
|
||||
VideoCapture cap;
|
||||
EXPECT_NO_THROW(cap.open(video_file, apiPref));
|
||||
|
Loading…
Reference in New Issue
Block a user