Framework for dynamic videoio backends, FFmpeg and GStreamer plugins
authorMaksim Shabunin <maksim.shabunin@gmail.com>
Mon, 14 Jan 2019 10:33:38 +0000 (13:33 +0300)
committerMaksim Shabunin <maksim.shabunin@gmail.com>
Tue, 26 Feb 2019 10:50:30 +0000 (13:50 +0300)
64 files changed:
modules/core/include/opencv2/core/private.hpp
modules/core/include/opencv2/core/utils/filesystem.hpp
modules/core/src/utils/datafile.cpp
modules/core/src/utils/filesystem.cpp
modules/videoio/CMakeLists.txt
modules/videoio/cmake/detect_ffmpeg.cmake
modules/videoio/cmake/init.cmake
modules/videoio/cmake/plugin.cmake [new file with mode: 0644]
modules/videoio/include/opencv2/videoio/registry.hpp
modules/videoio/misc/build_plugins.sh [new file with mode: 0755]
modules/videoio/misc/plugin_ffmpeg/.gitignore [new file with mode: 0644]
modules/videoio/misc/plugin_ffmpeg/CMakeLists.txt [new file with mode: 0644]
modules/videoio/misc/plugin_ffmpeg/Dockerfile-ffmpeg [new file with mode: 0644]
modules/videoio/misc/plugin_ffmpeg/Dockerfile-ubuntu [new file with mode: 0644]
modules/videoio/misc/plugin_ffmpeg/build-standalone.sh [new file with mode: 0755]
modules/videoio/misc/plugin_ffmpeg/build-ubuntu.sh [new file with mode: 0755]
modules/videoio/misc/plugin_gstreamer/CMakeLists.txt [new file with mode: 0644]
modules/videoio/misc/plugin_gstreamer/Dockerfile [new file with mode: 0644]
modules/videoio/misc/plugin_gstreamer/build.sh [new file with mode: 0755]
modules/videoio/src/backend.cpp [new file with mode: 0644]
modules/videoio/src/backend.hpp [new file with mode: 0644]
modules/videoio/src/cap.cpp
modules/videoio/src/cap_aravis.cpp
modules/videoio/src/cap_avfoundation.mm
modules/videoio/src/cap_avfoundation_mac.mm
modules/videoio/src/cap_dc1394_v2.cpp
modules/videoio/src/cap_dshow.cpp
modules/videoio/src/cap_dshow.hpp
modules/videoio/src/cap_ffmpeg.cpp
modules/videoio/src/cap_ffmpeg_impl.hpp
modules/videoio/src/cap_gphoto2.cpp
modules/videoio/src/cap_gstreamer.cpp
modules/videoio/src/cap_images.cpp
modules/videoio/src/cap_interface.hpp [new file with mode: 0644]
modules/videoio/src/cap_librealsense.cpp
modules/videoio/src/cap_librealsense.hpp
modules/videoio/src/cap_mfx_common.hpp
modules/videoio/src/cap_mfx_reader.cpp
modules/videoio/src/cap_mfx_reader.hpp
modules/videoio/src/cap_mfx_writer.cpp
modules/videoio/src/cap_mfx_writer.hpp
modules/videoio/src/cap_mjpeg_encoder.cpp
modules/videoio/src/cap_msmf.cpp
modules/videoio/src/cap_openni2.cpp
modules/videoio/src/cap_pvapi.cpp
modules/videoio/src/cap_v4l.cpp
modules/videoio/src/cap_winrt_capture.cpp
modules/videoio/src/cap_winrt_capture.hpp
modules/videoio/src/cap_ximea.cpp
modules/videoio/src/cap_xine.cpp
modules/videoio/src/plugin_api.cpp [new file with mode: 0644]
modules/videoio/src/plugin_api.hpp [new file with mode: 0644]
modules/videoio/src/precomp.hpp
modules/videoio/src/videoio_c.cpp
modules/videoio/src/videoio_registry.cpp
modules/videoio/src/videoio_registry.hpp
modules/videoio/test/test_camera.cpp
modules/videoio/test/test_container_avi.cpp
modules/videoio/test/test_dynamic.cpp [new file with mode: 0644]
modules/videoio/test/test_ffmpeg.cpp
modules/videoio/test/test_fourcc.cpp [deleted file]
modules/videoio/test/test_gstreamer.cpp
modules/videoio/test/test_mfx.cpp
modules/videoio/test/test_video_io.cpp

index b451875..32a5e6b 100644 (file)
@@ -865,6 +865,10 @@ Passed subdirectories are used in LIFO order.
 */
 CV_EXPORTS void addDataSearchSubDirectory(const cv::String& subdir);
 
+/** @brief Return location of OpenCV libraries or current executable
+ */
+CV_EXPORTS std::string getBinLocation();
+
 //! @}
 
 } // namespace utils
index 00b0dd1..9f043be 100644 (file)
@@ -26,6 +26,9 @@ CV_EXPORTS cv::String canonical(const cv::String& path);
 /** Join path components */
 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);
+
 /**
  * Generate a list of all files that match the globbing pattern.
  *
index f1107b0..b3dc31f 100644 (file)
@@ -144,6 +144,11 @@ static cv::String getModuleLocation(const void* addr)
     return cv::String();
 }
 
+std::string getBinLocation()
+{
+    return getModuleLocation((void*)getModuleLocation); // use code addr, doesn't work with static linkage!
+}
+
 cv::String findDataFile(const cv::String& relative_path,
                         const char* configuration_parameter,
                         const std::vector<String>* search_paths,
@@ -287,7 +292,7 @@ cv::String findDataFile(const cv::String& relative_path,
         }
     }
 
-    cv::String module_path = getModuleLocation((void*)getModuleLocation);  // use code addr, doesn't work with static linkage!
+    cv::String module_path = getBinLocation();
     CV_LOG_DEBUG(NULL, "Detected module path: '" << module_path << '\'');
 
     if (!has_tested_build_directory &&
index 43503f1..b0dc9d5 100644 (file)
@@ -83,6 +83,14 @@ cv::String join(const cv::String& base, const cv::String& path)
     return result;
 }
 
+CV_EXPORTS cv::String getParent(const cv::String &path)
+{
+    std::string::size_type loc = path.find_last_of("/\\");
+    if (loc == std::string::npos)
+        return std::string();
+    return std::string(path, 0, loc);
+}
+
 #if OPENCV_HAVE_FILESYSTEM_SUPPORT
 
 cv::String canonical(const cv::String& path)
index ebec00f..7dcabb3 100644 (file)
@@ -1,3 +1,8 @@
+set(VIDEOIO_PLUGIN_LIST "" CACHE STRING "List of videoio backends to be compiled as plugins (ffmpeg, gstreamer)")
+set(VIDEOIO_ENABLE_PLUGINS "ON" CACHE BOOL "Allow building videoio plugin support")
+set(VIDEOIO_ENABLE_STRICT_PLUGIN_CHECK "ON" CACHE BOOL "Make sure OpenCV version is the same in plugin and host code")
+mark_as_advanced(VIDEOIO_PLUGIN_LIST VIDEOIO_ENABLE_PLUGINS VIDEOIO_ENABLE_STRICT_PLUGIN_CHECK)
+
 ocv_add_module(videoio opencv_imgproc opencv_imgcodecs WRAP java python)
 
 set(videoio_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/precomp.hpp)
@@ -9,6 +14,7 @@ set(videoio_srcs
   "${CMAKE_CURRENT_LIST_DIR}/src/cap_images.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/src/cap_mjpeg_encoder.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/src/cap_mjpeg_decoder.cpp"
+  "${CMAKE_CURRENT_LIST_DIR}/src/backend.cpp"
   "${CMAKE_CURRENT_LIST_DIR}/src/container_avi.cpp")
 
 file(GLOB videoio_ext_hdrs
@@ -86,9 +92,15 @@ if(TARGET ocv.3rdparty.dc1394_2)
   list(APPEND tgts ocv.3rdparty.dc1394_2)
 endif()
 
+include(${CMAKE_CURRENT_LIST_DIR}/cmake/plugin.cmake)
+
 if(TARGET ocv.3rdparty.gstreamer)
-  list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_gstreamer.cpp)
-  list(APPEND tgts ocv.3rdparty.gstreamer)
+  if("gstreamer" IN_LIST VIDEOIO_PLUGIN_LIST)
+    ocv_create_builtin_videoio_plugin("opencv_videoio_gstreamer" ocv.3rdparty.gstreamer "cap_gstreamer.cpp")
+  else()
+    list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_gstreamer.cpp)
+    list(APPEND tgts ocv.3rdparty.gstreamer)
+  endif()
 endif()
 
 if(TARGET ocv.3rdparty.v4l)
@@ -107,9 +119,13 @@ if(TARGET ocv.3rdparty.ximea)
 endif()
 
 if(TARGET ocv.3rdparty.ffmpeg)
-  list(APPEND videoio_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/cap_ffmpeg_impl.hpp)
-  list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_ffmpeg.cpp)
-  list(APPEND tgts ocv.3rdparty.ffmpeg)
+  if("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)
+    list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_ffmpeg.cpp)
+    list(APPEND tgts ocv.3rdparty.ffmpeg)
+  endif()
 endif()
 
 if(TARGET ocv.3rdparty.pvapi)
@@ -155,6 +171,14 @@ ocv_create_module()
 ocv_add_accuracy_tests(${tgts})
 ocv_add_perf_tests(${tgts})
 
+if(VIDEOIO_ENABLE_PLUGINS)
+  ocv_target_compile_definitions(${the_module} PRIVATE ENABLE_PLUGINS)
+endif()
+
+if(VIDEOIO_ENABLE_STRICT_PLUGIN_CHECK)
+  ocv_target_compile_definitions(${the_module} PRIVATE STRICT_PLUGIN_CHECK)
+endif()
+
 ocv_target_link_libraries(${the_module} LINK_PRIVATE ${tgts})
 
 # copy FFmpeg dll to the output folder
index 46acaaa..ea1295d 100644 (file)
@@ -31,10 +31,9 @@ if(NOT HAVE_FFMPEG AND PKG_CONFIG_FOUND)
     if(FFMPEG_libavresample_FOUND)
       list(APPEND FFMPEG_LIBRARIES ${FFMPEG_libavresample_LIBRARIES})
     endif()
-
     # rewrite libraries to absolute paths
     foreach(lib ${FFMPEG_LIBRARIES})
-      find_library(FFMPEG_ABSOLUTE_${lib} "${lib}" PATHS "${FFMPEG_lib${lib}_LIBDIR}" NO_DEFAULT_PATH)
+      find_library(FFMPEG_ABSOLUTE_${lib} "${lib}" PATHS "${FFMPEG_lib${lib}_LIBDIR}" "${FFMPEG_LIBRARY_DIRS}" NO_DEFAULT_PATH)
       if(FFMPEG_ABSOLUTE_${lib})
         list(APPEND ffmpeg_abs_libs "${FFMPEG_ABSOLUTE_${lib}}")
       else()
@@ -49,7 +48,7 @@ endif()
 
 #==================================
 
-if(HAVE_FFMPEG AND NOT HAVE_FFMPEG_WRAPPER)
+if(HAVE_FFMPEG AND NOT HAVE_FFMPEG_WRAPPER AND NOT OPENCV_FFMPEG_SKIP_BUILD_CHECK)
   try_compile(__VALID_FFMPEG
       "${OpenCV_BINARY_DIR}"
       "${OpenCV_SOURCE_DIR}/cmake/checks/ffmpeg_test.cpp"
index 5e71c2e..56ff456 100644 (file)
@@ -19,6 +19,8 @@ function(ocv_add_external_target name inc link def)
   endif()
 endfunction()
 
+include(FindPkgConfig)
+
 add_backend("ffmpeg" WITH_FFMPEG)
 add_backend("gstreamer" WITH_GSTREAMER)
 add_backend("v4l" WITH_V4L)
diff --git a/modules/videoio/cmake/plugin.cmake b/modules/videoio/cmake/plugin.cmake
new file mode 100644 (file)
index 0000000..8aa05c2
--- /dev/null
@@ -0,0 +1,99 @@
+#=============================================
+# build with OpenCV
+
+function(ocv_create_builtin_videoio_plugin name target videoio_src_file)
+
+  if(NOT TARGET ${target})
+    message(FATAL_ERROR "${target} does not exist!")
+  endif()
+  if(NOT OpenCV_SOURCE_DIR)
+    message(FATAL_ERROR "OpenCV_SOURCE_DIR must be set to build the plugin!")
+  endif()
+
+  add_library(${name} MODULE
+    "${CMAKE_CURRENT_LIST_DIR}/src/${videoio_src_file}"
+    "${CMAKE_CURRENT_LIST_DIR}/src/plugin_api.cpp")
+  target_include_directories(${name} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
+  target_compile_definitions(${name} PRIVATE BUILD_PLUGIN)
+  target_link_libraries(${name} PRIVATE ${target})
+
+  foreach(mod opencv_videoio opencv_core opencv_imgproc opencv_imgcodecs)
+    target_link_libraries(${name} PRIVATE ${mod})
+    target_include_directories(${name} PRIVATE "${OPENCV_MODULE_${mod}_LOCATION}/include")
+  endforeach()
+
+  set_target_properties(${name} PROPERTIES
+    CXX_STANDARD 11
+    CXX_VISIBILITY_PRESET hidden
+  )
+  install(TARGETS ${name} LIBRARY DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT plugins OPTIONAL)
+
+endfunction()
+
+#=============================================
+# standalone build
+
+function(ocv_create_videoio_plugin default_name target target_desc videoio_src_file)
+
+  set(OPENCV_PLUGIN_NAME ${default_name} CACHE STRING "")
+  set(OPENCV_PLUGIN_DESTINATION "" CACHE PATH "")
+  project(${OPENCV_PLUGIN_NAME} LANGUAGES CXX)
+
+  set(BUILD_SHARED_LIBS ON CACHE BOOL "")
+  if(NOT BUILD_SHARED_LIBS)
+    message(FATAL_ERROR "Static plugin build does not make sense")
+  endif()
+
+  if(NOT OpenCV_SOURCE_DIR)
+    message(FATAL_ERROR "OpenCV_SOURCE_DIR must be set to build the plugin!")
+  endif()
+
+  include("${OpenCV_SOURCE_DIR}/modules/videoio/cmake/init.cmake")
+
+  if(NOT TARGET ${target})
+    message(FATAL_ERROR "${target_desc} was not found!")
+  endif()
+
+  set(modules_ROOT "${CMAKE_CURRENT_LIST_DIR}/../../..")
+  set(videoio_ROOT "${modules_ROOT}/videoio")
+  set(core_ROOT "${modules_ROOT}/core")
+  set(imgproc_ROOT "${modules_ROOT}/imgproc")
+  set(imgcodecs_ROOT "${modules_ROOT}/imgcodecs")
+
+  add_library(${OPENCV_PLUGIN_NAME} MODULE "${videoio_ROOT}/src/${videoio_src_file}" "${videoio_ROOT}/src/plugin_api.cpp")
+  target_include_directories(${OPENCV_PLUGIN_NAME} PRIVATE
+    "${CMAKE_CURRENT_BINARY_DIR}"
+    "${videoio_ROOT}/src"
+    "${videoio_ROOT}/include"
+    "${core_ROOT}/include"
+    "${imgproc_ROOT}/include"
+    "${imgcodecs_ROOT}/include"
+  )
+  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
+  )
+
+  # Hack for Windows
+  if(WIN32)
+    find_package(OpenCV REQUIRED core imgproc videoio)
+    target_link_libraries(${OPENCV_PLUGIN_NAME} ${OpenCV_LIBS})
+  endif()
+
+  if(OPENCV_PLUGIN_DESTINATION)
+    set_target_properties(${OPENCV_PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${OPENCV_PLUGIN_DESTINATION}")
+    message(STATUS "Output destination: ${OPENCV_PLUGIN_DESTINATION}")
+  endif()
+
+  message(STATUS "Library name: ${OPENCV_PLUGIN_NAME}")
+
+endfunction()
index 7404c68..0bc6ec5 100644 (file)
@@ -38,6 +38,16 @@ CV_EXPORTS_W std::vector<VideoCaptureAPIs> getStreamBackends();
 /** @brief Returns list of available backends which works via `cv::VideoWriter()` */
 CV_EXPORTS_W std::vector<VideoCaptureAPIs> getWriterBackends();
 
+enum Capability
+{
+    Read,
+    Write,
+    ReadWrite
+};
+
+/** @brief Returns true if backend is available */
+CV_EXPORTS bool hasBackend(VideoCaptureAPIs api, Capability cap = ReadWrite);
+
 //! @}
 }} // namespace
 
