videoio: update plugin API

pull/13970/head
Alexander Alekhin 6 years ago
parent b4cba524d3
commit 403f11fdbf
  1. 1
      modules/core/include/opencv2/core.hpp
  2. 94
      modules/core/include/opencv2/core/llapi/llapi.h
  3. 3
      modules/videoio/CMakeLists.txt
  4. 4
      modules/videoio/cmake/plugin.cmake
  5. 71
      modules/videoio/src/backend.hpp
  6. 558
      modules/videoio/src/backend_plugin.cpp
  7. 72
      modules/videoio/src/backend_static.cpp
  8. 182
      modules/videoio/src/cap_ffmpeg.cpp
  9. 6
      modules/videoio/src/cap_ffmpeg_api.hpp
  10. 169
      modules/videoio/src/cap_gstreamer.cpp
  11. 19
      modules/videoio/src/plugin_api.cpp
  12. 177
      modules/videoio/src/plugin_api.hpp

@ -92,6 +92,7 @@
@{
@defgroup core_hal_intrin_impl Private implementation helpers
@}
@defgroup core_lowlevel_api Low-level API for external libraries / plugins
@}
@}
*/

@ -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

@ -14,7 +14,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

@ -12,7 +12,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})
@ -60,7 +60,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"

@ -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
class IBackendFactory
{
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;
}
virtual ~IBackendFactory() {}
virtual Ptr<IBackend> getBackend() const = 0;
};
//==================================================================================================
//=============================================================================
class DynamicBackend : public IBackend
{
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;
};
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);
} // cv::
Ptr<IBackendFactory> createPluginBackendFactory(VideoCaptureAPIs id, const char* baseName);
} // namespace cv::
#endif // BACKEND_HPP_DEFINED

