diff --git a/modules/core/include/opencv2/core/operations.hpp b/modules/core/include/opencv2/core/operations.hpp index 64f71569c5..92943a62a8 100644 --- a/modules/core/include/opencv2/core/operations.hpp +++ b/modules/core/include/opencv2/core/operations.hpp @@ -52,7 +52,11 @@ #include #if defined(__GNUC__) || defined(__clang__) // at least GCC 3.1+, clang 3.5+ -# define CV_FORMAT_PRINTF(string_idx, first_to_check) __attribute__ ((format (printf, string_idx, first_to_check))) +# if defined(__MINGW_PRINTF_FORMAT) // https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. +# define CV_FORMAT_PRINTF(string_idx, first_to_check) __attribute__ ((format (__MINGW_PRINTF_FORMAT, string_idx, first_to_check))) +# else +# define CV_FORMAT_PRINTF(string_idx, first_to_check) __attribute__ ((format (printf, string_idx, first_to_check))) +# endif #else # define CV_FORMAT_PRINTF(A, B) #endif diff --git a/modules/core/include/opencv2/core/private.hpp b/modules/core/include/opencv2/core/private.hpp index 7762e075d8..5c10ba1f7e 100644 --- a/modules/core/include/opencv2/core/private.hpp +++ b/modules/core/include/opencv2/core/private.hpp @@ -872,9 +872,17 @@ Passed subdirectories are used in LIFO order. */ CV_EXPORTS void addDataSearchSubDirectory(const cv::String& subdir); -/** @brief Return location of OpenCV libraries or current executable +/** @brief Retrieve location of OpenCV libraries or current executable */ -CV_EXPORTS std::string getBinLocation(); +CV_EXPORTS bool getBinLocation(std::string& dst); + +#if defined(_WIN32) +/** @brief Retrieve location of OpenCV libraries or current executable + +@note WIN32 only + */ +CV_EXPORTS bool getBinLocation(std::wstring& dst); +#endif //! @} diff --git a/modules/core/include/opencv2/core/utils/filesystem.hpp b/modules/core/include/opencv2/core/utils/filesystem.hpp index 9f043bef50..a98d2202fc 100644 --- a/modules/core/include/opencv2/core/utils/filesystem.hpp +++ b/modules/core/include/opencv2/core/utils/filesystem.hpp @@ -28,6 +28,7 @@ CV_EXPORTS cv::String join(const cv::String& base, const cv::String& path); /** Get parent directory */ CV_EXPORTS cv::String getParent(const cv::String &path); +CV_EXPORTS std::wstring getParent(const std::wstring& path); /** * Generate a list of all files that match the globbing pattern. diff --git a/modules/core/src/utils/datafile.cpp b/modules/core/src/utils/datafile.cpp index b3dc31f52b..aafbfdf52d 100644 --- a/modules/core/src/utils/datafile.cpp +++ b/modules/core/src/utils/datafile.cpp @@ -144,11 +144,38 @@ static cv::String getModuleLocation(const void* addr) return cv::String(); } -std::string getBinLocation() +bool getBinLocation(std::string& dst) { - return getModuleLocation((void*)getModuleLocation); // use code addr, doesn't work with static linkage! + dst = getModuleLocation((void*)getModuleLocation); // using code address, doesn't work with static linkage! + return !dst.empty(); } +#ifdef _WIN32 +bool getBinLocation(std::wstring& dst) +{ + void* addr = (void*)getModuleLocation; // using code address, doesn't work with static linkage! + HMODULE m = 0; +#if _WIN32_WINNT >= 0x0501 + ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(addr), + &m); +#endif + if (m) + { + wchar_t path[4096]; + const size_t path_size = sizeof(path)/sizeof(*path); + size_t sz = GetModuleFileNameW(m, path, path_size); + if (sz > 0 && sz < path_size) + { + path[sz] = '\0'; + dst.assign(path, sz); + return true; + } + } + return false; +} +#endif + cv::String findDataFile(const cv::String& relative_path, const char* configuration_parameter, const std::vector* search_paths, @@ -292,8 +319,15 @@ cv::String findDataFile(const cv::String& relative_path, } } - cv::String module_path = getBinLocation(); - CV_LOG_DEBUG(NULL, "Detected module path: '" << module_path << '\''); + cv::String module_path; + if (getBinLocation(module_path)) + { + CV_LOG_DEBUG(NULL, "Detected module path: '" << module_path << '\''); + } + else + { + CV_LOG_INFO(NULL, "Can't detect module binaries location"); + } if (!has_tested_build_directory && (isSubDirectory(build_dir, module_path) || isSubDirectory(utils::fs::canonical(build_dir), utils::fs::canonical(module_path))) diff --git a/modules/core/src/utils/filesystem.cpp b/modules/core/src/utils/filesystem.cpp index a1f8396df0..9e606dcdbe 100644 --- a/modules/core/src/utils/filesystem.cpp +++ b/modules/core/src/utils/filesystem.cpp @@ -91,6 +91,14 @@ CV_EXPORTS cv::String getParent(const cv::String &path) return std::string(path, 0, loc); } +CV_EXPORTS std::wstring getParent(const std::wstring& path) +{ + std::wstring::size_type loc = path.find_last_of(L"/\\"); + if (loc == std::wstring::npos) + return std::wstring(); + return std::wstring(path, 0, loc); +} + #if OPENCV_HAVE_FILESYSTEM_SUPPORT cv::String canonical(const cv::String& path) diff --git a/modules/videoio/CMakeLists.txt b/modules/videoio/CMakeLists.txt index 24b5caf331..23cf0f9bb2 100644 --- a/modules/videoio/CMakeLists.txt +++ b/modules/videoio/CMakeLists.txt @@ -131,7 +131,9 @@ if(TARGET ocv.3rdparty.ximea) endif() if(TARGET ocv.3rdparty.ffmpeg) - if("ffmpeg" IN_LIST VIDEOIO_PLUGIN_LIST) + if(HAVE_FFMPEG_WRAPPER) + list(APPEND tgts ocv.3rdparty.ffmpeg) + elseif("ffmpeg" IN_LIST VIDEOIO_PLUGIN_LIST) ocv_create_builtin_videoio_plugin("opencv_videoio_ffmpeg" ocv.3rdparty.ffmpeg "cap_ffmpeg.cpp") else() list(APPEND videoio_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/cap_ffmpeg_impl.hpp) @@ -202,7 +204,7 @@ ocv_target_link_libraries(${the_module} LINK_PRIVATE ${tgts}) # copy FFmpeg dll to the output folder if(WIN32 AND HAVE_FFMPEG_WRAPPER) if(MSVC64 OR MINGW64) - set(FFMPEG_SUFFIX _64) + set(FFMPEG_SUFFIX "_64") endif() set(ffmpeg_dir "${OpenCV_BINARY_DIR}/3rdparty/ffmpeg") set(ffmpeg_bare_name "opencv_ffmpeg${FFMPEG_SUFFIX}.dll") diff --git a/modules/videoio/cmake/detect_ffmpeg.cmake b/modules/videoio/cmake/detect_ffmpeg.cmake index 57dd95cc55..58e16141d9 100644 --- a/modules/videoio/cmake/detect_ffmpeg.cmake +++ b/modules/videoio/cmake/detect_ffmpeg.cmake @@ -54,12 +54,10 @@ endif() #================================== -if(HAVE_FFMPEG) - set(defs "HAVE_FFMPEG") - if(HAVE_FFMPEG_WRAPPER) - list(APPEND defs "HAVE_FFMPEG_WRAPPER") - endif() - ocv_add_external_target(ffmpeg "${FFMPEG_INCLUDE_DIRS}" "${FFMPEG_LIBRARIES}" "${defs}") +if(HAVE_FFMPEG_WRAPPER) + ocv_add_external_target(ffmpeg "" "" "HAVE_FFMPEG_WRAPPER") +elseif(HAVE_FFMPEG) + ocv_add_external_target(ffmpeg "${FFMPEG_INCLUDE_DIRS}" "${FFMPEG_LIBRARIES}" "HAVE_FFMPEG") endif() set(HAVE_FFMPEG ${HAVE_FFMPEG} PARENT_SCOPE) diff --git a/modules/videoio/cmake/plugin.cmake b/modules/videoio/cmake/plugin.cmake index f7cdd6277d..445ce7db21 100644 --- a/modules/videoio/cmake/plugin.cmake +++ b/modules/videoio/cmake/plugin.cmake @@ -25,9 +25,22 @@ function(ocv_create_builtin_videoio_plugin name target) ocv_target_include_directories(${name} PRIVATE "${OPENCV_MODULE_${mod}_LOCATION}/include") endforeach() + if(WIN32) + set(OPENCV_PLUGIN_VERSION "${OPENCV_DLLVERSION}" CACHE STRING "") + if(CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8) + set(OPENCV_PLUGIN_ARCH "_64" CACHE STRING "") + else() + set(OPENCV_PLUGIN_ARCH "" CACHE STRING "") + endif() + else() + set(OPENCV_PLUGIN_VERSION "" CACHE STRING "") + set(OPENCV_PLUGIN_ARCH "" CACHE STRING "") + endif() + set_target_properties(${name} PROPERTIES CXX_STANDARD 11 CXX_VISIBILITY_PRESET hidden + OUTPUT_NAME "${name}${OPENCV_PLUGIN_VERSION}${OPENCV_PLUGIN_ARCH}" ) if(WIN32) diff --git a/modules/videoio/cmake/plugin_standalone.cmake b/modules/videoio/cmake/plugin_standalone.cmake index 045d029b7e..a1b4d7a4ce 100644 --- a/modules/videoio/cmake/plugin_standalone.cmake +++ b/modules/videoio/cmake/plugin_standalone.cmake @@ -28,7 +28,7 @@ function(ocv_create_videoio_plugin default_name target target_desc videoio_src_f message(FATAL_ERROR "${target_desc} was not found!") endif() - set(modules_ROOT "${CMAKE_CURRENT_LIST_DIR}/../../..") + get_filename_component(modules_ROOT "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE) set(videoio_ROOT "${modules_ROOT}/videoio") set(core_ROOT "${modules_ROOT}/core") set(imgproc_ROOT "${modules_ROOT}/imgproc") @@ -45,22 +45,20 @@ function(ocv_create_videoio_plugin default_name target target_desc videoio_src_f ) target_compile_definitions(${OPENCV_PLUGIN_NAME} PRIVATE BUILD_PLUGIN) - # Fixes for build - target_compile_definitions(${OPENCV_PLUGIN_NAME} PRIVATE __OPENCV_BUILD) - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cvconfig.h" "#pragma once") - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cv_cpu_config.h" "#pragma once") - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/opencv2/opencv_modules.hpp" "#pragma once") - target_link_libraries(${OPENCV_PLUGIN_NAME} PRIVATE ${target}) set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES CXX_STANDARD 11 CXX_VISIBILITY_PRESET hidden ) + if(DEFINED OPENCV_PLUGIN_MODULE_PREFIX) + set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES PREFIX "${OPENCV_PLUGIN_MODULE_PREFIX}") + endif() + # Hack for Windows if(WIN32) find_package(OpenCV REQUIRED core imgproc videoio) - target_link_libraries(${OPENCV_PLUGIN_NAME} ${OpenCV_LIBS}) + target_link_libraries(${OPENCV_PLUGIN_NAME} PRIVATE ${OpenCV_LIBS}) endif() if(OPENCV_PLUGIN_DESTINATION) @@ -68,6 +66,8 @@ function(ocv_create_videoio_plugin default_name target target_desc videoio_src_f message(STATUS "Output destination: ${OPENCV_PLUGIN_DESTINATION}") endif() + install(TARGETS ${OPENCV_PLUGIN_NAME} LIBRARY DESTINATION . COMPONENT plugins) + message(STATUS "Library name: ${OPENCV_PLUGIN_NAME}") endfunction() diff --git a/modules/videoio/src/backend_plugin.cpp b/modules/videoio/src/backend_plugin.cpp index a29e360784..17f7a1de4e 100644 --- a/modules/videoio/src/backend_plugin.cpp +++ b/modules/videoio/src/backend_plugin.cpp @@ -29,10 +29,43 @@ namespace cv { namespace impl { #if defined(_WIN32) typedef HMODULE LibHandle_t; -#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) +typedef wchar_t FileSystemChar_t; +typedef std::wstring FileSystemPath_t; + +static +FileSystemPath_t toFileSystemPath(const std::string& p) +{ + FileSystemPath_t result; + result.resize(p.size()); + for (size_t i = 0; i < p.size(); i++) + result[i] = (wchar_t)p[i]; + return result; +} +static +std::string toPrintablePath(const FileSystemPath_t& p) +{ + std::string result; + result.resize(p.size()); + for (size_t i = 0; i < p.size(); i++) + { + wchar_t ch = p[i]; + if ((int)ch >= ' ' && (int)ch < 128) + result[i] = (char)ch; + else + result[i] = '?'; + } + return result; +} +#else // !_WIN32 typedef void* LibHandle_t; +typedef char FileSystemChar_t; +typedef std::string FileSystemPath_t; + +static inline FileSystemPath_t toFileSystemPath(const std::string& p) { return p; } +static inline std::string toPrintablePath(const FileSystemPath_t& p) { return p; } #endif + static Mutex& getInitializationMutex() { static Mutex initializationMutex; @@ -50,12 +83,16 @@ void* getSymbol_(LibHandle_t h, const char* symbolName) } static inline -LibHandle_t libraryLoad_(const char* filename) +LibHandle_t libraryLoad_(const FileSystemPath_t& filename) { #if defined(_WIN32) - return LoadLibraryA(filename); +# ifdef WINRT + return LoadPackagedLibrary(filename.c_str(), 0); +# else + return LoadLibraryW(filename.c_str()); +#endif #elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) - return dlopen(filename, RTLD_LAZY); + return dlopen(filename.c_str(), RTLD_LAZY); #endif } @@ -73,7 +110,7 @@ static inline std::string libraryPrefix() { #if defined(_WIN32) - return string(); + return ""; #else return "lib"; #endif @@ -82,9 +119,13 @@ static inline std::string librarySuffix() { #if defined(_WIN32) - return ".dll"; -#elif defined(__APPLE__) - return ".dylib"; + const char* suffix = "" + CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION) + #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__) + "_64" + #endif + ".dll"; + return suffix; #else return ".so"; #endif @@ -96,10 +137,10 @@ class DynamicLib { private: LibHandle_t handle; - const std::string fname; + const FileSystemPath_t fname; public: - DynamicLib(const std::string &filename) + DynamicLib(const FileSystemPath_t& filename) : handle(0), fname(filename) { libraryLoad(filename); @@ -120,21 +161,21 @@ public: } void * res = getSymbol_(handle, symbolName); if (!res) - CV_LOG_ERROR(NULL, "No symbol '" << symbolName << "' in " << fname); + CV_LOG_ERROR(NULL, "No symbol '" << symbolName << "' in " << toPrintablePath(fname)); return res; } - const std::string& getName() const { return fname; } + const std::string getName() const { return toPrintablePath(fname); } private: - void libraryLoad(const std::string &filename) + void libraryLoad(const FileSystemPath_t& filename) { - handle = libraryLoad_(filename.c_str()); - CV_LOG_INFO(NULL, "load " << filename << " => " << (handle ? "OK" : "FAILED")); + handle = libraryLoad_(filename); + CV_LOG_INFO(NULL, "load " << toPrintablePath(filename) << " => " << (handle ? "OK" : "FAILED")); } void libraryRelease() { - CV_LOG_INFO(NULL, "unload "<< fname); if (handle) { + CV_LOG_INFO(NULL, "unload "<< toPrintablePath(fname)); libraryRelease_(handle); handle = 0; } @@ -230,39 +271,79 @@ protected: }; static -std::vector getPluginCandidates(const std::string& baseName) +std::vector 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 default_paths = { utils::fs::join(getParent(getBinLocation()), CV_VIDEOIO_PLUGIN_SUBDIRECTORY_STR) }; - const vector paths = getConfigurationParameterPaths("OPENCV_VIDEOIO_PLUGIN_PATH", default_paths); const string baseName_l = toLowerCase(baseName); const string baseName_u = toUpperCase(baseName); + const FileSystemPath_t baseName_l_fs = toFileSystemPath(baseName_l); + vector paths; + const vector paths_ = getConfigurationParameterPaths("OPENCV_VIDEOIO_PLUGIN_PATH", vector()); + if (paths_.size() != 0) + { + for (size_t i = 0; i < paths_.size(); i++) + { + paths.push_back(toFileSystemPath(paths_[i])); + } + } + else + { + FileSystemPath_t binaryLocation; + if (getBinLocation(binaryLocation)) + { + binaryLocation = getParent(binaryLocation); +#ifndef CV_VIDEOIO_PLUGIN_SUBDIRECTORY + paths.push_back(binaryLocation); +#else + paths.push_back(binaryLocation + toFileSystemPath("/") + toFileSystemPath(CV_VIDEOIO_PLUGIN_SUBDIRECTORY_STR)); +#endif + } + } 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 results; - for(const string & path : paths) + const string plugin_expr = getConfigurationParameterString((std::string("OPENCV_VIDEOIO_PLUGIN_") + baseName_u).c_str(), default_expr.c_str()); + vector results; +#ifdef _WIN32 + FileSystemPath_t moduleName = toFileSystemPath(libraryPrefix() + "opencv_videoio_" + baseName_l + librarySuffix()); +#ifndef WINRT + if (baseName_u == "FFMPEG") // backward compatibility + { + const wchar_t* ffmpeg_env_path = _wgetenv(L"OPENCV_FFMPEG_DLL_DIR"); + if (ffmpeg_env_path) + { + results.push_back(FileSystemPath_t(ffmpeg_env_path) + L"\\" + moduleName); + } + } +#endif + if (plugin_expr != default_expr) + { + moduleName = toFileSystemPath(plugin_expr); + results.push_back(moduleName); + } + for (const FileSystemPath_t& path : paths) + { + results.push_back(path + L"\\" + moduleName); + } + results.push_back(moduleName); +#else + CV_LOG_INFO(NULL, "VideoIO pluigin (" << baseName << "): glob is '" << plugin_expr << "', " << paths.size() << " location(s)"); + for (const string & path : paths) { if (path.empty()) continue; vector candidates; - cv::glob(utils::fs::join(path, expr), candidates); + cv::glob(utils::fs::join(path, plugin_expr), candidates); CV_LOG_INFO(NULL, " - " << path << ": " << candidates.size()); copy(candidates.begin(), candidates.end(), back_inserter(results)); } +#endif CV_LOG_INFO(NULL, "Found " << results.size() << " plugin(s) for " << baseName); return results; } void PluginBackendFactory::loadPlugin() { - for(const std::string & plugin : getPluginCandidates(baseName_)) + for (const FileSystemPath_t& plugin : getPluginCandidates(baseName_)) { Ptr lib = makePtr(plugin); if (!lib->isLoaded()) @@ -287,7 +368,7 @@ void PluginBackendFactory::loadPlugin() } catch (...) { - CV_LOG_INFO(NULL, "Video I/O: exception during plugin initialization: " << plugin << ". SKIP"); + CV_LOG_WARNING(NULL, "Video I/O: exception during plugin initialization: " << toPrintablePath(plugin) << ". SKIP"); } } } diff --git a/modules/videoio/src/cap_ffmpeg.cpp b/modules/videoio/src/cap_ffmpeg.cpp index 16e6637375..5d8003cdef 100644 --- a/modules/videoio/src/cap_ffmpeg.cpp +++ b/modules/videoio/src/cap_ffmpeg.cpp @@ -41,11 +41,12 @@ #include "precomp.hpp" -#if defined(HAVE_FFMPEG) +#if !defined(HAVE_FFMPEG) +#error "Build configuration error" +#endif #include -#if !defined(HAVE_FFMPEG_WRAPPER) #include "cap_ffmpeg_impl.hpp" #define icvCreateFileCapture_FFMPEG_p cvCreateFileCapture_FFMPEG @@ -58,152 +59,6 @@ #define icvReleaseVideoWriter_FFMPEG_p cvReleaseVideoWriter_FFMPEG #define icvWriteFrame_FFMPEG_p cvWriteFrame_FFMPEG -#else - -#include "cap_ffmpeg_api.hpp" - -namespace cv { namespace { - -static CvCreateFileCapture_Plugin icvCreateFileCapture_FFMPEG_p = 0; -static CvReleaseCapture_Plugin icvReleaseCapture_FFMPEG_p = 0; -static CvGrabFrame_Plugin icvGrabFrame_FFMPEG_p = 0; -static CvRetrieveFrame_Plugin icvRetrieveFrame_FFMPEG_p = 0; -static CvSetCaptureProperty_Plugin icvSetCaptureProperty_FFMPEG_p = 0; -static CvGetCaptureProperty_Plugin icvGetCaptureProperty_FFMPEG_p = 0; -static CvCreateVideoWriter_Plugin icvCreateVideoWriter_FFMPEG_p = 0; -static CvReleaseVideoWriter_Plugin icvReleaseVideoWriter_FFMPEG_p = 0; -static CvWriteFrame_Plugin icvWriteFrame_FFMPEG_p = 0; - -static cv::Mutex _icvInitFFMPEG_mutex; - -#if defined _WIN32 -static const HMODULE cv_GetCurrentModule() -{ - HMODULE h = 0; -#if _WIN32_WINNT >= 0x0501 - ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - reinterpret_cast(cv_GetCurrentModule), - &h); -#endif - return h; -} -#endif - -class icvInitFFMPEG -{ -public: - static void Init() - { - cv::AutoLock al(_icvInitFFMPEG_mutex); - static icvInitFFMPEG init; - } - -private: - #if defined _WIN32 - HMODULE icvFFOpenCV; - - ~icvInitFFMPEG() - { - if (icvFFOpenCV) - { - FreeLibrary(icvFFOpenCV); - icvFFOpenCV = 0; - } - } - #endif - - icvInitFFMPEG() - { -#if defined _WIN32 - const wchar_t* module_name_ = L"opencv_ffmpeg" - CVAUX_STRW(CV_MAJOR_VERSION) CVAUX_STRW(CV_MINOR_VERSION) CVAUX_STRW(CV_SUBMINOR_VERSION) - #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__) - L"_64" - #endif - L".dll"; - # ifdef WINRT - icvFFOpenCV = LoadPackagedLibrary( module_name_, 0 ); - # else - const std::wstring module_name(module_name_); - - const wchar_t* ffmpeg_env_path = _wgetenv(L"OPENCV_FFMPEG_DLL_DIR"); - std::wstring module_path = - ffmpeg_env_path - ? ((std::wstring(ffmpeg_env_path) + L"\\") + module_name) - : module_name; - - icvFFOpenCV = LoadLibraryW(module_path.c_str()); - if(!icvFFOpenCV && !ffmpeg_env_path) - { - HMODULE m = cv_GetCurrentModule(); - if (m) - { - wchar_t path[MAX_PATH]; - const size_t path_size = sizeof(path)/sizeof(*path); - size_t sz = GetModuleFileNameW(m, path, path_size); - /* Don't handle paths longer than MAX_PATH until that becomes a real issue */ - if (sz > 0 && sz < path_size) - { - wchar_t* s = wcsrchr(path, L'\\'); - if (s) - { - s[0] = 0; - module_path = (std::wstring(path) + L"\\") + module_name; - icvFFOpenCV = LoadLibraryW(module_path.c_str()); - } - } - } - } - # endif - - if( icvFFOpenCV ) - { - icvCreateFileCapture_FFMPEG_p = - (CvCreateFileCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateFileCapture_FFMPEG"); - icvReleaseCapture_FFMPEG_p = - (CvReleaseCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvReleaseCapture_FFMPEG"); - icvGrabFrame_FFMPEG_p = - (CvGrabFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvGrabFrame_FFMPEG"); - icvRetrieveFrame_FFMPEG_p = - (CvRetrieveFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvRetrieveFrame_FFMPEG"); - icvSetCaptureProperty_FFMPEG_p = - (CvSetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvSetCaptureProperty_FFMPEG"); - icvGetCaptureProperty_FFMPEG_p = - (CvGetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvGetCaptureProperty_FFMPEG"); - icvCreateVideoWriter_FFMPEG_p = - (CvCreateVideoWriter_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateVideoWriter_FFMPEG"); - icvReleaseVideoWriter_FFMPEG_p = - (CvReleaseVideoWriter_Plugin)GetProcAddress(icvFFOpenCV, "cvReleaseVideoWriter_FFMPEG"); - icvWriteFrame_FFMPEG_p = - (CvWriteFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvWriteFrame_FFMPEG"); -# endif // _WIN32 -#if 0 - if( icvCreateFileCapture_FFMPEG_p != 0 && - icvReleaseCapture_FFMPEG_p != 0 && - icvGrabFrame_FFMPEG_p != 0 && - icvRetrieveFrame_FFMPEG_p != 0 && - icvSetCaptureProperty_FFMPEG_p != 0 && - icvGetCaptureProperty_FFMPEG_p != 0 && - icvCreateVideoWriter_FFMPEG_p != 0 && - icvReleaseVideoWriter_FFMPEG_p != 0 && - icvWriteFrame_FFMPEG_p != 0 ) - { - printf("Successfully initialized ffmpeg plugin!\n"); - } - else - { - printf("Failed to load FFMPEG plugin: module handle=%p\n", icvFFOpenCV); - } -#endif - } - } -}; - - -}} // namespace -#endif // HAVE_FFMPEG_WRAPPER - - namespace cv { namespace { @@ -247,11 +102,7 @@ public: } virtual void close() { - if (ffmpegCapture -#if defined(HAVE_FFMPEG_WRAPPER) - && icvReleaseCapture_FFMPEG_p -#endif -) + if (ffmpegCapture) icvReleaseCapture_FFMPEG_p( &ffmpegCapture ); CV_Assert(ffmpegCapture == 0); ffmpegCapture = 0; @@ -268,11 +119,6 @@ protected: cv::Ptr cvCreateFileCapture_FFMPEG_proxy(const std::string &filename) { -#if defined(HAVE_FFMPEG_WRAPPER) - icvInitFFMPEG::Init(); - if (!icvCreateFileCapture_FFMPEG_p) - return cv::Ptr(); -#endif cv::Ptr capture = cv::makePtr(filename); if (capture && capture->isOpened()) return capture; @@ -308,11 +154,7 @@ public: virtual void close() { - if (ffmpegWriter -#if defined(HAVE_FFMPEG_WRAPPER) - && icvReleaseVideoWriter_FFMPEG_p -#endif - ) + if (ffmpegWriter) icvReleaseVideoWriter_FFMPEG_p( &ffmpegWriter ); CV_Assert(ffmpegWriter == 0); ffmpegWriter = 0; @@ -330,11 +172,6 @@ protected: cv::Ptr cvCreateVideoWriter_FFMPEG_proxy(const std::string& filename, int fourcc, double fps, const cv::Size &frameSize, bool isColor) { -#if defined(HAVE_FFMPEG_WRAPPER) - icvInitFFMPEG::Init(); - if (!icvCreateVideoWriter_FFMPEG_p) - return cv::Ptr(); -#endif cv::Ptr writer = cv::makePtr(filename, fourcc, fps, frameSize, isColor != 0); if (writer && writer->isOpened()) return writer; @@ -343,7 +180,7 @@ cv::Ptr cvCreateVideoWriter_FFMPEG_proxy(const std::string& fi } // namespace -#endif // defined(HAVE_FFMPEG) + //================================================================================================== diff --git a/modules/videoio/src/cap_ffmpeg_api.hpp b/modules/videoio/src/cap_ffmpeg_api.hpp deleted file mode 100644 index fe246ac68f..0000000000 --- a/modules/videoio/src/cap_ffmpeg_api.hpp +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef __OPENCV_FFMPEG_H__ -#define __OPENCV_FFMPEG_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -#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 -{ - CV_FFMPEG_CAP_PROP_POS_MSEC=0, - CV_FFMPEG_CAP_PROP_POS_FRAMES=1, - CV_FFMPEG_CAP_PROP_POS_AVI_RATIO=2, - CV_FFMPEG_CAP_PROP_FRAME_WIDTH=3, - CV_FFMPEG_CAP_PROP_FRAME_HEIGHT=4, - CV_FFMPEG_CAP_PROP_FPS=5, - CV_FFMPEG_CAP_PROP_FOURCC=6, - CV_FFMPEG_CAP_PROP_FRAME_COUNT=7, - CV_FFMPEG_CAP_PROP_SAR_NUM=40, - CV_FFMPEG_CAP_PROP_SAR_DEN=41 -}; - -typedef struct CvCapture_FFMPEG CvCapture_FFMPEG; -typedef struct CvVideoWriter_FFMPEG CvVideoWriter_FFMPEG; - -OPENCV_FFMPEG_API struct CvCapture_FFMPEG* cvCreateFileCapture_FFMPEG(const char* filename); -OPENCV_FFMPEG_API int cvSetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, - int prop, double value); -OPENCV_FFMPEG_API double cvGetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, int prop); -OPENCV_FFMPEG_API int cvGrabFrame_FFMPEG(struct CvCapture_FFMPEG* cap); -OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG(struct CvCapture_FFMPEG* capture, unsigned char** data, - int* step, int* width, int* height, int* cn); -OPENCV_FFMPEG_API void cvReleaseCapture_FFMPEG(struct CvCapture_FFMPEG** cap); - -OPENCV_FFMPEG_API struct CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG(const char* filename, - int fourcc, double fps, int width, int height, int isColor ); -OPENCV_FFMPEG_API int cvWriteFrame_FFMPEG(struct CvVideoWriter_FFMPEG* writer, const unsigned char* data, - int step, int width, int height, int cn, int origin); -OPENCV_FFMPEG_API void cvReleaseVideoWriter_FFMPEG(struct CvVideoWriter_FFMPEG** writer); - -typedef CvCapture_FFMPEG* (*CvCreateFileCapture_Plugin)( const char* filename ); -typedef CvCapture_FFMPEG* (*CvCreateCameraCapture_Plugin)( int index ); -typedef int (*CvGrabFrame_Plugin)( CvCapture_FFMPEG* capture_handle ); -typedef int (*CvRetrieveFrame_Plugin)( CvCapture_FFMPEG* capture_handle, unsigned char** data, int* step, - int* width, int* height, int* cn ); -typedef int (*CvSetCaptureProperty_Plugin)( CvCapture_FFMPEG* capture_handle, int prop_id, double value ); -typedef double (*CvGetCaptureProperty_Plugin)( CvCapture_FFMPEG* capture_handle, int prop_id ); -typedef void (*CvReleaseCapture_Plugin)( CvCapture_FFMPEG** capture_handle ); -typedef CvVideoWriter_FFMPEG* (*CvCreateVideoWriter_Plugin)( const char* filename, int fourcc, - double fps, int width, int height, int iscolor ); -typedef int (*CvWriteFrame_Plugin)( CvVideoWriter_FFMPEG* writer_handle, const unsigned char* data, int step, - int width, int height, int cn, int origin); -typedef void (*CvReleaseVideoWriter_Plugin)( CvVideoWriter_FFMPEG** writer ); - -/* - * For CUDA encoder - */ - -OPENCV_FFMPEG_API struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps); -OPENCV_FFMPEG_API void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream); -OPENCV_FFMPEG_API void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size, int keyFrame); - -typedef struct OutputMediaStream_FFMPEG* (*Create_OutputMediaStream_FFMPEG_Plugin)(const char* fileName, int width, int height, double fps); -typedef void (*Release_OutputMediaStream_FFMPEG_Plugin)(struct OutputMediaStream_FFMPEG* stream); -typedef void (*Write_OutputMediaStream_FFMPEG_Plugin)(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size, int keyFrame); - -/* - * For CUDA decoder - */ - -OPENCV_FFMPEG_API struct InputMediaStream_FFMPEG* create_InputMediaStream_FFMPEG(const char* fileName, int* codec, int* chroma_format, int* width, int* height); -OPENCV_FFMPEG_API void release_InputMediaStream_FFMPEG(struct InputMediaStream_FFMPEG* stream); -OPENCV_FFMPEG_API int read_InputMediaStream_FFMPEG(struct InputMediaStream_FFMPEG* stream, unsigned char** data, int* size, int* endOfFile); - -typedef struct InputMediaStream_FFMPEG* (*Create_InputMediaStream_FFMPEG_Plugin)(const char* fileName, int* codec, int* chroma_format, int* width, int* height); -typedef void (*Release_InputMediaStream_FFMPEG_Plugin)(struct InputMediaStream_FFMPEG* stream); -typedef int (*Read_InputMediaStream_FFMPEG_Plugin)(struct InputMediaStream_FFMPEG* stream, unsigned char** data, int* size, int* endOfFile); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp index ef2d8184bf..0239650470 100644 --- a/modules/videoio/src/cap_ffmpeg_impl.hpp +++ b/modules/videoio/src/cap_ffmpeg_impl.hpp @@ -40,7 +40,10 @@ // //M*/ -#include "cap_ffmpeg_api.hpp" +#include "cap_ffmpeg_legacy_api.hpp" + +using namespace cv; + #if !(defined(_WIN32) || defined(WINCE)) # include #endif @@ -631,6 +634,9 @@ void CvCapture_FFMPEG::close() #define AVSEEK_FLAG_ANY 1 #endif +#if defined(__OPENCV_BUILD) || defined(BUILD_PLUGIN) +typedef cv::Mutex ImplMutex; +#else class ImplMutex { public: @@ -751,16 +757,30 @@ void ImplMutex::lock() { impl->lock(); } void ImplMutex::unlock() { impl->unlock(); } bool ImplMutex::trylock() { return impl->trylock(); } +class AutoLock +{ +public: + AutoLock(ImplMutex& m) : mutex(&m) { mutex->lock(); } + ~AutoLock() { mutex->unlock(); } +protected: + ImplMutex* mutex; +private: + AutoLock(const AutoLock&); // disabled + AutoLock& operator = (const AutoLock&); // disabled +}; +#endif + +static ImplMutex _mutex; + static int LockCallBack(void **mutex, AVLockOp op) { ImplMutex* localMutex = reinterpret_cast(*mutex); switch (op) { case AV_LOCK_CREATE: - localMutex = reinterpret_cast(malloc(sizeof(ImplMutex))); + localMutex = new ImplMutex(); if (!localMutex) return 1; - localMutex->init(); *mutex = localMutex; if (!*mutex) return 1; @@ -775,8 +795,7 @@ static int LockCallBack(void **mutex, AVLockOp op) break; case AV_LOCK_DESTROY: - localMutex->destroy(); - free(localMutex); + delete localMutex; localMutex = NULL; *mutex = NULL; break; @@ -784,19 +803,6 @@ static int LockCallBack(void **mutex, AVLockOp op) return 0; } -static ImplMutex _mutex; - -class AutoLock -{ -public: - AutoLock(ImplMutex& m) : mutex(&m) { mutex->lock(); } - ~AutoLock() { mutex->unlock(); } -protected: - ImplMutex* mutex; -private: - AutoLock(const AutoLock&); // disabled - AutoLock& operator = (const AutoLock&); // disabled -}; static void ffmpeg_log_callback(void *ptr, int level, const char *fmt, va_list vargs) { @@ -1161,21 +1167,21 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const switch( property_id ) { - case CV_FFMPEG_CAP_PROP_POS_MSEC: + case CAP_PROP_POS_MSEC: return 1000.0*(double)frame_number/get_fps(); - case CV_FFMPEG_CAP_PROP_POS_FRAMES: + case CAP_PROP_POS_FRAMES: return (double)frame_number; - case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO: + case CAP_PROP_POS_AVI_RATIO: return r2d(ic->streams[video_stream]->time_base); - case CV_FFMPEG_CAP_PROP_FRAME_COUNT: + case CAP_PROP_FRAME_COUNT: return (double)get_total_frames(); - case CV_FFMPEG_CAP_PROP_FRAME_WIDTH: + case CAP_PROP_FRAME_WIDTH: return (double)frame.width; - case CV_FFMPEG_CAP_PROP_FRAME_HEIGHT: + case CAP_PROP_FRAME_HEIGHT: return (double)frame.height; - case CV_FFMPEG_CAP_PROP_FPS: + case CAP_PROP_FPS: return get_fps(); - case CV_FFMPEG_CAP_PROP_FOURCC: + case CAP_PROP_FOURCC: #if LIBAVFORMAT_BUILD > 4628 codec_id = video_st->codec->codec_id; codec_tag = (double) video_st->codec->codec_tag; @@ -1196,9 +1202,9 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const } return (double) CV_FOURCC(codec_fourcc[0], codec_fourcc[1], codec_fourcc[2], codec_fourcc[3]); - case CV_FFMPEG_CAP_PROP_SAR_NUM: + case CAP_PROP_SAR_NUM: return _opencv_ffmpeg_get_sample_aspect_ratio(ic->streams[video_stream]).num; - case CV_FFMPEG_CAP_PROP_SAR_DEN: + case CAP_PROP_SAR_DEN: return _opencv_ffmpeg_get_sample_aspect_ratio(ic->streams[video_stream]).den; default: break; @@ -1347,21 +1353,21 @@ bool CvCapture_FFMPEG::setProperty( int property_id, double value ) switch( property_id ) { - case CV_FFMPEG_CAP_PROP_POS_MSEC: - case CV_FFMPEG_CAP_PROP_POS_FRAMES: - case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO: + case CAP_PROP_POS_MSEC: + case CAP_PROP_POS_FRAMES: + case CAP_PROP_POS_AVI_RATIO: { switch( property_id ) { - case CV_FFMPEG_CAP_PROP_POS_FRAMES: + case CAP_PROP_POS_FRAMES: seek((int64_t)value); break; - case CV_FFMPEG_CAP_PROP_POS_MSEC: + case CAP_PROP_POS_MSEC: seek(value/1000.0); break; - case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO: + case CAP_PROP_POS_AVI_RATIO: seek((int64_t)(value*ic->duration)); break; } @@ -2433,577 +2439,3 @@ int cvWriteFrame_FFMPEG( CvVideoWriter_FFMPEG* writer, { return writer->writeFrame(data, step, width, height, cn, origin); } - - - -/* - * For CUDA encoder - */ - -struct OutputMediaStream_FFMPEG -{ - bool open(const char* fileName, int width, int height, double fps); - void close(); - - void write(unsigned char* data, int size, int keyFrame); - - // add a video output stream to the container - static AVStream* addVideoStream(AVFormatContext *oc, CV_CODEC_ID codec_id, int w, int h, int bitrate, double fps, AVPixelFormat pixel_format); - - AVOutputFormat* fmt_; - AVFormatContext* oc_; - AVStream* video_st_; -}; - -void OutputMediaStream_FFMPEG::close() -{ - // no more frame to compress. The codec has a latency of a few - // frames if using B frames, so we get the last frames by - // passing the same picture again - - // TODO -- do we need to account for latency here? - - if (oc_) - { - // write the trailer, if any - av_write_trailer(oc_); - - // free the streams - for (unsigned int i = 0; i < oc_->nb_streams; ++i) - { - av_freep(&oc_->streams[i]->codec); - av_freep(&oc_->streams[i]); - } - - if (!(fmt_->flags & AVFMT_NOFILE) && oc_->pb) - { - // close the output file - - #if LIBAVCODEC_VERSION_INT < ((52<<16)+(123<<8)+0) - #if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0) - url_fclose(oc_->pb); - #else - url_fclose(&oc_->pb); - #endif - #else - avio_close(oc_->pb); - #endif - } - - // free the stream - av_free(oc_); - } -} - -AVStream* OutputMediaStream_FFMPEG::addVideoStream(AVFormatContext *oc, CV_CODEC_ID codec_id, int w, int h, int bitrate, double fps, AVPixelFormat pixel_format) -{ - AVCodec* codec = avcodec_find_encoder(codec_id); - if (!codec) - { - fprintf(stderr, "Could not find encoder for codec id %d\n", codec_id); - return NULL; - } - - #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 10, 0) - AVStream* st = avformat_new_stream(oc, 0); - #else - AVStream* st = av_new_stream(oc, 0); - #endif - if (!st) - return 0; - - #if LIBAVFORMAT_BUILD > 4628 - AVCodecContext* c = st->codec; - #else - AVCodecContext* c = &(st->codec); - #endif - - c->codec_id = codec_id; - c->codec_type = AVMEDIA_TYPE_VIDEO; - - // put sample parameters - c->bit_rate = bitrate; - - // took advice from - // http://ffmpeg-users.933282.n4.nabble.com/warning-clipping-1-dct-coefficients-to-127-127-td934297.html - c->qmin = 3; - - // resolution must be a multiple of two - c->width = w; - c->height = h; - - // time base: this is the fundamental unit of time (in seconds) in terms - // of which frame timestamps are represented. for fixed-fps content, - // timebase should be 1/framerate and timestamp increments should be - // identically 1 - - int frame_rate = static_cast(fps+0.5); - int frame_rate_base = 1; - while (fabs((static_cast(frame_rate)/frame_rate_base) - fps) > 0.001) - { - frame_rate_base *= 10; - frame_rate = static_cast(fps*frame_rate_base + 0.5); - } - c->time_base.den = frame_rate; - c->time_base.num = frame_rate_base; - - #if LIBAVFORMAT_BUILD > 4752 - // adjust time base for supported framerates - if (codec && codec->supported_framerates) - { - AVRational req = {frame_rate, frame_rate_base}; - const AVRational* best = NULL; - AVRational best_error = {INT_MAX, 1}; - - for (const AVRational* p = codec->supported_framerates; p->den!=0; ++p) - { - AVRational error = av_sub_q(req, *p); - - if (error.num < 0) - error.num *= -1; - - if (av_cmp_q(error, best_error) < 0) - { - best_error= error; - best= p; - } - } - - if (best == NULL) - return NULL; - c->time_base.den= best->num; - c->time_base.num= best->den; - } - #endif - - c->gop_size = 12; // emit one intra frame every twelve frames at most - c->pix_fmt = pixel_format; - - if (c->codec_id == CV_CODEC(CODEC_ID_MPEG2VIDEO)) - c->max_b_frames = 2; - - if (c->codec_id == CV_CODEC(CODEC_ID_MPEG1VIDEO) || c->codec_id == CV_CODEC(CODEC_ID_MSMPEG4V3)) - { - // needed to avoid using macroblocks in which some coeffs overflow - // this doesn't happen with normal video, it just happens here as the - // motion of the chroma plane doesn't match the luma plane - - // avoid FFMPEG warning 'clipping 1 dct coefficients...' - - c->mb_decision = 2; - } - - #if LIBAVCODEC_VERSION_INT > 0x000409 - // some formats want stream headers to be separate - if (oc->oformat->flags & AVFMT_GLOBALHEADER) - { - #if LIBAVCODEC_BUILD > CALC_FFMPEG_VERSION(56, 35, 0) - c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; - #else - c->flags |= CODEC_FLAG_GLOBAL_HEADER; - #endif - } - #endif - - return st; -} - -bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height, double fps) -{ - fmt_ = 0; - oc_ = 0; - video_st_ = 0; - - // auto detect the output format from the name and fourcc code - #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) - fmt_ = av_guess_format(NULL, fileName, NULL); - #else - fmt_ = guess_format(NULL, fileName, NULL); - #endif - if (!fmt_) - return false; - - CV_CODEC_ID codec_id = CV_CODEC(CODEC_ID_H264); - - // alloc memory for context - #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) - oc_ = avformat_alloc_context(); - #else - oc_ = av_alloc_format_context(); - #endif - if (!oc_) - return false; - - // set some options - oc_->oformat = fmt_; - snprintf(oc_->filename, sizeof(oc_->filename), "%s", fileName); - - oc_->max_delay = (int)(0.7 * AV_TIME_BASE); // This reduces buffer underrun warnings with MPEG - - // set a few optimal pixel formats for lossless codecs of interest.. - AVPixelFormat codec_pix_fmt = AV_PIX_FMT_YUV420P; - int bitrate_scale = 64; - - // TODO -- safe to ignore output audio stream? - video_st_ = addVideoStream(oc_, codec_id, width, height, width * height * bitrate_scale, fps, codec_pix_fmt); - if (!video_st_) - return false; - - // set the output parameters (must be done even if no parameters) - #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) - if (av_set_parameters(oc_, NULL) < 0) - return false; - #endif - - // now that all the parameters are set, we can open the audio and - // video codecs and allocate the necessary encode buffers - - #if LIBAVFORMAT_BUILD > 4628 - AVCodecContext* c = (video_st_->codec); - #else - AVCodecContext* c = &(video_st_->codec); - #endif - - c->codec_tag = MKTAG('H', '2', '6', '4'); - c->bit_rate_tolerance = c->bit_rate; - - // open the output file, if needed - if (!(fmt_->flags & AVFMT_NOFILE)) - { - #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) - int err = url_fopen(&oc_->pb, fileName, URL_WRONLY); - #else - int err = avio_open(&oc_->pb, fileName, AVIO_FLAG_WRITE); - #endif - - if (err != 0) - return false; - } - - // write the stream header, if any - int header_err = - #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) - av_write_header(oc_); - #else - avformat_write_header(oc_, NULL); - #endif - if (header_err != 0) - return false; - - return true; -} - -void OutputMediaStream_FFMPEG::write(unsigned char* data, int size, int keyFrame) -{ - // if zero size, it means the image was buffered - if (size > 0) - { - AVPacket pkt; - av_init_packet(&pkt); - - if (keyFrame) - pkt.flags |= PKT_FLAG_KEY; - - pkt.stream_index = video_st_->index; - pkt.data = data; - pkt.size = size; - - // write the compressed frame in the media file - av_write_frame(oc_, &pkt); - } -} - -struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps) -{ - OutputMediaStream_FFMPEG* stream = (OutputMediaStream_FFMPEG*) malloc(sizeof(OutputMediaStream_FFMPEG)); - if (!stream) - return 0; - - if (stream->open(fileName, width, height, fps)) - return stream; - - stream->close(); - free(stream); - - return 0; -} - -void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream) -{ - stream->close(); - free(stream); -} - -void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size, int keyFrame) -{ - stream->write(data, size, keyFrame); -} - -/* - * For CUDA decoder - */ - -enum -{ - VideoCodec_MPEG1 = 0, - VideoCodec_MPEG2, - VideoCodec_MPEG4, - VideoCodec_VC1, - VideoCodec_H264, - VideoCodec_JPEG, - VideoCodec_H264_SVC, - VideoCodec_H264_MVC, - - // Uncompressed YUV - VideoCodec_YUV420 = (('I'<<24)|('Y'<<16)|('U'<<8)|('V')), // Y,U,V (4:2:0) - VideoCodec_YV12 = (('Y'<<24)|('V'<<16)|('1'<<8)|('2')), // Y,V,U (4:2:0) - VideoCodec_NV12 = (('N'<<24)|('V'<<16)|('1'<<8)|('2')), // Y,UV (4:2:0) - VideoCodec_YUYV = (('Y'<<24)|('U'<<16)|('Y'<<8)|('V')), // YUYV/YUY2 (4:2:2) - VideoCodec_UYVY = (('U'<<24)|('Y'<<16)|('V'<<8)|('Y')) // UYVY (4:2:2) -}; - -enum -{ - VideoChromaFormat_Monochrome = 0, - VideoChromaFormat_YUV420, - VideoChromaFormat_YUV422, - VideoChromaFormat_YUV444 -}; - -struct InputMediaStream_FFMPEG -{ -public: - bool open(const char* fileName, int* codec, int* chroma_format, int* width, int* height); - void close(); - - bool read(unsigned char** data, int* size, int* endOfFile); - -private: - InputMediaStream_FFMPEG(const InputMediaStream_FFMPEG&); - InputMediaStream_FFMPEG& operator =(const InputMediaStream_FFMPEG&); - - AVFormatContext* ctx_; - int video_stream_id_; - AVPacket pkt_; - -#if USE_AV_INTERRUPT_CALLBACK - AVInterruptCallbackMetadata interrupt_metadata; -#endif -}; - -bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma_format, int* width, int* height) -{ - int err; - - ctx_ = 0; - video_stream_id_ = -1; - memset(&pkt_, 0, sizeof(AVPacket)); - -#if USE_AV_INTERRUPT_CALLBACK - /* interrupt callback */ - interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_OPEN_TIMEOUT_MS; - get_monotonic_time(&interrupt_metadata.value); - - ctx_ = avformat_alloc_context(); - ctx_->interrupt_callback.callback = _opencv_ffmpeg_interrupt_callback; - ctx_->interrupt_callback.opaque = &interrupt_metadata; -#endif - - #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0) - avformat_network_init(); - #endif - - #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 6, 0) - err = avformat_open_input(&ctx_, fileName, 0, 0); - #else - err = av_open_input_file(&ctx_, fileName, 0, 0, 0); - #endif - if (err < 0) - return false; - - #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 6, 0) - err = avformat_find_stream_info(ctx_, 0); - #else - err = av_find_stream_info(ctx_); - #endif - if (err < 0) - return false; - - for (unsigned int i = 0; i < ctx_->nb_streams; ++i) - { - #if LIBAVFORMAT_BUILD > 4628 - AVCodecContext *enc = ctx_->streams[i]->codec; - #else - AVCodecContext *enc = &ctx_->streams[i]->codec; - #endif - - if (enc->codec_type == AVMEDIA_TYPE_VIDEO) - { - video_stream_id_ = static_cast(i); - - switch (enc->codec_id) - { - case CV_CODEC(CODEC_ID_MPEG1VIDEO): - *codec = ::VideoCodec_MPEG1; - break; - - case CV_CODEC(CODEC_ID_MPEG2VIDEO): - *codec = ::VideoCodec_MPEG2; - break; - - case CV_CODEC(CODEC_ID_MPEG4): - *codec = ::VideoCodec_MPEG4; - break; - - case CV_CODEC(CODEC_ID_VC1): - *codec = ::VideoCodec_VC1; - break; - - case CV_CODEC(CODEC_ID_H264): - *codec = ::VideoCodec_H264; - break; - - default: - return false; - }; - - switch (enc->pix_fmt) - { - case AV_PIX_FMT_YUV420P: - *chroma_format = ::VideoChromaFormat_YUV420; - break; - - case AV_PIX_FMT_YUV422P: - *chroma_format = ::VideoChromaFormat_YUV422; - break; - - case AV_PIX_FMT_YUV444P: - *chroma_format = ::VideoChromaFormat_YUV444; - break; - - default: - return false; - } - - *width = enc->coded_width; - *height = enc->coded_height; - - break; - } - } - - if (video_stream_id_ < 0) - return false; - - av_init_packet(&pkt_); - -#if USE_AV_INTERRUPT_CALLBACK - // deactivate interrupt callback - interrupt_metadata.timeout_after_ms = 0; -#endif - - return true; -} - -void InputMediaStream_FFMPEG::close() -{ - if (ctx_) - { - #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 24, 2) - avformat_close_input(&ctx_); - #else - av_close_input_file(ctx_); - #endif - } - - // free last packet if exist - if (pkt_.data) - _opencv_ffmpeg_av_packet_unref(&pkt_); -} - -bool InputMediaStream_FFMPEG::read(unsigned char** data, int* size, int* endOfFile) -{ - bool result = false; - -#if USE_AV_INTERRUPT_CALLBACK - // activate interrupt callback - get_monotonic_time(&interrupt_metadata.value); - interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_READ_TIMEOUT_MS; -#endif - - // free last packet if exist - if (pkt_.data) - _opencv_ffmpeg_av_packet_unref(&pkt_); - - // get the next frame - for (;;) - { -#if USE_AV_INTERRUPT_CALLBACK - if(interrupt_metadata.timeout) - { - break; - } -#endif - - int ret = av_read_frame(ctx_, &pkt_); - - if (ret == AVERROR(EAGAIN)) - continue; - - if (ret < 0) - { - if (ret == (int)AVERROR_EOF) - *endOfFile = true; - break; - } - - if (pkt_.stream_index != video_stream_id_) - { - _opencv_ffmpeg_av_packet_unref(&pkt_); - continue; - } - - result = true; - break; - } - -#if USE_AV_INTERRUPT_CALLBACK - // deactivate interrupt callback - interrupt_metadata.timeout_after_ms = 0; -#endif - - if (result) - { - *data = pkt_.data; - *size = pkt_.size; - *endOfFile = false; - } - - return result; -} - -InputMediaStream_FFMPEG* create_InputMediaStream_FFMPEG(const char* fileName, int* codec, int* chroma_format, int* width, int* height) -{ - InputMediaStream_FFMPEG* stream = (InputMediaStream_FFMPEG*) malloc(sizeof(InputMediaStream_FFMPEG)); - if (!stream) - return 0; - - if (stream && stream->open(fileName, codec, chroma_format, width, height)) - return stream; - - stream->close(); - free(stream); - - return 0; -} - -void release_InputMediaStream_FFMPEG(InputMediaStream_FFMPEG* stream) -{ - stream->close(); - free(stream); -} - -int read_InputMediaStream_FFMPEG(InputMediaStream_FFMPEG* stream, unsigned char** data, int* size, int* endOfFile) -{ - return stream->read(data, size, endOfFile); -} diff --git a/modules/videoio/src/cap_ffmpeg_legacy_api.hpp b/modules/videoio/src/cap_ffmpeg_legacy_api.hpp new file mode 100644 index 0000000000..d918765e2e --- /dev/null +++ b/modules/videoio/src/cap_ffmpeg_legacy_api.hpp @@ -0,0 +1,46 @@ +// 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_FFMPEG_LEGACY_API_H__ +#define __OPENCV_FFMPEG_LEGACY_API_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef OPENCV_FFMPEG_API +#if defined(__OPENCV_BUILD) +# 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 + +typedef struct CvCapture_FFMPEG CvCapture_FFMPEG; +typedef struct CvVideoWriter_FFMPEG CvVideoWriter_FFMPEG; + +OPENCV_FFMPEG_API struct CvCapture_FFMPEG* cvCreateFileCapture_FFMPEG(const char* filename); +OPENCV_FFMPEG_API int cvSetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, + int prop, double value); +OPENCV_FFMPEG_API double cvGetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, int prop); +OPENCV_FFMPEG_API int cvGrabFrame_FFMPEG(struct CvCapture_FFMPEG* cap); +OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG(struct CvCapture_FFMPEG* capture, unsigned char** data, + int* step, int* width, int* height, int* cn); +OPENCV_FFMPEG_API void cvReleaseCapture_FFMPEG(struct CvCapture_FFMPEG** cap); + +OPENCV_FFMPEG_API struct CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG(const char* filename, + int fourcc, double fps, int width, int height, int isColor ); +OPENCV_FFMPEG_API int cvWriteFrame_FFMPEG(struct CvVideoWriter_FFMPEG* writer, const unsigned char* data, + int step, int width, int height, int cn, int origin); +OPENCV_FFMPEG_API void cvReleaseVideoWriter_FFMPEG(struct CvVideoWriter_FFMPEG** writer); + +#ifdef __cplusplus +} +#endif + +#endif // __OPENCV_FFMPEG_LEGACY_API_H__ diff --git a/modules/videoio/src/precomp.hpp b/modules/videoio/src/precomp.hpp index f4eb697d92..f044c6348a 100644 --- a/modules/videoio/src/precomp.hpp +++ b/modules/videoio/src/precomp.hpp @@ -46,7 +46,9 @@ #include "opencv2/videoio/legacy/constants_c.h" #include "opencv2/core/utility.hpp" +#ifdef __OPENCV_BUILD #include "opencv2/core/private.hpp" +#endif #include #include diff --git a/modules/videoio/src/videoio_registry.cpp b/modules/videoio/src/videoio_registry.cpp index c35f2b2f78..a98b907a46 100644 --- a/modules/videoio/src/videoio_registry.cpp +++ b/modules/videoio/src/videoio_registry.cpp @@ -58,7 +58,7 @@ static const struct VideoBackendInfo builtin_backends[] = { #ifdef HAVE_FFMPEG DECLARE_STATIC_BACKEND(CAP_FFMPEG, "FFMPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER, cvCreateFileCapture_FFMPEG_proxy, 0, cvCreateVideoWriter_FFMPEG_proxy), -#elif defined(ENABLE_PLUGINS) +#elif defined(ENABLE_PLUGINS) || defined(HAVE_FFMPEG_WRAPPER) DECLARE_DYNAMIC_BACKEND(CAP_FFMPEG, "FFMPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER), #endif