diff --git a/modules/videoio/misc/build_plugins.sh b/modules/videoio/misc/build_plugins.sh
new file mode 100755 (executable)
index 0000000..938ae76
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+set -e
+
+if [ -z $1 ] ; then
+    echo "<script> <destination directory>"
+    exit 1
+fi
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+OCV="$( cd "${DIR}/../../.." >/dev/null 2>&1 && pwd )"
+mkdir -p "${1}"  # Docker creates non-existed mounts with 'root' owner, lets ensure that dir exists under the current user to avoid "Permission denied" problem
+DST="$( cd "$1" >/dev/null 2>&1 && pwd )"
+CFG=$2
+
+do_build()
+{
+TAG=$1
+D=$2
+F=$3
+shift 3
+docker build \
+    --build-arg http_proxy \
+    --build-arg https_proxy \
+    $@ \
+    -t $TAG \
+    -f "${D}/${F}" \
+    "${D}"
+}
+
+do_run()
+{
+TAG=$1
+shift 1
+docker run \
+    -it \
+    --rm \
+    -v "${OCV}":/opencv:ro \
+    -v "${DST}":/dst \
+    -e CFG=$CFG \
+    --user $(id -u):$(id -g) \
+    $TAG \
+    $@
+}
+
+build_gstreamer()
+{
+TAG=opencv_gstreamer_builder
+do_build $TAG "${DIR}/plugin_gstreamer" Dockerfile
+do_run $TAG /opencv/modules/videoio/misc/plugin_gstreamer/build.sh /dst $CFG
+}
+
+build_ffmpeg_ubuntu()
+{
+VER=$1
+TAG=opencv_ffmpeg_ubuntu_builder:${VER}
+do_build $TAG "${DIR}/plugin_ffmpeg" Dockerfile-ubuntu --build-arg VER=${VER}
+do_run $TAG /opencv/modules/videoio/misc/plugin_ffmpeg/build-ubuntu.sh /dst ${VER} ${CFG}
+}
+
+build_ffmpeg()
+{
+VER=$1
+TAG=opencv_ffmpeg_builder:${VER}
+ARCHIVE="${DIR}/plugin_ffmpeg/ffmpeg-${VER}.tar.xz"
+if [ ! -f "${ARCHIVE}" ] ; then
+    wget https://www.ffmpeg.org/releases/ffmpeg-${VER}.tar.xz -O "${ARCHIVE}"
+fi
+do_build $TAG "${DIR}/plugin_ffmpeg" Dockerfile-ffmpeg --build-arg VER=${VER}
+do_run $TAG /opencv/modules/videoio/misc/plugin_ffmpeg/build-standalone.sh /dst ${VER} ${CFG}
+}
+
+echo "OpenCV: ${OCV}"
+echo "Destination: ${DST}"
+
+build_gstreamer
+build_ffmpeg_ubuntu 18.04
+build_ffmpeg_ubuntu 16.04
+build_ffmpeg 4.1
+build_ffmpeg 3.4.5
+build_ffmpeg 2.8.15
diff --git a/modules/videoio/misc/plugin_ffmpeg/.gitignore b/modules/videoio/misc/plugin_ffmpeg/.gitignore
new file mode 100644 (file)
index 0000000..b5624b7
--- /dev/null
@@ -0,0 +1 @@
+*.tar.xz
diff --git a/modules/videoio/misc/plugin_ffmpeg/CMakeLists.txt b/modules/videoio/misc/plugin_ffmpeg/CMakeLists.txt
new file mode 100644 (file)
index 0000000..347b4da
--- /dev/null
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.5)
+
+set(OpenCV_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../..")
+set(WITH_FFMPEG ON)
+set(OPENCV_FFMPEG_SKIP_BUILD_CHECK ON)
+include("${OpenCV_SOURCE_DIR}/modules/videoio/cmake/plugin.cmake")
+ocv_create_videoio_plugin("opencv_videoio_ffmpeg" "ocv.3rdparty.ffmpeg" "FFmpeg" "cap_ffmpeg.cpp")
+
+message(STATUS "FFMPEG_libavcodec_VERSION=${FFMPEG_libavcodec_VERSION}")
+message(STATUS "FFMPEG_libavformat_VERSION=${FFMPEG_libavformat_VERSION}")
+message(STATUS "FFMPEG_libavutil_VERSION=${FFMPEG_libavutil_VERSION}")
+message(STATUS "FFMPEG_libswscale_VERSION=${FFMPEG_libswscale_VERSION}")
+message(STATUS "FFMPEG_libavresample_VERSION=${FFMPEG_libavresample_VERSION}")
diff --git a/modules/videoio/misc/plugin_ffmpeg/Dockerfile-ffmpeg b/modules/videoio/misc/plugin_ffmpeg/Dockerfile-ffmpeg
new file mode 100644 (file)
index 0000000..69444a4
--- /dev/null
@@ -0,0 +1,45 @@
+FROM ubuntu:18.04
+
+RUN apt-get update && apt-get install -y \
+        pkg-config \
+        cmake \
+        g++ \
+        ninja-build \
+        make \
+        nasm \
+    && \
+    rm -rf /var/lib/apt/lists/*
+
+ARG VER
+
+ADD ffmpeg-${VER}.tar.xz /ffmpeg/
+
+WORKDIR /ffmpeg/ffmpeg-${VER}
+RUN ./configure \
+    --enable-avresample \
+    --prefix=/ffmpeg-shared \
+    --enable-shared \
+    --disable-static \
+    --disable-programs \
+    --disable-doc \
+    --disable-avdevice \
+    --disable-postproc \
+    && make -j8 install \
+    && make clean \
+    && make distclean
+
+RUN ./configure \
+    --enable-avresample \
+    --prefix=/ffmpeg-static \
+    --disable-shared \
+    --enable-static \
+    --enable-pic \
+    --disable-programs \
+    --disable-doc \
+    --disable-avdevice \
+    --disable-postproc \
+    && make -j8 install \
+    && make clean \
+    && make distclean
+
+WORKDIR /tmp
diff --git a/modules/videoio/misc/plugin_ffmpeg/Dockerfile-ubuntu b/modules/videoio/misc/plugin_ffmpeg/Dockerfile-ubuntu
new file mode 100644 (file)
index 0000000..ed75fe5
--- /dev/null
@@ -0,0 +1,17 @@
+ARG VER
+FROM ubuntu:$VER
+
+RUN apt-get update && apt-get install -y \
+        libavcodec-dev \
+        libavfilter-dev \
+        libavformat-dev \
+        libavresample-dev \
+        libavutil-dev \
+        pkg-config \
+        cmake \
+        g++ \
+        ninja-build \
+    && \
+    rm -rf /var/lib/apt/lists/*
+
+WORKDIR /tmp
diff --git a/modules/videoio/misc/plugin_ffmpeg/build-standalone.sh b/modules/videoio/misc/plugin_ffmpeg/build-standalone.sh
new file mode 100755 (executable)
index 0000000..eae2fc7
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -e
+
+mkdir -p build_shared && pushd build_shared
+PKG_CONFIG_PATH=/ffmpeg-shared/lib/pkgconfig \
+cmake -GNinja \
+    -DOPENCV_PLUGIN_NAME=opencv_videoio_ffmpeg_shared_$2 \
+    -DOPENCV_PLUGIN_DESTINATION=$1 \
+    -DCMAKE_BUILD_TYPE=$3 \
+    /opencv/modules/videoio/misc/plugin_ffmpeg
+ninja
+popd
+
+mkdir -p build_static && pushd build_static
+PKG_CONFIG_PATH=/ffmpeg-static/lib/pkgconfig \
+cmake -GNinja \
+    -DOPENCV_PLUGIN_NAME=opencv_videoio_ffmpeg_static_$2 \
+    -DOPENCV_PLUGIN_DESTINATION=$1 \
+    -DCMAKE_MODULE_LINKER_FLAGS=-Wl,-Bsymbolic \
+    -DCMAKE_BUILD_TYPE=$3 \
+    /opencv/modules/videoio/misc/plugin_ffmpeg
+ninja
+popd
diff --git a/modules/videoio/misc/plugin_ffmpeg/build-ubuntu.sh b/modules/videoio/misc/plugin_ffmpeg/build-ubuntu.sh
new file mode 100755 (executable)
index 0000000..07c9f69
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+set -e
+
+cmake -GNinja \
+    -DOPENCV_PLUGIN_NAME=opencv_videoio_ffmpeg_ubuntu_$2 \
+    -DOPENCV_PLUGIN_DESTINATION=$1 \
+    -DCMAKE_BUILD_TYPE=$3 \
+    /opencv/modules/videoio/misc/plugin_ffmpeg
+ninja
diff --git a/modules/videoio/misc/plugin_gstreamer/CMakeLists.txt b/modules/videoio/misc/plugin_gstreamer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b95424c
--- /dev/null
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.5)
+
+set(OpenCV_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../..")
+set(WITH_GSTREAMER ON)
+include("${OpenCV_SOURCE_DIR}/modules/videoio/cmake/plugin.cmake")
+ocv_create_videoio_plugin("opencv_videoio_gstreamer" "ocv.3rdparty.gstreamer" "GStreamer" "cap_gstreamer.cpp")
+
+message(STATUS "Using GStreamer: ${GSTREAMER_VERSION}")
diff --git a/modules/videoio/misc/plugin_gstreamer/Dockerfile b/modules/videoio/misc/plugin_gstreamer/Dockerfile
new file mode 100644 (file)
index 0000000..1b72b86
--- /dev/null
@@ -0,0 +1,13 @@
+FROM ubuntu:18.04
+
+RUN apt-get update && apt-get install -y \
+        libgstreamer-plugins-base1.0-dev \
+        libgstreamer-plugins-good1.0-dev \
+        libgstreamer1.0-dev \
+        cmake \
+        g++ \
+        ninja-build \
+    && \
+    rm -rf /var/lib/apt/lists/*
+
+WORKDIR /tmp
diff --git a/modules/videoio/misc/plugin_gstreamer/build.sh b/modules/videoio/misc/plugin_gstreamer/build.sh
new file mode 100755 (executable)
index 0000000..3d18afe
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+
+cmake -GNinja \
+    -DOPENCV_PLUGIN_NAME=opencv_videoio_gstreamer \
+    -DOPENCV_PLUGIN_DESTINATION=$1 \
+    -DCMAKE_BUILD_TYPE=$2 \
+    /opencv/modules/videoio/misc/plugin_gstreamer
+
+ninja
diff --git a/modules/videoio/src/backend.cpp b/modules/videoio/src/backend.cpp
new file mode 100644 (file)
index 0000000..49e2bad
--- /dev/null
@@ -0,0 +1,491 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "precomp.hpp"
+
+#include "backend.hpp"
+#include "plugin_api.hpp"
+
+#include "opencv2/core/utils/filesystem.hpp"
+#include "opencv2/core/utils/configuration.private.hpp"
+#include "opencv2/core/private.hpp"
+#include "videoio_registry.hpp"
+
+//==================================================================================================
+// IBackend implementation
+
+namespace cv {
+
+static bool param_VIDEOIO_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOIO_DEBUG", false);
+static bool param_VIDEOCAPTURE_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOCAPTURE_DEBUG", false);
+static bool param_VIDEOWRITER_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOWRITER_DEBUG", false);
+
+Ptr<IVideoCapture> IBackend::tryOpenCapture(const std::string & backendName, const std::string & filename, int cameraNum) const
+{
+    try
+    {
+        if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG)
+            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", backendName.c_str()));
+        Ptr<IVideoCapture> icap = createCapture(filename, cameraNum);
+        if (param_VIDEOIO_DEBUG ||param_VIDEOCAPTURE_DEBUG)
+            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p isOpened=%d ...\n", backendName.c_str(), icap.empty() ? NULL : icap.get(), icap.empty() ? -1: icap->isOpened()));
+        return icap;
+    }
+    catch(const cv::Exception& e)
+    {
+        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", backendName.c_str(), e.what()));
+    }
+    catch (const std::exception& e)
+    {
+        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", backendName.c_str(), e.what()));
+    }
+    catch(...)
+    {
+        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", backendName.c_str()));
+    }
+    return 0;
+}
+
+Ptr<IVideoWriter> IBackend::tryOpenWriter(const std::string & backendName, const std::string& filename, int _fourcc, double fps, const Size &frameSize, bool isColor) const
+{
+    try
+    {
+        if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG)
+            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", backendName.c_str()));
+        Ptr<IVideoWriter> iwriter = createWriter(filename, _fourcc, fps, frameSize, isColor);
+        if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG)
+            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p  isOpened=%d...\n", backendName.c_str(), iwriter.empty() ? NULL : iwriter.get(), iwriter.empty() ? iwriter->isOpened() : -1));
+        return iwriter;
+    }
+    catch(const cv::Exception& e)
+    {
+        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", backendName.c_str(), e.what()));
+    }
+    catch (const std::exception& e)
+    {
+        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", backendName.c_str(), e.what()));
+    }
+    catch(...)
+    {
+        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", backendName.c_str()));
+    }
+    return 0;
+}
+
+} // cv::
+
+//==================================================================================================
+// Dynamic backend implementation
+
+#include "opencv2/core/utils/logger.hpp"
+#include <sstream>
+using namespace std;
+
+#if defined(_WIN32)
+#include <windows.h>
+#elif defined(__linux__) || defined(__APPLE__)
+#include <dlfcn.h>
+#endif
+
+inline static void * getSymbol_(void *h, const std::string &symbolName)
+{
+#if defined(_WIN32)
+    return (void*)GetProcAddress(static_cast<HMODULE>(h), symbolName.c_str());
+#elif defined(__linux__) || defined(__APPLE__)
+    return dlsym(h, symbolName.c_str());
+#endif
+}
+
+inline static void * libraryLoad_(const std::string &filename)
+{
+#if defined(_WIN32)
+    return static_cast<HMODULE>(LoadLibraryA(filename.c_str()));
+#elif defined(__linux__) || defined(__APPLE__)
+    return dlopen(filename.c_str(), RTLD_LAZY);
+#endif
+}
+
+inline static void libraryRelease_(void *h)
+{
+#if defined(_WIN32)
+    FreeLibrary(static_cast<HMODULE>(h));
+#elif defined(__linux__) || defined(__APPLE__)
+    dlclose(h);
+#endif
+}
+
+inline static std::string libraryPrefix()
+{
+#if defined(_WIN32)
+    return string();
+#else
+    return "lib";
+#endif
+}
+inline static std::string librarySuffix()
+{
+#if defined(_WIN32)
+    return "dll";
+#elif defined(__APPLE__)
+    return "dylib";
+#else
+    return "so";
+#endif
+}
+
+//============================
+
+class cv::DynamicBackend::DynamicLib
+{
+private:
+    void * handle;
+    const std::string fname;
+
+public:
+    DynamicLib(const std::string &filename)
+        : handle(0), fname(filename)
+    {
+        libraryLoad(filename);
+    }
+    ~DynamicLib()
+    {
+        libraryRelease();
+    }
+    bool isLoaded() const
+    {
+        return handle != NULL;
+    }
+    void* getSymbol(const std::string & symbolName) const
+    {
+        if (!handle)
+        {
+            return 0;
+        }
+        void * res = getSymbol_(handle, symbolName);
+        if (!res)
+            CV_LOG_ERROR(NULL, "No symbol '" << symbolName << "' in " << fname);
+        return res;
+    }
+
+private:
+    void libraryLoad(const std::string &filename)
+    {
+        handle = libraryLoad_(filename);
+        CV_LOG_INFO(NULL, "load " << filename << " => " << (handle ? "OK" : "FAILED"));
+    }
+    void libraryRelease()
+    {
+        CV_LOG_INFO(NULL, "unload "<< fname);
+        if (handle)
+        {
+            libraryRelease_(handle);
+            handle = 0;
+        }
+    }
+
+private:
+    DynamicLib(const DynamicLib &);
+    DynamicLib &operator=(const DynamicLib &);
+};
+
+
+//============================
+
+// Utility function
+static bool verifyVersion(cv_get_version_t * fun)
+{
+    if (!fun)
+        return false;
+    int major, minor, patch, api, abi;
+    fun(major, minor, patch, api, abi);
+    if (api < API_VERSION || abi != ABI_VERSION)
+    {
+        CV_LOG_ERROR(NULL, "Bad plugin API/ABI (" << api << "/" << abi << "), expected " << API_VERSION << "/" << ABI_VERSION);
+        return false;
+    }
+#ifdef STRICT_PLUGIN_CHECK
+    if (major != CV_MAJOR_VERSION || minor != CV_MINOR_VERSION)
+    {
+        CV_LOG_ERROR(NULL, "Bad plugin version (" << major << "." << minor << "), expected " << CV_MAJOR_VERSION << "/" << CV_MINOR_VERSION);
+        return false;
+    }
+#endif
+    return true;
+}
+
+//============================
+
+class cv::DynamicBackend::CaptureTable
+{
+public:
+    cv_get_version_t *cv_get_version;
+    cv_domain_t *cv_domain;
+    cv_open_capture_t *cv_open_capture;
+    cv_get_cap_prop_t *cv_get_cap_prop;
+    cv_set_cap_prop_t *cv_set_cap_prop;
+    cv_grab_t *cv_grab;
+    cv_retrieve_t *cv_retrieve;
+    cv_release_capture_t *cv_release_capture;
+    bool isComplete;
+public:
+    CaptureTable(const cv::DynamicBackend::DynamicLib & p)
+        : isComplete(true)
+    {
+    #define READ_FUN(name) \
+        name = reinterpret_cast<name##_t*>(p.getSymbol(#name)); \
+        isComplete = isComplete && (name)
+
+        READ_FUN(cv_get_version);
+        READ_FUN(cv_domain);
+        READ_FUN(cv_open_capture);
+        READ_FUN(cv_get_cap_prop);
+        READ_FUN(cv_set_cap_prop);
+        READ_FUN(cv_grab);
+        READ_FUN(cv_retrieve);
+        READ_FUN(cv_release_capture);
+
+    #undef READ_FUN
+    }
+};
+
+class cv::DynamicBackend::WriterTable
+{
+public:
+    cv_get_version_t *cv_get_version;
+    cv_domain_t *cv_domain;
+    cv_open_writer_t *cv_open_writer;
+    cv_get_wri_prop_t *cv_get_wri_prop;
+    cv_set_wri_prop_t *cv_set_wri_prop;
+    cv_write_t *cv_write;
+    cv_release_writer_t *cv_release_writer;
+    bool isComplete;
+public:
+    WriterTable(const cv::DynamicBackend::DynamicLib & p)
+        : isComplete(true)
+    {
+    #define READ_FUN(name) \
+        name = reinterpret_cast<name##_t*>(p.getSymbol(#name)); \
+        isComplete = isComplete && (name)
+
+        READ_FUN(cv_get_version);
+        READ_FUN(cv_domain);
+        READ_FUN(cv_open_writer);
+        READ_FUN(cv_get_wri_prop);
+        READ_FUN(cv_set_wri_prop);
+        READ_FUN(cv_write);
+        READ_FUN(cv_release_writer);
+
+    #undef READ_FUN
+    }
+};
+
+//============================
+
+class DynamicCapture;
+class DynamicWriter;
+
+cv::DynamicBackend::DynamicBackend(const std::string &filename)
+    : lib(0), cap_tbl(0), wri_tbl(0)
+{
+    lib = new DynamicLib(filename);
+    if (lib->isLoaded())
+    {
+        cap_tbl = new CaptureTable(*lib);
+        wri_tbl = new WriterTable(*lib);
+    }
+}
+
+cv::DynamicBackend::~DynamicBackend()
+{
+    if (cap_tbl)
+        delete cap_tbl;
+    if (wri_tbl)
+        delete wri_tbl;
+    if (lib)
+        delete lib;
+}
+
+bool cv::DynamicBackend::canCreateCapture(VideoCaptureAPIs api) const
+{
+    return lib && lib->isLoaded() && cap_tbl && cap_tbl->isComplete && verifyVersion(cap_tbl->cv_get_version) && (cap_tbl->cv_domain() == api);
+}
+
+bool cv::DynamicBackend::canCreateWriter(VideoCaptureAPIs api) const
+{
+    return lib && lib->isLoaded() && wri_tbl && wri_tbl->isComplete && verifyVersion(wri_tbl->cv_get_version) && (wri_tbl->cv_domain() == api);
+}
+
+cv::Ptr<cv::IVideoCapture> cv::DynamicBackend::createCapture(const std::string & filename, int camera) const
+{
+    return makePtr<DynamicCapture>(cap_tbl, filename, camera).staticCast<IVideoCapture>();
+}
+
+cv::Ptr<cv::IVideoWriter> cv::DynamicBackend::createWriter(const std::string & filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const
+{
+    return makePtr<DynamicWriter>(wri_tbl, filename, fourcc, fps, sz, isColor).staticCast<IVideoWriter>();
+}
+
+inline static std::vector<string> getPluginCandidates()
+{
+    using namespace cv::utils;
+    using namespace cv::utils::fs;
+    const vector<string> default_paths = { getParent(getBinLocation()) };
+    const vector<string> paths = getConfigurationParameterPaths("OPENCV_VIDEOIO_PLUGIN_PATH", default_paths);
+    const string default_expr = libraryPrefix() + "opencv_videoio_*." + librarySuffix();
+    const string expr = getConfigurationParameterString("OPENCV_VIDEOIO_PLUGIN_NAME", default_expr.c_str());
+    CV_LOG_INFO(NULL, "VideoIO pluigins: glob is '" << expr << "', " << paths.size() << " location(s)");
+    vector<string> results;
+    for(const string & path : paths)
+    {
+        if (path.empty())
+            continue;
+        vector<string> candidates;
+        cv::glob(join(path, expr), candidates);
+        CV_LOG_INFO(NULL, "VideoIO pluigins in " << path << ": " << candidates.size());
+        copy(candidates.begin(), candidates.end(), back_inserter(results));
+    }
+    CV_LOG_INFO(NULL, "Found " << results.size() << " plugin(s)");
+    return results;
+}
+
+cv::Ptr<cv::DynamicBackend> cv::DynamicBackend::load(cv::VideoCaptureAPIs api, int mode)
+{
+    for(const std::string & plugin : getPluginCandidates())
+    {
+        bool res = true;
+        Ptr<DynamicBackend> factory = makePtr<DynamicBackend>(plugin);
+        if (factory)
+            if (mode & cv::MODE_CAPTURE_BY_INDEX || mode & cv::MODE_CAPTURE_BY_FILENAME)
+            {
+                res = res && factory->canCreateCapture(api);
+            }
+        if (mode & cv::MODE_WRITER)
+        {
+            res = res && factory->canCreateWriter(api);
+        }
+        if (res)
+            return factory;
+    }
+    return 0;
+}
+
+//==================================================================================================
+// DynamicCapture
+
+class DynamicCapture : public cv::IVideoCapture
+{
+    const cv::DynamicBackend::CaptureTable * tbl;
+    void * capture;
+public:
+    DynamicCapture(const cv::DynamicBackend::CaptureTable * tbl_, const std::string &filename, int camera)
+        : tbl(tbl_), capture(0)
+    {
+        CV_Assert(!capture);
+        if (tbl->cv_open_capture)
+            tbl->cv_open_capture(filename.empty() ? 0 : filename.c_str(), camera, capture);
+    }
+    ~DynamicCapture()
+    {
+        if (capture)
+        {
+            CV_Assert(tbl->cv_release_capture);
+            tbl->cv_release_capture(capture);
+            capture = 0;
+        }
+    }
+    double getProperty(int prop) const CV_OVERRIDE
+    {
+        CV_Assert(capture);
+        double val = -1;
+        tbl->cv_get_cap_prop(capture, prop, val);
+        return val;
+    }
+    bool setProperty(int prop, double val) CV_OVERRIDE
+    {
+        CV_Assert(capture);
+        return tbl->cv_set_cap_prop(capture, prop, val);
+    }
+    bool grabFrame() CV_OVERRIDE
+    {
+        CV_Assert(capture);
+        return tbl->cv_grab(capture);
+    }
+    static bool local_retrieve(unsigned char * data, int step, int width, int height, int cn, void * userdata)
+    {
+        cv::Mat * img = static_cast<cv::Mat*>(userdata);
+        if (!img)
+            return false;
+        cv::Mat(cv::Size(width, height), CV_MAKETYPE(CV_8U, cn), data, step).copyTo(*img);
+        return true;
+    }
+    bool retrieveFrame(int idx, cv::OutputArray img) CV_OVERRIDE
+    {
+        CV_Assert(capture);
+        cv::Mat frame;
+        bool res = tbl->cv_retrieve(capture, idx, &local_retrieve, &frame);
+        if (res)
+            frame.copyTo(img);
+        return res;
+    }
+    bool isOpened() const CV_OVERRIDE
+    {
+        return capture != NULL;
+    }
+    int getCaptureDomain() CV_OVERRIDE
+    {
+        return tbl->cv_domain();
+    }
+};
+
+//==================================================================================================
+// DynamicWriter
+
+class DynamicWriter : public cv::IVideoWriter
+{
+    const cv::DynamicBackend::WriterTable * tbl;
+    void * writer;
+public:
+    DynamicWriter(const cv::DynamicBackend::WriterTable * tbl_, const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor)
+        : tbl(tbl_), writer(0)
+    {
+        CV_Assert(!writer);
+        if(tbl->cv_open_writer)
+            tbl->cv_open_writer(filename.empty() ? 0 : filename.c_str(), fourcc, fps, sz.width, sz.height, isColor, writer);
+    }
+    ~DynamicWriter()
+    {
+        if (writer)
+        {
+            CV_Assert(tbl->cv_release_writer);
+            tbl->cv_release_writer(writer);
+            writer = 0;
+        }
+    }
+    double getProperty(int prop) const CV_OVERRIDE
+    {
+        CV_Assert(writer);
+        double val = -1;
+        tbl->cv_get_wri_prop(writer, prop, val);
+        return val;
+    }
+    bool setProperty(int prop, double val) CV_OVERRIDE
+    {
+        CV_Assert(writer);
+        return tbl->cv_set_wri_prop(writer, prop, val);
+    }
+    bool isOpened() const CV_OVERRIDE
+    {
+        return writer != NULL;
+    }
+    void write(cv::InputArray arr) CV_OVERRIDE
+    {
+        cv::Mat img = arr.getMat();
+        CV_Assert(writer);
+        tbl->cv_write(writer, img.data, (int)img.step[0], img.cols, img.rows, img.channels());
+    }
+    int getCaptureDomain() const CV_OVERRIDE
+    {
+        return tbl->cv_domain();
+    }
+};
diff --git a/modules/videoio/src/backend.hpp b/modules/videoio/src/backend.hpp
new file mode 100644 (file)
index 0000000..251b4d3
--- /dev/null
@@ -0,0 +1,85 @@
+// 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 BACKEND_HPP_DEFINED
+#define BACKEND_HPP_DEFINED
+
+#include "cap_interface.hpp"
+#include "opencv2/videoio/registry.hpp"
+
+namespace cv {
+
+// TODO: move to public interface
+// TODO: allow runtime backend registration
+class IBackend
+{
+public:
+    Ptr<IVideoCapture> tryOpenCapture(const std::string & backendName, const std::string & filename, int cameraNum) const;
+    Ptr<IVideoWriter> tryOpenWriter(const std::string & backendName, const std::string& filename, int _fourcc, double fps, const Size &frameSize, bool isColor) const;
+protected:
+    virtual Ptr<IVideoCapture> createCapture(const std::string &filename, int camera) const = 0;
+    virtual Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const = 0;
+    virtual ~IBackend() {}
+};
+
+//==================================================================================================
+
+class StaticBackend : public IBackend
+{
+    typedef Ptr<IVideoCapture> (*OpenFileFun)(const std::string &);
+    typedef Ptr<IVideoCapture> (*OpenCamFun)(int);
+    typedef Ptr<IVideoWriter> (*OpenWriterFun)(const std::string&, int, double, const Size&, bool);
+private:
+    OpenFileFun FUN_FILE;
+    OpenCamFun FUN_CAM;
+    OpenWriterFun FUN_WRITE;
+public:
+    StaticBackend(OpenFileFun f1, OpenCamFun f2, OpenWriterFun f3)
+        : FUN_FILE(f1), FUN_CAM(f2), FUN_WRITE(f3)
+    {
+    }
+protected:
+    Ptr<IVideoCapture> createCapture(const std::string &filename, int camera) const CV_OVERRIDE
+    {
+        if (filename.empty() && FUN_CAM)
+            return FUN_CAM(camera);
+        if (FUN_FILE)
+            return FUN_FILE(filename);
+        return 0;
+    }
+    Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const Size &sz, bool isColor) const CV_OVERRIDE
+    {
+        if (FUN_WRITE)
+            return FUN_WRITE(filename, fourcc, fps, sz, isColor);
+        return 0;
+    }
+};
+
+//==================================================================================================
+
+class DynamicBackend : public IBackend
+{
+public:
+    class CaptureTable;
+    class WriterTable;
+    class DynamicLib;
+private:
+    DynamicLib * lib;
+    CaptureTable const * cap_tbl;
+    WriterTable const * wri_tbl;
+public:
+    DynamicBackend(const std::string &filename);
+    ~DynamicBackend();
+    static Ptr<DynamicBackend> load(VideoCaptureAPIs api, int mode);
+protected:
+    bool canCreateCapture(cv::VideoCaptureAPIs api) const;
+    bool canCreateWriter(VideoCaptureAPIs api) const;
+    Ptr<IVideoCapture> createCapture(const std::string &filename, int camera) const CV_OVERRIDE;
+    Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const CV_OVERRIDE;
+};
+
+} // cv::
+
+
+#endif // BACKEND_HPP_DEFINED
index 473609d..b229b4f 100644 (file)
@@ -68,9 +68,7 @@ VideoCapture::VideoCapture(int index, int apiPreference)
 VideoCapture::~VideoCapture()
 {
     CV_TRACE_FUNCTION();
-
     icap.release();
-    cap.release();
 }
 
 bool VideoCapture::open(const String& filename, int apiPreference)
@@ -79,32 +77,28 @@ bool VideoCapture::open(const String& filename, int apiPreference)
 
     if (isOpened()) release();
 
-    const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByFilename();
+    const std::vector<VideoCaptureAPIs> backends = cv::videoio_registry::getStreamBackends();
     for (size_t i = 0; i < backends.size(); i++)
     {
-        const VideoBackendInfo& info = backends[i];
-        if (apiPreference == CAP_ANY || apiPreference == info.id)
+        const VideoCaptureAPIs id = backends[i];
+        const std::string backendName = cv::videoio_registry::getBackendName(id);
+        if (apiPreference == CAP_ANY || apiPreference == id)
         {
-            CvCapture* capture = NULL;
-            VideoCapture_create(capture, icap, info.id, filename);
+            Ptr<IBackend> factory = VideoBackendRegistry::getInstance().getBackend(id);
+            if (factory)
+                icap = factory->tryOpenCapture(backendName, filename, 0);
             if (!icap.empty())
             {
                 if (icap->isOpened())
                     return true;
                 icap.release();
             }
-            if (capture)
-            {
-                cap.reset(capture);
-                // assume it is opened
-                return true;
-            }
         }
     }
     return false;
 }
 
-bool  VideoCapture::open(int cameraNum, int apiPreference)
+bool VideoCapture::open(int cameraNum, int apiPreference)
 {
     CV_TRACE_FUNCTION();
 
@@ -121,26 +115,22 @@ bool  VideoCapture::open(int cameraNum, int apiPreference)
         }
     }
 
-    const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByIndex();
+    const std::vector<VideoCaptureAPIs> backends = cv::videoio_registry::getCameraBackends();
     for (size_t i = 0; i < backends.size(); i++)
     {
-        const VideoBackendInfo& info = backends[i];
-        if (apiPreference == CAP_ANY || apiPreference == info.id)
+        const VideoCaptureAPIs id = backends[i];
+        const std::string backendName = cv::videoio_registry::getBackendName(id);
+        if (apiPreference == CAP_ANY || apiPreference == id)
         {
-            CvCapture* capture = NULL;
-            VideoCapture_create(capture, icap, info.id, cameraNum);
+            Ptr<IBackend> factory = VideoBackendRegistry::getInstance().getBackend(id);
+            if (factory)
+                icap = factory->tryOpenCapture(backendName, std::string(), cameraNum);
             if (!icap.empty())
             {
                 if (icap->isOpened())
                     return true;
                 icap.release();
             }
-            if (capture)
-            {
-                cap.reset(capture);
-                // assume it is opened
-                return true;
-            }
         }
     }
     return false;
@@ -148,9 +138,7 @@ bool  VideoCapture::open(int cameraNum, int apiPreference)
 
 bool VideoCapture::isOpened() const
 {
-    if (!icap.empty())
-        return icap->isOpened();
-    return !cap.empty();  // legacy interface doesn't support closed files
+    return !icap.empty() ? icap->isOpened() : false;
 }
 
 String VideoCapture::getBackendName() const
@@ -158,8 +146,6 @@ String VideoCapture::getBackendName() const
     int api = 0;
     if (icap)
         api = icap->isOpened() ? icap->getCaptureDomain() : 0;
-    else if (cap)
-        api = cap->getCaptureDomain();
     CV_Assert(api != 0);
     return cv::videoio_registry::getBackendName((VideoCaptureAPIs)api);
 }
@@ -168,39 +154,20 @@ void VideoCapture::release()
 {
     CV_TRACE_FUNCTION();
     icap.release();
-    cap.release();
 }
 
 bool VideoCapture::grab()
 {
     CV_INSTRUMENT_REGION();
-
-    if (!icap.empty())
-        return icap->grabFrame();
-    return cvGrabFrame(cap) != 0;
+    return !icap.empty() ? icap->grabFrame() : false;
 }
 
 bool VideoCapture::retrieve(OutputArray image, int channel)
 {
     CV_INSTRUMENT_REGION();
-
     if (!icap.empty())
         return icap->retrieveFrame(channel, image);
-
-    IplImage* _img = cvRetrieveFrame(cap, channel);
-    if( !_img )
-    {
-        image.release();
-        return false;
-    }
-    if(_img->origin == IPL_ORIGIN_TL)
-        cv::cvarrToMat(_img).copyTo(image);
-    else
-    {
-        Mat temp = cv::cvarrToMat(_img);
-        flip(temp, image, 0);
-    }
-    return true;
+    return false;
 }
 
 bool VideoCapture::read(OutputArray image)
@@ -253,10 +220,7 @@ VideoCapture& VideoCapture::operator >> (UMat& image)
 bool VideoCapture::set(int propId, double value)
 {
     CV_CheckNE(propId, (int)CAP_PROP_BACKEND, "Can't set read-only property");
-
-    if (!icap.empty())
-        return icap->setProperty(propId, value);
-    return cvSetCaptureProperty(cap, propId, value) != 0;
+    return !icap.empty() ? icap->setProperty(propId, value) : false;
 }
 
 double VideoCapture::get(int propId) const
@@ -266,15 +230,11 @@ double VideoCapture::get(int propId) const
         int api = 0;
         if (icap)
             api = icap->isOpened() ? icap->getCaptureDomain() : 0;
-        else if (cap)
-            api = cap->getCaptureDomain();
         if (api <= 0)
             return -1.0;
         return (double)api;
     }
-    if (!icap.empty())
-        return icap->getProperty(propId);
-    return cap ? cap->getProperty(propId) : 0;
+    return !icap.empty() ? icap->getProperty(propId) : 0;
 }
 
 
@@ -299,7 +259,6 @@ VideoWriter::VideoWriter(const String& filename, int apiPreference, int _fourcc,
 void VideoWriter::release()
 {
     iwriter.release();
-    writer.release();
 }
 
 VideoWriter::~VideoWriter()
@@ -318,26 +277,22 @@ bool VideoWriter::open(const String& filename, int apiPreference, int _fourcc, d
 
     if (isOpened()) release();
 
-    const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_Writer();
+    const std::vector<VideoCaptureAPIs> backends = cv::videoio_registry::getWriterBackends();
     for (size_t i = 0; i < backends.size(); i++)
     {
-        const VideoBackendInfo& info = backends[i];
-        if (apiPreference == CAP_ANY || apiPreference == info.id)
+        const VideoCaptureAPIs id = backends[i];
+        const std::string backendName = cv::videoio_registry::getBackendName(id);
+        if (apiPreference == CAP_ANY || apiPreference == id)
         {
-            CvVideoWriter* writer_ = NULL;
-            VideoWriter_create(writer_, iwriter, info.id, filename, _fourcc, fps, frameSize, isColor);
+            Ptr<IBackend> factory = VideoBackendRegistry::getInstance().getBackend(id);
+            if (factory)
+                iwriter = factory->tryOpenWriter(backendName, filename, _fourcc, fps, frameSize, isColor);
             if (!iwriter.empty())
             {
                 if (iwriter->isOpened())
                     return true;
                 iwriter.release();
             }
-            if (writer_)
-            {
-                // assume it is opened
-                writer.reset(writer_);
-                return true;
-            }
         }
     }
     return false;
@@ -345,7 +300,7 @@ bool VideoWriter::open(const String& filename, int apiPreference, int _fourcc, d
 
 bool VideoWriter::isOpened() const
 {
-    return !iwriter.empty() || !writer.empty();
+    return !iwriter.empty();
 }
 
 
@@ -365,8 +320,6 @@ double VideoWriter::get(int propId) const
         int api = 0;
         if (iwriter)
             api = iwriter->getCaptureDomain();
-        else if (writer)
-            api = writer->getCaptureDomain();
         if (api <= 0)
             return -1.0;
         return (double)api;
@@ -381,8 +334,6 @@ String VideoWriter::getBackendName() const
     int api = 0;
     if (iwriter)
         api = iwriter->getCaptureDomain();
-    else if (writer)
-        api = writer->getCaptureDomain();
     CV_Assert(api != 0);
     return cv::videoio_registry::getBackendName((VideoCaptureAPIs)api);
 }
@@ -393,11 +344,6 @@ void VideoWriter::write(InputArray image)
 
     if( iwriter )
         iwriter->write(image);
-    else
-    {
-        IplImage _img = cvIplImage(image.getMat());
-        cvWriteFrame(writer, &_img);
-    }
 }
 
 VideoWriter& VideoWriter::operator << (const Mat& image)
index 1d09826..6fa2895 100644 (file)
@@ -44,6 +44,7 @@
 //
 
 #include "precomp.hpp"
+#include "cap_interface.hpp"
 
 #ifdef HAVE_ARAVIS_API
 
@@ -606,12 +607,12 @@ bool CvCaptureCAM_Aravis::startCapture()
     return false;
 }
 
-CvCapture* cvCreateCameraCapture_Aravis( int index )
+cv::Ptr<cv::IVideoCapture> cv::create_Aravis_capture( int index )
 {
     CvCaptureCAM_Aravis* capture = new CvCaptureCAM_Aravis;
 
     if(capture->open(index)) {
-        return capture;
+        return cv::makePtr<cv::LegacyCapture>(capture);
     }
 
     delete capture;
index 372140e..7f0fa14 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "precomp.hpp"
 #include "opencv2/imgproc.hpp"
+#include "cap_interface.hpp"
 #include <iostream>
 #import <AVFoundation/AVFoundation.h>
 #import <Foundation/NSException.h>
@@ -197,28 +198,30 @@ class CvVideoWriter_AVFoundation : public CvVideoWriter{
 /****************** Implementation of interface functions ********************/
 
 
-CvCapture* cvCreateFileCapture_AVFoundation(const char* filename) {
-    CvCaptureFile *retval = new CvCaptureFile(filename);
-
+cv::Ptr<cv::IVideoCapture> cv::create_AVFoundation_capture_file(const std::string &filename)
+{
+    CvCaptureFile *retval = new CvCaptureFile(filename.c_str());
     if(retval->didStart())
-        return retval;
+        return makePtr<LegacyCapture>(retval);
     delete retval;
     return NULL;
-}
 
-CvCapture* cvCreateCameraCapture_AVFoundation(int index ) {
-
-    CvCapture* retval = new CvCaptureCAM(index);
-    if (!((CvCaptureCAM *)retval)->didStart())
-        cvReleaseCapture(&retval);
-    return retval;
+}
 
+cv::Ptr<cv::IVideoCapture> cv::create_AVFoundation_capture_cam(int index)
+{
+    CvCaptureCAM* retval = new CvCaptureCAM(index);
+    if (retval->didStart())
+        return cv::makePtr<cv::LegacyCapture>(retval);
+    delete retval;
+    return 0;
 }
 
-CvVideoWriter* cvCreateVideoWriter_AVFoundation(const char* filename, int fourcc,
-        double fps, CvSize frame_size,
-        int is_color) {
-    return new CvVideoWriter_AVFoundation(filename, fourcc, fps, frame_size,is_color);
+cv::Ptr<cv::IVideoWriter> cv::create_AVFoundation_writer(const std::string& filename, int fourcc, double fps, const cv::Size &frameSize, bool isColor)
+{
+    CvSize sz = { frameSize.width, frameSize.height };
+    CvVideoWriter_AVFoundation* wrt = new CvVideoWriter_AVFoundation(filename.c_str(), fourcc, fps, sz, isColor);
+    return cv::makePtr<cv::LegacyWriter>(wrt);
 }
 
 /********************** Implementation of Classes ****************************/
index 621e3b1..f68316c 100644 (file)
@@ -208,27 +208,30 @@ class CvVideoWriter_AVFoundation : public CvVideoWriter {
 
 /****************** Implementation of interface functions ********************/
 
-
-CvCapture* cvCreateFileCapture_AVFoundation(const char* filename) {
-    CvCaptureFile *retval = new CvCaptureFile(filename);
-
+cv::Ptr<cv::IVideoCapture> cv::create_AVFoundation_capture_file(const std::string &filename)
+{
+    CvCaptureFile *retval = new CvCaptureFile(filename.c_str());
     if(retval->didStart())
-        return retval;
+        return makePtr<LegacyCapture>(retval);
     delete retval;
     return NULL;
+
 }
 
-CvCapture* cvCreateCameraCapture_AVFoundation(int index ) {
-    CvCapture* retval = new CvCaptureCAM(index);
-    if (!((CvCaptureCAM *)retval)->didStart())
-        cvReleaseCapture(&retval);
-    return retval;
+cv::Ptr<cv::IVideoCapture> cv::create_AVFoundation_capture_cam(int index)
+{
+    CvCaptureCAM* retval = new CvCaptureCAM(index);
+    if (retval->didStart())
+        return cv::makePtr<cv::LegacyCapture>(retval);
+    delete retval;
+    return 0;
 }
 
-CvVideoWriter* cvCreateVideoWriter_AVFoundation(const char* filename, int fourcc,
-                                     double fps, CvSize frame_size,
-                                     int is_color) {
-    return new CvVideoWriter_AVFoundation(filename, fourcc, fps, frame_size,is_color);
+cv::Ptr<cv::IVideoWriter> cv::create_AVFoundation_writer(const std::string& filename, int fourcc, double fps, const cv::Size &frameSize, bool isColor)
+{
+    CvSize sz = { frameSize.width, frameSize.height };
+    CvVideoWriter_AVFoundation* wrt = new CvVideoWriter_AVFoundation(filename.c_str(), fourcc, fps, sz, isColor);
+    return cv::makePtr<cv::LegacyWriter>(wrt);
 }
 
 /********************** Implementation of Classes ****************************/
index 000dcf9..f79d472 100644 (file)
@@ -40,6 +40,7 @@
 //M*/
 
 #include "precomp.hpp"
+#include "cap_interface.hpp"
 
 #ifdef HAVE_DC1394_2
 
@@ -797,13 +798,11 @@ bool CvCaptureCAM_DC1394_v2_CPP::setProperty(int propId, double value)
 }
 
 
-CvCapture* cvCreateCameraCapture_DC1394_2(int index)
+cv::Ptr<cv::IVideoCapture> cv::create_DC1394_capture(int index)
 {
     CvCaptureCAM_DC1394_v2_CPP* capture = new CvCaptureCAM_DC1394_v2_CPP;
-
     if (capture->open(index))
-        return capture;
-
+        return cv::makePtr<cv::LegacyCapture>(capture);
     delete capture;
     return 0;
 }
index 7087185..8aba42a 100644 (file)
@@ -3580,6 +3580,12 @@ void VideoCapture_DShow::close()
     m_widthSet = m_heightSet = m_width = m_height = -1;
 }
 
+Ptr<IVideoCapture> create_DShow_capture(int index)
+{
+    return makePtr<VideoCapture_DShow>(index);
+}
+
+
 }
 
 #endif
index f5bf80c..edb694e 100644 (file)
@@ -43,4 +43,4 @@ protected:
 }
 
 #endif //HAVE_DSHOW
-#endif //_CAP_DSHOW_HPP_
\ No newline at end of file
+#endif //_CAP_DSHOW_HPP_
index df7e446..136cc21 100644 (file)
@@ -266,7 +266,7 @@ protected:
 
 } // namespace
 
-cv::Ptr<cv::IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const cv::String& filename)
+cv::Ptr<cv::IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const std::string &filename)
 {
 #if defined(HAVE_FFMPEG_WRAPPER)
     icvInitFFMPEG::Init();
@@ -328,8 +328,7 @@ protected:
 
 } // namespace
 