@ -12,69 +12,6 @@
#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
@ -88,34 +25,52 @@ using namespace std;
#include <dlfcn.h>
#endif
inline static void * getSymbol_(void *h, const std::string &symbolName)
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(static_cast<HMODULE>(h), symbolName.c_str());
return (void*)GetProcAddress(h, symbolName);
#elif defined(__linux__) || defined(__APPLE__)
return dlsym(h, symbolName.c_str());
return dlsym(h, symbolName);
#endif
}
inline static void * libraryLoad_(const std::string &filename)
static inline
LibHandle_t libraryLoad_(const char* filename)
{
#if defined(_WIN32)
return static_cast<HMODULE>(LoadLibraryA(filename.c_str()));
return LoadLibraryA(filename);
#elif defined(__linux__) || defined(__APPLE__)
return dlopen(filename.c_str(), RTLD_LAZY);
return dlopen(filename, RTLD_LAZY);
#endif
}
inline static void libraryRelease_(void *h)
static inline
void libraryRelease_(LibHandle_t h)
{
#if defined(_WIN32)
FreeLibrary(static_cast<HMODULE>(h));
FreeLibrary(h);
#elif defined(__linux__) || defined(__APPLE__)
dlclose(h);
#endif
}
inline static std::string libraryPrefix()
static inline
std::string libraryPrefix()
{
#if defined(_WIN32)
return string();
@ -123,23 +78,24 @@ inline static std::string libraryPrefix()
return "lib";
#endif
}
inline static std::string librarySuffix()
static inline
std::string librarySuffix()
{
#if defined(_WIN32)
return "dll";
return ".dll";
#elif defined(__APPLE__)
return "dylib";
return ".dylib";
#else
return "so";
return ".so";
#endif
}
//============================
class cv::DynamicBackend::DynamicLib
class DynamicLib
{
private:
void * handle;
LibHandle_t handle;
const std::string fname;
public:
@ -156,7 +112,7 @@ public:
{
return handle != NULL;
}
void* getSymbol(const std::string & symbolName) const
void* getSymbol(const char* symbolName) const
{
if (!handle)
{
@ -167,11 +123,11 @@ public:
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);
handle = libraryLoad_(filename.c_str());
CV_LOG_INFO(NULL, "load " << filename << " => " << (handle ? "OK" : "FAILED"));
}
void libraryRelease()
@ -192,300 +148,346 @@ private:
//============================
// Utility function
static bool verifyVersion(cv_get_version_t * fun)
class PluginBackend: public IBackend
{
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)
public:
Ptr<DynamicLib> lib_;
const OpenCV_VideoIO_Plugin_API_preview* plugin_api_;
PluginBackend(const Ptr<DynamicLib>& lib) :
lib_(lib), plugin_api_(NULL)
{
CV_LOG_ERROR(NULL, "Bad plugin version (" << major << "." << minor << "), expected " << CV_MAJOR_VERSION << "/" << CV_MINOR_VERSION);
return false;
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;
}
// 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());
}
}
#endif
return true;
}
//============================
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 cv::DynamicBackend::CaptureTable
class PluginBackendFactory : public IBackendFactory
{
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;
VideoCaptureAPIs id_;
const char* baseName_;
Ptr<PluginBackend> backend;
bool initialized;
public:
CaptureTable(const cv::DynamicBackend::DynamicLib & p)
: isComplete(true)
PluginBackendFactory(VideoCaptureAPIs id, const char* baseName) :
id_(id), baseName_(baseName),
initialized(false)
{
#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
// nothing, plugins are loaded on demand
}
};
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)
Ptr<IBackend> getBackend() const CV_OVERRIDE
{
#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
if (!initialized)
{
const_cast<PluginBackendFactory*>(this)->initBackend();
}
return backend.staticCast<IBackend>();
}
};
//============================
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())
protected:
void initBackend()
{
cap_tbl = new CaptureTable(*lib);
wri_tbl = new WriterTable(*lib);
AutoLock lock(getInitializationMutex());
try {
if (!initialized)
loadPlugin();
}
catch (...)
{
CV_LOG_INFO(NULL, "Video I/O: exception during plugin loading: " << baseName_ << ". SKIP");
}
initialized = true;
}
}
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>();
}
void loadPlugin();
};
inline static std::vector<string> getPluginCandidates()
static
std::vector<string> getPluginCandidates(const std::string& baseName)
{
using namespace cv::utils;
using namespace cv::utils::fs;
const vector<string> default_paths = { getParent(getBinLocation()) };
#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 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)");
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(join(path, expr), candidates);
CV_LOG_INFO(NULL, "VideoIO pluigins in " << path << ": " << candidates.size());
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)");
CV_LOG_INFO(NULL, "Found " << results.size() << " plugin(s) for " << baseName);
return results;
}
cv::Ptr<cv::DynamicBackend> cv::DynamicBackend::load(cv::VideoCaptureAPIs api, int mode)
void PluginBackendFactory::loadPlugin()
{
for(const std::string & plugin : getPluginCandidates())
for(const std::string & plugin : getPluginCandidates(baseName_))
{
bool res = true;
Ptr<DynamicBackend> factory = makePtr<DynamicBackend>(plugin);
if (factory)
if (mode & cv::MODE_CAPTURE_BY_INDEX || mode & cv::MODE_CAPTURE_BY_FILENAME)
Ptr<DynamicLib> lib = makePtr<DynamicLib>(plugin);
if (!lib->isLoaded())
continue;
try
{
Ptr<PluginBackend> pluginBackend = makePtr<PluginBackend>(lib);
if (pluginBackend && pluginBackend->plugin_api_)
{
res = res && factory->canCreateCapture(api);
backend = pluginBackend;
return;
}
if (mode & cv::MODE_WRITER)
}
catch (...)
{
res = res && factory->canCreateWriter(api);
CV_LOG_INFO(NULL, "Video I/O: exception during plugin initialization: " << plugin << ". SKIP");
}
if (res)
return factory;
}
return 0;
}
//==================================================================================================
// DynamicCapture
class DynamicCapture : public cv::IVideoCapture
class PluginCapture : public cv::IVideoCapture
{
const cv::DynamicBackend::CaptureTable * tbl;
void * capture;
const OpenCV_VideoIO_Plugin_API_preview* plugin_api_;
CvPluginCapture capture_;
public:
DynamicCapture(const cv::DynamicBackend::CaptureTable * tbl_, const std::string &filename, int camera)
: tbl(tbl_), capture(0)
static
Ptr<PluginCapture> create(const OpenCV_VideoIO_Plugin_API_preview* plugin_api,
const std::string &filename, int camera)
{
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(plugin_api);
CvPluginCapture capture = NULL;
if (plugin_api->Capture_open)
{
CV_Assert(tbl->cv_release_capture);
tbl->cv_release_capture(capture);
capture = 0;
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
{
CV_Assert(capture);
double val = -1;
tbl->cv_get_cap_prop(capture, prop, val);
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
{
CV_Assert(capture);
return tbl->cv_set_cap_prop(capture, prop, val);
if (plugin_api_->Capture_setProperty)
if (CV_ERROR_OK == plugin_api_->Capture_setProperty(capture_, prop, val))
return true;
return false;
}
bool grabFrame() CV_OVERRIDE
{
CV_Assert(capture);
return tbl->cv_grab(capture);
if (plugin_api_->Capture_grab)
if (CV_ERROR_OK == plugin_api_->Capture_grab(capture_))
return true;
return false;
}
static bool local_retrieve(unsigned char * data, int step, int width, int height, int cn, void * userdata)
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::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;
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
{
CV_Assert(capture);
cv::Mat frame;
bool res = tbl->cv_retrieve(capture, idx, &local_retrieve, &frame);
if (res)
frame.copyTo(img);
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;
return capture_ != NULL; // TODO always true
}
int getCaptureDomain() CV_OVERRIDE
{
return tbl->cv_domain();
return plugin_api_->captureAPI;
}
};
//==================================================================================================
// DynamicWriter
class DynamicWriter : public cv::IVideoWriter
class PluginWriter : public cv::IVideoWriter
{
const cv::DynamicBackend::WriterTable * tbl;
void * writer;
const OpenCV_VideoIO_Plugin_API_preview* plugin_api_;
CvPluginWriter 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)
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(!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(plugin_api);
CvPluginWriter writer = NULL;
if (plugin_api->Writer_open)
{
CV_Assert(tbl->cv_release_writer);
tbl->cv_release_writer(writer);
writer = 0;
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
{
CV_Assert(writer);
double val = -1;
tbl->cv_get_wri_prop(writer, prop, val);
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
{
CV_Assert(writer);
return tbl->cv_set_wri_prop(writer, prop, val);
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;
return writer_ != NULL; // TODO always true
}
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());
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 tbl->cv_domain();
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

@ -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

@ -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)
{
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)
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)
{
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;
}
static
CvResult CV_API_CALL cv_writer_release(CvPluginWriter handle)
{
if (!handle)
return CV_ERROR_FAIL;
CvVideoWriter_FFMPEG_proxy* instance = (CvVideoWriter_FFMPEG_proxy*)handle;
delete instance;
return CV_ERROR_OK;
}
CV_EXTERN_C bool cv_get_wri_prop(void*, int, double&)
static
CvResult CV_API_CALL cv_writer_get_prop(CvPluginWriter /*handle*/, int /*prop*/, CV_OUT double* /*val*/)
{
return false;
return CV_ERROR_FAIL;
}
CV_EXTERN_C bool cv_set_wri_prop(void*, int, double)
static
CvResult CV_API_CALL cv_writer_set_prop(CvPluginWriter /*handle*/, int /*prop*/, double /*val*/)
{
return false;
return CV_ERROR_FAIL;
}
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_write(CvPluginWriter handle, const unsigned char *data, int step, int width, int height, int cn)
{
if (!handle)
return false;
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(...)
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
{
GStreamerCapture * instance = static_cast<GStreamerCapture*>(handle);
return instance->setProperty(prop, val);
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_grab(void * handle)
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->grabFrame();
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_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
{
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&)
static
CvResult CV_API_CALL cv_writer_release(CvPluginWriter handle)
{
return false;
if (!handle)
return CV_ERROR_FAIL;
CvVideoWriter_GStreamer* instance = (CvVideoWriter_GStreamer*)handle;
delete instance;
return CV_ERROR_OK;
}
CV_EXTERN_C bool cv_set_wri_prop(void*, int, double)
static
CvResult CV_API_CALL cv_writer_get_prop(CvPluginWriter /*handle*/, int /*prop*/, CV_OUT double* /*val*/)
{
return false;
return CV_ERROR_FAIL;
}
static
CvResult CV_API_CALL cv_writer_set_prop(CvPluginWriter /*handle*/, int /*prop*/, double /*val*/)
{
return CV_ERROR_FAIL;
}
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_write(CvPluginWriter handle, const unsigned char *data, int step, int width, int height, int cn)
{
if (!handle)
return false;
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,63 +5,164 @@
#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();
// 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);
// 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 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);
typedef struct CvPluginCapture_t* CvPluginCapture;
typedef struct CvPluginWriter_t* CvPluginWriter;
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
#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;
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;
#endif
#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

Loading…
Cancel
Save