mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
videoio: plugins support on Win32
This commit is contained in:
parent
66d7956e67
commit
7b099e0fe2
@ -52,7 +52,11 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#if defined(__GNUC__) || defined(__clang__) // at least GCC 3.1+, clang 3.5+
|
#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
|
#else
|
||||||
# define CV_FORMAT_PRINTF(A, B)
|
# define CV_FORMAT_PRINTF(A, B)
|
||||||
#endif
|
#endif
|
||||||
|
@ -872,9 +872,17 @@ Passed subdirectories are used in LIFO order.
|
|||||||
*/
|
*/
|
||||||
CV_EXPORTS void addDataSearchSubDirectory(const cv::String& subdir);
|
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
|
||||||
|
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ CV_EXPORTS cv::String join(const cv::String& base, const cv::String& path);
|
|||||||
|
|
||||||
/** Get parent directory */
|
/** Get parent directory */
|
||||||
CV_EXPORTS cv::String getParent(const cv::String &path);
|
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.
|
* Generate a list of all files that match the globbing pattern.
|
||||||
|
@ -144,11 +144,38 @@ static cv::String getModuleLocation(const void* addr)
|
|||||||
return cv::String();
|
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<LPCTSTR>(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,
|
cv::String findDataFile(const cv::String& relative_path,
|
||||||
const char* configuration_parameter,
|
const char* configuration_parameter,
|
||||||
const std::vector<String>* search_paths,
|
const std::vector<String>* search_paths,
|
||||||
@ -292,8 +319,15 @@ cv::String findDataFile(const cv::String& relative_path,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::String module_path = getBinLocation();
|
cv::String module_path;
|
||||||
CV_LOG_DEBUG(NULL, "Detected module path: '" << 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 &&
|
if (!has_tested_build_directory &&
|
||||||
(isSubDirectory(build_dir, module_path) || isSubDirectory(utils::fs::canonical(build_dir), utils::fs::canonical(module_path)))
|
(isSubDirectory(build_dir, module_path) || isSubDirectory(utils::fs::canonical(build_dir), utils::fs::canonical(module_path)))
|
||||||
|
@ -91,6 +91,14 @@ CV_EXPORTS cv::String getParent(const cv::String &path)
|
|||||||
return std::string(path, 0, loc);
|
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
|
#if OPENCV_HAVE_FILESYSTEM_SUPPORT
|
||||||
|
|
||||||
cv::String canonical(const cv::String& path)
|
cv::String canonical(const cv::String& path)
|
||||||
|
@ -131,7 +131,9 @@ if(TARGET ocv.3rdparty.ximea)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(TARGET ocv.3rdparty.ffmpeg)
|
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")
|
ocv_create_builtin_videoio_plugin("opencv_videoio_ffmpeg" ocv.3rdparty.ffmpeg "cap_ffmpeg.cpp")
|
||||||
else()
|
else()
|
||||||
list(APPEND videoio_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/cap_ffmpeg_impl.hpp)
|
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
|
# copy FFmpeg dll to the output folder
|
||||||
if(WIN32 AND HAVE_FFMPEG_WRAPPER)
|
if(WIN32 AND HAVE_FFMPEG_WRAPPER)
|
||||||
if(MSVC64 OR MINGW64)
|
if(MSVC64 OR MINGW64)
|
||||||
set(FFMPEG_SUFFIX _64)
|
set(FFMPEG_SUFFIX "_64")
|
||||||
endif()
|
endif()
|
||||||
set(ffmpeg_dir "${OpenCV_BINARY_DIR}/3rdparty/ffmpeg")
|
set(ffmpeg_dir "${OpenCV_BINARY_DIR}/3rdparty/ffmpeg")
|
||||||
set(ffmpeg_bare_name "opencv_ffmpeg${FFMPEG_SUFFIX}.dll")
|
set(ffmpeg_bare_name "opencv_ffmpeg${FFMPEG_SUFFIX}.dll")
|
||||||
|
@ -54,12 +54,10 @@ endif()
|
|||||||
|
|
||||||
#==================================
|
#==================================
|
||||||
|
|
||||||
if(HAVE_FFMPEG)
|
if(HAVE_FFMPEG_WRAPPER)
|
||||||
set(defs "HAVE_FFMPEG")
|
ocv_add_external_target(ffmpeg "" "" "HAVE_FFMPEG_WRAPPER")
|
||||||
if(HAVE_FFMPEG_WRAPPER)
|
elseif(HAVE_FFMPEG)
|
||||||
list(APPEND defs "HAVE_FFMPEG_WRAPPER")
|
ocv_add_external_target(ffmpeg "${FFMPEG_INCLUDE_DIRS}" "${FFMPEG_LIBRARIES}" "HAVE_FFMPEG")
|
||||||
endif()
|
|
||||||
ocv_add_external_target(ffmpeg "${FFMPEG_INCLUDE_DIRS}" "${FFMPEG_LIBRARIES}" "${defs}")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(HAVE_FFMPEG ${HAVE_FFMPEG} PARENT_SCOPE)
|
set(HAVE_FFMPEG ${HAVE_FFMPEG} PARENT_SCOPE)
|
||||||
|
@ -25,9 +25,22 @@ function(ocv_create_builtin_videoio_plugin name target)
|
|||||||
ocv_target_include_directories(${name} PRIVATE "${OPENCV_MODULE_${mod}_LOCATION}/include")
|
ocv_target_include_directories(${name} PRIVATE "${OPENCV_MODULE_${mod}_LOCATION}/include")
|
||||||
endforeach()
|
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
|
set_target_properties(${name} PROPERTIES
|
||||||
CXX_STANDARD 11
|
CXX_STANDARD 11
|
||||||
CXX_VISIBILITY_PRESET hidden
|
CXX_VISIBILITY_PRESET hidden
|
||||||
|
OUTPUT_NAME "${name}${OPENCV_PLUGIN_VERSION}${OPENCV_PLUGIN_ARCH}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
@ -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!")
|
message(FATAL_ERROR "${target_desc} was not found!")
|
||||||
endif()
|
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(videoio_ROOT "${modules_ROOT}/videoio")
|
||||||
set(core_ROOT "${modules_ROOT}/core")
|
set(core_ROOT "${modules_ROOT}/core")
|
||||||
set(imgproc_ROOT "${modules_ROOT}/imgproc")
|
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)
|
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})
|
target_link_libraries(${OPENCV_PLUGIN_NAME} PRIVATE ${target})
|
||||||
set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES
|
set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES
|
||||||
CXX_STANDARD 11
|
CXX_STANDARD 11
|
||||||
CXX_VISIBILITY_PRESET hidden
|
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
|
# Hack for Windows
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
find_package(OpenCV REQUIRED core imgproc videoio)
|
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()
|
endif()
|
||||||
|
|
||||||
if(OPENCV_PLUGIN_DESTINATION)
|
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}")
|
message(STATUS "Output destination: ${OPENCV_PLUGIN_DESTINATION}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS ${OPENCV_PLUGIN_NAME} LIBRARY DESTINATION . COMPONENT plugins)
|
||||||
|
|
||||||
message(STATUS "Library name: ${OPENCV_PLUGIN_NAME}")
|
message(STATUS "Library name: ${OPENCV_PLUGIN_NAME}")
|
||||||
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
@ -29,10 +29,43 @@ namespace cv { namespace impl {
|
|||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
typedef HMODULE LibHandle_t;
|
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 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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static Mutex& getInitializationMutex()
|
static Mutex& getInitializationMutex()
|
||||||
{
|
{
|
||||||
static Mutex initializationMutex;
|
static Mutex initializationMutex;
|
||||||
@ -50,12 +83,16 @@ void* getSymbol_(LibHandle_t h, const char* symbolName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
LibHandle_t libraryLoad_(const char* filename)
|
LibHandle_t libraryLoad_(const FileSystemPath_t& filename)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#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__)
|
#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
|
||||||
return dlopen(filename, RTLD_LAZY);
|
return dlopen(filename.c_str(), RTLD_LAZY);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +110,7 @@ static inline
|
|||||||
std::string libraryPrefix()
|
std::string libraryPrefix()
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
return string();
|
return "";
|
||||||
#else
|
#else
|
||||||
return "lib";
|
return "lib";
|
||||||
#endif
|
#endif
|
||||||
@ -82,9 +119,13 @@ static inline
|
|||||||
std::string librarySuffix()
|
std::string librarySuffix()
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
return ".dll";
|
const char* suffix = ""
|
||||||
#elif defined(__APPLE__)
|
CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION)
|
||||||
return ".dylib";
|
#if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
|
||||||
|
"_64"
|
||||||
|
#endif
|
||||||
|
".dll";
|
||||||
|
return suffix;
|
||||||
#else
|
#else
|
||||||
return ".so";
|
return ".so";
|
||||||
#endif
|
#endif
|
||||||
@ -96,10 +137,10 @@ class DynamicLib
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
LibHandle_t handle;
|
LibHandle_t handle;
|
||||||
const std::string fname;
|
const FileSystemPath_t fname;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DynamicLib(const std::string &filename)
|
DynamicLib(const FileSystemPath_t& filename)
|
||||||
: handle(0), fname(filename)
|
: handle(0), fname(filename)
|
||||||
{
|
{
|
||||||
libraryLoad(filename);
|
libraryLoad(filename);
|
||||||
@ -120,21 +161,21 @@ public:
|
|||||||
}
|
}
|
||||||
void * res = getSymbol_(handle, symbolName);
|
void * res = getSymbol_(handle, symbolName);
|
||||||
if (!res)
|
if (!res)
|
||||||
CV_LOG_ERROR(NULL, "No symbol '" << symbolName << "' in " << fname);
|
CV_LOG_ERROR(NULL, "No symbol '" << symbolName << "' in " << toPrintablePath(fname));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
const std::string& getName() const { return fname; }
|
const std::string getName() const { return toPrintablePath(fname); }
|
||||||
private:
|
private:
|
||||||
void libraryLoad(const std::string &filename)
|
void libraryLoad(const FileSystemPath_t& filename)
|
||||||
{
|
{
|
||||||
handle = libraryLoad_(filename.c_str());
|
handle = libraryLoad_(filename);
|
||||||
CV_LOG_INFO(NULL, "load " << filename << " => " << (handle ? "OK" : "FAILED"));
|
CV_LOG_INFO(NULL, "load " << toPrintablePath(filename) << " => " << (handle ? "OK" : "FAILED"));
|
||||||
}
|
}
|
||||||
void libraryRelease()
|
void libraryRelease()
|
||||||
{
|
{
|
||||||
CV_LOG_INFO(NULL, "unload "<< fname);
|
|
||||||
if (handle)
|
if (handle)
|
||||||
{
|
{
|
||||||
|
CV_LOG_INFO(NULL, "unload "<< toPrintablePath(fname));
|
||||||
libraryRelease_(handle);
|
libraryRelease_(handle);
|
||||||
handle = 0;
|
handle = 0;
|
||||||
}
|
}
|
||||||
@ -230,39 +271,79 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static
|
static
|
||||||
std::vector<string> getPluginCandidates(const std::string& baseName)
|
std::vector<FileSystemPath_t> getPluginCandidates(const std::string& baseName)
|
||||||
{
|
{
|
||||||
using namespace cv::utils;
|
using namespace cv::utils;
|
||||||
using namespace cv::utils::fs;
|
using namespace cv::utils::fs;
|
||||||
#ifndef CV_VIDEOIO_PLUGIN_SUBDIRECTORY
|
|
||||||
#define CV_VIDEOIO_PLUGIN_SUBDIRECTORY_STR ""
|
|
||||||
#else
|
|
||||||
#define CV_VIDEOIO_PLUGIN_SUBDIRECTORY_STR CVAUX_STR(CV_VIDEOIO_PLUGIN_SUBDIRECTORY)
|
|
||||||
#endif
|
|
||||||
const vector<string> default_paths = { utils::fs::join(getParent(getBinLocation()), CV_VIDEOIO_PLUGIN_SUBDIRECTORY_STR) };
|
|
||||||
const vector<string> paths = getConfigurationParameterPaths("OPENCV_VIDEOIO_PLUGIN_PATH", default_paths);
|
|
||||||
const string baseName_l = toLowerCase(baseName);
|
const string baseName_l = toLowerCase(baseName);
|
||||||
const string baseName_u = toUpperCase(baseName);
|
const string baseName_u = toUpperCase(baseName);
|
||||||
|
const FileSystemPath_t baseName_l_fs = toFileSystemPath(baseName_l);
|
||||||
|
vector<FileSystemPath_t> paths;
|
||||||
|
const vector<string> paths_ = getConfigurationParameterPaths("OPENCV_VIDEOIO_PLUGIN_PATH", vector<string>());
|
||||||
|
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 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());
|
const string plugin_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<FileSystemPath_t> results;
|
||||||
vector<string> results;
|
#ifdef _WIN32
|
||||||
for(const string & path : paths)
|
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())
|
if (path.empty())
|
||||||
continue;
|
continue;
|
||||||
vector<string> candidates;
|
vector<string> 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());
|
CV_LOG_INFO(NULL, " - " << path << ": " << candidates.size());
|
||||||
copy(candidates.begin(), candidates.end(), back_inserter(results));
|
copy(candidates.begin(), candidates.end(), back_inserter(results));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
CV_LOG_INFO(NULL, "Found " << results.size() << " plugin(s) for " << baseName);
|
CV_LOG_INFO(NULL, "Found " << results.size() << " plugin(s) for " << baseName);
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginBackendFactory::loadPlugin()
|
void PluginBackendFactory::loadPlugin()
|
||||||
{
|
{
|
||||||
for(const std::string & plugin : getPluginCandidates(baseName_))
|
for (const FileSystemPath_t& plugin : getPluginCandidates(baseName_))
|
||||||
{
|
{
|
||||||
Ptr<DynamicLib> lib = makePtr<DynamicLib>(plugin);
|
Ptr<DynamicLib> lib = makePtr<DynamicLib>(plugin);
|
||||||
if (!lib->isLoaded())
|
if (!lib->isLoaded())
|
||||||
@ -287,7 +368,7 @@ void PluginBackendFactory::loadPlugin()
|
|||||||
}
|
}
|
||||||
catch (...)
|
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,11 +41,12 @@
|
|||||||
|
|
||||||
#include "precomp.hpp"
|
#include "precomp.hpp"
|
||||||
|
|
||||||
#if defined(HAVE_FFMPEG)
|
#if !defined(HAVE_FFMPEG)
|
||||||
|
#error "Build configuration error"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#if !defined(HAVE_FFMPEG_WRAPPER)
|
|
||||||
#include "cap_ffmpeg_impl.hpp"
|
#include "cap_ffmpeg_impl.hpp"
|
||||||
|
|
||||||
#define icvCreateFileCapture_FFMPEG_p cvCreateFileCapture_FFMPEG
|
#define icvCreateFileCapture_FFMPEG_p cvCreateFileCapture_FFMPEG
|
||||||
@ -58,152 +59,6 @@
|
|||||||
#define icvReleaseVideoWriter_FFMPEG_p cvReleaseVideoWriter_FFMPEG
|
#define icvReleaseVideoWriter_FFMPEG_p cvReleaseVideoWriter_FFMPEG
|
||||||
#define icvWriteFrame_FFMPEG_p cvWriteFrame_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<LPCTSTR>(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 cv {
|
||||||
namespace {
|
namespace {
|
||||||
@ -247,11 +102,7 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void close()
|
virtual void close()
|
||||||
{
|
{
|
||||||
if (ffmpegCapture
|
if (ffmpegCapture)
|
||||||
#if defined(HAVE_FFMPEG_WRAPPER)
|
|
||||||
&& icvReleaseCapture_FFMPEG_p
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
icvReleaseCapture_FFMPEG_p( &ffmpegCapture );
|
icvReleaseCapture_FFMPEG_p( &ffmpegCapture );
|
||||||
CV_Assert(ffmpegCapture == 0);
|
CV_Assert(ffmpegCapture == 0);
|
||||||
ffmpegCapture = 0;
|
ffmpegCapture = 0;
|
||||||
@ -268,11 +119,6 @@ protected:
|
|||||||
|
|
||||||
cv::Ptr<cv::IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const std::string &filename)
|
cv::Ptr<cv::IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const std::string &filename)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_FFMPEG_WRAPPER)
|
|
||||||
icvInitFFMPEG::Init();
|
|
||||||
if (!icvCreateFileCapture_FFMPEG_p)
|
|
||||||
return cv::Ptr<cv::IVideoCapture>();
|
|
||||||
#endif
|
|
||||||
cv::Ptr<CvCapture_FFMPEG_proxy> capture = cv::makePtr<CvCapture_FFMPEG_proxy>(filename);
|
cv::Ptr<CvCapture_FFMPEG_proxy> capture = cv::makePtr<CvCapture_FFMPEG_proxy>(filename);
|
||||||
if (capture && capture->isOpened())
|
if (capture && capture->isOpened())
|
||||||
return capture;
|
return capture;
|
||||||
@ -308,11 +154,7 @@ public:
|
|||||||
|
|
||||||
virtual void close()
|
virtual void close()
|
||||||
{
|
{
|
||||||
if (ffmpegWriter
|
if (ffmpegWriter)
|
||||||
#if defined(HAVE_FFMPEG_WRAPPER)
|
|
||||||
&& icvReleaseVideoWriter_FFMPEG_p
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
icvReleaseVideoWriter_FFMPEG_p( &ffmpegWriter );
|
icvReleaseVideoWriter_FFMPEG_p( &ffmpegWriter );
|
||||||
CV_Assert(ffmpegWriter == 0);
|
CV_Assert(ffmpegWriter == 0);
|
||||||
ffmpegWriter = 0;
|
ffmpegWriter = 0;
|
||||||
@ -330,11 +172,6 @@ protected:
|
|||||||
|
|
||||||
cv::Ptr<cv::IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const std::string& filename, int fourcc, double fps, const cv::Size &frameSize, bool isColor)
|
cv::Ptr<cv::IVideoWriter> 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<cv::IVideoWriter>();
|
|
||||||
#endif
|
|
||||||
cv::Ptr<CvVideoWriter_FFMPEG_proxy> writer = cv::makePtr<CvVideoWriter_FFMPEG_proxy>(filename, fourcc, fps, frameSize, isColor != 0);
|
cv::Ptr<CvVideoWriter_FFMPEG_proxy> writer = cv::makePtr<CvVideoWriter_FFMPEG_proxy>(filename, fourcc, fps, frameSize, isColor != 0);
|
||||||
if (writer && writer->isOpened())
|
if (writer && writer->isOpened())
|
||||||
return writer;
|
return writer;
|
||||||
@ -343,7 +180,7 @@ cv::Ptr<cv::IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const std::string& fi
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#endif // defined(HAVE_FFMPEG)
|
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
|
@ -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
|
|
@ -40,7 +40,10 @@
|
|||||||
//
|
//
|
||||||
//M*/
|
//M*/
|
||||||
|
|
||||||
#include "cap_ffmpeg_api.hpp"
|
#include "cap_ffmpeg_legacy_api.hpp"
|
||||||
|
|
||||||
|
using namespace cv;
|
||||||
|
|
||||||
#if !(defined(_WIN32) || defined(WINCE))
|
#if !(defined(_WIN32) || defined(WINCE))
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
@ -631,6 +634,9 @@ void CvCapture_FFMPEG::close()
|
|||||||
#define AVSEEK_FLAG_ANY 1
|
#define AVSEEK_FLAG_ANY 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__OPENCV_BUILD) || defined(BUILD_PLUGIN)
|
||||||
|
typedef cv::Mutex ImplMutex;
|
||||||
|
#else
|
||||||
class ImplMutex
|
class ImplMutex
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -751,16 +757,30 @@ void ImplMutex::lock() { impl->lock(); }
|
|||||||
void ImplMutex::unlock() { impl->unlock(); }
|
void ImplMutex::unlock() { impl->unlock(); }
|
||||||
bool ImplMutex::trylock() { return impl->trylock(); }
|
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)
|
static int LockCallBack(void **mutex, AVLockOp op)
|
||||||
{
|
{
|
||||||
ImplMutex* localMutex = reinterpret_cast<ImplMutex*>(*mutex);
|
ImplMutex* localMutex = reinterpret_cast<ImplMutex*>(*mutex);
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case AV_LOCK_CREATE:
|
case AV_LOCK_CREATE:
|
||||||
localMutex = reinterpret_cast<ImplMutex*>(malloc(sizeof(ImplMutex)));
|
localMutex = new ImplMutex();
|
||||||
if (!localMutex)
|
if (!localMutex)
|
||||||
return 1;
|
return 1;
|
||||||
localMutex->init();
|
|
||||||
*mutex = localMutex;
|
*mutex = localMutex;
|
||||||
if (!*mutex)
|
if (!*mutex)
|
||||||
return 1;
|
return 1;
|
||||||
@ -775,8 +795,7 @@ static int LockCallBack(void **mutex, AVLockOp op)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case AV_LOCK_DESTROY:
|
case AV_LOCK_DESTROY:
|
||||||
localMutex->destroy();
|
delete localMutex;
|
||||||
free(localMutex);
|
|
||||||
localMutex = NULL;
|
localMutex = NULL;
|
||||||
*mutex = NULL;
|
*mutex = NULL;
|
||||||
break;
|
break;
|
||||||
@ -784,19 +803,6 @@ static int LockCallBack(void **mutex, AVLockOp op)
|
|||||||
return 0;
|
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)
|
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 )
|
switch( property_id )
|
||||||
{
|
{
|
||||||
case CV_FFMPEG_CAP_PROP_POS_MSEC:
|
case CAP_PROP_POS_MSEC:
|
||||||
return 1000.0*(double)frame_number/get_fps();
|
return 1000.0*(double)frame_number/get_fps();
|
||||||
case CV_FFMPEG_CAP_PROP_POS_FRAMES:
|
case CAP_PROP_POS_FRAMES:
|
||||||
return (double)frame_number;
|
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);
|
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();
|
return (double)get_total_frames();
|
||||||
case CV_FFMPEG_CAP_PROP_FRAME_WIDTH:
|
case CAP_PROP_FRAME_WIDTH:
|
||||||
return (double)frame.width;
|
return (double)frame.width;
|
||||||
case CV_FFMPEG_CAP_PROP_FRAME_HEIGHT:
|
case CAP_PROP_FRAME_HEIGHT:
|
||||||
return (double)frame.height;
|
return (double)frame.height;
|
||||||
case CV_FFMPEG_CAP_PROP_FPS:
|
case CAP_PROP_FPS:
|
||||||
return get_fps();
|
return get_fps();
|
||||||
case CV_FFMPEG_CAP_PROP_FOURCC:
|
case CAP_PROP_FOURCC:
|
||||||
#if LIBAVFORMAT_BUILD > 4628
|
#if LIBAVFORMAT_BUILD > 4628
|
||||||
codec_id = video_st->codec->codec_id;
|
codec_id = video_st->codec->codec_id;
|
||||||
codec_tag = (double) video_st->codec->codec_tag;
|
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]);
|
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;
|
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;
|
return _opencv_ffmpeg_get_sample_aspect_ratio(ic->streams[video_stream]).den;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -1347,21 +1353,21 @@ bool CvCapture_FFMPEG::setProperty( int property_id, double value )
|
|||||||
|
|
||||||
switch( property_id )
|
switch( property_id )
|
||||||
{
|
{
|
||||||
case CV_FFMPEG_CAP_PROP_POS_MSEC:
|
case CAP_PROP_POS_MSEC:
|
||||||
case CV_FFMPEG_CAP_PROP_POS_FRAMES:
|
case CAP_PROP_POS_FRAMES:
|
||||||
case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
|
case CAP_PROP_POS_AVI_RATIO:
|
||||||
{
|
{
|
||||||
switch( property_id )
|
switch( property_id )
|
||||||
{
|
{
|
||||||
case CV_FFMPEG_CAP_PROP_POS_FRAMES:
|
case CAP_PROP_POS_FRAMES:
|
||||||
seek((int64_t)value);
|
seek((int64_t)value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CV_FFMPEG_CAP_PROP_POS_MSEC:
|
case CAP_PROP_POS_MSEC:
|
||||||
seek(value/1000.0);
|
seek(value/1000.0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
|
case CAP_PROP_POS_AVI_RATIO:
|
||||||
seek((int64_t)(value*ic->duration));
|
seek((int64_t)(value*ic->duration));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2433,577 +2439,3 @@ int cvWriteFrame_FFMPEG( CvVideoWriter_FFMPEG* writer,
|
|||||||
{
|
{
|
||||||
return writer->writeFrame(data, step, width, height, cn, origin);
|
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<int>(fps+0.5);
|
|
||||||
int frame_rate_base = 1;
|
|
||||||
while (fabs((static_cast<double>(frame_rate)/frame_rate_base) - fps) > 0.001)
|
|
||||||
{
|
|
||||||
frame_rate_base *= 10;
|
|
||||||
frame_rate = static_cast<int>(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<int>(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);
|
|
||||||
}
|
|
||||||
|
46
modules/videoio/src/cap_ffmpeg_legacy_api.hpp
Normal file
46
modules/videoio/src/cap_ffmpeg_legacy_api.hpp
Normal file
@ -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__
|
@ -46,7 +46,9 @@
|
|||||||
#include "opencv2/videoio/legacy/constants_c.h"
|
#include "opencv2/videoio/legacy/constants_c.h"
|
||||||
|
|
||||||
#include "opencv2/core/utility.hpp"
|
#include "opencv2/core/utility.hpp"
|
||||||
|
#ifdef __OPENCV_BUILD
|
||||||
#include "opencv2/core/private.hpp"
|
#include "opencv2/core/private.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <opencv2/core/utils/configuration.private.hpp>
|
#include <opencv2/core/utils/configuration.private.hpp>
|
||||||
#include <opencv2/core/utils/logger.hpp>
|
#include <opencv2/core/utils/logger.hpp>
|
||||||
|
@ -58,7 +58,7 @@ static const struct VideoBackendInfo builtin_backends[] =
|
|||||||
{
|
{
|
||||||
#ifdef HAVE_FFMPEG
|
#ifdef HAVE_FFMPEG
|
||||||
DECLARE_STATIC_BACKEND(CAP_FFMPEG, "FFMPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER, cvCreateFileCapture_FFMPEG_proxy, 0, cvCreateVideoWriter_FFMPEG_proxy),
|
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),
|
DECLARE_DYNAMIC_BACKEND(CAP_FFMPEG, "FFMPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user