-cv::Ptr<cv::IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const cv::String& filename, int fourcc,
-                                                           double fps, cv::Size frameSize, int 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();
@@ -345,3 +344,169 @@ cv::Ptr<cv::IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const cv::String& fil
 } // namespace
 
 #endif // defined(HAVE_FFMPEG)
+
+//==================================================================================================
+
+#if defined(BUILD_PLUGIN)
+
+#include "plugin_api.hpp"
+
+CV_EXTERN_C int cv_domain()
+{
+    return cv::CAP_FFMPEG;
+}
+
+CV_EXTERN_C bool cv_open_capture(const char * filename, int, void * &handle)
+{
+    if (!filename)
+        return false;
+    cv::CvCapture_FFMPEG_proxy *cap = 0;
+    try
+    {
+        cap = new cv::CvCapture_FFMPEG_proxy(filename);
+        if (cap->isOpened())
+        {
+            handle = cap;
+            return true;
+        }
+    }
+    catch (...)
+    {
+    }
+    if (cap)
+        delete cap;
+    return false;
+}
+
+CV_EXTERN_C bool cv_get_cap_prop(void * handle, int prop, double & val)
+{
+    if (!handle)
+        return false;
+    try
+    {
+        cv::CvCapture_FFMPEG_proxy *instance = static_cast<cv::CvCapture_FFMPEG_proxy*>(handle);
+        val = instance->getProperty(prop);
+        return true;
+    }
+    catch (...)
+    {
+        return false;
+    }
+}
+
+CV_EXTERN_C bool cv_set_cap_prop(void * handle, int prop, double val)
+{
+    if (!handle)
+        return false;
+    try
+    {
+        cv::CvCapture_FFMPEG_proxy *instance = static_cast<cv::CvCapture_FFMPEG_proxy*>(handle);
+        return instance->setProperty(prop, val);
+    }
+    catch(...)
+    {
+        return false;
+    }
+}
+
+CV_EXTERN_C bool cv_grab(void * handle)
+{
+    if (!handle)
+        return false;
+    try
+    {
+        cv::CvCapture_FFMPEG_proxy *instance = static_cast<cv::CvCapture_FFMPEG_proxy*>(handle);
+        return instance->grabFrame();
+    }
+    catch(...)
+    {
+        return false;
+    }
+}
+
+CV_EXTERN_C bool cv_retrieve(void * handle, int idx, cv_retrieve_cb_t * callback, void * userdata)
+{
+    if (!handle)
+        return false;
+    try
+    {
+        cv::CvCapture_FFMPEG_proxy *instance = static_cast<cv::CvCapture_FFMPEG_proxy*>(handle);
+        cv::Mat img;
+        // TODO: avoid unnecessary copying
+        if (instance->retrieveFrame(idx, img))
+            return callback(img.data, img.step, img.cols, img.rows, img.channels(), userdata);
+        return false;
+    }
+    catch(...)
+    {
+        return false;
+    }
+}
+
+CV_EXTERN_C bool cv_release_capture(void * handle)
+{
+    if (!handle)
+        return false;
+    cv::CvCapture_FFMPEG_proxy *instance = static_cast<cv::CvCapture_FFMPEG_proxy*>(handle);
+    delete instance;
+    return true;
+}
+
+CV_EXTERN_C bool cv_open_writer(const char * filename, int fourcc, double fps, int width, int height, int isColor, void * &handle)
+{
+    cv::Size sz(width, height);
+    cv::CvVideoWriter_FFMPEG_proxy* wrt = 0;
+    try
+    {
+        wrt = new cv::CvVideoWriter_FFMPEG_proxy(filename, fourcc, fps, sz, isColor != 0);
+        if(wrt && wrt->isOpened())
+        {
+            handle = wrt;
+            return true;
+        }
+    }
+    catch(...)
+    {
+    }
+    if (wrt)
+        delete wrt;
+    return false;
+}
+
+CV_EXTERN_C bool cv_get_wri_prop(void*, int, double&)
+{
+    return false;
+}
+
+CV_EXTERN_C bool cv_set_wri_prop(void*, int, double)
+{
+    return false;
+}
+
+CV_EXTERN_C bool cv_write(void * handle, const unsigned char * data, int step, int width, int height, int cn)
+{
+    if (!handle)
+        return false;
+    try
+    {
+        cv::CvVideoWriter_FFMPEG_proxy * instance = static_cast<cv::CvVideoWriter_FFMPEG_proxy*>(handle);
+        cv::Mat img(cv::Size(width, height), CV_MAKETYPE(CV_8U, cn), const_cast<uchar*>(data), step);
+        instance->write(img);
+        return true;
+    }
+    catch(...)
+    {
+        return false;
+    }
+}
+
+CV_EXTERN_C bool cv_release_writer(void * handle)
+{
+    if (!handle)
+        return false;
+    cv::CvVideoWriter_FFMPEG_proxy * instance = static_cast<cv::CvVideoWriter_FFMPEG_proxy*>(handle);
+    delete instance;
+    return true;
+}
+
+#endif // BUILD_PLUGIN
index 17fc67e..0d360ad 100644 (file)
@@ -785,7 +785,6 @@ static int LockCallBack(void **mutex, AVLockOp op)
 }
 
 static ImplMutex _mutex;
-static bool _initialized = false;
 
 class AutoLock
 {
@@ -814,49 +813,45 @@ static void ffmpeg_log_callback(void *ptr, int level, const char *fmt, va_list v
 class InternalFFMpegRegister
 {
 public:
-    InternalFFMpegRegister()
+    static void init()
     {
         AutoLock lock(_mutex);
-        if (!_initialized)
-        {
-    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0)
-            avformat_network_init();
-    #endif
+        static InternalFFMpegRegister instance;
+    }
+    InternalFFMpegRegister()
+    {
+#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0)
+        avformat_network_init();
+#endif
 
-            /* register all codecs, demux and protocols */
-            av_register_all();
+        /* register all codecs, demux and protocols */
+        av_register_all();
 
-            /* register a callback function for synchronization */
-            av_lockmgr_register(&LockCallBack);
+        /* register a callback function for synchronization */
+        av_lockmgr_register(&LockCallBack);
 
 #ifndef NO_GETENV
-            char* debug_option = getenv("OPENCV_FFMPEG_DEBUG");
-            if (debug_option != NULL)
-            {
-                av_log_set_level(AV_LOG_VERBOSE);
-                av_log_set_callback(ffmpeg_log_callback);
-            }
-            else
+        char* debug_option = getenv("OPENCV_FFMPEG_DEBUG");
+        if (debug_option != NULL)
+        {
+            av_log_set_level(AV_LOG_VERBOSE);
+            av_log_set_callback(ffmpeg_log_callback);
+        }
+        else
 #endif
-            {
-                av_log_set_level(AV_LOG_ERROR);
-            }
-
-            _initialized = true;
+        {
+            av_log_set_level(AV_LOG_ERROR);
         }
     }
-
     ~InternalFFMpegRegister()
     {
-        _initialized = false;
         av_lockmgr_register(NULL);
     }
 };
 
-static InternalFFMpegRegister _init;
-
 bool CvCapture_FFMPEG::open( const char* _filename )
 {
+    InternalFFMpegRegister::init();
     AutoLock lock(_mutex);
     unsigned i;
     bool valid = false;
@@ -1997,6 +1992,7 @@ static inline void cv_ff_codec_tag_dump(const AVCodecTag *const *tags)
 bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
                                  double fps, int width, int height, bool is_color )
 {
+    InternalFFMpegRegister::init();
     CV_CODEC_ID codec_id = CV_CODEC(CODEC_ID_NONE);
     int err, codec_pix_fmt;
     double bitrate_scale = 1;
index 300a46a..40fcdc4 100644 (file)
@@ -1207,7 +1207,7 @@ Ptr<IVideoCapture> createGPhoto2Capture(int index)
  *
  * @param deviceName is a substring in digital camera model name.
  */
-Ptr<IVideoCapture> createGPhoto2Capture(const String & deviceName)
+Ptr<IVideoCapture> createGPhoto2Capture(const std::string & deviceName)
 {
     Ptr<IVideoCapture> capture = makePtr<gphoto2::DigitalCameraCapture>(deviceName);
 
index a525535..1886653 100644 (file)
@@ -71,7 +71,7 @@ using namespace std;
 #ifdef NDEBUG
 #define CV_WARN(message)
 #else
-#define CV_WARN(message) fprintf(stderr, "OpenCV | GStreamer warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
+#define CV_WARN(message) CV_LOG_WARNING(0, message)
 #endif
 
 #define COLOR_ELEM "videoconvert"
@@ -232,7 +232,7 @@ GStreamerCapture::~GStreamerCapture()
  */
 bool GStreamerCapture::grabFrame()
 {
-    if(!pipeline)
+    if(!GST_IS_ELEMENT(pipeline))
         return false;
 
     // start the pipeline if it was not in playing state yet
@@ -372,6 +372,11 @@ bool GStreamerCapture::determineFrameDims(Size &sz)
  */
 bool GStreamerCapture::isPipelinePlaying()
 {
+    if (!GST_IS_ELEMENT(pipeline))
+    {
+        CV_WARN("GStreamer: pipeline have not been created");
+        return false;
+    }
     GstState current, pending;
     GstClockTime timeout = 5*GST_SECOND;
     GstStateChangeReturn ret = gst_element_get_state(pipeline, &current, &pending, timeout);
@@ -389,8 +394,12 @@ bool GStreamerCapture::isPipelinePlaying()
  */
 void GStreamerCapture::startPipeline()
 {
-    //fprintf(stderr, "relinked, pausing\n");
-    GstStateChangeReturn status = gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING);
+    if (!GST_IS_ELEMENT(pipeline))
+    {
+        CV_WARN("GStreamer: pipeline have not been created");
+        return;
+    }
+    GstStateChangeReturn status = gst_element_set_state(pipeline, GST_STATE_PLAYING);
     if (status == GST_STATE_CHANGE_ASYNC)
     {
         // wait for status update
@@ -408,7 +417,6 @@ void GStreamerCapture::startPipeline()
     if (isPosFramesEmulated)
         emulatedFrameNumber = 0;
 
-    //printf("state now playing\n");
     handleMessage(pipeline);
 }
 
@@ -418,8 +426,12 @@ void GStreamerCapture::startPipeline()
  */
 void GStreamerCapture::stopPipeline()
 {
-    //fprintf(stderr, "restarting pipeline, going to ready\n");
-    if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL) == GST_STATE_CHANGE_FAILURE)
+    if (!GST_IS_ELEMENT(pipeline))
+    {
+        CV_WARN("GStreamer: pipeline have not been created");
+        return;
+    }
+    if(gst_element_set_state(pipeline, GST_STATE_NULL) == GST_STATE_CHANGE_FAILURE)
     {
         CV_WARN("GStreamer: unable to stop pipeline");
         gst_object_unref(pipeline);
@@ -449,7 +461,6 @@ void GStreamerCapture::restartPipeline()
  */
 void GStreamerCapture::setFilter(const char *prop, int type, int v1, int v2)
 {
-    //printf("GStreamer: setFilter \n");
     if(!caps || !( GST_IS_CAPS (caps) ))
     {
         if(type == G_TYPE_INT)
@@ -475,7 +486,6 @@ void GStreamerCapture::setFilter(const char *prop, int type, int v1, int v2)
     caps = gst_caps_fixate(caps);
 
     gst_app_sink_set_caps(GST_APP_SINK(sink), caps);
-    //printf("filtering with %s\n", gst_caps_to_string(caps));
 }
 
 /*!
@@ -511,7 +521,6 @@ void GStreamerCapture::newPad(GstElement *, GstPad *pad, gpointer data)
 
     sinkpad = gst_element_get_static_pad (color, "sink");
     if (!sinkpad){
-        //fprintf(stderr, "Gstreamer: no pad named sink\n");
         return;
     }
 
@@ -622,7 +631,7 @@ bool GStreamerCapture::open(const String &filename_)
             uridecodebin = gst_parse_launch(filename, &err);
             if(!uridecodebin)
             {
-                fprintf(stderr, "GStreamer: Error opening bin: %s\n", err->message);
+                CV_WARN("GStreamer: Error opening bin: " << err->message);
                 return false;
             }
             //stream = true;
@@ -835,11 +844,11 @@ bool GStreamerCapture::open(const String &filename_)
             gboolean status_;
 
             format_ = GST_FORMAT_DEFAULT;
+
             status_ = gst_element_query_position(sink, format_, &value_);
             if (!status_ || value_ != 0 || duration < 0)
             {
-                CV_WARN(cv::format("Cannot query video position: status=%d value=%lld duration=%lld\n",
-                                   (int)status_, (long long int)value_, (long long int)duration).c_str());
+                CV_WARN("Cannot query video position: status=" << status_ << ", value=" << value_ << ", duration=" << duration);
                 isPosFramesSupported = false;
                 isPosFramesEmulated = true;
                 emulatedFrameNumber = 0;
@@ -1099,7 +1108,7 @@ bool GStreamerCapture::setProperty(int propId, double value)
 }
 
 
-Ptr<IVideoCapture> cv::createGStreamerCapture(const String& filename)
+Ptr<IVideoCapture> cv::createGStreamerCapture_file(const String& filename)
 {
     Ptr<GStreamerCapture> cap = makePtr<GStreamerCapture>();
     if (cap && cap->open(filename))
@@ -1107,7 +1116,7 @@ Ptr<IVideoCapture> cv::createGStreamerCapture(const String& filename)
     return Ptr<IVideoCapture>();
 }
 
-Ptr<IVideoCapture> cv::createGStreamerCapture(int index)
+Ptr<IVideoCapture> cv::createGStreamerCapture_cam(int index)
 {
     Ptr<GStreamerCapture> cap = makePtr<GStreamerCapture>();
     if (cap && cap->open(index))
@@ -1133,10 +1142,10 @@ public:
 
     int getCaptureDomain() const CV_OVERRIDE { return cv::CAP_GSTREAMER; }
 
-    virtual bool open( const char* filename, int fourcc,
-                       double fps, CvSize frameSize, bool isColor );
-    virtual void close();
-    virtual bool writeFrame( const IplImage* image ) CV_OVERRIDE;
+    bool open(const char* filename, int fourcc,
+                       double fps, const Size &frameSize, bool isColor );
+    void close();
+    bool writeFrame( const IplImage* image ) CV_OVERRIDE;
 protected:
     const char* filenameToMimetype(const char* filename);
     GstElement* pipeline;
@@ -1272,7 +1281,7 @@ const char* CvVideoWriter_GStreamer::filenameToMimetype(const char *filename)
  *
  */
 bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc,
-                                    double fps, CvSize frameSize, bool is_color )
+                                    double fps, const cv::Size &frameSize, bool is_color )
 {
     // check arguments
     assert (filename);
@@ -1532,22 +1541,11 @@ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
     return true;
 }
 
-/*!
- * \brief cvCreateVideoWriter_GStreamer
- * \param filename
- * \param fourcc
- * \param fps
- * \param frameSize
- * \param isColor
- * \return
- * Constructor
- */
-CvVideoWriter* cvCreateVideoWriter_GStreamer(const char* filename, int fourcc, double fps,
-                                             CvSize frameSize, int isColor )
+Ptr<IVideoWriter> cv::create_GStreamer_writer(const std::string& filename, int fourcc, double fps, const cv::Size &frameSize, bool isColor)
 {
     CvVideoWriter_GStreamer* wrt = new CvVideoWriter_GStreamer;
-    if( wrt->open(filename, fourcc, fps,frameSize, isColor))
-        return wrt;
+    if (wrt->open(filename.c_str(), fourcc, fps, frameSize, isColor))
+        return makePtr<LegacyWriter>(wrt);
 
     delete wrt;
     return 0;
@@ -1593,8 +1591,6 @@ void handleMessage(GstElement * pipeline)
     while(gst_bus_have_pending(bus)) {
         msg = gst_bus_pop(bus);
 
-        //printf("\t\tGot %s message\n", GST_MESSAGE_TYPE_NAME(msg));
-
         if(gst_is_missing_plugin_message(msg))
         {
             CV_WARN("your gstreamer installation is missing a required plugin\n");
@@ -1605,30 +1601,19 @@ void handleMessage(GstElement * pipeline)
             case GST_MESSAGE_STATE_CHANGED:
                 GstState oldstate, newstate, pendstate;
                 gst_message_parse_state_changed(msg, &oldstate, &newstate, &pendstate);
-                //fprintf(stderr, "\t\t%s: state changed from %s to %s (pending: %s)\n",
-                //                gst_element_get_name(GST_MESSAGE_SRC (msg)),
-                //                gst_element_state_get_name(oldstate),
-                //                gst_element_state_get_name(newstate), gst_element_state_get_name(pendstate));
                 break;
             case GST_MESSAGE_ERROR:
                 gst_message_parse_error(msg, &err, &debug);
-                //fprintf(stderr, "\t\tGStreamer Plugin: Embedded video playback halted; module %s reported: %s\n",
-                //                gst_element_get_name(GST_MESSAGE_SRC (msg)), err->message);
-
                 g_error_free(err);
                 g_free(debug);
-
                 gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
                 break;
             case GST_MESSAGE_EOS:
-                //fprintf(stderr, "\t\treached the end of the stream.");
                 break;
             case GST_MESSAGE_STREAM_STATUS:
                 gst_message_parse_stream_status(msg,&tp,&elem);
-                //fprintf(stderr, "\t\tstream status: elem %s, %i\n", GST_ELEMENT_NAME(elem), tp);
                 break;
             default:
-                //fprintf(stderr, "\t\tunhandled message %s\n",GST_MESSAGE_TYPE_NAME(msg));
                 break;
             }
         }
@@ -1637,3 +1622,174 @@ void handleMessage(GstElement * pipeline)
 
     gst_object_unref(GST_OBJECT(bus));
 }
+
+//==================================================================================================
+
+#if defined(BUILD_PLUGIN)
+
+#include "plugin_api.hpp"
+
+CV_EXTERN_C int cv_domain()
+{
+    return cv::CAP_GSTREAMER;
+}
+
+CV_EXTERN_C bool cv_open_capture(const char * filename, int camera_index, void * &handle)
+{
+    GStreamerCapture *cap = 0;
+    try
+    {
+        cap = new GStreamerCapture();
+        bool res;
+        if (filename)
+            res = cap->open(string(filename));
+        else
+            res = cap->open(camera_index);
+        if (res)
+        {
+            handle = cap;
+            return true;
+        }
+    }
+    catch (...)
+    {
+    }
+    if (cap)
+        delete cap;
+    return false;
+}
+
+CV_EXTERN_C bool cv_get_cap_prop(void * handle, int prop, double & val)
+{
+    if (!handle)
+        return false;
+    try
+    {
+        GStreamerCapture * instance = static_cast<GStreamerCapture*>(handle);
+        val = instance->getProperty(prop);
+        return true;
+    }
+    catch(...)
+    {
+        return false;
+    }
+}
+
+CV_EXTERN_C bool cv_set_cap_prop(void * handle, int prop, double val)
+{
+    if (!handle)
+        return false;
+    try
+    {
+        GStreamerCapture * instance = static_cast<GStreamerCapture*>(handle);
+        return instance->setProperty(prop, val);
+    }
+    catch(...)
+    {
+        return false;
+    }
+}
+
+CV_EXTERN_C bool cv_grab(void * handle)
+{
+    if (!handle)
+        return false;
+    try
+    {
+        GStreamerCapture * instance = static_cast<GStreamerCapture*>(handle);
+        return instance->grabFrame();
+    }
+    catch(...)
+    {
+        return false;
+    }
+}
+
+CV_EXTERN_C bool cv_retrieve(void * handle, int idx, cv_retrieve_cb_t * callback, void * userdata)
+{
+    if (!handle)
+        return false;
+    try
+    {
+        GStreamerCapture * instance = static_cast<GStreamerCapture*>(handle);
+        Mat img;
+        // TODO: avoid unnecessary copying - implement lower level GStreamerCapture::retrieve
+        if (instance->retrieveFrame(idx, img))
+            return callback(img.data, img.step, img.cols, img.rows, img.channels(), userdata);
+        return false;
+    }
+    catch(...)
+    {
+        return false;
+    }
+}
+
+CV_EXTERN_C bool cv_release_capture(void * handle)
+{
+    if (!handle)
+        return false;
+    GStreamerCapture * instance = static_cast<GStreamerCapture*>(handle);
+    delete instance;
+    return true;
+}
+
+CV_EXTERN_C bool cv_open_writer(const char * filename, int fourcc, double fps, int width, int height, int isColor, void * &handle)
+{
+    CvVideoWriter_GStreamer* wrt = 0;
+    try
+    {
+        wrt = new CvVideoWriter_GStreamer();
+        CvSize sz = { width, height };
+        if(wrt && wrt->open(filename, fourcc, fps, sz, isColor))
+        {
+            handle = wrt;
+            return true;
+        }
+    }
+    catch(...)
+    {
+    }
+    if (wrt)
+        delete wrt;
+    return false;
+}
+
+CV_EXTERN_C bool cv_get_wri_prop(void*, int, double&)
+{
+    return false;
+}
+
+CV_EXTERN_C bool cv_set_wri_prop(void*, int, double)
+{
+    return false;
+}
+
+CV_EXTERN_C bool cv_write(void * handle, const unsigned char * data, int step, int width, int height, int cn)
+{
+    if (!handle)
+        return false;
+    try
+    {
+        CvVideoWriter_GStreamer * instance = static_cast<CvVideoWriter_GStreamer*>(handle);
+        CvSize sz = { width, height };
+        IplImage img;
+        cvInitImageHeader(&img, sz, IPL_DEPTH_8U, cn);
+        cvSetData(&img, const_cast<unsigned char*>(data), step);
+        return instance->writeFrame(&img);
+    }
+    catch(...)
+    {
+        return false;
+    }
+}
+
+CV_EXTERN_C bool cv_release_writer(void * handle)
+{
+    if (!handle)
+        return false;
+    CvVideoWriter_GStreamer * instance = static_cast<CvVideoWriter_GStreamer*>(handle);
+    delete instance;
+    return true;
+}
+
+#endif // BUILD_PLUGIN
index f0ac734..f6f603d 100644 (file)
@@ -315,14 +315,9 @@ bool CvCapture_Images::isOpened() const
     return !filename.empty();
 }
 
-Ptr<IVideoCapture> createFileCapture_Images(const String& filename)
+Ptr<IVideoCapture> create_Images_capture(const std::string &filename)
 {
-    Ptr<IVideoCapture> capture(new CvCapture_Images(filename));
-    if( capture->isOpened() )
-        return capture;
-    return Ptr<IVideoCapture>();
-}
-
+    return makePtr<CvCapture_Images>(filename);
 }
 
 //
@@ -410,14 +405,15 @@ bool CvVideoWriter_Images::setProperty( int id, double value )
     return false; // not supported
 }
 
-
-CvVideoWriter* cvCreateVideoWriter_Images( const char* filename )
+Ptr<IVideoWriter> create_Images_writer(const std::string &filename, int, double, const Size &, bool)
 {
     CvVideoWriter_Images *writer = new CvVideoWriter_Images;
 
-    if( writer->open( filename ))
-        return writer;
+    if( writer->open( filename.c_str() ))
+        return makePtr<LegacyWriter>(writer);
 
     delete writer;
     return 0;
 }
+
+} // cv::
diff --git a/modules/videoio/src/cap_interface.hpp b/modules/videoio/src/cap_interface.hpp
new file mode 100644 (file)
index 0000000..dc92039
--- /dev/null
@@ -0,0 +1,211 @@
+// 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 CAP_INTERFACE_HPP
+#define CAP_INTERFACE_HPP
+
+#include "opencv2/core.hpp"
+#include "opencv2/core/core_c.h"
+#include "opencv2/videoio.hpp"
+#include "opencv2/videoio/videoio_c.h"
+
+//===================================================
+
+// Legacy structs
+
+struct CvCapture
+{
+    virtual ~CvCapture() {}
+    virtual double getProperty(int) const { return 0; }
+    virtual bool setProperty(int, double) { return 0; }
+    virtual bool grabFrame() { return true; }
+    virtual IplImage* retrieveFrame(int) { return 0; }
+    virtual int getCaptureDomain() { return cv::CAP_ANY; } // Return the type of the capture object: CAP_DSHOW, etc...
+};
+
+struct CvVideoWriter
+{
+    virtual ~CvVideoWriter() {}
+    virtual bool writeFrame(const IplImage*) { return false; }
+    virtual int getCaptureDomain() const { return cv::CAP_ANY; } // Return the type of the capture object: CAP_FFMPEG, etc...
+};
+
+//===================================================
+
+// Modern classes
+
+namespace cv
+{
+
+class IVideoCapture
+{
+public:
+    virtual ~IVideoCapture() {}
+    virtual double getProperty(int) const { return 0; }
+    virtual bool setProperty(int, double) { return false; }
+    virtual bool grabFrame() = 0;
+    virtual bool retrieveFrame(int, OutputArray) = 0;
+    virtual bool isOpened() const = 0;
+    virtual int getCaptureDomain() { return CAP_ANY; } // Return the type of the capture object: CAP_DSHOW, etc...
+};
+
+class IVideoWriter
+{
+public:
+    virtual ~IVideoWriter() {}
+    virtual double getProperty(int) const { return 0; }
+    virtual bool setProperty(int, double) { return false; }
+    virtual bool isOpened() const = 0;
+    virtual void write(InputArray) = 0;
+    virtual int getCaptureDomain() const { return cv::CAP_ANY; } // Return the type of the capture object: CAP_FFMPEG, etc...
+};
+
+//===================================================
+
+// Wrapper
+
+class LegacyCapture : public IVideoCapture
+{
+private:
+    CvCapture * cap;
+    LegacyCapture(const LegacyCapture &);
+    LegacyCapture& operator=(const LegacyCapture &);
+public:
+    LegacyCapture(CvCapture * cap_) : cap(cap_) {}
+    ~LegacyCapture()
+    {
+        cvReleaseCapture(&cap);
+    }
+    double getProperty(int propId) const CV_OVERRIDE
+    {
+        return cap ? cap->getProperty(propId) : 0;
+    }
+    bool setProperty(int propId, double value) CV_OVERRIDE
+    {
+        return cvSetCaptureProperty(cap, propId, value) != 0;
+    }
+    bool grabFrame() CV_OVERRIDE
+    {
+        return cap ? cvGrabFrame(cap) != 0 : false;
+    }
+    bool retrieveFrame(int channel, OutputArray image) CV_OVERRIDE
+    {
+        IplImage* _img = cvRetrieveFrame(cap, channel);
+        if( !_img )
+        {
+            image.release();
+            return false;
+        }
+        if(_img->origin == IPL_ORIGIN_TL)
+        {
+            cv::cvarrToMat(_img).copyTo(image);
+        }
+        else
+        {
+            Mat temp = cv::cvarrToMat(_img);
+            flip(temp, image, 0);
+        }
+        return true;
+    }
+    bool isOpened() const CV_OVERRIDE
+    {
+        return cap != 0;  // legacy interface doesn't support closed files
+    }
+    int getCaptureDomain() CV_OVERRIDE
+    {
+        return cap ? cap->getCaptureDomain() : 0;
+    }
+};
+
+class LegacyWriter : public IVideoWriter
+{
+private:
+    CvVideoWriter * writer;
+    LegacyWriter(const LegacyWriter &);
+    LegacyWriter& operator=(const LegacyWriter &);
+public:
+    LegacyWriter(CvVideoWriter * wri_) : writer(wri_)
+    {}
+    ~LegacyWriter()
+    {
+        cvReleaseVideoWriter(&writer);
+    }
+    double getProperty(int) const CV_OVERRIDE
+    {
+        return 0.;
+    }
+    bool setProperty(int, double) CV_OVERRIDE
+    {
+        return false;
+    }
+    bool isOpened() const CV_OVERRIDE
+    {
+        return writer != NULL;
+    }
+    void write(InputArray image) CV_OVERRIDE
+    {
+        IplImage _img = cvIplImage(image.getMat());
+        cvWriteFrame(writer, &_img);
+    }
+    int getCaptureDomain() const CV_OVERRIDE
+    {
+        return writer ? writer->getCaptureDomain() : 0;
+    }
+};
+
+//==================================================================================================
+
+Ptr<IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const std::string &filename);
+Ptr<IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const std::string& filename, int fourcc, double fps, const Size &frameSize, bool isColor);
+
+Ptr<IVideoCapture> createGStreamerCapture_file(const std::string& filename);
+Ptr<IVideoCapture> createGStreamerCapture_cam(int index);
+Ptr<IVideoWriter> create_GStreamer_writer(const std::string& filename, int fourcc, double fps, const Size &frameSize, bool isColor);
+
+Ptr<IVideoCapture> create_MFX_capture(const std::string &filename);
+Ptr<IVideoWriter> create_MFX_writer(const std::string &filename, int _fourcc, double fps, const Size &frameSize, bool isColor);
+
+Ptr<IVideoCapture> create_AVFoundation_capture_file(const std::string &filename);
+Ptr<IVideoCapture> create_AVFoundation_capture_cam(int index);
+Ptr<IVideoWriter> create_AVFoundation_writer(const std::string& filename, int fourcc, double fps, const Size &frameSize, bool isColor);
+
+Ptr<IVideoCapture> create_WRT_capture(int device);
+
+Ptr<IVideoCapture> cvCreateCapture_MSMF(int index);
+Ptr<IVideoCapture> cvCreateCapture_MSMF(const std::string& filename);
+Ptr<IVideoWriter> cvCreateVideoWriter_MSMF(const std::string& filename, int fourcc, double fps, const Size &frameSize, bool is_color);
+
+Ptr<IVideoCapture> create_DShow_capture(int index);
+
+Ptr<IVideoCapture> create_V4L_capture_cam(int index);
+Ptr<IVideoCapture> create_V4L_capture_file(const std::string &filename);
+
+Ptr<IVideoCapture> create_OpenNI2_capture_cam( int index );
+Ptr<IVideoCapture> create_OpenNI2_capture_file( const std::string &filename );
+
+Ptr<IVideoCapture> create_Images_capture(const std::string &filename);
+Ptr<IVideoWriter> create_Images_writer(const std::string &filename, int fourcc, double fps, const Size &frameSize, bool iscolor);
+
+Ptr<IVideoCapture> create_DC1394_capture(int index);
+
+Ptr<IVideoCapture> create_RealSense_capture(int index);
+
+Ptr<IVideoCapture> create_PvAPI_capture( int index );
+
+Ptr<IVideoCapture> create_XIMEA_capture_cam( int index );
+Ptr<IVideoCapture> create_XIMEA_capture_file( const std::string &serialNumber );
+
+Ptr<IVideoCapture> create_Aravis_capture( int index );
+
+Ptr<IVideoCapture> createMotionJpegCapture(const std::string& filename);
+Ptr<IVideoWriter> createMotionJpegWriter(const std::string &filename, int fourcc, double fps, const Size &frameSize, bool iscolor);
+
+Ptr<IVideoCapture> createGPhoto2Capture(int index);
+Ptr<IVideoCapture> createGPhoto2Capture(const std::string& deviceName);
+
+Ptr<IVideoCapture> createXINECapture(const std::string &filename);
+
+} // cv::
+
+#endif // CAP_INTERFACE_HPP
index 30fc66c..3096ffd 100644 (file)
@@ -238,6 +238,12 @@ bool VideoCapture_LibRealsense::isOpened() const
     return bool(std::shared_ptr<rs2_pipeline>(mPipe));
 }
 
+Ptr<IVideoCapture> create_RealSense_capture(int index)
+{
+    return makePtr<VideoCapture_LibRealsense>(index);
+}
+
+
 }
 
 #endif
index 1f59668..bd43db0 100644 (file)
@@ -25,6 +25,7 @@ public:
     virtual bool retrieveFrame(int outputType, OutputArray frame) CV_OVERRIDE;
     virtual int getCaptureDomain() CV_OVERRIDE;
     virtual bool isOpened() const CV_OVERRIDE;
+
 protected:
     rs2::pipeline mPipe;
     rs2::frameset mData;
index b4d2d9a..ea944ae 100644 (file)
@@ -298,7 +298,7 @@ public:
 private:
     VAHandle(const VAHandle &);
     VAHandle &operator=(const VAHandle &);
-    virtual bool initDeviceSession(MFXVideoSession &session);
+    bool initDeviceSession(MFXVideoSession &session) CV_OVERRIDE;
 private:
     VADisplay display;
     int file;
@@ -319,7 +319,7 @@ public:
 private:
     DXHandle(const DXHandle &);
     DXHandle &operator=(const DXHandle &);
-    virtual bool initDeviceSession(MFXVideoSession &) { return true; }
+    bool initDeviceSession(MFXVideoSession &) CV_OVERRIDE { return true; }
 };
 
 #endif // _WIN32
index f2ec1c4..2a25ddb 100644 (file)
@@ -6,6 +6,7 @@
 #include "opencv2/core/base.hpp"
 #include "cap_mfx_common.hpp"
 #include "opencv2/imgproc/hal/hal.hpp"
+#include "cap_interface.hpp"
 
 using namespace cv;
 using namespace std;
@@ -264,3 +265,8 @@ int VideoCapture_IntelMFX::getCaptureDomain()
 }
 
 //==================================================================================================
+
+cv::Ptr<IVideoCapture> cv::create_MFX_capture(const std::string &filename)
+{
+    return cv::makePtr<VideoCapture_IntelMFX>(filename);
+}
index cad5297..26e8f77 100644 (file)
@@ -19,13 +19,13 @@ class VideoCapture_IntelMFX : public cv::IVideoCapture
 {
 public:
     VideoCapture_IntelMFX(const cv::String &filename);
-    virtual ~VideoCapture_IntelMFX();
-    virtual double getProperty(int) const CV_OVERRIDE;
-    virtual bool setProperty(int, double) CV_OVERRIDE;
-    virtual bool grabFrame() CV_OVERRIDE;
-    virtual bool retrieveFrame(int, cv::OutputArray out) CV_OVERRIDE;
-    virtual bool isOpened() const CV_OVERRIDE;
-    virtual int getCaptureDomain() CV_OVERRIDE;
+    ~VideoCapture_IntelMFX();
+    double getProperty(int) const CV_OVERRIDE;
+    bool setProperty(int, double) CV_OVERRIDE;
+    bool grabFrame() CV_OVERRIDE;
+    bool retrieveFrame(int, cv::OutputArray out) CV_OVERRIDE;
+    bool isOpened() const CV_OVERRIDE;
+    int getCaptureDomain() CV_OVERRIDE;
 private:
     MFXVideoSession *session;
     Plugin *plugin;
index a8e2406..3204d37 100644 (file)
@@ -6,6 +6,7 @@
 #include "opencv2/core/base.hpp"
 #include "cap_mfx_common.hpp"
 #include "opencv2/imgproc/hal/hal.hpp"
+#include "cap_interface.hpp"
 
 using namespace std;
 using namespace cv;
@@ -244,7 +245,7 @@ bool VideoWriter_IntelMFX::write_one(cv::InputArray bgr)
     }
 }
 
-Ptr<VideoWriter_IntelMFX> VideoWriter_IntelMFX::create(const String &filename, int _fourcc, double fps, Size frameSize, bool isColor)
+Ptr<IVideoWriter> cv::create_MFX_writer(const std::string &filename, int _fourcc, double fps, const Size &frameSize, bool isColor)
 {
     if (codecIdByFourCC(_fourcc) > 0)
     {
index 26b1d0d..f4913a8 100644 (file)
@@ -19,14 +19,12 @@ class VideoWriter_IntelMFX : public cv::IVideoWriter
 {
 public:
     VideoWriter_IntelMFX(const cv::String &filename, int _fourcc, double fps, cv::Size frameSize, bool isColor);
-    virtual ~VideoWriter_IntelMFX();
-    virtual double getProperty(int) const;
-    virtual bool setProperty(int, double);
-    virtual bool isOpened() const;
-    virtual void write(cv::InputArray input);
-    static cv::Ptr<VideoWriter_IntelMFX> create(const cv::String& filename, int _fourcc, double fps, cv::Size frameSize, bool isColor);
-
-    virtual int getCaptureDomain() const { return cv::CAP_INTEL_MFX; }
+    ~VideoWriter_IntelMFX() CV_OVERRIDE;
+    double getProperty(int) const CV_OVERRIDE;
+    bool setProperty(int, double) CV_OVERRIDE;
+    bool isOpened() const CV_OVERRIDE;
+    void write(cv::InputArray input) CV_OVERRIDE;
+    int getCaptureDomain() const CV_OVERRIDE { return cv::CAP_INTEL_MFX; }
 protected:
     bool write_one(cv::InputArray bgr);
 
index 7f4c8a6..851710c 100644 (file)
@@ -1532,7 +1532,7 @@ void MotionJpegWriter::writeFrameData( const uchar* data, int step, int colorspa
 
 }
 
-Ptr<IVideoWriter> createMotionJpegWriter(const String& filename, int fourcc, double fps, Size frameSize, bool iscolor)
+Ptr<IVideoWriter> createMotionJpegWriter(const std::string &filename, int fourcc, double fps, const Size &frameSize, bool iscolor)
 {
     if (fourcc != CV_FOURCC('M', 'J', 'P', 'G'))
         return Ptr<IVideoWriter>();
index 10b9a41..6d17df0 100644 (file)
@@ -2159,13 +2159,13 @@ void CvVideoWriter_MSMF::write(cv::InputArray img)
     }
 }
 
-cv::Ptr<cv::IVideoWriter> cv::cvCreateVideoWriter_MSMF( const cv::String& filename, int fourcc,
-                                                        double fps, cv::Size frameSize, int isColor )
+cv::Ptr<cv::IVideoWriter> cv::cvCreateVideoWriter_MSMF( const std::string& filename, int fourcc,
+                                                        double fps, const cv::Size &frameSize, bool isColor )
 {
     cv::Ptr<CvVideoWriter_MSMF> writer = cv::makePtr<CvVideoWriter_MSMF>();
     if (writer)
     {
-        writer->open(filename, fourcc, fps, frameSize, isColor != 0);
+        writer->open(filename, fourcc, fps, frameSize, isColor);
         if (writer->isOpened())
             return writer;
     }
index b5c4268..adec735 100644 (file)
@@ -39,6 +39,7 @@
 //
 //M*/
 #include "precomp.hpp"
+#include "cap_interface.hpp"
 #include "opencv2/core.hpp"
 #include "opencv2/imgproc.hpp"
 
@@ -1100,23 +1101,23 @@ IplImage* CvCapture_OpenNI2::retrieveFrame( int outputType )
     return image;
 }
 
-CvCapture* cvCreateCameraCapture_OpenNI2( int index )
+cv::Ptr<cv::IVideoCapture> cv::create_OpenNI2_capture_cam( int index )
 {
     CvCapture_OpenNI2* capture = new CvCapture_OpenNI2( index );
 
     if( capture->isOpened() )
-        return capture;
+        return cv::makePtr<cv::LegacyCapture>(capture);
 
     delete capture;
     return 0;
 }
 
-CvCapture* cvCreateFileCapture_OpenNI2( const char* filename )
+cv::Ptr<cv::IVideoCapture> cv::create_OpenNI2_capture_file( const std::string &filename )
 {
-    CvCapture_OpenNI2* capture = new CvCapture_OpenNI2( filename );
+    CvCapture_OpenNI2* capture = new CvCapture_OpenNI2( filename.c_str() );
 
     if( capture->isOpened() )
-        return capture;
+        return cv::makePtr<cv::LegacyCapture>(capture);
 
     delete capture;
     return 0;
index c793191..c85c2fe 100644 (file)
@@ -44,6 +44,7 @@
 //
 
 #include "precomp.hpp"
+#include "cap_interface.hpp"
 
 #ifdef HAVE_PVAPI
 #if !defined _WIN32 && !defined _LINUX
@@ -599,12 +600,12 @@ bool CvCaptureCAM_PvAPI::resizeCaptureFrame (int frameWidth, int frameHeight)
     return true;
 }
 
-CvCapture* cvCreateCameraCapture_PvAPI( int index )
+cv::Ptr<cv::IVideoCapture> cv::create_PvAPI_capture( int index )
 {
     CvCaptureCAM_PvAPI* capture = new CvCaptureCAM_PvAPI;
 
     if ( capture->open( index ))
-        return capture;
+        return cv::makePtr<cv::LegacyCapture>(capture);
 
     delete capture;
     return NULL;
index f34564d..449af48 100644 (file)
@@ -1930,28 +1930,28 @@ IplImage *CvCaptureCAM_V4L::retrieveFrame(int)
     return &frame;
 }
 
-} // end namespace cv
-
-CvCapture* cvCreateCameraCapture_V4L( int index )
+Ptr<IVideoCapture> create_V4L_capture_cam(int index)
 {
     cv::CvCaptureCAM_V4L* capture = new cv::CvCaptureCAM_V4L();
 
-    if(capture->open(index))
-        return capture;
+    if (capture->open(index))
+        return makePtr<LegacyCapture>(capture);
 
     delete capture;
     return NULL;
 }
 
-CvCapture* cvCreateCameraCapture_V4L( const char * deviceName )
+Ptr<IVideoCapture> create_V4L_capture_file(const std::string &filename)
 {
     cv::CvCaptureCAM_V4L* capture = new cv::CvCaptureCAM_V4L();
 
-    if(capture->open( deviceName ))
-        return capture;
+    if (capture->open(filename.c_str()))
+        return makePtr<LegacyCapture>(capture);
 
     delete capture;
     return NULL;
 }
 
+} // cv::
+
 #endif
index a6752bd..7a38617 100644 (file)
@@ -195,6 +195,12 @@ namespace cv {
         }
         return true;
     }
+
+Ptr<IVideoCapture> create_WRT_capture(int device)
+{
+    return makePtr<VideoCapture_WinRT>(device);
+}
+
 }
 
-// end
\ No newline at end of file
+// end
index 476a854..d91aefa 100644 (file)
@@ -67,4 +67,4 @@ namespace cv {
         unsigned long           frameCurrent;
         std::atomic<bool>       isFrameNew;
     };
-}
\ No newline at end of file
+}
index 0dd3e93..7d572a2 100644 (file)
@@ -42,23 +42,23 @@ private:
 
 /**********************************************************************************/
 
-CvCapture* cvCreateCameraCapture_XIMEA( int index )
+cv::Ptr<cv::IVideoCapture> cv::create_XIMEA_capture_cam( int index )
 {
     CvCaptureCAM_XIMEA* capture = new CvCaptureCAM_XIMEA;
 
     if( capture->open( index ))
-        return capture;
+        return cv::makePtr<cv::LegacyCapture>(capture);
 
     delete capture;
     return 0;
 }
 
-CvCapture* cvCreateCameraCapture_XIMEA( const char* serialNumber )
+cv::Ptr<cv::IVideoCapture> cv::create_XIMEA_capture_file( const std::string &serialNumber )
 {
     CvCaptureCAM_XIMEA* capture = new CvCaptureCAM_XIMEA;
 
-    if( capture->open( serialNumber ))
-        return capture;
+    if( capture->open( serialNumber.c_str() ))
+        return cv::makePtr<cv::LegacyCapture>(capture);
 
     delete capture;
     return 0;
@@ -1791,4 +1791,4 @@ void CvCaptureCAM_XIMEA::errMsg(const char* msg, int errNum) const
     #endif
 }
 
-/**********************************************************************************/
\ No newline at end of file
+/**********************************************************************************/
index e1c3d99..67de7b9 100644 (file)
@@ -346,10 +346,10 @@ protected:
     }
 };
 
-Ptr<IVideoCapture> cv::createXINECapture(const char *filename)
+Ptr<IVideoCapture> cv::createXINECapture(const std::string &filename)
 {
     Ptr<XINECapture> res = makePtr<XINECapture>();
-    if (res && res->open(filename))
+    if (res && res->open(filename.c_str()))
         return res;
     return Ptr<IVideoCapture>();
 }
diff --git a/modules/videoio/src/plugin_api.cpp b/modules/videoio/src/plugin_api.cpp
new file mode 100644 (file)
index 0000000..d8119b7
--- /dev/null
@@ -0,0 +1,19 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#ifdef BUILD_PLUGIN
+
+#include "plugin_api.hpp"
+#include "opencv2/core/version.hpp"
+
+void cv_get_version(int & major, int & minor, int & patch, int & api, int & abi)
+{
+    major = CV_VERSION_MAJOR;
+    minor = CV_VERSION_MINOR;
+    patch = CV_VERSION_REVISION;
+    api = API_VERSION;
+    abi = ABI_VERSION;
+}
+
+#endif // BUILD_PLUGIN
diff --git a/modules/videoio/src/plugin_api.hpp b/modules/videoio/src/plugin_api.hpp
new file mode 100644 (file)
index 0000000..672f725
--- /dev/null
@@ -0,0 +1,71 @@
+// 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 PLUGIN_API_HPP
+#define PLUGIN_API_HPP
+
+// increase for backward-compatible changes, e.g. add new function
+// Main API <= Plugin API -> plugin is compatible
+#define API_VERSION 1
+// increase for incompatible changes, e.g. remove function argument
+// Main ABI == Plugin ABI -> plugin is compatible
+#define ABI_VERSION 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// common
+typedef void cv_get_version_t(int & major, int & minor, int & patch, int & api, int & abi);
+typedef int cv_domain_t();
+
+// capture
+typedef bool cv_open_capture_t(const char * filename, int camera_index, void * &handle);
+typedef bool cv_get_cap_prop_t(void * handle, int prop, double & val);
+typedef bool cv_set_cap_prop_t(void * handle, int prop, double val);
+typedef bool cv_grab_t(void * handle);
+// callback function type
+typedef bool cv_retrieve_cb_t(unsigned char * data, int step, int width, int height, int cn, void * userdata);
+typedef bool cv_retrieve_t(void * handle, int idx, cv_retrieve_cb_t * cb, void * userdata);
+typedef bool cv_release_capture_t(void * handle);
+
+// writer
+typedef bool cv_open_writer_t(const char * filename, int fourcc, double fps, int width, int height, int isColor, void * &handle);
+typedef bool cv_get_wri_prop_t(void * handle, int prop, double & val);
+typedef bool cv_set_wri_prop_t(void * handle, int prop, double val);
+typedef bool cv_write_t(void * handle, const unsigned char * data, int step, int width, int height, int cn);
+typedef bool cv_release_writer_t(void * handle);
+
+#ifdef BUILD_PLUGIN
+
+#if (defined _WIN32 || defined WINCE || defined __CYGWIN__)
+#  define CV_PLUGIN_EXPORTS __declspec(dllexport)
+#elif defined __GNUC__ && __GNUC__ >= 4
+#  define CV_PLUGIN_EXPORTS __attribute__ ((visibility ("default")))
+#endif
+
+CV_PLUGIN_EXPORTS cv_get_version_t cv_get_version;
+CV_PLUGIN_EXPORTS cv_domain_t cv_domain;
+
+CV_PLUGIN_EXPORTS cv_open_capture_t cv_open_capture;
+CV_PLUGIN_EXPORTS cv_get_cap_prop_t cv_get_cap_prop;
+CV_PLUGIN_EXPORTS cv_set_cap_prop_t cv_set_cap_prop;
+CV_PLUGIN_EXPORTS cv_grab_t cv_grab;
+CV_PLUGIN_EXPORTS cv_retrieve_t cv_retrieve;
+CV_PLUGIN_EXPORTS cv_release_capture_t cv_release_capture;
+
+CV_PLUGIN_EXPORTS cv_open_writer_t cv_open_writer;
+CV_PLUGIN_EXPORTS cv_get_wri_prop_t cv_get_wri_prop;
+CV_PLUGIN_EXPORTS cv_set_wri_prop_t cv_set_wri_prop;
+CV_PLUGIN_EXPORTS cv_write_t cv_write;
+CV_PLUGIN_EXPORTS cv_release_writer_t cv_release_writer;
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PLUGIN_API_HPP
index bfeb42a..f4eb697 100644 (file)
     #undef abs
 #endif
 
-#define __BEGIN__ __CV_BEGIN__
-#define __END__  __CV_END__
-#define EXIT __CV_EXIT__
-
-/***************************** CvCapture structure ******************************/
-
-struct CvCapture
-{
-    virtual ~CvCapture() {}
-    virtual double getProperty(int) const { return 0; }
-    virtual bool setProperty(int, double) { return 0; }
-    virtual bool grabFrame() { return true; }
-    virtual IplImage* retrieveFrame(int) { return 0; }
-    virtual int getCaptureDomain() { return cv::CAP_ANY; } // Return the type of the capture object: CAP_DSHOW, etc...
-};
-
-/*************************** CvVideoWriter structure ****************************/
-
-struct CvVideoWriter
-{
-    virtual ~CvVideoWriter() {}
-    virtual bool writeFrame(const IplImage*) { return false; }
-    virtual int getCaptureDomain() const { return cv::CAP_ANY; } // Return the type of the capture object: CAP_FFMPEG, etc...
-};
-
-CvCapture * cvCreateCameraCapture_V4L( int index );
-CvCapture * cvCreateCameraCapture_V4L( const char* deviceName );
-CvCapture * cvCreateCameraCapture_DC1394_2( int index );
-CvCapture* cvCreateCameraCapture_MIL( int index );
-CvCapture* cvCreateCameraCapture_Giganetix( int index );
-CvCapture* cvCreateFileCapture_Win32( const char* filename );
-CvVideoWriter* cvCreateVideoWriter_Win32( const char* filename, int fourcc,
-                                          double fps, CvSize frameSize, int is_color );
-CvCapture* cvCreateCameraCapture_DShow( int index );
-CvCapture* cvCreateCameraCapture_OpenNI( int index );
-CvCapture* cvCreateCameraCapture_OpenNI2( int index );
-CvCapture* cvCreateFileCapture_OpenNI( const char* filename );
-CvCapture* cvCreateFileCapture_OpenNI2( const char* filename );
-CvCapture* cvCreateCameraCapture_Android( int index );
-CvCapture* cvCreateCameraCapture_XIMEA( int index );
-CvCapture* cvCreateCameraCapture_XIMEA( const char* serialNumber );
-CvCapture* cvCreateCameraCapture_AVFoundation(int index);
-CvCapture* cvCreateCameraCapture_Aravis( int index );
-
-CvVideoWriter* cvCreateVideoWriter_Images(const char* filename);
-
-
-#define CV_CAP_GSTREAMER_1394          0
-#define CV_CAP_GSTREAMER_V4L           1
-#define CV_CAP_GSTREAMER_V4L2          2
-#define CV_CAP_GSTREAMER_FILE          3
-
-CvCapture * cvCreateFileCapture_QT (const char  * filename);
-CvCapture * cvCreateCameraCapture_QT  (const int     index);
-
-CvVideoWriter* cvCreateVideoWriter_QT ( const char* filename, int fourcc,
-                                        double fps, CvSize frameSize, int is_color );
-
-CvCapture* cvCreateFileCapture_AVFoundation (const char * filename);
-CvVideoWriter* cvCreateVideoWriter_AVFoundation( const char* filename, int fourcc,
-                                                double fps, CvSize frameSize, int is_color );
-
-
-CvCapture * cvCreateCameraCapture_PvAPI  (const int     index);
-CvVideoWriter* cvCreateVideoWriter_GStreamer( const char* filename, int fourcc,
-                                            double fps, CvSize frameSize, int is_color );
-
-
-namespace cv
-{
-    class IVideoCapture
-    {
-    public:
-        virtual ~IVideoCapture() {}
-        virtual double getProperty(int) const { return 0; }
-        virtual bool setProperty(int, double) { return false; }
-        virtual bool grabFrame() = 0;
-        virtual bool retrieveFrame(int, OutputArray) = 0;
-        virtual bool isOpened() const = 0;
-        virtual int getCaptureDomain() { return CAP_ANY; } // Return the type of the capture object: CAP_DSHOW, etc...
-    };
-
-    class IVideoWriter
-    {
-    public:
-        virtual ~IVideoWriter() {}
-        virtual double getProperty(int) const { return 0; }
-        virtual bool setProperty(int, double) { return false; }
-
-        virtual bool isOpened() const = 0;
-        virtual void write(InputArray) = 0;
-
-        virtual int getCaptureDomain() const { return cv::CAP_ANY; } // Return the type of the capture object: CAP_FFMPEG, etc...
-    };
-
-    Ptr<IVideoCapture> createFileCapture_Images(const String& filename);
-
-    Ptr<IVideoCapture> createMotionJpegCapture(const String& filename);
-    Ptr<IVideoWriter> createMotionJpegWriter(const String& filename, int fourcc, double fps, Size frameSize, bool iscolor);
-
-    Ptr<IVideoCapture> createGPhoto2Capture(int index);
-    Ptr<IVideoCapture> createGPhoto2Capture(const String& deviceName);
-
-
-    Ptr<IVideoCapture> createXINECapture(const char* filename);
-
-    Ptr<IVideoCapture> createGStreamerCapture(const String& filename);
-    Ptr<IVideoCapture> createGStreamerCapture(int index);
-
-    Ptr<cv::IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const String& filename);
-    Ptr<IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const String& filename, int fourcc, double fps, Size frameSize, int isColor);
-
-    Ptr<IVideoCapture> cvCreateCapture_MSMF(int index);
-    Ptr<IVideoCapture> cvCreateCapture_MSMF(const String& filename);
-    Ptr<IVideoWriter> cvCreateVideoWriter_MSMF(const String& filename, int fourcc, double fps, Size frameSize, int is_color);
-}
+#include "cap_interface.hpp"
 
 #endif /* __VIDEOIO_H_ */
index 59a4522..72e65a7 100644 (file)
@@ -3,65 +3,22 @@
 // of this distribution and at http://opencv.org/license.html.
 
 #include "precomp.hpp"
-
+#include "opencv2/videoio/registry.hpp"
 #include "videoio_registry.hpp"
 
 using namespace cv;
 
 // Legacy C-like API
 
-CV_IMPL CvCapture* cvCreateCameraCapture(int index)
+CV_IMPL CvCapture* cvCreateCameraCapture(int)
 {
-    // interpret preferred interface (0 = autodetect)
-    int apiPreference = (index / 100) * 100;
-    if (apiPreference)
-    {
-        index %= 100;
-    }
-
-    const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByIndex();
-    for (size_t i = 0; i < backends.size(); i++)
-    {
-        const VideoBackendInfo& info = backends[i];
-        if (apiPreference == CAP_ANY || apiPreference == info.id)
-        {
-            CvCapture* capture = NULL;
-            Ptr<IVideoCapture> icap; // unused
-            VideoCapture_create(capture, icap, info.id, index);
-            if (capture)
-            {
-                return capture;
-            }
-            if (!icap.empty())
-            {
-                CV_LOG_WARNING(NULL, "cvCreateFileCaptureWithPreference: backend " << info.name << " doesn't support legacy API anymore.")
-            }
-        }
-    }
+    CV_LOG_WARNING(NULL, "cvCreateCameraCapture doesn't support legacy API anymore.")
     return NULL;
 }
 
-CV_IMPL CvCapture* cvCreateFileCaptureWithPreference(const char* filename, int apiPreference)
+CV_IMPL CvCapture* cvCreateFileCaptureWithPreference(const char*, int)
 {
-    const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByFilename();
-    for (size_t i = 0; i < backends.size(); i++)
-    {
-        const VideoBackendInfo& info = backends[i];
-        if (apiPreference == CAP_ANY || apiPreference == info.id)
-        {
-            CvCapture* capture = NULL;
-            Ptr<IVideoCapture> icap; // unused
-            VideoCapture_create(capture, icap, info.id, filename);
-            if (capture)
-            {
-                return capture;
-            }
-            if (!icap.empty())
-            {
-                CV_LOG_WARNING(NULL, "cvCreateFileCaptureWithPreference: backend " << info.name << " doesn't support legacy API anymore.")
-            }
-        }
-    }
+    CV_LOG_WARNING(NULL, "cvCreateFileCaptureWithPreference doesn't support legacy API anymore.")
     return NULL;
 }
 
@@ -70,27 +27,9 @@ CV_IMPL CvCapture* cvCreateFileCapture(const char * filename)
     return cvCreateFileCaptureWithPreference(filename, CAP_ANY);
 }
 
-CV_IMPL CvVideoWriter* cvCreateVideoWriter(const char* filename, int fourcc,
-                                           double fps, CvSize frameSize, int is_color)
+CV_IMPL CvVideoWriter* cvCreateVideoWriter(const char*, int, double, CvSize, int)
 {
-    const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_Writer();
-    for (size_t i = 0; i < backends.size(); i++)
-    {
-        const VideoBackendInfo& info = backends[i];
-        {
-            CvVideoWriter* writer_ = NULL;
-            Ptr<IVideoWriter> iwriter;  // unused
-            VideoWriter_create(writer_, iwriter, info.id, filename, fourcc, fps, frameSize, is_color != 0);
-            if (writer_)
-            {
-                return writer_;
-            }
-            if (!iwriter.empty())
-            {
-                CV_LOG_WARNING(NULL, "cvCreateVideoWriter: backend " << info.name << " doesn't support legacy API anymore.")
-            }
-        }
-    }
+    CV_LOG_WARNING(NULL, "cvCreateVideoWriter doesn't support legacy API anymore.")
     return NULL;
 }
 
index c11a805..116e2d0 100644 (file)
@@ -3,11 +3,14 @@
 // of this distribution and at http://opencv.org/license.html.
 
 #include "precomp.hpp"
+#include <map>
 
 #include "videoio_registry.hpp"
 
 #include "opencv2/videoio/registry.hpp"
 
+#include <iostream>
+
 #include "cap_librealsense.hpp"
 #include "cap_dshow.hpp"
 
@@ -16,6 +19,8 @@
 #include "cap_mfx_writer.hpp"
 #endif
 
+#include "plugin_api.hpp"
+
 // All WinRT versions older than 8.0 should provide classes used for video support
 #if defined(WINRT) && !defined(WINRT_8_0) && defined(__cplusplus_winrt)
 #   include "cap_winrt_capture.hpp"
 #pragma warning(disable: 4748)
 #endif
 
-using namespace cv;
+//=================================================================
+// Private interface
+//=================================================================
 
 namespace cv
 {
+#define DECLARE_DYNAMIC_BACKEND(cap, name, mode) \
+{ \
+    cap, (BackendMode)(mode | MODE_DYNAMIC), 1000, name "_DYNAMIC", 0 \
+}
 
-static bool param_VIDEOIO_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOIO_DEBUG", false);
-static bool param_VIDEOCAPTURE_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOCAPTURE_DEBUG", false);
-static bool param_VIDEOWRITER_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOWRITER_DEBUG", false);
-
-namespace {
-
-#define DECLARE_BACKEND(cap, name, mode) { cap, (BackendMode)(mode), 1000, name }
+#define DECLARE_STATIC_BACKEND(cap, name, mode, f1, f2, f3) \
+{ \
+    cap, (BackendMode)(mode), 1000, name, Ptr<StaticBackend>(new StaticBackend(f1, f2, f3)) \
+}
 
 /** Ordering guidelines:
 - modern optimized, multi-platform libraries: ffmpeg, gstreamer, Media SDK
@@ -52,246 +60,221 @@ namespace {
 static const struct VideoBackendInfo builtin_backends[] =
 {
 #ifdef HAVE_FFMPEG
-    DECLARE_BACKEND(CAP_FFMPEG, "FFMPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
+    DECLARE_STATIC_BACKEND(CAP_FFMPEG, "FFMPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER, cvCreateFileCapture_FFMPEG_proxy, 0, cvCreateVideoWriter_FFMPEG_proxy),
+#elif defined(ENABLE_PLUGINS)
+    DECLARE_DYNAMIC_BACKEND(CAP_FFMPEG, "FFMPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
 #endif
+
 #ifdef HAVE_GSTREAMER
-    DECLARE_BACKEND(CAP_GSTREAMER, "GSTREAMER", MODE_CAPTURE_ALL | MODE_WRITER),
+    DECLARE_STATIC_BACKEND(CAP_GSTREAMER, "GSTREAMER", MODE_CAPTURE_ALL | MODE_WRITER, createGStreamerCapture_file, createGStreamerCapture_cam, create_GStreamer_writer),
+#elif defined(ENABLE_PLUGINS)
+    DECLARE_DYNAMIC_BACKEND(CAP_GSTREAMER, "GSTREAMER", MODE_CAPTURE_ALL | MODE_WRITER),
 #endif
+
 #ifdef HAVE_MFX // Media SDK
-    DECLARE_BACKEND(CAP_INTEL_MFX, "INTEL_MFX", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
+    DECLARE_STATIC_BACKEND(CAP_INTEL_MFX, "INTEL_MFX", MODE_CAPTURE_BY_FILENAME | MODE_WRITER, create_MFX_capture, 0, create_MFX_writer),
 #endif
 
-
     // Apple platform
 #ifdef HAVE_AVFOUNDATION
-    DECLARE_BACKEND(CAP_AVFOUNDATION, "AVFOUNDATION", MODE_CAPTURE_ALL | MODE_WRITER),
+    DECLARE_STATIC_BACKEND(CAP_AVFOUNDATION, "AVFOUNDATION", MODE_CAPTURE_ALL | MODE_WRITER, create_AVFoundation_capture_file, create_AVFoundation_capture_cam, create_AVFoundation_writer),
 #endif
 
     // Windows
 #ifdef WINRT_VIDEO
-    DECLARE_BACKEND(CAP_WINRT, "WINRT", MODE_CAPTURE_BY_INDEX),
+    DECLARE_STATIC_BACKEND(CAP_WINRT, "WINRT", MODE_CAPTURE_BY_INDEX, 0, create_WRT_capture, 0),
 #endif
 #ifdef HAVE_MSMF
-    DECLARE_BACKEND(CAP_MSMF, "MSMF", MODE_CAPTURE_ALL | MODE_WRITER),
+    DECLARE_STATIC_BACKEND(CAP_MSMF, "MSMF", MODE_CAPTURE_ALL | MODE_WRITER, cvCreateCapture_MSMF, cvCreateCapture_MSMF, cvCreateVideoWriter_MSMF),
 #endif
 #ifdef HAVE_DSHOW
-    DECLARE_BACKEND(CAP_DSHOW, "DSHOW", MODE_CAPTURE_BY_INDEX),
+    DECLARE_STATIC_BACKEND(CAP_DSHOW, "DSHOW", MODE_CAPTURE_BY_INDEX, 0, create_DShow_capture, 0),
 #endif
 
     // Linux, some Unix
 #if defined HAVE_CAMV4L2
-    DECLARE_BACKEND(CAP_V4L2, "V4L2", MODE_CAPTURE_ALL),
+    DECLARE_STATIC_BACKEND(CAP_V4L2, "V4L2", MODE_CAPTURE_ALL, create_V4L_capture_file, create_V4L_capture_cam, 0),
 #elif defined HAVE_VIDEOIO
-    DECLARE_BACKEND(CAP_V4L, "V4L_BSD", MODE_CAPTURE_ALL),
+    DECLARE_STATIC_BACKEND(CAP_V4L, "V4L_BSD", MODE_CAPTURE_ALL, create_V4L_capture_file, create_V4L_capture_cam, 0),
 #endif
 
 
     // RGB-D universal
 #ifdef HAVE_OPENNI2
-    DECLARE_BACKEND(CAP_OPENNI2, "OPENNI2", MODE_CAPTURE_ALL),
+    DECLARE_STATIC_BACKEND(CAP_OPENNI2, "OPENNI2", MODE_CAPTURE_ALL, create_OpenNI2_capture_file, create_OpenNI2_capture_cam, 0),
 #endif
 
 #ifdef HAVE_LIBREALSENSE
-    DECLARE_BACKEND(CAP_REALSENSE, "INTEL_REALSENSE", MODE_CAPTURE_BY_INDEX),
+    DECLARE_STATIC_BACKEND(CAP_REALSENSE, "INTEL_REALSENSE", MODE_CAPTURE_BY_INDEX, 0, create_RealSense_capture, 0),
 #endif
 
     // OpenCV file-based only
-    DECLARE_BACKEND(CAP_IMAGES, "CV_IMAGES", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
-    DECLARE_BACKEND(CAP_OPENCV_MJPEG, "CV_MJPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
+    DECLARE_STATIC_BACKEND(CAP_IMAGES, "CV_IMAGES", MODE_CAPTURE_BY_FILENAME | MODE_WRITER, create_Images_capture, 0, create_Images_writer),
+    DECLARE_STATIC_BACKEND(CAP_OPENCV_MJPEG, "CV_MJPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER, createMotionJpegCapture, 0, createMotionJpegWriter),
 
     // special interfaces / stereo cameras / other SDKs
 #if defined(HAVE_DC1394_2)
-    DECLARE_BACKEND(CAP_FIREWIRE, "FIREWIRE", MODE_CAPTURE_BY_INDEX),
+    DECLARE_STATIC_BACKEND(CAP_FIREWIRE, "FIREWIRE", MODE_CAPTURE_BY_INDEX, 0, create_DC1394_capture, 0),
 #endif
     // GigE
 #ifdef HAVE_PVAPI
-    DECLARE_BACKEND(CAP_PVAPI, "PVAPI", MODE_CAPTURE_BY_INDEX),
+    DECLARE_STATIC_BACKEND(CAP_PVAPI, "PVAPI", MODE_CAPTURE_BY_INDEX, 0, create_PvAPI_capture, 0),
 #endif
 #ifdef HAVE_XIMEA
-    DECLARE_BACKEND(CAP_XIAPI, "XIMEA", MODE_CAPTURE_ALL),
+    DECLARE_STATIC_BACKEND(CAP_XIAPI, "XIMEA", MODE_CAPTURE_ALL, create_XIMEA_capture_file, create_XIMEA_capture_cam, 0),
 #endif
 #ifdef HAVE_ARAVIS_API
-    DECLARE_BACKEND(CAP_ARAVIS, "ARAVIS", MODE_CAPTURE_BY_INDEX),
+    DECLARE_STATIC_BACKEND(CAP_ARAVIS, "ARAVIS", MODE_CAPTURE_BY_INDEX, 0, create_Aravis_capture, 0),
 #endif
 
 #ifdef HAVE_GPHOTO2
-    DECLARE_BACKEND(CAP_GPHOTO2, "GPHOTO2", MODE_CAPTURE_ALL),
+    DECLARE_STATIC_BACKEND(CAP_GPHOTO2, "GPHOTO2", MODE_CAPTURE_ALL, createGPhoto2Capture, createGPhoto2Capture, 0),
 #endif
 #ifdef HAVE_XINE
-    DECLARE_BACKEND(CAP_XINE, "XINE", MODE_CAPTURE_BY_FILENAME),
+    DECLARE_STATIC_BACKEND(CAP_XINE, "XINE", MODE_CAPTURE_BY_FILENAME, createXINECapture, 0, 0),
 #endif
-
     // dropped backends: MIL, TYZX, Android
 };
 
-bool sortByPriority(const VideoBackendInfo &lhs, const VideoBackendInfo &rhs)
+inline static bool sortByPriority(const VideoBackendInfo &lhs, const VideoBackendInfo &rhs)
 {
     return lhs.priority > rhs.priority;
 }
 
-/** @brief Manages list of enabled backends
- */
-class VideoBackendRegistry
+inline static std::vector<std::string> tokenize_string(const std::string& input, char token = ',')
 {
-protected:
-    std::vector<VideoBackendInfo> enabledBackends;
-    VideoBackendRegistry()
+    std::vector<std::string> result;
+    std::string::size_type prev_pos = 0, pos = 0;
+    while((pos = input.find(token, pos)) != std::string::npos)
     {
-        const int N = sizeof(builtin_backends)/sizeof(builtin_backends[0]);
-        enabledBackends.assign(builtin_backends, builtin_backends + N);
-        for (int i = 0; i < N; i++)
-        {
-            VideoBackendInfo& info = enabledBackends[i];
-            info.priority = 1000 - i * 10;
-        }
-        CV_LOG_DEBUG(NULL, "VIDEOIO: Builtin backends(" << N << "): " << dumpBackends());
-        if (readPrioritySettings())
-        {
-            CV_LOG_INFO(NULL, "VIDEOIO: Updated backends priorities: " << dumpBackends());
-        }
-        int enabled = 0;
-        for (int i = 0; i < N; i++)
-        {
-            VideoBackendInfo& info = enabledBackends[enabled];
-            if (enabled != i)
-                info = enabledBackends[i];
-            size_t param_priority = utils::getConfigurationParameterSizeT(cv::format("OPENCV_VIDEOIO_PRIORITY_%s", info.name).c_str(), (size_t)info.priority);
-            CV_Assert(param_priority == (size_t)(int)param_priority); // overflow check
-            if (param_priority > 0)
-            {
-                info.priority = (int)param_priority;
-                enabled++;
-            }
-            else
-            {
-                CV_LOG_INFO(NULL, "VIDEOIO: Disable backend: " << info.name);
-            }
-        }
-        enabledBackends.resize(enabled);
-        CV_LOG_DEBUG(NULL, "VIDEOIO: Available backends(" << enabled << "): " << dumpBackends());
-        std::sort(enabledBackends.begin(), enabledBackends.end(), sortByPriority);
-        CV_LOG_INFO(NULL, "VIDEOIO: Enabled backends(" << enabled << ", sorted by priority): " << dumpBackends());
+        result.push_back(input.substr(prev_pos, pos-prev_pos));
+        prev_pos = ++pos;
     }
+    result.push_back(input.substr(prev_pos));
+    return result;
+}
 
-    static std::vector<std::string> tokenize_string(const std::string& input, char token)
+VideoBackendRegistry::VideoBackendRegistry()
+{
+    typedef std::vector<std::string> PriorityVec;
+    using namespace cv::utils;
+    const std::string backendOrder_str = getConfigurationParameterString("OPENCV_VIDEOIO_PRIORITY_LIST", NULL);
+    const PriorityVec backendOrder = tokenize_string(backendOrder_str);
+    if (!backendOrder.empty())
     {
-        std::vector<std::string> result;
-        std::string::size_type prev_pos = 0, pos = 0;
-        while((pos = input.find(token, pos)) != std::string::npos)
-        {
-            result.push_back(input.substr(prev_pos, pos-prev_pos));
-            prev_pos = ++pos;
-        }
-        result.push_back(input.substr(prev_pos));
-        return result;
+        CV_LOG_INFO(NULL, "VIDEOIO: Configured priority list (OPENCV_VIDEOIO_PRIORITY_LIST): " << backendOrder_str);
     }
-    bool readPrioritySettings()
+
+    const int N = sizeof(builtin_backends)/sizeof(builtin_backends[0]);
+    for (int i = 0; i < N; ++i)
     {
-        bool hasChanges = false;
-        cv::String prioritized_backends = utils::getConfigurationParameterString("OPENCV_VIDEOIO_PRIORITY_LIST", NULL);
-        if (prioritized_backends.empty())
-            return hasChanges;
-        CV_LOG_INFO(NULL, "VIDEOIO: Configured priority list (OPENCV_VIDEOIO_PRIORITY_LIST): " << prioritized_backends);
-        const std::vector<std::string> names = tokenize_string(prioritized_backends, ',');
-        for (size_t i = 0; i < names.size(); i++)
+        VideoBackendInfo be = builtin_backends[i];
+
+        // Check if backend needs plugin
+        if (be.mode & MODE_DYNAMIC)
         {
-            const std::string& name = names[i];
-            bool found = false;
-            for (size_t k = 0; k < enabledBackends.size(); k++)
+            Ptr<DynamicBackend> plugin = DynamicBackend::load(be.id, (int)be.mode);
+            if (!plugin)
             {
-                VideoBackendInfo& info = enabledBackends[k];
-                if (name == info.name)
-                {
-                    info.priority = (int)(100000 + (names.size() - i) * 1000);
-                    CV_LOG_DEBUG(NULL, "VIDEOIO: New backend priority: '" << name << "' => " << info.priority);
-                    found = true;
-                    hasChanges = true;
-                    break;
-                }
+                CV_LOG_INFO(NULL, "VIDEOIO: Disable backend: " << be.name << " (no plugin)");
+                continue;
             }
-            if (!found)
+            else
             {
-                CV_LOG_WARNING(NULL, "VIDEOIO: Can't prioritize unknown/unavailable backend: '" << name << "'");
+                be.backendFactory = plugin;
             }
         }
-        return hasChanges;
-    }
-public:
-    std::string dumpBackends() const
-    {
-        std::ostringstream os;
-        for (size_t i = 0; i < enabledBackends.size(); i++)
-        {
-            if (i > 0) os << "; ";
-            const VideoBackendInfo& info = enabledBackends[i];
-            os << info.name << '(' << info.priority << ')';
-        }
-        return os.str();
-    }
 
-    static VideoBackendRegistry& getInstance()
-    {
-        static VideoBackendRegistry g_instance;
-        return g_instance;
-    }
-
-    inline std::vector<VideoBackendInfo> getEnabledBackends() const { return enabledBackends; }
+        // initial priority (e.g. for 4 elems: 1000, 990, 980, 970)
+        be.priority = 1000 - i * 10;
+        CV_LOG_INFO(NULL, "VIDEOIO: Init backend priority: " << be.name << " -> " << be.priority);
 
-    inline std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex() const
-    {
-        std::vector<VideoBackendInfo> result;
-        for (size_t i = 0; i < enabledBackends.size(); i++)
+        // priority from environment list (e.g. for 4 elems: 13000, 12000, 11000, 10000)
+        PriorityVec::const_iterator backendPos = std::find(backendOrder.begin(), backendOrder.end(), be.name);
+        if (backendPos != backendOrder.end())
         {
-            const VideoBackendInfo& info = enabledBackends[i];
-            if (info.mode & MODE_CAPTURE_BY_INDEX)
-                result.push_back(info);
+            const int env_priority2 = static_cast<int>(backendOrder.end() - backendPos - 1);
+            be.priority = 10000 + 1000 * env_priority2;
+            CV_LOG_INFO(NULL, "VIDEOIO: Update backend priority: " << be.name << " -> " << be.priority);
         }
-        return result;
-    }
-    inline std::vector<VideoBackendInfo> getAvailableBackends_CaptureByFilename() const
-    {
-        std::vector<VideoBackendInfo> result;
-        for (size_t i = 0; i < enabledBackends.size(); i++)
+
+        // priority from environment variable
+        const std::string priority_var = std::string("OPENCV_VIDEOIO_PRIORITY_") + be.name;
+        const size_t env_priority2 = getConfigurationParameterSizeT(priority_var.c_str(), (size_t)be.priority);
+        CV_Assert(env_priority2 == (size_t)(int)env_priority2); // overflow check
+        if (env_priority2 == 0)
         {
-            const VideoBackendInfo& info = enabledBackends[i];
-            if (info.mode & MODE_CAPTURE_BY_FILENAME)
-                result.push_back(info);
+            CV_LOG_INFO(NULL, "VIDEOIO: Disable backend: " << be.name << " (user)");
+            continue;
         }
-        return result;
-    }
-    inline std::vector<VideoBackendInfo> getAvailableBackends_Writer() const
-    {
-        std::vector<VideoBackendInfo> result;
-        for (size_t i = 0; i < enabledBackends.size(); i++)
+        else if (be.priority != (int)env_priority2)
         {
-            const VideoBackendInfo& info = enabledBackends[i];
-            if (info.mode & MODE_WRITER)
-                result.push_back(info);
+            be.priority = (int)env_priority2;
+            CV_LOG_INFO(NULL, "VIDEOIO: Update backend priority: " << be.name << " -> " << be.priority);
         }
-        return result;
+
+        enabledBackends.push_back(be);
     }
-};
+    std::sort(enabledBackends.begin(), enabledBackends.end(), sortByPriority);
+    CV_LOG_INFO(NULL, "VIDEOIO: Enabled backends: " << dumpBackends());
+}
 
-} // namespace
+std::string VideoBackendRegistry::dumpBackends() const
+{
+    std::ostringstream os;
+    for (size_t i = 0; i < enabledBackends.size(); i++)
+    {
+        if (i > 0) os << "; ";
+        const VideoBackendInfo& info = enabledBackends[i];
+        os << info.name << '(' << info.priority << ')';
+    }
+    return os.str();
+}
 
-namespace videoio_registry {
+VideoBackendRegistry &VideoBackendRegistry::getInstance()
+{
+    static VideoBackendRegistry g_instance;
+    return g_instance;
+}
 
-std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex()
+Ptr<IBackend> VideoBackendRegistry::getBackend(VideoCaptureAPIs api) const
 {
-    const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByIndex();
-    return result;
+    BackendsVec result;
+    for (BackendsVec::const_iterator i = enabledBackends.begin(); i != enabledBackends.end(); i++)
+        if (api == i->id)
+            return i->backendFactory;
+    return Ptr<IBackend>(0);
 }
-std::vector<VideoBackendInfo> getAvailableBackends_CaptureByFilename()
+
+VideoBackendRegistry::BackendsVec VideoBackendRegistry::getBackends(int capabilityMask, VideoCaptureAPIs filter) const
 {
-    const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename();
+    BackendsVec result;
+    for (BackendsVec::const_iterator i = enabledBackends.begin(); i != enabledBackends.end(); i++)
+    {
+        if (filter != CAP_ANY && filter != i->id)
+            continue;
+        if (i->mode & capabilityMask)
+            result.push_back(*i);
+    }
     return result;
 }
-std::vector<VideoBackendInfo> getAvailableBackends_Writer()
+
+bool VideoBackendRegistry::hasBackend(int mask, VideoCaptureAPIs api) const
 {
-    const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_Writer();
-    return result;
+    for (BackendsVec::const_iterator i = enabledBackends.begin(); i != enabledBackends.end(); i++)
+        if (api == i->id && mask & i->mode)
+            return true;
+    return false;
 }
 
+} // cv::
+
+//=================================================================
+// Public interface
+//=================================================================
+
+namespace cv {  namespace videoio_registry {
+
 cv::String getBackendName(VideoCaptureAPIs api)
 {
     if (api == CAP_ANY)
@@ -306,317 +289,42 @@ cv::String getBackendName(VideoCaptureAPIs api)
     return cv::format("UnknownVideoAPI(%d)", (int)api);
 }
 
-std::vector<VideoCaptureAPIs> getBackends()
+bool hasBackend(VideoCaptureAPIs api, Capability cap)
 {
-    std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getEnabledBackends();
-    std::vector<VideoCaptureAPIs> result;
-    for (size_t i = 0; i < backends.size(); i++)
-        result.push_back((VideoCaptureAPIs)backends[i].id);
-    return result;
+    int mask = 0;
+    if (cap == Read || cap == ReadWrite)
+        mask |= MODE_CAPTURE_ALL;
+    if (cap == Write || cap == ReadWrite)
+        mask |= MODE_WRITER;
+    return VideoBackendRegistry::getInstance().hasBackend(mask, api);
 }
 
-std::vector<VideoCaptureAPIs> getCameraBackends()
+inline static std::vector<VideoCaptureAPIs> toIDs(const std::vector<VideoBackendInfo> &backends)
 {
-    const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByIndex();
     std::vector<VideoCaptureAPIs> result;
     for (size_t i = 0; i < backends.size(); i++)
         result.push_back((VideoCaptureAPIs)backends[i].id);
     return result;
-
 }
 
-std::vector<VideoCaptureAPIs> getStreamBackends()
-{
-    const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename();
-    std::vector<VideoCaptureAPIs> result;
-    for (size_t i = 0; i < backends.size(); i++)
-        result.push_back((VideoCaptureAPIs)backends[i].id);
-    return result;
-
-}
-
-std::vector<VideoCaptureAPIs> getWriterBackends()
+std::vector<VideoCaptureAPIs> getBackends()
 {
-    const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_Writer();
-    std::vector<VideoCaptureAPIs> result;
-    for (size_t i = 0; i < backends.size(); i++)
-        result.push_back((VideoCaptureAPIs)backends[i].id);
-    return result;
-}
-
-} // namespace registry
-
-#define TRY_OPEN(backend_func) \
-{ \
-    try { \
-        if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \
-            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \
-        icap = backend_func; \
-        if (param_VIDEOIO_DEBUG ||param_VIDEOCAPTURE_DEBUG) \
-            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p isOpened=%d ...\n", \
-                #backend_func, icap.empty() ? NULL : icap.get(), icap.empty() ? -1: icap->isOpened())); \
-    } catch(const cv::Exception& e) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \
-    } catch (const std::exception& e) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \
-    } catch(...) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \
-    } \
-    break; \
+    return toIDs(VideoBackendRegistry::getInstance().getBackends(MODE_CAPTURE_ALL + MODE_WRITER));
 }
 
-#define TRY_OPEN_LEGACY(backend_func) \
-{ \
-    try { \
-        if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \
-            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \
-        capture = backend_func; \
-        if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \
-            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p ...\n", #backend_func, capture)); \
-    } catch(const cv::Exception& e) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \
-    } catch (const std::exception& e) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \
-    } catch(...) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \
-    } \
-    break; \
-}
-
-
-void VideoCapture_create(CvCapture*& capture, Ptr<IVideoCapture>& icap, VideoCaptureAPIs api, int index)
+std::vector<VideoCaptureAPIs> getCameraBackends()
 {
-    CV_UNUSED(capture); CV_UNUSED(icap);
-    switch (api)
-    {
-    default:
-        CV_LOG_WARNING(NULL, "VideoCapture(index=" << index << ") was built without support of requested backendID=" << (int)api);
-        break;
-#ifdef HAVE_GSTREAMER
-    case CAP_GSTREAMER:
-        TRY_OPEN(createGStreamerCapture(index));
-        break;
-#endif
-#ifdef HAVE_MSMF
-    case CAP_MSMF:
-        TRY_OPEN(cvCreateCapture_MSMF(index));
-        break;
-#endif
-#ifdef HAVE_DSHOW
-    case CAP_DSHOW:
-        TRY_OPEN(makePtr<VideoCapture_DShow>(index));
-        break;
-#endif
-#ifdef HAVE_LIBREALSENSE
-    case CAP_REALSENSE:
-        TRY_OPEN(makePtr<VideoCapture_LibRealsense>(index));
-        break;
-#endif
-#ifdef WINRT_VIDEO
-    case CAP_WINRT:
-        TRY_OPEN(makePtr<cv::VideoCapture_WinRT>(index));
-        break;
-#endif
-#ifdef HAVE_GPHOTO2
-    case CAP_GPHOTO2:
-        TRY_OPEN(createGPhoto2Capture(index));
-        break;
-#endif
-#if defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO
-    case CAP_V4L:
-        TRY_OPEN_LEGACY(cvCreateCameraCapture_V4L(index))
-        break;
-#endif
-    case CAP_FIREWIRE:
-#ifdef HAVE_DC1394_2
-        TRY_OPEN_LEGACY(cvCreateCameraCapture_DC1394_2(index))
-#endif
-        break; // CAP_FIREWIRE
-#ifdef HAVE_MIL
-    case CAP_MIL:
-        TRY_OPEN_LEGACY(cvCreateCameraCapture_MIL(index))
-        break;
-#endif
-#ifdef HAVE_PVAPI
-    case CAP_PVAPI:
-        TRY_OPEN_LEGACY(cvCreateCameraCapture_PvAPI(index))
-        break;
-#endif
-#ifdef HAVE_OPENNI2
-    case CAP_OPENNI2:
-        TRY_OPEN_LEGACY(cvCreateCameraCapture_OpenNI2(index))
-        break;
-#endif
-#ifdef HAVE_XIMEA
-    case CAP_XIAPI:
-        TRY_OPEN_LEGACY(cvCreateCameraCapture_XIMEA(index))
-        break;
-#endif
-
-#ifdef HAVE_AVFOUNDATION
-    case CAP_AVFOUNDATION:
-        TRY_OPEN_LEGACY(cvCreateCameraCapture_AVFoundation(index))
-        break;
-#endif
-
-#ifdef HAVE_ARAVIS_API
-    case CAP_ARAVIS:
-        TRY_OPEN_LEGACY(cvCreateCameraCapture_Aravis(index))
-        break;
-#endif
-    } // switch (api)
+    return toIDs(VideoBackendRegistry::getInstance().getBackends(MODE_CAPTURE_BY_INDEX));
 }
 
-void VideoCapture_create(CvCapture*& capture, Ptr<IVideoCapture>& icap, VideoCaptureAPIs api, const cv::String& filename)
+std::vector<VideoCaptureAPIs> getStreamBackends()
 {
-    CV_UNUSED(capture);
-    switch (api)
-    {
-    default:
-        CV_LOG_WARNING(NULL, "VideoCapture(filename=" << filename << ") was built without support of requested backendID=" << (int)api);
-        break;
-#if defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO
-    case CAP_V4L:
-        TRY_OPEN_LEGACY(cvCreateCameraCapture_V4L(filename.c_str()))
-        break;
-#endif
-
-#ifdef HAVE_AVFOUNDATION
-    case CAP_AVFOUNDATION:
-        TRY_OPEN_LEGACY(cvCreateFileCapture_AVFoundation(filename.c_str()))
-        break;
-#endif
-
-#ifdef HAVE_OPENNI2
-    case CAP_OPENNI2:
-        TRY_OPEN_LEGACY(cvCreateFileCapture_OpenNI2(filename.c_str()))
-        break;
-#endif
-#ifdef HAVE_XIMEA
-    case CAP_XIAPI:
-        TRY_OPEN_LEGACY(cvCreateCameraCapture_XIMEA(filename.c_str()))
-        break;
-#endif
-    case CAP_IMAGES:
-        TRY_OPEN(createFileCapture_Images(filename))
-        break;
-#ifdef HAVE_FFMPEG
-    case CAP_FFMPEG:
-        TRY_OPEN(cvCreateFileCapture_FFMPEG_proxy(filename))
-        break;
-#endif
-#ifdef HAVE_GSTREAMER
-    case CAP_GSTREAMER:
-        TRY_OPEN(createGStreamerCapture(filename))
-        break;
-#endif
-#ifdef HAVE_XINE
-    case CAP_XINE:
-        TRY_OPEN(createXINECapture(filename.c_str()))
-        break;
-#endif
-#ifdef HAVE_MSMF
-    case CAP_MSMF:
-        TRY_OPEN(cvCreateCapture_MSMF(filename))
-        break;
-#endif
-#ifdef HAVE_GPHOTO2
-    case CAP_GPHOTO2:
-        TRY_OPEN(createGPhoto2Capture(filename))
-        break;
-#endif
-#ifdef HAVE_MFX
-    case CAP_INTEL_MFX:
-        TRY_OPEN(makePtr<VideoCapture_IntelMFX>(filename))
-        break;
-#endif
-    case CAP_OPENCV_MJPEG:
-        TRY_OPEN(createMotionJpegCapture(filename))
-        break;
-    } // switch
+    return toIDs(VideoBackendRegistry::getInstance().getBackends(MODE_CAPTURE_BY_FILENAME));
 }
 
-
-void VideoWriter_create(CvVideoWriter*& writer, Ptr<IVideoWriter>& iwriter, VideoCaptureAPIs api,
-        const String& filename, int fourcc, double fps, const Size& frameSize, bool isColor)
+std::vector<VideoCaptureAPIs> getWriterBackends()
 {
-#define CREATE_WRITER(backend_func) \
-{ \
-    try { \
-        if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \
-            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \
-        iwriter = backend_func; \
-        if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \
-            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p  isOpened=%d...\n", #backend_func, iwriter.empty() ? NULL : iwriter.get(), iwriter.empty() ? iwriter->isOpened() : -1)); \
-    } catch(const cv::Exception& e) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \
-    } catch (const std::exception& e) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \
-    } catch(...) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \
-    } \
-    break; \
-}
-
-#define CREATE_WRITER_LEGACY(backend_func) \
-{ \
-    try { \
-        if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \
-            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \
-        writer = backend_func; \
-        if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \
-            CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p...\n", #backend_func, writer)); \
-    } catch(const cv::Exception& e) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \
-    } catch (const std::exception& e) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \
-    } catch(...) { \
-        CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \
-    } \
-    break; \
+    return toIDs(VideoBackendRegistry::getInstance().getBackends(MODE_WRITER));
 }
 
-    switch (api)
-    {
-    default:
-        CV_LOG_ERROR(NULL, "Unknown VideoWriter backend (check getBuildInformation()): " << (int)api);
-        break;
-#ifdef HAVE_FFMPEG
-    case CAP_FFMPEG:
-        CREATE_WRITER(cvCreateVideoWriter_FFMPEG_proxy(filename, fourcc, fps, frameSize, isColor));
-        break;
-#endif
-#ifdef HAVE_MSMF
-    case CAP_MSMF:
-        CREATE_WRITER(cvCreateVideoWriter_MSMF(filename, fourcc, fps, frameSize, isColor));
-        break;
-#endif
-#ifdef HAVE_MFX
-    case CAP_INTEL_MFX:
-        CREATE_WRITER(VideoWriter_IntelMFX::create(filename, fourcc, fps, frameSize, isColor));
-        break;
-#endif
-#ifdef HAVE_AVFOUNDATION
-    case CAP_AVFOUNDATION:
-        CREATE_WRITER_LEGACY(cvCreateVideoWriter_AVFoundation(filename.c_str(), fourcc, fps, cvSize(frameSize), isColor))
-        break;
-#endif
-#ifdef HAVE_GSTREAMER
-case CAP_GSTREAMER:
-        CREATE_WRITER_LEGACY(cvCreateVideoWriter_GStreamer (filename.c_str(), fourcc, fps, cvSize(frameSize), isColor))
-        break;
-#endif
-    case CAP_OPENCV_MJPEG:
-        CREATE_WRITER(createMotionJpegWriter(filename, fourcc, fps, frameSize, isColor));
-        break;
-    case CAP_IMAGES:
-        if(!fourcc || !fps)
-        {
-            CREATE_WRITER_LEGACY(cvCreateVideoWriter_Images(filename.c_str()));
-        }
-        break;
-    } // switch(api)
-}
-
-
-} // namespace
+}} // cv::videoio_registry::
index a6d4755..6a2ec0a 100644 (file)
@@ -5,6 +5,10 @@
 #ifndef __OPENCV_VIDEOIO_VIDEOIO_REGISTRY_HPP__
 #define __OPENCV_VIDEOIO_VIDEOIO_REGISTRY_HPP__
 
+#include "opencv2/videoio.hpp"
+#include "opencv2/videoio/registry.hpp"
+#include "backend.hpp"
+
 namespace cv
 {
 
@@ -13,6 +17,7 @@ enum BackendMode {
     MODE_CAPTURE_BY_INDEX    = 1 << 0,           //!< device index
     MODE_CAPTURE_BY_FILENAME = 1 << 1,           //!< filename or device path (v4l2)
     MODE_WRITER              = 1 << 4,            //!< writer
+    MODE_DYNAMIC             = 1 << 5,
 
     MODE_CAPTURE_ALL = MODE_CAPTURE_BY_INDEX + MODE_CAPTURE_BY_FILENAME,
 };
@@ -24,20 +29,26 @@ struct VideoBackendInfo {
                       // 0 - disabled (OPENCV_VIDEOIO_PRIORITY_<name> = 0)
                       // >10000 - prioritized list (OPENCV_VIDEOIO_PRIORITY_LIST)
     const char* name;
+    Ptr<IBackend> backendFactory;
 };
 
-namespace videoio_registry {
-
-std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex();
-std::vector<VideoBackendInfo> getAvailableBackends_CaptureByFilename();
-std::vector<VideoBackendInfo> getAvailableBackends_Writer();
-
-} // namespace
-
-void VideoCapture_create(CvCapture*& capture, Ptr<IVideoCapture>& icap, VideoCaptureAPIs api, int index);
-void VideoCapture_create(CvCapture*& capture, Ptr<IVideoCapture>& icap, VideoCaptureAPIs api, const cv::String& filename);
-void VideoWriter_create(CvVideoWriter*& writer, Ptr<IVideoWriter>& iwriter, VideoCaptureAPIs api,
-        const String& filename, int fourcc, double fps, const Size& frameSize, bool isColor);
+/** @brief Manages list of enabled backends
+ */
+class VideoBackendRegistry
+{
+public:
+    typedef std::vector<VideoBackendInfo> BackendsVec;
+protected:
+    BackendsVec enabledBackends;
+    VideoBackendRegistry();
+public:
+    std::string dumpBackends() const;
+    Ptr<IBackend> getBackend(VideoCaptureAPIs api) const;
+    BackendsVec getBackends(int capabilityMask, VideoCaptureAPIs filter = CAP_ANY) const;
+    bool hasBackend(int mask, VideoCaptureAPIs api) const;
+
+    static VideoBackendRegistry& getInstance();
+};
 
 } // namespace
 #endif // __OPENCV_VIDEOIO_VIDEOIO_REGISTRY_HPP__
index ac115b1..9a51e75 100644 (file)
@@ -5,7 +5,7 @@
 // Note: all tests here are DISABLED by default due specific requirements.
 // Don't use #if 0 - these tests should be tested for compilation at least.
 //
-// Usage: opencv_test_videoio --gtest_also_run_disabled_tests --gtest_filter=*VideoIO_Camera*<tested case>*
+// Usage: opencv_test_videoio --gtest_also_run_disabled_tests --gtest_filter=*videoio_camera*<tested case>*
 
 #include "test_precomp.hpp"
 
@@ -29,7 +29,7 @@ static void test_readFrames(/*const*/ VideoCapture& capture, const int N = 100,
     if (lastFrame) *lastFrame = frame.clone();
 }
 
-TEST(DISABLED_VideoIO_Camera, basic)
+TEST(DISABLED_videoio_camera, basic)
 {
     VideoCapture capture(0);
     ASSERT_TRUE(capture.isOpened());
@@ -41,7 +41,7 @@ TEST(DISABLED_VideoIO_Camera, basic)
     capture.release();
 }
 
-TEST(DISABLED_VideoIO_Camera, validate_V4L2_MJPEG)
+TEST(DISABLED_videoio_camera, v4l_read_mjpg)
 {
     VideoCapture capture(CAP_V4L2);
     ASSERT_TRUE(capture.isOpened());
@@ -57,7 +57,7 @@ TEST(DISABLED_VideoIO_Camera, validate_V4L2_MJPEG)
 }
 
 //Following test if for capture device using PhysConn_Video_SerialDigital as crossbar input pin
-TEST(DISABLED_VideoIO_Camera, dshow_avermedia_capture)
+TEST(DISABLED_videoio_camera, channel6)
 {
     VideoCapture capture(0);
     ASSERT_TRUE(capture.isOpened());
@@ -70,7 +70,7 @@ TEST(DISABLED_VideoIO_Camera, dshow_avermedia_capture)
     capture.release();
 }
 
-TEST(DISABLED_VideoIO_Camera, validate_V4L2_FrameSize)
+TEST(DISABLED_videoio_camera, v4l_read_framesize)
 {
     VideoCapture capture(CAP_V4L2);
     ASSERT_TRUE(capture.isOpened());
index d4400e3..45542ab 100644 (file)
@@ -8,10 +8,10 @@
 
 using namespace cv;
 
-namespace opencv_test
-{
+namespace opencv_test { namespace {
 
-TEST(videoio_avi, good_MJPG) {
+TEST(videoio_builtin, basic_avi)
+{
     String filename = BunnyParameters::getFilename(".mjpg.avi");
     AVIReadContainer in;
     in.initStream(filename);
@@ -23,7 +23,8 @@ TEST(videoio_avi, good_MJPG) {
     EXPECT_EQ(in.getFps(), static_cast<unsigned>(BunnyParameters::getFps()));
 }
 
-TEST(videoio_avi, bad_MJPG) {
+TEST(videoio_builtin, invalid_avi)
+{
     String filename = BunnyParameters::getFilename(".avi");
     AVIReadContainer in;
     in.initStream(filename);
@@ -32,7 +33,7 @@ TEST(videoio_avi, bad_MJPG) {
     EXPECT_EQ(frames.size(), static_cast<unsigned>(0));
 }
 
-TEST(videoio_avi, basic)
+TEST(videoio_builtin, read_write_avi)
 {
     const String filename = cv::tempfile("test.avi");
     const double fps = 100;
@@ -84,4 +85,4 @@ TEST(videoio_avi, basic)
     remove(filename.c_str());
 }
 
-}
+}} // opencv_test::<anonymous>::
diff --git a/modules/videoio/test/test_dynamic.cpp b/modules/videoio/test/test_dynamic.cpp
new file mode 100644 (file)
index 0000000..0e14094
--- /dev/null
@@ -0,0 +1,83 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "test_precomp.hpp"
+
+using namespace std;
+
+namespace opencv_test { namespace {
+
+const int FRAME_COUNT = 120;
+
+inline void generateFrame(int i, Mat & frame)
+{
+    ::generateFrame(i, FRAME_COUNT, frame);
+}
+
+TEST(videoio_dynamic, basic_write)
+{
+    const Size FRAME_SIZE(640, 480);
+    const double FPS = 100;
+    const String filename = cv::tempfile(".avi");
+    const int fourcc = VideoWriter::fourcc('H', '2', '6', '4');
+
+    bool fileExists = false;
+    {
+        vector<VideoCaptureAPIs> backends = videoio_registry::getWriterBackends();
+        for (VideoCaptureAPIs be : backends)
+        {
+            VideoWriter writer;
+            writer.open(filename, be, fourcc, FPS, FRAME_SIZE, true);
+            if (writer.isOpened())
+            {
+                Mat frame(FRAME_SIZE, CV_8UC3);
+                for (int j = 0; j < FRAME_COUNT; ++j)
+                {
+                    generateFrame(j, frame);
+                    writer << frame;
+                }
+                writer.release();
+                fileExists = true;
+            }
+            EXPECT_FALSE(writer.isOpened());
+        }
+    }
+    if (!fileExists)
+    {
+        cout << "None of backends has been able to write video file - SKIP reading part" << endl;
+        return;
+    }
+    {
+        vector<VideoCaptureAPIs> backends = videoio_registry::getStreamBackends();
+        for (VideoCaptureAPIs be : backends)
+        {
+            VideoCapture cap;
+            cap.open(filename, be);
+            if(cap.isOpened())
+            {
+                int count = 0;
+                while (true)
+                {
+                    Mat frame;
+                    if (cap.grab())
+                    {
+                        if (cap.retrieve(frame))
+                        {
+                            ++count;
+                            continue;
+                        }
+                    }
+                    break;
+                }
+                EXPECT_EQ(count, FRAME_COUNT);
+                cap.release();
+            }
+            EXPECT_FALSE(cap.isOpened());
+        }
+    }
+    remove(filename.c_str());
+}
+
+
+}} // opencv_test::<anonymous>::
index 0bbab69..e581cb5 100644 (file)
-/*M///////////////////////////////////////////////////////////////////////////////////////
-//
-//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
-//
-//  By downloading, copying, installing or using the software you agree to this license.
-//  If you do not agree to this license, do not download, install,
-//  copy or use the software.
-//
-//
-//                           License Agreement
-//                For Open Source Computer Vision Library
-//
-// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
-// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
-// Third party copyrights are property of their respective owners.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-//   * Redistribution's of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//
-//   * Redistribution's in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//
-//   * The name of the copyright holders may not be used to endorse or promote products
-//     derived from this software without specific prior written permission.
-//
-// This software is provided by the copyright holders and contributors "as is" and
-// any express or implied warranties, including, but not limited to, the implied
-// warranties of merchantability and fitness for a particular purpose are disclaimed.
-// In no event shall the Intel Corporation or contributors be liable for any direct,
-// indirect, incidental, special, exemplary, or consequential damages
-// (including, but not limited to, procurement of substitute goods or services;
-// loss of use, data, or profits; or business interruption) however caused
-// and on any theory of liability, whether in contract, strict liability,
-// or tort (including negligence or otherwise) arising in any way out of
-// the use of this software, even if advised of the possibility of such damage.
-//
-//M*/
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
 
 #include "test_precomp.hpp"
 
-namespace opencv_test { namespace {
-
-#ifdef HAVE_FFMPEG
-
 using namespace std;
 
-static const char* AVI_EXT = ".avi";
-static const char* MP4_EXT = ".mp4";
+namespace opencv_test { namespace {
 
-class CV_FFmpegWriteBigVideoTest : public cvtest::BaseTest
+static inline long long getFileSize(const string &filename)
 {
-    struct TestFormatEntry {
-        int tag;
-        const char* ext;
-        bool required;
-    };
-
-    static long int getFileSize(string filename)
-    {
-        FILE *p_file = NULL;
-        p_file = fopen(filename.c_str(), "rb");
-        if (p_file == NULL)
-            return -1;
-        fseek(p_file, 0, SEEK_END);
-        long int size = ftell(p_file);
-        fclose(p_file);
-        return size;
-    }
-public:
-    void run(int)
-    {
-        const int img_r = 4096;
-        const int img_c = 4096;
-        const double fps0 = 15;
-        const double time_sec = 1;
-
-        const TestFormatEntry entries[] = {
-            {0, AVI_EXT, true},
-            //{VideoWriter::fourcc('D', 'I', 'V', '3'), AVI_EXT, true},
-            //{VideoWriter::fourcc('D', 'I', 'V', 'X'), AVI_EXT, true},
-            {VideoWriter::fourcc('D', 'X', '5', '0'), AVI_EXT, true},
-            {VideoWriter::fourcc('F', 'L', 'V', '1'), AVI_EXT, true},
-            {VideoWriter::fourcc('H', '2', '6', '1'), AVI_EXT, true},
-            {VideoWriter::fourcc('H', '2', '6', '3'), AVI_EXT, true},
-            {VideoWriter::fourcc('I', '4', '2', '0'), AVI_EXT, true},
-            //{VideoWriter::fourcc('j', 'p', 'e', 'g'), AVI_EXT, true},
-            {VideoWriter::fourcc('M', 'J', 'P', 'G'), AVI_EXT, true},
-            {VideoWriter::fourcc('m', 'p', '4', 'v'), AVI_EXT, true},
-            {VideoWriter::fourcc('M', 'P', 'E', 'G'), AVI_EXT, true},
-            //{VideoWriter::fourcc('W', 'M', 'V', '1'), AVI_EXT, true},
-            //{VideoWriter::fourcc('W', 'M', 'V', '2'), AVI_EXT, true},
-            {VideoWriter::fourcc('X', 'V', 'I', 'D'), AVI_EXT, true},
-            //{VideoWriter::fourcc('Y', 'U', 'Y', '2'), AVI_EXT, true},
-            {VideoWriter::fourcc('H', '2', '6', '4'), MP4_EXT, false}
-        };
-
-        const size_t n = sizeof(entries)/sizeof(entries[0]);
-
-        for (size_t j = 0; j < n; ++j)
-        {
-            int tag = entries[j].tag;
-            const char* ext = entries[j].ext;
-            string s = cv::format("%08x%s", tag, ext);
-
-            const string filename = tempfile(s.c_str());
-
-            try
-            {
-                double fps = fps0;
-                Size frame_s = Size(img_c, img_r);
+    ifstream f(filename, ios_base::in | ios_base::binary);
+    f.seekg(0, ios_base::end);
+    return f.tellg();
+}
 
-                if( tag == VideoWriter::fourcc('H', '2', '6', '1') )
-                    frame_s = Size(352, 288);
-                else if( tag == VideoWriter::fourcc('H', '2', '6', '3') )
-                    frame_s = Size(704, 576);
-                else if( tag == VideoWriter::fourcc('H', '2', '6', '4') )
-                    // OpenH264 1.5.0 has resolution limitations, so lets use DCI 4K resolution
-                    frame_s = Size(4096, 2160);
-                /*else if( tag == CV_FOURCC('M', 'J', 'P', 'G') ||
-                         tag == CV_FOURCC('j', 'p', 'e', 'g') )
-                    frame_s = Size(1920, 1080);*/
+typedef tuple<string, string, Size> FourCC_Ext_Size;
+typedef testing::TestWithParam< FourCC_Ext_Size > videoio_ffmpeg;
 
-                if( tag == VideoWriter::fourcc('M', 'P', 'E', 'G') )
-                {
-                    frame_s = Size(720, 576);
-                    fps = 25;
-                }
+TEST_P(videoio_ffmpeg, write_big)
+{
+    if (!videoio_registry::hasBackend(CAP_FFMPEG))
+        throw SkipTestException("FFmpeg backend was not found");
 
-                VideoWriter writer(filename, CAP_FFMPEG, tag, fps, frame_s);
+    const string fourcc = get<0>(GetParam());
+    const string ext = get<1>(GetParam());
+    const Size sz = get<2>(GetParam());
+    const double time_sec = 1;
+    const double fps = 25;
 
-                if (writer.isOpened() == false)
-                {
-                    fprintf(stderr, "\n\nFile name: %s\n", filename.c_str());
-                    fprintf(stderr, "Codec id: %d   Codec tag: %c%c%c%c\n", (int)j,
-                               tag & 255, (tag >> 8) & 255, (tag >> 16) & 255, (tag >> 24) & 255);
-                    fprintf(stderr, "Error: cannot create video file.\n");
-                    if (entries[j].required)
-                        ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT);
-                }
-                else
-                {
-                    Mat img(frame_s, CV_8UC3, Scalar::all(0));
-                    const int coeff = cvRound(min(frame_s.width, frame_s.height)/(fps0 * time_sec));
+    ostringstream buf;
+    buf << "write_big_" << fourcc << "." << ext;
+    const string filename = tempfile(buf.str().c_str());
 
-                    for (int i = 0 ; i < static_cast<int>(fps * time_sec); i++ )
-                    {
-                        //circle(img, Point2i(img_c / 2, img_r / 2), min(img_r, img_c) / 2 * (i + 1), Scalar(255, 0, 0, 0), 2);
-                        rectangle(img, Point2i(coeff * i, coeff * i), Point2i(coeff * (i + 1), coeff * (i + 1)),
-                                  Scalar::all(255 * (1.0 - static_cast<double>(i) / (fps * time_sec * 2) )), -1);
-                        writer << img;
-                    }
-
-                    writer.release();
-                    long int sz = getFileSize(filename);
-                    if (sz < 0)
-                    {
-                        fprintf(stderr, "ERROR: File name: %s was not created\n", filename.c_str());
-                        if (entries[j].required)
-                            ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT);
-                    }
-                    else
-                    {
-                        printf("Case: '%s' (frame size %dx%d fps=%g). FileSize=%lld bytes\n",
-                               s.c_str(), frame_s.width, frame_s.height, fps, (long long int)sz);
-                        if (sz < 8192)
-                        {
-                            fprintf(stderr, "ERROR: File name: %s is very small (data write problems?)\n", filename.c_str());
-                            if (entries[j].required)
-                                ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT);
-                        }
-                        remove(filename.c_str());
-                    }
-                }
-            }
-            catch(...)
-            {
-                ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT);
-            }
-            ts->set_failed_test_info(cvtest::TS::OK);
-        }
+    VideoWriter writer(filename, CAP_FFMPEG, fourccFromString(fourcc), fps, sz);
+    if (ext == "mp4" && fourcc == "H264" && !writer.isOpened())
+    {
+        throw cvtest::SkipTestException("H264/mp4 codec is not supported - SKIP");
     }
-};
-
-TEST(Videoio_Video, ffmpeg_writebig) { CV_FFmpegWriteBigVideoTest test; test.safe_run(); }
-
-class CV_FFmpegReadImageTest : public cvtest::BaseTest
-{
-public:
-    void run(int)
+    ASSERT_TRUE(writer.isOpened());
+    Mat img(sz, CV_8UC3, Scalar::all(0));
+    const int coeff = cvRound(min(sz.width, sz.height)/(fps * time_sec));
+    for (int i = 0 ; i < static_cast<int>(fps * time_sec); i++ )
     {
-        try
-        {
-            string filename = ts->get_data_path() + "readwrite/ordinary.bmp";
-            VideoCapture cap(filename, CAP_FFMPEG);
-            Mat img0 = imread(filename, 1);
-            Mat img, img_next;
-            cap >> img;
-            cap >> img_next;
-
-            CV_Assert( !img0.empty() && !img.empty() && img_next.empty() );
-
-            double diff = cvtest::norm(img0, img, CV_C);
-            CV_Assert( diff == 0 );
-        }
-        catch(...)
-        {
-            ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT);
-        }
-        ts->set_failed_test_info(cvtest::TS::OK);
+        rectangle(img,
+                  Point2i(coeff * i, coeff * i),
+                  Point2i(coeff * (i + 1), coeff * (i + 1)),
+                  Scalar::all(255 * (1.0 - static_cast<double>(i) / (fps * time_sec * 2))),
+                  -1);
+        writer << img;
     }
-};
-
-TEST(Videoio_Video, ffmpeg_image) { CV_FFmpegReadImageTest test; test.safe_run(); }
-
-#endif
-
-#if defined(HAVE_FFMPEG)
+    writer.release();
+    EXPECT_GT(getFileSize(filename), 8192);
+    remove(filename.c_str());
+}
 
-//////////////////////////////// Parallel VideoWriters and VideoCaptures ////////////////////////////////////
+static const Size bigSize(4096, 4096);
 
-class CreateVideoWriterInvoker :
-    public ParallelLoopBody
+const FourCC_Ext_Size entries[] =
 {
-public:
-    const static Size FrameSize;
-    static std::string TmpDirectory;
-
-    CreateVideoWriterInvoker(std::vector<VideoWriter*>& _writers, std::vector<std::string>& _files) :
-        writers(_writers), files(_files)
-    {
-    }
+    make_tuple("", "avi", bigSize),
+    make_tuple("DX50", "avi", bigSize),
+    make_tuple("FLV1", "avi", bigSize),
+    make_tuple("H261", "avi", Size(352, 288)),
+    make_tuple("H263", "avi", Size(704, 576)),
+    make_tuple("I420", "avi", bigSize),
+    make_tuple("MJPG", "avi", bigSize),
+    make_tuple("mp4v", "avi", bigSize),
+    make_tuple("MPEG", "avi", Size(720, 576)),
+    make_tuple("XVID", "avi", bigSize),
+    make_tuple("H264", "mp4", Size(4096, 2160))
+};
 
-    virtual void operator() (const Range& range) const CV_OVERRIDE
-    {
-        for (int i = range.start; i != range.end; ++i)
-        {
-            std::ostringstream stream;
-            stream << i << ".avi";
-            std::string fileName = tempfile(stream.str().c_str());
+INSTANTIATE_TEST_CASE_P(videoio, videoio_ffmpeg, testing::ValuesIn(entries));
 
-            files[i] = fileName;
-            writers[i] = new VideoWriter(fileName, CAP_FFMPEG, VideoWriter::fourcc('X','V','I','D'), 25.0f, FrameSize);
+//==========================================================================
 
-            CV_Assert(writers[i]->isOpened());
-        }
-    }
+TEST(videoio_ffmpeg, image)
+{
+    if (!videoio_registry::hasBackend(CAP_FFMPEG))
+        throw SkipTestException("FFmpeg backend was not found");
+
+    const string filename = findDataFile("readwrite/ordinary.bmp");
+    Mat image = imread(filename, IMREAD_COLOR);
+    ASSERT_FALSE(image.empty());
+    VideoCapture cap(filename, CAP_FFMPEG);
+    ASSERT_TRUE(cap.isOpened());
+    Mat frame1, frame2;
+    cap >> frame1 >> frame2;
+    ASSERT_FALSE(frame1.empty());
+    ASSERT_TRUE(frame2.empty());
+    ASSERT_EQ(0, cvtest::norm(image, frame1, NORM_INF));
+}
 
-private:
-    std::vector<VideoWriter*>& writers;
-    std::vector<std::string>& files;
-};
+//==========================================================================
 
-std::string CreateVideoWriterInvoker::TmpDirectory;
-const Size CreateVideoWriterInvoker::FrameSize(1020, 900);
 
-class WriteVideo_Invoker :
-    public ParallelLoopBody
+static void generateFrame(Mat &frame, unsigned int i, const Point &center, const Scalar &color)
 {
-public:
-    enum { FrameCount = 300 };
-
-    static const Scalar ObjectColor;
-    static const Point Center;
-
-    WriteVideo_Invoker(const std::vector<VideoWriter*>& _writers) :
-        ParallelLoopBody(), writers(&_writers)
-    {
-    }
+    frame = Scalar::all(i % 255);
+    stringstream buf(ios::out);
+    buf << "frame #" << i;
+    putText(frame, buf.str(), Point(50, center.y), FONT_HERSHEY_SIMPLEX, 5.0, color, 5, CV_AA);
+    circle(frame, center, i + 2, color, 2, CV_AA);
+}
 
-    static void GenerateFrame(Mat& frame, unsigned int i)
+TEST(videoio_ffmpeg, parallel)
+{
+    if (!videoio_registry::hasBackend(CAP_FFMPEG))
+        throw SkipTestException("FFmpeg backend was not found");
+
+    const int NUM = 4;
+    const int GRAN = 4;
+    const Range R(0, NUM);
+    const Size sz(1020, 900);
+    const int frameNum = 300;
+    const Scalar color(Scalar::all(0));
+    const Point center(sz.height / 2, sz.width / 2);
+
+    // Generate filenames
+    vector<string> files;
+    for (int i = 0; i < NUM; ++i)
     {
-        frame = Scalar::all(i % 255);
-
-        std::string text = to_string(i);
-        putText(frame, text, Point(50, Center.y), FONT_HERSHEY_SIMPLEX, 5.0, ObjectColor, 5, CV_AA);
-        circle(frame, Center, i + 2, ObjectColor, 2, CV_AA);
+        ostringstream stream;
+        stream << i << ".avi";
+        files.push_back(tempfile(stream.str().c_str()));
     }
-
-    virtual void operator() (const Range& range) const CV_OVERRIDE
+    // Write videos
     {
-        for (int j = range.start; j < range.end; ++j)
+        vector< Ptr<VideoWriter> > writers(NUM);
+        auto makeWriters = [&](const Range &r)
         {
-            VideoWriter* writer = writers->operator[](j);
-            CV_Assert(writer != NULL);
-            CV_Assert(writer->isOpened());
-
-            Mat frame(CreateVideoWriterInvoker::FrameSize, CV_8UC3);
-            for (unsigned int i = 0; i < FrameCount; ++i)
+            for (int i = r.start; i != r.end; ++i)
+                writers[i] = makePtr<VideoWriter>(files[i],
+                                                  CAP_FFMPEG,
+                                                  VideoWriter::fourcc('X','V','I','D'),
+                                                  25.0f,
+                                                  sz);
+        };
+        parallel_for_(R, makeWriters, GRAN);
+        for(int i = 0; i < NUM; ++i)
+        {
+            ASSERT_TRUE(writers[i]);
+            ASSERT_TRUE(writers[i]->isOpened());
+        }
+        auto writeFrames = [&](const Range &r)
+        {
+            for (int j = r.start; j < r.end; ++j)
             {
-                GenerateFrame(frame, i);
-                writer->operator<< (frame);
+                Mat frame(sz, CV_8UC3);
+                for (int i = 0; i < frameNum; ++i)
+                {
+                    generateFrame(frame, i, center, color);
+                    writers[j]->write(frame);
+                }
             }
-        }
-    }
-
-protected:
-    static std::string to_string(unsigned int i)
-    {
-        std::stringstream stream(std::ios::out);
-        stream << "frame #" << i;
-        return stream.str();
+        };
+        parallel_for_(R, writeFrames, GRAN);
     }
-
-private:
-    const std::vector<VideoWriter*>* writers;
-};
-
-const Scalar WriteVideo_Invoker::ObjectColor(Scalar::all(0));
-const Point WriteVideo_Invoker::Center(CreateVideoWriterInvoker::FrameSize.height / 2,
-    CreateVideoWriterInvoker::FrameSize.width / 2);
-
-class CreateVideoCaptureInvoker :
-    public ParallelLoopBody
-{
-public:
-    CreateVideoCaptureInvoker(std::vector<VideoCapture*>& _readers, const std::vector<std::string>& _files) :
-        ParallelLoopBody(), readers(&_readers), files(&_files)
+    // Read videos
     {
-    }
-
-    virtual void operator() (const Range& range) const CV_OVERRIDE
-    {
-        for (int i = range.start; i != range.end; ++i)
+        vector< Ptr<VideoCapture> > readers(NUM);
+        auto makeCaptures = [&](const Range &r)
+        {
+            for (int i = r.start; i != r.end; ++i)
+                readers[i] = makePtr<VideoCapture>(files[i], CAP_FFMPEG);
+        };
+        parallel_for_(R, makeCaptures, GRAN);
+        for(int i = 0; i < NUM; ++i)
         {
-            readers->operator[](i) = new VideoCapture(files->operator[](i), CAP_FFMPEG);
-            CV_Assert(readers->operator[](i)->isOpened());
+            ASSERT_TRUE(readers[i]);
+            ASSERT_TRUE(readers[i]->isOpened());
         }
-    }
-private:
-    std::vector<VideoCapture*>* readers;
-    const std::vector<std::string>* files;
-};
-
-class ReadImageAndTest :
-    public ParallelLoopBody
-{
-public:
-    ReadImageAndTest(const std::vector<VideoCapture*>& _readers, cvtest::TS* _ts) :
-        ParallelLoopBody(), readers(&_readers), ts(_ts)
-    {
-    }
-
-    virtual void operator() (const Range& range) const CV_OVERRIDE
-    {
-        for (int j = range.start; j < range.end; ++j)
+        auto readFrames = [&](const Range &r)
         {
-            VideoCapture* capture = readers->operator[](j);
-            CV_Assert(capture != NULL);
-            CV_Assert(capture->isOpened());
-
-            const static double eps = 23.0;
-            unsigned int frameCount = static_cast<unsigned int>(capture->get(CAP_PROP_FRAME_COUNT));
-            CV_Assert(frameCount == WriteVideo_Invoker::FrameCount);
-            Mat reference(CreateVideoWriterInvoker::FrameSize, CV_8UC3);
-
-            for (unsigned int i = 0; i < frameCount && next; ++i)
+            for (int j = r.start; j < r.end; ++j)
             {
-                SCOPED_TRACE(cv::format("frame=%d/%d", (int)i, (int)frameCount));
-
-                Mat actual;
-                (*capture) >> actual;
-
-                WriteVideo_Invoker::GenerateFrame(reference, i);
-
-                EXPECT_EQ(reference.cols, actual.cols);
-                EXPECT_EQ(reference.rows, actual.rows);
-                EXPECT_EQ(reference.depth(), actual.depth());
-                EXPECT_EQ(reference.channels(), actual.channels());
-
-                double psnr = cvtest::PSNR(actual, reference);
-                if (psnr < eps)
+                Mat reference(sz, CV_8UC3);
+                for (int i = 0; i < frameNum; ++i)
                 {
-    #define SUM cvtest::TS::SUMMARY
-                    ts->printf(SUM, "\nPSNR: %lf\n", psnr);
-                    ts->printf(SUM, "Video #: %d\n", range.start);
-                    ts->printf(SUM, "Frame #: %d\n", i);
-    #undef SUM
-                    ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
-                    ts->set_gtest_status();
-
-                    Mat diff;
-                    absdiff(actual, reference, diff);
-
-                    EXPECT_EQ(countNonZero(diff.reshape(1) > 1), 0);
-
-                    next = false;
+                    Mat actual;
+                    EXPECT_TRUE(readers[j]->read(actual));
+                    EXPECT_FALSE(actual.empty());
+                    generateFrame(reference, i, center, color);
+                    EXPECT_EQ(reference.size(), actual.size());
+                    EXPECT_EQ(reference.depth(), actual.depth());
+                    EXPECT_EQ(reference.channels(), actual.channels());
+                    EXPECT_GE(cvtest::PSNR(actual, reference), 35.0) << "cap" << j << ", frame " << i;
                 }
             }
-        }
+        };
+        parallel_for_(R, readFrames, GRAN);
     }
-
-    static bool next;
-
-private:
-    const std::vector<VideoCapture*>* readers;
-    cvtest::TS* ts;
-};
-
-bool ReadImageAndTest::next;
-
-TEST(Videoio_Video_parallel_writers_and_readers, accuracy)
-{
-    const unsigned int threadsCount = 4;
-    cvtest::TS* ts = cvtest::TS::ptr();
-
-    // creating VideoWriters
-    std::vector<VideoWriter*> writers(threadsCount);
-    Range range(0, threadsCount);
-    std::vector<std::string> files(threadsCount);
-    CreateVideoWriterInvoker invoker1(writers, files);
-    parallel_for_(range, invoker1);
-
-    // write a video
-    parallel_for_(range, WriteVideo_Invoker(writers));
-
-    // deleting the writers
-    for (std::vector<VideoWriter*>::iterator i = writers.begin(), end = writers.end(); i != end; ++i)
-        delete *i;
-    writers.clear();
-
-    std::vector<VideoCapture*> readers(threadsCount);
-    CreateVideoCaptureInvoker invoker2(readers, files);
-    parallel_for_(range, invoker2);
-
-    ReadImageAndTest::next = true;
-
-    parallel_for_(range, ReadImageAndTest(readers, ts));
-
-    // deleting tmp video files
-    for (std::vector<std::string>::const_iterator i = files.begin(), end = files.end(); i != end; ++i)
+    // Remove files
+    for(int i = 0; i < NUM; ++i)
     {
-        int code = remove(i->c_str());
-        if (code == 1)
-            std::cerr << "Couldn't delete " << *i << std::endl;
+        remove(files[i].c_str());
     }
-
-    // delete the readers
-    for (std::vector<VideoCapture *>::iterator i = readers.begin(), end = readers.end(); i != end; ++i)
-        delete *i;
 }
 
-#endif
 }} // namespace
diff --git a/modules/videoio/test/test_fourcc.cpp b/modules/videoio/test/test_fourcc.cpp
deleted file mode 100644 (file)
index 77f3281..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*M///////////////////////////////////////////////////////////////////////////////////////
-//
-//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
-//
-//  By downloading, copying, installing or using the software you agree to this license.
-//  If you do not agree to this license, do not download, install,
-//  copy or use the software.
-//
-//
-//                           License Agreement
-//                For Open Source Computer Vision Library
-//
-// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
-// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
-// Third party copyrights are property of their respective owners.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-//   * Redistribution's of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//
-//   * Redistribution's in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//
-//   * The name of the copyright holders may not be used to endorse or promote products
-//     derived from this software without specific prior written permission.
-//
-// This software is provided by the copyright holders and contributors "as is" and
-// any express or implied warranties, including, but not limited to, the implied
-// warranties of merchantability and fitness for a particular purpose are disclaimed.
-// In no event shall the Intel Corporation or contributors be liable for any direct,
-// indirect, incidental, special, exemplary, or consequential damages
-// (including, but not limited to, procurement of substitute goods or services;
-// loss of use, data, or profits; or business interruption) however caused
-// and on any theory of liability, whether in contract, strict liability,
-// or tort (including negligence or otherwise) arising in any way out of
-// the use of this software, even if advised of the possibility of such damage.
-//
-//M*/
-
-#include "test_precomp.hpp"
-
-namespace opencv_test { namespace {
-
-#undef DEFINE_GUID
-#define DEFINE_GUID(n, fourcc, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) fourcc,
-
-unsigned long allfourcc[] = {
-
-DEFINE_GUID(MEDIASUBTYPE_GREY, 0x59455247, 0x0000, 0x0010, 0x80, 0x00,
-    0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)
-DEFINE_GUID(MEDIASUBTYPE_Y8, 0x20203859, 0x0000, 0x0010, 0x80, 0x00,
-    0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)
-DEFINE_GUID(MEDIASUBTYPE_Y800, 0x30303859, 0x0000, 0x0010, 0x80, 0x00,
-    0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)
-
-DEFINE_GUID(CLSID_CaptureGraphBuilder2,0xbf87b6e1,0x8c27,0x11d0,0xb3,0xf0,0x00,0xaa,0x00,0x37,0x61,0xc5)
-DEFINE_GUID(CLSID_FilterGraph,0xe436ebb3,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70)
-DEFINE_GUID(CLSID_NullRenderer,0xc1f400a4,0x3f08,0x11d3,0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37)
-DEFINE_GUID(CLSID_SampleGrabber,0xc1f400a0,0x3f08,0x11d3,0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37)
-DEFINE_GUID(CLSID_SystemDeviceEnum,0x62be5d10,0x60eb,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86)
-DEFINE_GUID(CLSID_VideoInputDeviceCategory,0x860bb310,0x5d01,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86)
-DEFINE_GUID(FORMAT_VideoInfo,0x05589f80,0xc356,0x11ce,0xbf,0x01,0x00,0xaa,0x00,0x55,0x59,0x5a)
-DEFINE_GUID(IID_IAMAnalogVideoDecoder,0xc6e13350,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56)
-DEFINE_GUID(IID_IAMCameraControl,0xc6e13370,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56)
-DEFINE_GUID(IID_IAMCrossbar,0xc6e13380,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56)
-DEFINE_GUID(IID_IAMStreamConfig,0xc6e13340,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56)
-DEFINE_GUID(IID_IAMVideoProcAmp,0xc6e13360,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56)
-DEFINE_GUID(IID_IBaseFilter,0x56a86895,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70)
-DEFINE_GUID(IID_ICaptureGraphBuilder2,0x93e5a4e0,0x2d50,0x11d2,0xab,0xfa,0x00,0xa0,0xc9,0xc6,0xe3,0x8d)
-DEFINE_GUID(IID_ICreateDevEnum,0x29840822,0x5b84,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86)
-DEFINE_GUID(IID_IGraphBuilder,0x56a868a9,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70)
-DEFINE_GUID(IID_IMPEG2PIDMap,0xafb6c2a1,0x2c41,0x11d3,0x8a,0x60,0x00,0x00,0xf8,0x1e,0x0e,0x4a)
-DEFINE_GUID(IID_IMediaControl,0x56a868b1,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70)
-DEFINE_GUID(IID_IMediaFilter,0x56a86899,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70)
-DEFINE_GUID(IID_ISampleGrabber,0x6b652fff,0x11fe,0x4fce,0x92,0xad,0x02,0x66,0xb5,0xd7,0xc7,0x8f)
-DEFINE_GUID(LOOK_UPSTREAM_ONLY,0xac798be0,0x98e3,0x11d1,0xb3,0xf1,0x00,0xaa,0x00,0x37,0x61,0xc5)
-DEFINE_GUID(MEDIASUBTYPE_AYUV,0x56555941,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_IYUV,0x56555949,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_RGB24,0xe436eb7d,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70)
-DEFINE_GUID(MEDIASUBTYPE_RGB32,0xe436eb7e,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70)
-DEFINE_GUID(MEDIASUBTYPE_RGB555,0xe436eb7c,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70)
-DEFINE_GUID(MEDIASUBTYPE_RGB565,0xe436eb7b,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70)
-DEFINE_GUID(MEDIASUBTYPE_I420,0x49343230,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_UYVY,0x59565955,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_Y211,0x31313259,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_Y411,0x31313459,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_Y41P,0x50313459,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_YUY2,0x32595559,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_YUYV,0x56595559,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_YV12,0x32315659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_YVU9,0x39555659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_YVYU,0x55595659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIASUBTYPE_MJPG,0x47504A4D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71) // MGB
-DEFINE_GUID(MEDIATYPE_Interleaved,0x73766169,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(MEDIATYPE_Video,0x73646976,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71)
-DEFINE_GUID(PIN_CATEGORY_CAPTURE,0xfb6c4281,0x0353,0x11d1,0x90,0x5f,0x00,0x00,0xc0,0xcc,0x16,0xba)
-DEFINE_GUID(PIN_CATEGORY_PREVIEW,0xfb6c4282,0x0353,0x11d1,0x90,0x5f,0x00,0x00,0xc0,0xcc,0x16,0xba)
-
-0};
-
-
-TEST(Videoio_dshow, fourcc_conversion)
-{
-    for(int i = 0; allfourcc[i]; ++i)
-    {
-        unsigned long fourcc = allfourcc[i];
-
-        double paramValue = fourcc;
-        int fourccFromParam = (int)(unsigned long)(paramValue);
-
-        EXPECT_EQ(fourcc, (unsigned long)(unsigned)fourccFromParam);
-    }
-}
-
-}} // namespace
index 55accb5..7cadde1 100644 (file)
@@ -3,16 +3,18 @@
 // of this distribution and at http://opencv.org/license.html.
 
 #include "test_precomp.hpp"
-#ifdef HAVE_GSTREAMER
 
 namespace opencv_test
 {
 
 typedef tuple< string, Size, Size, int > Param;
-typedef testing::TestWithParam< Param > Videoio_Gstreamer_Test;
+typedef testing::TestWithParam< Param > videoio_gstreamer;
 
-TEST_P(Videoio_Gstreamer_Test, test_object_structure)
+TEST_P(videoio_gstreamer, read_write)
 {
+    if (!videoio_registry::hasBackend(CAP_GSTREAMER))
+        throw SkipTestException("GStreamer backend was not found");
+
     string format    = get<0>(GetParam());
     Size frame_size  = get<1>(GetParam());
     Size mat_size    = get<2>(GetParam());
@@ -69,8 +71,6 @@ Param test_data[] = {
     make_tuple("jpegenc ! image/jpeg"     , Size(640, 480), Size(640, 480), COLOR_BGR2RGB)
 };
 
-INSTANTIATE_TEST_CASE_P(videoio, Videoio_Gstreamer_Test, testing::ValuesIn(test_data));
+INSTANTIATE_TEST_CASE_P(videoio, videoio_gstreamer, testing::ValuesIn(test_data));
 
 } // namespace
-
-#endif
index caa3fe9..1c8f48e 100644 (file)
@@ -8,7 +8,7 @@
 
 namespace opencv_test { namespace {
 
-TEST(Videoio_MFX, read_invalid)
+TEST(videoio_mfx, read_invalid)
 {
     VideoCapture cap;
     ASSERT_NO_THROW(cap.open("nonexistent-file", CAP_INTEL_MFX));
@@ -18,7 +18,7 @@ TEST(Videoio_MFX, read_invalid)
     ASSERT_TRUE(img.empty());
 }
 
-TEST(Videoio_MFX, write_invalid)
+TEST(videoio_mfx, write_invalid)
 {
     const string filename = cv::tempfile(".264");
     VideoWriter writer;
@@ -80,9 +80,9 @@ inline int fourccByExt(const String &ext)
 //==================================================================================================
 
 typedef tuple<Size, double, const char *> Size_FPS_Ext;
-typedef testing::TestWithParam< Size_FPS_Ext > Videoio_MFX;
+typedef testing::TestWithParam< Size_FPS_Ext > videoio_mfx;
 
-TEST_P(Videoio_MFX, read_write_raw)
+TEST_P(videoio_mfx, read_write_raw)
 {
     const Size FRAME_SIZE = get<0>(GetParam());
     const double FPS = get<1>(GetParam());
@@ -137,7 +137,7 @@ TEST_P(Videoio_MFX, read_write_raw)
     remove(filename.c_str());
 }
 
-INSTANTIATE_TEST_CASE_P(videoio, Videoio_MFX,
+INSTANTIATE_TEST_CASE_P(videoio, videoio_mfx,
                         testing::Combine(
                             testing::Values(Size(640, 480), Size(638, 478), Size(636, 476), Size(1920, 1080)),
                             testing::Values(1, 30, 100),
index ddc976d..2d07cfe 100644 (file)
@@ -55,6 +55,7 @@ protected:
 protected:
     Videoio_Test_Base() {}
     virtual ~Videoio_Test_Base() {}
+    virtual void writeVideo() {}
     virtual void checkFrameContent(Mat &, int) {}
     virtual void checkFrameCount(int &) {}
     void checkFrameRead(int idx, VideoCapture & cap)
@@ -81,8 +82,9 @@ protected:
 public:
     void doTest()
     {
-        if (!isBackendAvailable(apiPref, cv::videoio_registry::getStreamBackends()))
+        if (!videoio_registry::hasBackend(apiPref, videoio_registry::Read))
             throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
+        writeVideo();
         VideoCapture cap;
         ASSERT_NO_THROW(cap.open(video_file, apiPref));
         if (!cap.isOpened())
@@ -154,11 +156,11 @@ public:
 //==================================================================================================
 typedef tuple<string, VideoCaptureAPIs> Backend_Type_Params;
 
-class Videoio_Bunny : public Videoio_Test_Base, public testing::TestWithParam<Backend_Type_Params>
+class videoio_bunny : public Videoio_Test_Base, public testing::TestWithParam<Backend_Type_Params>
 {
     BunnyParameters bunny_param;
 public:
-    Videoio_Bunny()
+    videoio_bunny()
     {
         ext = get<0>(GetParam());
         apiPref = get<1>(GetParam());
@@ -166,7 +168,7 @@ public:
     }
     void doFrameCountTest()
     {
-        if (!isBackendAvailable(apiPref, cv::videoio_registry::getStreamBackends()))
+        if (!videoio_registry::hasBackend(apiPref, videoio_registry::Read))
             throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
         VideoCapture cap;
         EXPECT_NO_THROW(cap.open(video_file, apiPref));
@@ -232,7 +234,7 @@ struct Ext_Fourcc_PSNR
 };
 typedef tuple<Size, Ext_Fourcc_PSNR> Size_Ext_Fourcc_PSNR;
 
-class Videoio_Synthetic : public Videoio_Test_Base, public testing::TestWithParam<Size_Ext_Fourcc_PSNR>
+class videoio_synthetic : public Videoio_Test_Base, public testing::TestWithParam<Size_Ext_Fourcc_PSNR>
 {
     Size frame_size;
     int fourcc;
@@ -240,7 +242,7 @@ class Videoio_Synthetic : public Videoio_Test_Base, public testing::TestWithPara
     int frame_count;
     double fps;
 public:
-    Videoio_Synthetic()
+    videoio_synthetic()
     {
         frame_size = get<0>(GetParam());
         const Ext_Fourcc_PSNR p = get<1>(GetParam());
@@ -252,7 +254,11 @@ public:
         fps = 25.;
         apiPref = p.api;
     }
-    void SetUp()
+    void TearDown()
+    {
+        remove(video_file.c_str());
+    }
+    virtual void writeVideo()
     {
         Mat img(frame_size, CV_8UC3);
         VideoWriter writer;
@@ -265,10 +271,6 @@ public:
         }
         EXPECT_NO_THROW(writer.release());
     }
-    void TearDown()
-    {
-        remove(video_file.c_str());
-    }
     virtual void checkFrameContent(Mat & img, int idx)
     {
         Mat imgGT(frame_size, CV_8UC3);
@@ -311,13 +313,8 @@ static const VideoCaptureAPIs backend_params[] = {
     CAP_MSMF,
 #endif
 
-#ifdef HAVE_GSTREAMER
     CAP_GSTREAMER,
-#endif
-
-#ifdef HAVE_FFMPEG
     CAP_FFMPEG,
-#endif
 
 #ifdef HAVE_XINE
     CAP_XINE,
@@ -338,11 +335,11 @@ static const string bunny_params[] = {
     string("mjpg.avi")
 };
 
-TEST_P(Videoio_Bunny, read_position) { doTest(); }
+TEST_P(videoio_bunny, read_position) { doTest(); }
 
-TEST_P(Videoio_Bunny, frame_count) { doFrameCountTest(); }
+TEST_P(videoio_bunny, frame_count) { doFrameCountTest(); }
 
-INSTANTIATE_TEST_CASE_P(videoio, Videoio_Bunny,
+INSTANTIATE_TEST_CASE_P(videoio, videoio_bunny,
                           testing::Combine(
                               testing::ValuesIn(bunny_params),
                               testing::ValuesIn(backend_params)));
@@ -388,7 +385,6 @@ static Ext_Fourcc_PSNR synthetic_params[] = {
    makeParam("3gp", "MJPG", 30.f, CAP_AVFOUNDATION),
 #endif
 
-#ifdef HAVE_FFMPEG
     makeParam("avi", "XVID", 30.f, CAP_FFMPEG),
     makeParam("avi", "MPEG", 30.f, CAP_FFMPEG),
     makeParam("avi", "IYUV", 30.f, CAP_FFMPEG),
@@ -397,9 +393,7 @@ static Ext_Fourcc_PSNR synthetic_params[] = {
     makeParam("mkv", "XVID", 30.f, CAP_FFMPEG),
     makeParam("mkv", "MPEG", 30.f, CAP_FFMPEG),
     makeParam("mkv", "MJPG", 30.f, CAP_FFMPEG),
-#endif
 
-#ifdef HAVE_GSTREAMER
     makeParam("avi", "MPEG", 30.f, CAP_GSTREAMER),
     makeParam("avi", "MJPG", 30.f, CAP_GSTREAMER),
     makeParam("avi", "H264", 30.f, CAP_GSTREAMER),
@@ -408,7 +402,6 @@ static Ext_Fourcc_PSNR synthetic_params[] = {
     makeParam("mkv", "MJPG", 30.f, CAP_GSTREAMER),
     makeParam("mkv", "H264", 30.f, CAP_GSTREAMER),
 
-#endif
     makeParam("avi", "MJPG", 30.f, CAP_OPENCV_MJPEG),
 };
 
@@ -418,9 +411,9 @@ Size all_sizes[] = {
     Size(976, 768)
 };
 
-TEST_P(Videoio_Synthetic, write_read_position) { doTest(); }
+TEST_P(videoio_synthetic, write_read_position) { doTest(); }
 
-INSTANTIATE_TEST_CASE_P(videoio, Videoio_Synthetic,
+INSTANTIATE_TEST_CASE_P(videoio, videoio_synthetic,
                         testing::Combine(
                             testing::ValuesIn(all_sizes),
                             testing::ValuesIn(synthetic_params)));