From 0f1e19319365f1c753735b8e04e58461276f77fd Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Mon, 26 Feb 2018 00:16:02 +0300 Subject: [PATCH 01/36] Fixed two issues found by static analysis --- modules/dnn/src/layers/pooling_layer.cpp | 2 ++ modules/imgcodecs/src/grfmt_tiff.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/modules/dnn/src/layers/pooling_layer.cpp b/modules/dnn/src/layers/pooling_layer.cpp index 3cdc786517..1aeba3a7be 100644 --- a/modules/dnn/src/layers/pooling_layer.cpp +++ b/modules/dnn/src/layers/pooling_layer.cpp @@ -323,6 +323,8 @@ public: #if CV_SIMD128 const int* ofsptr = ofsbuf.empty() ? 0 : (const int*)&ofsbuf[0]; + if (poolingType == MAX && !compMaxIdx && !ofsptr) + CV_Error(Error::StsBadArg, "ofsbuf should be initialized in this mode"); v_float32x4 idx00(0.f, (float)stride_w, (float)(stride_w*2), (float)(stride_w*3)); v_float32x4 ones = v_setall_f32(1.f); v_float32x4 idx_delta = v_setall_f32((float)(inp_width - kernel_w)); diff --git a/modules/imgcodecs/src/grfmt_tiff.cpp b/modules/imgcodecs/src/grfmt_tiff.cpp index 372176ec40..e2aa2bd989 100644 --- a/modules/imgcodecs/src/grfmt_tiff.cpp +++ b/modules/imgcodecs/src/grfmt_tiff.cpp @@ -775,6 +775,7 @@ bool TiffEncoder::writeLibTiff( const std::vector& img_vec, const std::vect } default: { + TIFFClose(pTiffHandle); return false; } } From ca9af2017981b73903123a0de5f33c60b06e1c45 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 19 Feb 2018 17:39:30 +0300 Subject: [PATCH 02/36] OpenCV version '-cvsdk' --- modules/core/include/opencv2/core/version.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/version.hpp b/modules/core/include/opencv2/core/version.hpp index c999a80245..3af07cd9cb 100644 --- a/modules/core/include/opencv2/core/version.hpp +++ b/modules/core/include/opencv2/core/version.hpp @@ -8,7 +8,7 @@ #define CV_VERSION_MAJOR 3 #define CV_VERSION_MINOR 4 #define CV_VERSION_REVISION 1 -#define CV_VERSION_STATUS "" +#define CV_VERSION_STATUS "-cvsdk" #define CVAUX_STR_EXP(__A) #__A #define CVAUX_STR(__A) CVAUX_STR_EXP(__A) From e969f184e11d45e7d6deb13326cda3b5d52181a7 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 27 Feb 2018 15:48:19 +0300 Subject: [PATCH 03/36] 3rdparty: fix protobuf version in README file --- 3rdparty/protobuf/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/protobuf/README.md b/3rdparty/protobuf/README.md index 6c5b6396d2..e0edb75f58 100644 --- a/3rdparty/protobuf/README.md +++ b/3rdparty/protobuf/README.md @@ -1,3 +1,3 @@ Project: Protocol Buffers - Google's data interchange format Source code: https://github.com/google/protobuf -Version: 3.1.0 +Version: 3.5.1 From 4a6d582f2ef3ddbcf16e7ad7b00359827640e8d3 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 28 Feb 2018 13:58:55 +0300 Subject: [PATCH 04/36] dnn: make OpenCL DNN code optional --- cmake/OpenCVModule.cmake | 8 ++++++-- modules/dnn/CMakeLists.txt | 19 +++++++++++++++++-- .../INIT_MODULE_SOURCES_opencv_dnn.cmake | 3 +++ modules/dnn/src/layers/batch_norm_layer.cpp | 3 +++ modules/dnn/src/layers/concat_layer.cpp | 3 +++ modules/dnn/src/layers/convolution_layer.cpp | 2 +- .../dnn/src/layers/detection_output_layer.cpp | 3 +++ modules/dnn/src/layers/elementwise_layers.cpp | 5 ++++- modules/dnn/src/layers/eltwise_layer.cpp | 3 +++ .../dnn/src/layers/fully_connected_layer.cpp | 2 +- modules/dnn/src/layers/layers_common.cpp | 1 + modules/dnn/src/layers/layers_common.hpp | 2 +- modules/dnn/src/layers/lrn_layer.cpp | 2 +- modules/dnn/src/layers/mvn_layer.cpp | 5 ++++- modules/dnn/src/layers/permute_layer.cpp | 3 +++ modules/dnn/src/layers/pooling_layer.cpp | 3 ++- modules/dnn/src/layers/prior_box_layer.cpp | 3 +++ modules/dnn/src/layers/region_layer.cpp | 3 +++ modules/dnn/src/layers/reorg_layer.cpp | 3 +++ modules/dnn/src/layers/slice_layer.cpp | 3 +++ modules/dnn/src/layers/softmax_layer.cpp | 3 ++- modules/dnn/src/ocl4dnn/include/common.hpp | 3 --- .../src/ocl4dnn/include/math_functions.hpp | 3 --- modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp | 8 +++----- modules/dnn/src/ocl4dnn/src/common.cpp | 5 +---- .../dnn/src/ocl4dnn/src/math_functions.cpp | 18 ++++-------------- .../src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp | 15 ++++++--------- .../src/ocl4dnn/src/ocl4dnn_inner_product.cpp | 13 +++++-------- modules/dnn/src/ocl4dnn/src/ocl4dnn_lrn.cpp | 11 ++++------- modules/dnn/src/ocl4dnn/src/ocl4dnn_pool.cpp | 11 ++++------- .../dnn/src/ocl4dnn/src/ocl4dnn_softmax.cpp | 11 ++++------- modules/dnn/src/precomp.hpp | 17 ++++++++++++++++- 32 files changed, 117 insertions(+), 80 deletions(-) create mode 100644 modules/dnn/cmake/hooks/INIT_MODULE_SOURCES_opencv_dnn.cmake diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index 3f22788745..f5beeba09a 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -747,7 +747,7 @@ endmacro() # finds and sets headers and sources for the standard OpenCV module # Usage: -# ocv_glob_module_sources([EXCLUDE_CUDA] ) +# ocv_glob_module_sources([EXCLUDE_CUDA] [EXCLUDE_OPENCL] ) macro(ocv_glob_module_sources) ocv_debug_message("ocv_glob_module_sources(" ${ARGN} ")") set(_argn ${ARGN}) @@ -755,6 +755,10 @@ macro(ocv_glob_module_sources) if(NOT exclude_cuda EQUAL -1) list(REMOVE_AT _argn ${exclude_cuda}) endif() + list(FIND _argn "EXCLUDE_OPENCL" exclude_opencl) + if(NOT exclude_opencl EQUAL -1) + list(REMOVE_AT _argn ${exclude_opencl}) + endif() file(GLOB_RECURSE lib_srcs "${CMAKE_CURRENT_LIST_DIR}/src/*.cpp" @@ -801,7 +805,7 @@ macro(ocv_glob_module_sources) file(GLOB cl_kernels "${CMAKE_CURRENT_LIST_DIR}/src/opencl/*.cl" ) - if(cl_kernels) + if(cl_kernels AND exclude_opencl EQUAL -1) set(OCL_NAME opencl_kernels_${name}) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${OCL_NAME}.cpp" # don't add .hpp file here to optimize build process diff --git a/modules/dnn/CMakeLists.txt b/modules/dnn/CMakeLists.txt index 7971046851..9f105d3453 100644 --- a/modules/dnn/CMakeLists.txt +++ b/modules/dnn/CMakeLists.txt @@ -11,6 +11,14 @@ set(the_description "Deep neural network module. It allows to load models from d ocv_add_dispatched_file_force_all("layers/layers_common" AVX AVX2 AVX512_SKX) ocv_add_module(dnn opencv_core opencv_imgproc WRAP python matlab java js) + +ocv_option(OPENCV_DNN_OPENCL "Build with OpenCL support" HAVE_OPENCL) +if(OPENCV_DNN_OPENCL AND HAVE_OPENCL) + add_definitions(-DCV_OCL4DNN=1) +else() + ocv_cmake_hook_append(INIT_MODULE_SOURCES_opencv_dnn "${CMAKE_CURRENT_LIST_DIR}/cmake/hooks/INIT_MODULE_SOURCES_opencv_dnn.cmake") +endif() + ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-shadow -Wno-parentheses -Wmaybe-uninitialized -Wsign-promo -Wmissing-declarations -Wmissing-prototypes ) @@ -63,8 +71,15 @@ else() set(fw_inc "${CMAKE_CURRENT_LIST_DIR}/misc/caffe" "${CMAKE_CURRENT_LIST_DIR}/misc/tensorflow") endif() -ocv_module_include_directories(${fw_inc} ${CMAKE_CURRENT_LIST_DIR}/src/ocl4dnn/include ${OPENCL_INCLUDE_DIRS}) -ocv_glob_module_sources(SOURCES ${fw_srcs}) +set(include_dirs ${fw_inc}) +set(sources_options "") +if(OPENCV_DNN_OPENCL AND HAVE_OPENCL) + list(APPEND include_dirs ${OPENCL_INCLUDE_DIRS}) +else() + set(sources_options EXCLUDE_OPENCL) +endif() +ocv_module_include_directories(${include_dirs}) +ocv_glob_module_sources(${sources_options} SOURCES ${fw_srcs}) ocv_create_module(libprotobuf ${LAPACK_LIBRARIES}) ocv_add_samples() ocv_add_accuracy_tests() diff --git a/modules/dnn/cmake/hooks/INIT_MODULE_SOURCES_opencv_dnn.cmake b/modules/dnn/cmake/hooks/INIT_MODULE_SOURCES_opencv_dnn.cmake new file mode 100644 index 0000000000..f19002d13a --- /dev/null +++ b/modules/dnn/cmake/hooks/INIT_MODULE_SOURCES_opencv_dnn.cmake @@ -0,0 +1,3 @@ +message(STATUS "opencv_dnn: filter out ocl4dnn source code") +ocv_list_filterout(OPENCV_MODULE_${the_module}_SOURCES "/ocl4dnn/") +ocv_list_filterout(OPENCV_MODULE_${the_module}_HEADERS "/ocl4dnn/") diff --git a/modules/dnn/src/layers/batch_norm_layer.cpp b/modules/dnn/src/layers/batch_norm_layer.cpp index cab9bb7b60..ef8735aa21 100644 --- a/modules/dnn/src/layers/batch_norm_layer.cpp +++ b/modules/dnn/src/layers/batch_norm_layer.cpp @@ -13,7 +13,10 @@ Implementation of Batch Normalization layer. #include "op_halide.hpp" #include "op_inf_engine.hpp" #include + +#ifdef HAVE_OPENCL #include "opencl_kernels_dnn.hpp" +#endif namespace cv { diff --git a/modules/dnn/src/layers/concat_layer.cpp b/modules/dnn/src/layers/concat_layer.cpp index 63b722ee9a..f9c4494b47 100644 --- a/modules/dnn/src/layers/concat_layer.cpp +++ b/modules/dnn/src/layers/concat_layer.cpp @@ -44,7 +44,10 @@ #include "layers_common.hpp" #include "op_halide.hpp" #include "op_inf_engine.hpp" + +#ifdef HAVE_OPENCL #include "opencl_kernels_dnn.hpp" +#endif namespace cv { diff --git a/modules/dnn/src/layers/convolution_layer.cpp b/modules/dnn/src/layers/convolution_layer.cpp index 40681c963f..79a833ba15 100644 --- a/modules/dnn/src/layers/convolution_layer.cpp +++ b/modules/dnn/src/layers/convolution_layer.cpp @@ -47,9 +47,9 @@ #include "opencv2/core/hal/hal.hpp" #include "opencv2/core/hal/intrin.hpp" #include -#include "opencl_kernels_dnn.hpp" #ifdef HAVE_OPENCL +#include "opencl_kernels_dnn.hpp" using namespace cv::dnn::ocl4dnn; #endif diff --git a/modules/dnn/src/layers/detection_output_layer.cpp b/modules/dnn/src/layers/detection_output_layer.cpp index 70d7dfb0b1..712d542ed7 100644 --- a/modules/dnn/src/layers/detection_output_layer.cpp +++ b/modules/dnn/src/layers/detection_output_layer.cpp @@ -46,7 +46,10 @@ #include #include #include "../nms.inl.hpp" + +#ifdef HAVE_OPENCL #include "opencl_kernels_dnn.hpp" +#endif namespace cv { diff --git a/modules/dnn/src/layers/elementwise_layers.cpp b/modules/dnn/src/layers/elementwise_layers.cpp index adf51c8942..7394f2ed70 100644 --- a/modules/dnn/src/layers/elementwise_layers.cpp +++ b/modules/dnn/src/layers/elementwise_layers.cpp @@ -46,9 +46,12 @@ #include "op_inf_engine.hpp" #include "opencv2/imgproc.hpp" #include -#include "opencl_kernels_dnn.hpp" #include +#ifdef HAVE_OPENCL +#include "opencl_kernels_dnn.hpp" +#endif + namespace cv { namespace dnn diff --git a/modules/dnn/src/layers/eltwise_layer.cpp b/modules/dnn/src/layers/eltwise_layer.cpp index 0e09202909..65238318be 100644 --- a/modules/dnn/src/layers/eltwise_layer.cpp +++ b/modules/dnn/src/layers/eltwise_layer.cpp @@ -44,7 +44,10 @@ #include "layers_common.hpp" #include "op_halide.hpp" #include "op_inf_engine.hpp" + +#ifdef HAVE_OPENCL #include "opencl_kernels_dnn.hpp" +#endif namespace cv { diff --git a/modules/dnn/src/layers/fully_connected_layer.cpp b/modules/dnn/src/layers/fully_connected_layer.cpp index ccc8dec96a..174421e37b 100644 --- a/modules/dnn/src/layers/fully_connected_layer.cpp +++ b/modules/dnn/src/layers/fully_connected_layer.cpp @@ -44,10 +44,10 @@ #include "layers_common.hpp" #include "op_halide.hpp" #include "op_inf_engine.hpp" -#include "opencl_kernels_dnn.hpp" #include #ifdef HAVE_OPENCL +#include "opencl_kernels_dnn.hpp" using namespace cv::dnn::ocl4dnn; #endif diff --git a/modules/dnn/src/layers/layers_common.cpp b/modules/dnn/src/layers/layers_common.cpp index 8552a4a0cc..f854d91ccc 100644 --- a/modules/dnn/src/layers/layers_common.cpp +++ b/modules/dnn/src/layers/layers_common.cpp @@ -40,6 +40,7 @@ // //M*/ +#include "../precomp.hpp" #include "layers_common.hpp" namespace cv diff --git a/modules/dnn/src/layers/layers_common.hpp b/modules/dnn/src/layers/layers_common.hpp index ed8add94ff..97902138b1 100644 --- a/modules/dnn/src/layers/layers_common.hpp +++ b/modules/dnn/src/layers/layers_common.hpp @@ -52,7 +52,7 @@ #undef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY #ifdef HAVE_OPENCL -#include "ocl4dnn.hpp" +#include "../ocl4dnn/include/ocl4dnn.hpp" #endif namespace cv diff --git a/modules/dnn/src/layers/lrn_layer.cpp b/modules/dnn/src/layers/lrn_layer.cpp index a01d5f0a8d..1011cb66f2 100644 --- a/modules/dnn/src/layers/lrn_layer.cpp +++ b/modules/dnn/src/layers/lrn_layer.cpp @@ -47,10 +47,10 @@ #include "opencv2/imgproc.hpp" #include "opencv2/dnn/shape_utils.hpp" #include "opencv2/core/hal/hal.hpp" -#include "opencl_kernels_dnn.hpp" #include #ifdef HAVE_OPENCL +#include "opencl_kernels_dnn.hpp" using namespace cv::dnn::ocl4dnn; #endif diff --git a/modules/dnn/src/layers/mvn_layer.cpp b/modules/dnn/src/layers/mvn_layer.cpp index be44435386..09993a3c04 100644 --- a/modules/dnn/src/layers/mvn_layer.cpp +++ b/modules/dnn/src/layers/mvn_layer.cpp @@ -43,8 +43,11 @@ #include "../precomp.hpp" #include "layers_common.hpp" #include -#include "math_functions.hpp" + +#ifdef HAVE_OPENCL +#include "../ocl4dnn/include/math_functions.hpp" #include "opencl_kernels_dnn.hpp" +#endif namespace cv { diff --git a/modules/dnn/src/layers/permute_layer.cpp b/modules/dnn/src/layers/permute_layer.cpp index bdc47fb737..b98365848f 100644 --- a/modules/dnn/src/layers/permute_layer.cpp +++ b/modules/dnn/src/layers/permute_layer.cpp @@ -45,7 +45,10 @@ #include "op_inf_engine.hpp" #include #include + +#ifdef HAVE_OPENCL #include "opencl_kernels_dnn.hpp" +#endif namespace cv { diff --git a/modules/dnn/src/layers/pooling_layer.cpp b/modules/dnn/src/layers/pooling_layer.cpp index 1aeba3a7be..9918cad91f 100644 --- a/modules/dnn/src/layers/pooling_layer.cpp +++ b/modules/dnn/src/layers/pooling_layer.cpp @@ -45,12 +45,13 @@ #include "opencv2/core/hal/intrin.hpp" #include "op_halide.hpp" #include "op_inf_engine.hpp" -#include "opencl_kernels_dnn.hpp" #include #include using std::max; using std::min; + #ifdef HAVE_OPENCL +#include "opencl_kernels_dnn.hpp" using namespace cv::dnn::ocl4dnn; #endif diff --git a/modules/dnn/src/layers/prior_box_layer.cpp b/modules/dnn/src/layers/prior_box_layer.cpp index 848e1921be..d8ea5b6042 100644 --- a/modules/dnn/src/layers/prior_box_layer.cpp +++ b/modules/dnn/src/layers/prior_box_layer.cpp @@ -46,7 +46,10 @@ #include #include #include + +#ifdef HAVE_OPENCL #include "opencl_kernels_dnn.hpp" +#endif namespace cv { diff --git a/modules/dnn/src/layers/region_layer.cpp b/modules/dnn/src/layers/region_layer.cpp index 688cb90218..3f9ba1fc0c 100644 --- a/modules/dnn/src/layers/region_layer.cpp +++ b/modules/dnn/src/layers/region_layer.cpp @@ -44,7 +44,10 @@ #include #include #include "nms.inl.hpp" + +#ifdef HAVE_OPENCL #include "opencl_kernels_dnn.hpp" +#endif namespace cv { diff --git a/modules/dnn/src/layers/reorg_layer.cpp b/modules/dnn/src/layers/reorg_layer.cpp index 51da9fd12e..b5e1149497 100644 --- a/modules/dnn/src/layers/reorg_layer.cpp +++ b/modules/dnn/src/layers/reorg_layer.cpp @@ -44,7 +44,10 @@ #include #include #include + +#ifdef HAVE_OPENCL #include "opencl_kernels_dnn.hpp" +#endif namespace cv { diff --git a/modules/dnn/src/layers/slice_layer.cpp b/modules/dnn/src/layers/slice_layer.cpp index 2d8b4dc777..728d571dce 100644 --- a/modules/dnn/src/layers/slice_layer.cpp +++ b/modules/dnn/src/layers/slice_layer.cpp @@ -43,7 +43,10 @@ #include "../precomp.hpp" #include "layers_common.hpp" #include + +#ifdef HAVE_OPENCL #include "opencl_kernels_dnn.hpp" +#endif namespace cv { diff --git a/modules/dnn/src/layers/softmax_layer.cpp b/modules/dnn/src/layers/softmax_layer.cpp index 49807cd8ac..55ae3addb7 100644 --- a/modules/dnn/src/layers/softmax_layer.cpp +++ b/modules/dnn/src/layers/softmax_layer.cpp @@ -44,11 +44,12 @@ #include "layers_common.hpp" #include "op_halide.hpp" #include "op_inf_engine.hpp" -#include "opencl_kernels_dnn.hpp" #include #include using std::max; + #ifdef HAVE_OPENCL +#include "opencl_kernels_dnn.hpp" using namespace cv::dnn::ocl4dnn; #endif diff --git a/modules/dnn/src/ocl4dnn/include/common.hpp b/modules/dnn/src/ocl4dnn/include/common.hpp index 41466429b0..1cc1d7d5e8 100644 --- a/modules/dnn/src/ocl4dnn/include/common.hpp +++ b/modules/dnn/src/ocl4dnn/include/common.hpp @@ -45,8 +45,6 @@ #include "../../caffe/glog_emulator.hpp" #include -#ifdef HAVE_OPENCL - // Macro to select the single (_float) or double (_double) precision kernel #define CL_KERNEL_SELECT(kernel) kernel "_float" @@ -58,5 +56,4 @@ bool clOptionSupport(cv::String option); -#endif // HAVE_OPENCL #endif diff --git a/modules/dnn/src/ocl4dnn/include/math_functions.hpp b/modules/dnn/src/ocl4dnn/include/math_functions.hpp index cac860490f..241f515752 100644 --- a/modules/dnn/src/ocl4dnn/include/math_functions.hpp +++ b/modules/dnn/src/ocl4dnn/include/math_functions.hpp @@ -52,7 +52,6 @@ namespace dnn namespace ocl4dnn { -#ifdef HAVE_OPENCL enum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113}; template @@ -81,8 +80,6 @@ bool ocl4dnnAXPY(const int32_t N, const Dtype alpha, const UMat x, const int32_t offx, UMat y, const int32_t offy); -#endif // HAVE_OPENCL - } // namespace ocl4dnn } // namespace dnn } // namespce cv diff --git a/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp b/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp index 70ced11276..e4cf304ca9 100644 --- a/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp +++ b/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp @@ -51,7 +51,6 @@ #include "common.hpp" namespace cv { namespace dnn { namespace ocl4dnn { -#ifdef HAVE_OPENCL struct OCL4DNNConvConfig { @@ -507,8 +506,7 @@ class OCL4DNNSoftmax bool log_softmax_; UMat scale_data_; }; -#endif // HAVE_OPENCL -} // namespace ocl4dnn -} // namespace dnn -} // namespce cv + +}}} // namespace cv::dnn::ocl4dnn + #endif diff --git a/modules/dnn/src/ocl4dnn/src/common.cpp b/modules/dnn/src/ocl4dnn/src/common.cpp index 5a18c41110..7ca196b355 100644 --- a/modules/dnn/src/ocl4dnn/src/common.cpp +++ b/modules/dnn/src/ocl4dnn/src/common.cpp @@ -41,17 +41,14 @@ //M*/ #include "../../precomp.hpp" -#include "common.hpp" +#include "../include/common.hpp" #include "opencl_kernels_dnn.hpp" using namespace cv; -#ifdef HAVE_OPENCL bool clOptionSupport(cv::String option) { cv::String errmsg; ocl::Program program = ocl::Context::getDefault().getProg(ocl::dnn::dummy_oclsrc, option, errmsg); return program.ptr() ? true : false; } - -#endif // HAVE_OPENCL diff --git a/modules/dnn/src/ocl4dnn/src/math_functions.cpp b/modules/dnn/src/ocl4dnn/src/math_functions.cpp index 05cfd509b9..3f4a70bc03 100644 --- a/modules/dnn/src/ocl4dnn/src/math_functions.cpp +++ b/modules/dnn/src/ocl4dnn/src/math_functions.cpp @@ -41,19 +41,13 @@ //M*/ #include "../../precomp.hpp" -#include "common.hpp" -#include "math_functions.hpp" +#include "../include/common.hpp" +#include "../include/math_functions.hpp" #include #include "opencl_kernels_dnn.hpp" -namespace cv -{ -namespace dnn -{ -namespace ocl4dnn -{ +namespace cv { namespace dnn { namespace ocl4dnn { -#ifdef HAVE_OPENCL // Create and copy buffer to image for GEMM's matrix A and B. // Will return image to caller if the input image is NULL. Otherwise, // will use the image directly. It's caller's responsibility to @@ -527,8 +521,4 @@ template bool ocl4dnnAXPY(const int32_t N, const float alpha, const UMat X, const int32_t offX, UMat Y, const int32_t offY); -#endif // HAVE_OPENCL - -} // namespace ocl4dnn -} // namespace dnn -} // namespce cv +}}} // namespace cv::dnn::ocl4dnn diff --git a/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp b/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp index 84ea1914dc..c58545f50f 100644 --- a/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp +++ b/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp @@ -49,18 +49,17 @@ #include #include #include -#include "common.hpp" -#include "ocl4dnn.hpp" +#include "../include/common.hpp" +#include "../include/ocl4dnn.hpp" #include "opencl_kernels_dnn.hpp" -#include "math_functions.hpp" -#include "default_kernel_config.hpp" +#include "../include/math_functions.hpp" +#include "../include/default_kernel_config.hpp" #if defined WIN32 || defined _WIN32 #include #include #endif -#ifdef HAVE_OPENCL namespace cv { namespace dnn { namespace ocl4dnn { static cv::Mutex kernelConfigMutex; typedef std::map kernel_hash_t; @@ -1855,7 +1854,5 @@ bool OCL4DNNConvSpatial::loadTunedConfig() } template class OCL4DNNConvSpatial; -} // namespace ocl4dnn -} -} -#endif // HAVE_OPENCL + +}}} // namespace cv::dnn::ocl4dnn diff --git a/modules/dnn/src/ocl4dnn/src/ocl4dnn_inner_product.cpp b/modules/dnn/src/ocl4dnn/src/ocl4dnn_inner_product.cpp index b6c1df9908..aabee57984 100644 --- a/modules/dnn/src/ocl4dnn/src/ocl4dnn_inner_product.cpp +++ b/modules/dnn/src/ocl4dnn/src/ocl4dnn_inner_product.cpp @@ -41,11 +41,10 @@ //M*/ #include "../../precomp.hpp" -#include "common.hpp" -#include "ocl4dnn.hpp" -#include "math_functions.hpp" +#include "../include/common.hpp" +#include "../include/ocl4dnn.hpp" +#include "../include/math_functions.hpp" -#ifdef HAVE_OPENCL namespace cv { namespace dnn { namespace ocl4dnn { template OCL4DNNInnerProduct::OCL4DNNInnerProduct(OCL4DNNInnerProductConfig config) @@ -102,7 +101,5 @@ bool OCL4DNNInnerProduct::Forward(const UMat& bottom, } template class OCL4DNNInnerProduct; -} // namespace ocl4dnn -} -} -#endif // HAVE_OPENCL + +}}} // namespace cv::dnn::ocl4dnn diff --git a/modules/dnn/src/ocl4dnn/src/ocl4dnn_lrn.cpp b/modules/dnn/src/ocl4dnn/src/ocl4dnn_lrn.cpp index 476d05287f..c7062f4090 100644 --- a/modules/dnn/src/ocl4dnn/src/ocl4dnn_lrn.cpp +++ b/modules/dnn/src/ocl4dnn/src/ocl4dnn_lrn.cpp @@ -41,11 +41,10 @@ //M*/ #include "../../precomp.hpp" -#include "common.hpp" -#include "ocl4dnn.hpp" +#include "../include/common.hpp" +#include "../include/ocl4dnn.hpp" #include "opencl_kernels_dnn.hpp" -#ifdef HAVE_OPENCL namespace cv { namespace dnn { namespace ocl4dnn { template OCL4DNNLRN::OCL4DNNLRN(OCL4DNNLRNConfig config) @@ -119,7 +118,5 @@ bool OCL4DNNLRN::crossChannelForward(const UMat& bottom, UMat& top) } template class OCL4DNNLRN; -} // namespace ocl4dnn -} -} -#endif // HAVE_OPENCL + +}}} // namespace cv::dnn::ocl4dnn diff --git a/modules/dnn/src/ocl4dnn/src/ocl4dnn_pool.cpp b/modules/dnn/src/ocl4dnn/src/ocl4dnn_pool.cpp index 4d4ea9e2a9..2d9c4dcf77 100644 --- a/modules/dnn/src/ocl4dnn/src/ocl4dnn_pool.cpp +++ b/modules/dnn/src/ocl4dnn/src/ocl4dnn_pool.cpp @@ -42,11 +42,10 @@ #include "../../precomp.hpp" #include #include -#include "common.hpp" -#include "ocl4dnn.hpp" +#include "../include/common.hpp" +#include "../include/ocl4dnn.hpp" #include "opencl_kernels_dnn.hpp" -#ifdef HAVE_OPENCL namespace cv { namespace dnn { namespace ocl4dnn { template OCL4DNNPool::OCL4DNNPool(OCL4DNNPoolConfig config) @@ -208,7 +207,5 @@ bool OCL4DNNPool::Forward(const UMat& bottom, } template class OCL4DNNPool; -} // namespace ocl4dnn -} -} -#endif // HAVE_OPENCL + +}}} // namespace cv::dnn::ocl4dnn diff --git a/modules/dnn/src/ocl4dnn/src/ocl4dnn_softmax.cpp b/modules/dnn/src/ocl4dnn/src/ocl4dnn_softmax.cpp index f2452ff654..6b957649e8 100644 --- a/modules/dnn/src/ocl4dnn/src/ocl4dnn_softmax.cpp +++ b/modules/dnn/src/ocl4dnn/src/ocl4dnn_softmax.cpp @@ -41,11 +41,10 @@ #include "../../precomp.hpp" #include -#include "common.hpp" -#include "ocl4dnn.hpp" +#include "../include/common.hpp" +#include "../include/ocl4dnn.hpp" #include "opencl_kernels_dnn.hpp" -#ifdef HAVE_OPENCL namespace cv { namespace dnn { namespace ocl4dnn { template OCL4DNNSoftmax::OCL4DNNSoftmax(OCL4DNNSoftmaxConfig config) @@ -130,7 +129,5 @@ bool OCL4DNNSoftmax::Forward(const UMat& bottom, UMat& top) } template class OCL4DNNSoftmax; -} // namespace ocl4dnn -} -} -#endif // HAVE_OPENCL + +}}} // namespace cv::dnn::ocl4dnn diff --git a/modules/dnn/src/precomp.hpp b/modules/dnn/src/precomp.hpp index 8b5a31c1c4..356eaff165 100644 --- a/modules/dnn/src/precomp.hpp +++ b/modules/dnn/src/precomp.hpp @@ -40,13 +40,28 @@ //M*/ #include +#include "cvconfig.h" + +#ifndef CV_OCL4DNN +#define CV_OCL4DNN 0 +#endif + +#if CV_OCL4DNN +#ifndef HAVE_OPENCL +#error "Configuration error: re-run CMake from clean build directory" +#endif +#else +#undef HAVE_OPENCL +#endif #include #include + + #include -#include "cvconfig.h" #include #include + namespace cv { namespace dnn { CV__DNN_EXPERIMENTAL_NS_BEGIN Mutex& getInitializationMutex(); From e79be78ef4ed1e284f84e1d14c8cee4d46b230e2 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 28 Feb 2018 15:22:20 +0300 Subject: [PATCH 05/36] dnn(workaround): switch to CPU target if compiled without OpenCL --- modules/dnn/src/dnn.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index 194648c6ea..15755f73e9 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -53,6 +53,7 @@ #include #include +#include namespace cv { namespace dnn { @@ -846,6 +847,13 @@ struct Net::Impl if (!netWasAllocated || this->blobsToKeep != blobsToKeep_) { +#ifndef HAVE_OPENCL + if (preferableBackend == DNN_BACKEND_DEFAULT && preferableTarget == DNN_TARGET_OPENCL) + { + CV_LOG_WARNING(NULL, "DNN: OpenCL target is not available in this OpenCV build, switching to CPU.") + preferableTarget = DNN_TARGET_CPU; + } +#endif clear(); allocateLayers(blobsToKeep_); From ed962799202d0d3b02bcbf6f5b64db31eae09493 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 1 Mar 2018 13:52:43 +0300 Subject: [PATCH 06/36] ocl: update getOpenCLErrorString() code --- modules/core/src/ocl.cpp | 163 ++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 88 deletions(-) diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index 5bbed96749..e17464e3cb 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -6015,98 +6015,85 @@ const char* convertTypeStr(int sdepth, int ddepth, int cn, char* buf) const char* getOpenCLErrorString(int errorCode) { +#define CV_OCL_CODE(id) case id: return #id +#define CV_OCL_CODE_(id, name) case id: return #name switch (errorCode) { - case 0: return "CL_SUCCESS"; - case -1: return "CL_DEVICE_NOT_FOUND"; - case -2: return "CL_DEVICE_NOT_AVAILABLE"; - case -3: return "CL_COMPILER_NOT_AVAILABLE"; - case -4: return "CL_MEM_OBJECT_ALLOCATION_FAILURE"; - case -5: return "CL_OUT_OF_RESOURCES"; - case -6: return "CL_OUT_OF_HOST_MEMORY"; - case -7: return "CL_PROFILING_INFO_NOT_AVAILABLE"; - case -8: return "CL_MEM_COPY_OVERLAP"; - case -9: return "CL_IMAGE_FORMAT_MISMATCH"; - case -10: return "CL_IMAGE_FORMAT_NOT_SUPPORTED"; - case -11: return "CL_BUILD_PROGRAM_FAILURE"; - case -12: return "CL_MAP_FAILURE"; - case -13: return "CL_MISALIGNED_SUB_BUFFER_OFFSET"; - case -14: return "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST"; - case -15: return "CL_COMPILE_PROGRAM_FAILURE"; - case -16: return "CL_LINKER_NOT_AVAILABLE"; - case -17: return "CL_LINK_PROGRAM_FAILURE"; - case -18: return "CL_DEVICE_PARTITION_FAILED"; - case -19: return "CL_KERNEL_ARG_INFO_NOT_AVAILABLE"; - case -30: return "CL_INVALID_VALUE"; - case -31: return "CL_INVALID_DEVICE_TYPE"; - case -32: return "CL_INVALID_PLATFORM"; - case -33: return "CL_INVALID_DEVICE"; - case -34: return "CL_INVALID_CONTEXT"; - case -35: return "CL_INVALID_QUEUE_PROPERTIES"; - case -36: return "CL_INVALID_COMMAND_QUEUE"; - case -37: return "CL_INVALID_HOST_PTR"; - case -38: return "CL_INVALID_MEM_OBJECT"; - case -39: return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR"; - case -40: return "CL_INVALID_IMAGE_SIZE"; - case -41: return "CL_INVALID_SAMPLER"; - case -42: return "CL_INVALID_BINARY"; - case -43: return "CL_INVALID_BUILD_OPTIONS"; - case -44: return "CL_INVALID_PROGRAM"; - case -45: return "CL_INVALID_PROGRAM_EXECUTABLE"; - case -46: return "CL_INVALID_KERNEL_NAME"; - case -47: return "CL_INVALID_KERNEL_DEFINITION"; - case -48: return "CL_INVALID_KERNEL"; - case -49: return "CL_INVALID_ARG_INDEX"; - case -50: return "CL_INVALID_ARG_VALUE"; - case -51: return "CL_INVALID_ARG_SIZE"; - case -52: return "CL_INVALID_KERNEL_ARGS"; - case -53: return "CL_INVALID_WORK_DIMENSION"; - case -54: return "CL_INVALID_WORK_GROUP_SIZE"; - case -55: return "CL_INVALID_WORK_ITEM_SIZE"; - case -56: return "CL_INVALID_GLOBAL_OFFSET"; - case -57: return "CL_INVALID_EVENT_WAIT_LIST"; - case -58: return "CL_INVALID_EVENT"; - case -59: return "CL_INVALID_OPERATION"; - case -60: return "CL_INVALID_GL_OBJECT"; - case -61: return "CL_INVALID_BUFFER_SIZE"; - case -62: return "CL_INVALID_MIP_LEVEL"; - case -63: return "CL_INVALID_GLOBAL_WORK_SIZE"; - case -64: return "CL_INVALID_PROPERTY"; - case -65: return "CL_INVALID_IMAGE_DESCRIPTOR"; - case -66: return "CL_INVALID_COMPILER_OPTIONS"; - case -67: return "CL_INVALID_LINKER_OPTIONS"; - case -68: return "CL_INVALID_DEVICE_PARTITION_COUNT"; - case -69: return "CL_INVALID_PIPE_SIZE"; - case -70: return "CL_INVALID_DEVICE_QUEUE"; - case -1000: return "CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR"; - case -1001: return "CL_PLATFORM_NOT_FOUND_KHR"; - case -1002: return "CL_INVALID_D3D10_DEVICE_KHR"; - case -1003: return "CL_INVALID_D3D10_RESOURCE_KHR"; - case -1004: return "CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR"; - case -1005: return "CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR"; - case -1024: return "clBLAS: Functionality is not implemented"; - case -1023: return "clBLAS: Library is not initialized yet"; - case -1022: return "clBLAS: Matrix A is not a valid memory object"; - case -1021: return "clBLAS: Matrix B is not a valid memory object"; - case -1020: return "clBLAS: Matrix C is not a valid memory object"; - case -1019: return "clBLAS: Vector X is not a valid memory object"; - case -1018: return "clBLAS: Vector Y is not a valid memory object"; - case -1017: return "clBLAS: An input dimension (M:N:K) is invalid"; - case -1016: return "clBLAS: Leading dimension A must not be less than the " - "size of the first dimension"; - case -1015: return "clBLAS: Leading dimension B must not be less than the " - "size of the second dimension"; - case -1014: return "clBLAS: Leading dimension C must not be less than the " - "size of the third dimension"; - case -1013: return "clBLAS: The increment for a vector X must not be 0"; - case -1012: return "clBLAS: The increment for a vector Y must not be 0"; - case -1011: return "clBLAS: The memory object for Matrix A is too small"; - case -1010: return "clBLAS: The memory object for Matrix B is too small"; - case -1009: return "clBLAS: The memory object for Matrix C is too small"; - case -1008: return "clBLAS: The memory object for Vector X is too small"; - case -1007: return "clBLAS: The memory object for Vector Y is too small"; + CV_OCL_CODE(CL_SUCCESS); + CV_OCL_CODE(CL_DEVICE_NOT_FOUND); + CV_OCL_CODE(CL_DEVICE_NOT_AVAILABLE); + CV_OCL_CODE(CL_COMPILER_NOT_AVAILABLE); + CV_OCL_CODE(CL_MEM_OBJECT_ALLOCATION_FAILURE); + CV_OCL_CODE(CL_OUT_OF_RESOURCES); + CV_OCL_CODE(CL_OUT_OF_HOST_MEMORY); + CV_OCL_CODE(CL_PROFILING_INFO_NOT_AVAILABLE); + CV_OCL_CODE(CL_MEM_COPY_OVERLAP); + CV_OCL_CODE(CL_IMAGE_FORMAT_MISMATCH); + CV_OCL_CODE(CL_IMAGE_FORMAT_NOT_SUPPORTED); + CV_OCL_CODE(CL_BUILD_PROGRAM_FAILURE); + CV_OCL_CODE(CL_MAP_FAILURE); + CV_OCL_CODE(CL_MISALIGNED_SUB_BUFFER_OFFSET); + CV_OCL_CODE(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST); + CV_OCL_CODE(CL_COMPILE_PROGRAM_FAILURE); + CV_OCL_CODE(CL_LINKER_NOT_AVAILABLE); + CV_OCL_CODE(CL_LINK_PROGRAM_FAILURE); + CV_OCL_CODE(CL_DEVICE_PARTITION_FAILED); + CV_OCL_CODE(CL_KERNEL_ARG_INFO_NOT_AVAILABLE); + CV_OCL_CODE(CL_INVALID_VALUE); + CV_OCL_CODE(CL_INVALID_DEVICE_TYPE); + CV_OCL_CODE(CL_INVALID_PLATFORM); + CV_OCL_CODE(CL_INVALID_DEVICE); + CV_OCL_CODE(CL_INVALID_CONTEXT); + CV_OCL_CODE(CL_INVALID_QUEUE_PROPERTIES); + CV_OCL_CODE(CL_INVALID_COMMAND_QUEUE); + CV_OCL_CODE(CL_INVALID_HOST_PTR); + CV_OCL_CODE(CL_INVALID_MEM_OBJECT); + CV_OCL_CODE(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR); + CV_OCL_CODE(CL_INVALID_IMAGE_SIZE); + CV_OCL_CODE(CL_INVALID_SAMPLER); + CV_OCL_CODE(CL_INVALID_BINARY); + CV_OCL_CODE(CL_INVALID_BUILD_OPTIONS); + CV_OCL_CODE(CL_INVALID_PROGRAM); + CV_OCL_CODE(CL_INVALID_PROGRAM_EXECUTABLE); + CV_OCL_CODE(CL_INVALID_KERNEL_NAME); + CV_OCL_CODE(CL_INVALID_KERNEL_DEFINITION); + CV_OCL_CODE(CL_INVALID_KERNEL); + CV_OCL_CODE(CL_INVALID_ARG_INDEX); + CV_OCL_CODE(CL_INVALID_ARG_VALUE); + CV_OCL_CODE(CL_INVALID_ARG_SIZE); + CV_OCL_CODE(CL_INVALID_KERNEL_ARGS); + CV_OCL_CODE(CL_INVALID_WORK_DIMENSION); + CV_OCL_CODE(CL_INVALID_WORK_GROUP_SIZE); + CV_OCL_CODE(CL_INVALID_WORK_ITEM_SIZE); + CV_OCL_CODE(CL_INVALID_GLOBAL_OFFSET); + CV_OCL_CODE(CL_INVALID_EVENT_WAIT_LIST); + CV_OCL_CODE(CL_INVALID_EVENT); + CV_OCL_CODE(CL_INVALID_OPERATION); + CV_OCL_CODE(CL_INVALID_GL_OBJECT); + CV_OCL_CODE(CL_INVALID_BUFFER_SIZE); + CV_OCL_CODE(CL_INVALID_MIP_LEVEL); + CV_OCL_CODE(CL_INVALID_GLOBAL_WORK_SIZE); + // OpenCL 1.1 + CV_OCL_CODE(CL_INVALID_PROPERTY); + // OpenCL 1.2 + CV_OCL_CODE(CL_INVALID_IMAGE_DESCRIPTOR); + CV_OCL_CODE(CL_INVALID_COMPILER_OPTIONS); + CV_OCL_CODE(CL_INVALID_LINKER_OPTIONS); + CV_OCL_CODE(CL_INVALID_DEVICE_PARTITION_COUNT); + // OpenCL 2.0 + CV_OCL_CODE_(-69, CL_INVALID_PIPE_SIZE); + CV_OCL_CODE_(-70, CL_INVALID_DEVICE_QUEUE); + // Extensions + CV_OCL_CODE_(-1000, CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR); + CV_OCL_CODE_(-1001, CL_PLATFORM_NOT_FOUND_KHR); + CV_OCL_CODE_(-1002, CL_INVALID_D3D10_DEVICE_KHR); + CV_OCL_CODE_(-1003, CL_INVALID_D3D10_RESOURCE_KHR); + CV_OCL_CODE_(-1004, CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR); + CV_OCL_CODE_(-1005, CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR); default: return "Unknown OpenCL error"; } +#undef CV_OCL_CODE +#undef CV_OCL_CODE_ } template From e283a75a19b1593b4e8fa82b93d5af03a2c69427 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Mon, 19 Feb 2018 18:53:17 +0300 Subject: [PATCH 07/36] Minor refactoring in several C++ samples: - bgfg_segm - peopledetect - opencv_version - dnn/colorization - tapi/opencl_custom_kernel - tapi/dense_optical_flow (renamed tvl1_optical_flow) --- samples/cpp/bgfg_segm.cpp | 20 ++- samples/cpp/opencv_version.cpp | 14 +- samples/cpp/peopledetect.cpp | 213 +++++++++-------------- samples/dnn/colorization.cpp | 95 ++++++----- samples/tapi/dense_optical_flow.cpp | 151 +++++++++++++++++ samples/tapi/opencl_custom_kernel.cpp | 4 + samples/tapi/tvl1_optical_flow.cpp | 233 -------------------------- 7 files changed, 304 insertions(+), 426 deletions(-) create mode 100644 samples/tapi/dense_optical_flow.cpp delete mode 100644 samples/tapi/tvl1_optical_flow.cpp diff --git a/samples/cpp/bgfg_segm.cpp b/samples/cpp/bgfg_segm.cpp index 71473d124a..9fc2780b07 100644 --- a/samples/cpp/bgfg_segm.cpp +++ b/samples/cpp/bgfg_segm.cpp @@ -1,3 +1,7 @@ +// 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 "opencv2/core.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/video.hpp" @@ -10,10 +14,10 @@ using namespace cv; int main(int argc, const char** argv) { - const String keys = "{c camera||use video stream from camera (default is NO)}" - "{fn file_name|../data/tree.avi|video file}" - "{m method|mog2|method: background subtraction algorithm ('knn', 'mog2')}" - "{h help||show help message}"; + const String keys = "{c camera | 0 | use video stream from camera (device index starting from 0) }" + "{fn file_name | | use video file as input }" + "{m method | mog2 | method: background subtraction algorithm ('knn', 'mog2')}" + "{h help | | show help message}"; CommandLineParser parser(argc, argv, keys); parser.about("This sample demonstrates background segmentation."); if (parser.has("help")) @@ -21,7 +25,7 @@ int main(int argc, const char** argv) parser.printMessage(); return 0; } - bool useCamera = parser.has("camera"); + int camera = parser.get("camera"); String file = parser.get("file_name"); String method = parser.get("method"); if (!parser.check()) @@ -31,13 +35,13 @@ int main(int argc, const char** argv) } VideoCapture cap; - if (useCamera) - cap.open(0); + if (file.empty()) + cap.open(camera); else cap.open(file.c_str()); if (!cap.isOpened()) { - cout << "Can not open video stream: '" << (useCamera ? "" : file) << "'" << endl; + cout << "Can not open video stream: '" << (file.empty() ? "" : file) << "'" << endl; return 2; } diff --git a/samples/cpp/opencv_version.cpp b/samples/cpp/opencv_version.cpp index 0ee3494a40..b500f117e3 100644 --- a/samples/cpp/opencv_version.cpp +++ b/samples/cpp/opencv_version.cpp @@ -1,16 +1,17 @@ +// 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 #include -const char* keys = -{ - "{ b build | | print complete build info }" - "{ h help | | print this help }" -}; +static const std::string keys = "{ b build | | print complete build info }" + "{ h help | | print this help }"; int main(int argc, const char* argv[]) { cv::CommandLineParser parser(argc, argv, keys); - + parser.about("This sample outputs OpenCV version and build configuration."); if (parser.has("help")) { parser.printMessage(); @@ -27,6 +28,5 @@ int main(int argc, const char* argv[]) { std::cout << "Welcome to OpenCV " << CV_VERSION << std::endl; } - return 0; } diff --git a/samples/cpp/peopledetect.cpp b/samples/cpp/peopledetect.cpp index 5fa2382f0f..ea45ae9c9b 100644 --- a/samples/cpp/peopledetect.cpp +++ b/samples/cpp/peopledetect.cpp @@ -1,177 +1,126 @@ -#include -#include +// 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 #include #include -#include -#include #include +#include +#include using namespace cv; using namespace std; - -const char* keys = +class Detector { - "{ help h | | print help message }" - "{ image i | | specify input image}" - "{ camera c | | enable camera capturing }" - "{ video v | ../data/vtest.avi | use video as input }" - "{ directory d | | images directory}" -}; - -static void detectAndDraw(const HOGDescriptor &hog, Mat &img) -{ - vector found, found_filtered; - double t = (double) getTickCount(); - // Run the detector with default parameters. to get a higher hit-rate - // (and more false alarms, respectively), decrease the hitThreshold and - // groupThreshold (set groupThreshold to 0 to turn off the grouping completely). - hog.detectMultiScale(img, found, 0, Size(8,8), Size(32,32), 1.05, 2); - t = (double) getTickCount() - t; - cout << "detection time = " << (t*1000./cv::getTickFrequency()) << " ms" << endl; - - for(size_t i = 0; i < found.size(); i++ ) + enum Mode { Default, Daimler } m; + HOGDescriptor hog, hog_d; +public: + Detector() : m(Default), hog(), hog_d(Size(48, 96), Size(16, 16), Size(8, 8), Size(8, 8), 9) { - Rect r = found[i]; - - size_t j; - // Do not add small detections inside a bigger detection. - for ( j = 0; j < found.size(); j++ ) - if ( j != i && (r & found[j]) == r ) - break; - - if ( j == found.size() ) - found_filtered.push_back(r); + hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector()); + hog_d.setSVMDetector(HOGDescriptor::getDaimlerPeopleDetector()); } - - for (size_t i = 0; i < found_filtered.size(); i++) + void toggleMode() { m = (m == Default ? Daimler : Default); } + string modeName() const { return (m == Default ? "Default" : "Daimler"); } + vector detect(InputArray img) + { + // Run the detector with default parameters. to get a higher hit-rate + // (and more false alarms, respectively), decrease the hitThreshold and + // groupThreshold (set groupThreshold to 0 to turn off the grouping completely). + vector found; + if (m == Default) + hog.detectMultiScale(img, found, 0, Size(8,8), Size(32,32), 1.05, 2, false); + else if (m == Daimler) + hog_d.detectMultiScale(img, found, 0.5, Size(8,8), Size(32,32), 1.05, 2, true); + return found; + } + void adjustRect(Rect & r) const { - Rect r = found_filtered[i]; - // The HOG detector returns slightly larger rectangles than the real objects, // so we slightly shrink the rectangles to get a nicer output. r.x += cvRound(r.width*0.1); r.width = cvRound(r.width*0.8); r.y += cvRound(r.height*0.07); r.height = cvRound(r.height*0.8); - rectangle(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3); } -} +}; + +static const string keys = "{ help h | | print help message }" + "{ camera c | 0 | capture video from camera (device index starting from 0) }" + "{ video v | | use video as input }"; int main(int argc, char** argv) { CommandLineParser parser(argc, argv, keys); - + parser.about("This sample demonstrates the use ot the HoG descriptor."); if (parser.has("help")) { - cout << "\nThis program demonstrates the use of the HoG descriptor using\n" - " HOGDescriptor::hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());\n"; parser.printMessage(); - cout << "During execution:\n\tHit q or ESC key to quit.\n" - "\tUsing OpenCV version " << CV_VERSION << "\n" - "Note: camera device number must be different from -1.\n" << endl; return 0; } - - HOGDescriptor hog; - hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector()); - namedWindow("people detector", 1); - - string pattern_glob = ""; - string video_filename = "../data/vtest.avi"; - int camera_id = -1; - if (parser.has("directory")) + int camera = parser.get("camera"); + string file = parser.get("video"); + if (!parser.check()) { - pattern_glob = parser.get("directory"); - } - else if (parser.has("image")) - { - pattern_glob = parser.get("image"); - } - else if (parser.has("camera")) - { - camera_id = parser.get("camera"); - } - else if (parser.has("video")) - { - video_filename = parser.get("video"); + parser.printErrors(); + return 1; } - if (!pattern_glob.empty() || camera_id != -1 || !video_filename.empty()) + VideoCapture cap; + if (file.empty()) + cap.open(camera); + else + cap.open(file.c_str()); + if (!cap.isOpened()) { - //Read from input image files - vector filenames; - //Read from video file - VideoCapture vc; - Mat frame; + cout << "Can not open video stream: '" << (file.empty() ? "" : file) << "'" << endl; + return 2; + } - if (!pattern_glob.empty()) + cout << "Press 'q' or to quit." << endl; + cout << "Press to toggle between Default and Daimler detector" << endl; + Detector detector; + Mat frame; + for (;;) + { + cap >> frame; + if (frame.empty()) { - String folder(pattern_glob); - glob(folder, filenames); + cout << "Finished reading: empty frame" << endl; + break; } - else if (camera_id != -1) + int64 t = getTickCount(); + vector found = detector.detect(frame); + t = getTickCount() - t; + + // show the window { - vc.open(camera_id); - if (!vc.isOpened()) - { - stringstream msg; - msg << "can't open camera: " << camera_id; - throw runtime_error(msg.str()); - } + ostringstream buf; + buf << "Mode: " << detector.modeName() << " ||| " + << "FPS: " << fixed << setprecision(1) << (getTickFrequency() / (double)t); + putText(frame, buf.str(), Point(10, 30), FONT_HERSHEY_PLAIN, 2.0, Scalar(0, 0, 255), 2, LINE_AA); } - else + for (vector::iterator i = found.begin(); i != found.end(); ++i) { - vc.open(video_filename.c_str()); - if (!vc.isOpened()) - throw runtime_error(string("can't open video file: " + video_filename)); + Rect &r = *i; + detector.adjustRect(r); + rectangle(frame, r.tl(), r.br(), cv::Scalar(0, 255, 0), 2); } + imshow("People detector", frame); - vector::const_iterator it_image = filenames.begin(); - - for (;;) + // interact with user + const char key = (char)waitKey(30); + if (key == 27 || key == 'q') // ESC { - if (!pattern_glob.empty()) - { - bool read_image_ok = false; - for (; it_image != filenames.end(); ++it_image) - { - cout << "\nRead: " << *it_image << endl; - // Read current image - frame = imread(*it_image); - - if (!frame.empty()) - { - ++it_image; - read_image_ok = true; - break; - } - } - - //No more valid images - if (!read_image_ok) - { - //Release the image in order to exit the while loop - frame.release(); - } - } - else - { - vc >> frame; - } - - if (frame.empty()) - break; - - detectAndDraw(hog, frame); - - imshow("people detector", frame); - int c = waitKey( vc.isOpened() ? 30 : 0 ) & 255; - if ( c == 'q' || c == 'Q' || c == 27) - break; + cout << "Exit requested" << endl; + break; + } + else if (key == ' ') + { + detector.toggleMode(); } } - return 0; } diff --git a/samples/dnn/colorization.cpp b/samples/dnn/colorization.cpp index 1c4ae07aac..9329e11d6a 100644 --- a/samples/dnn/colorization.cpp +++ b/samples/dnn/colorization.cpp @@ -1,20 +1,18 @@ -// -// This program is based on https://github.com/richzhang/colorization/blob/master/colorization/colorize.py -// download the caffemodel from: http://eecs.berkeley.edu/~rich.zhang/projects/2016_colorization/files/demo_v2/colorization_release_v2.caffemodel -// and the prototxt from: https://github.com/richzhang/colorization/blob/master/colorization/models/colorization_deploy_v2.prototxt -// +// 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 #include #include +#include + using namespace cv; using namespace cv::dnn; - -#include using namespace std; - // the 313 ab cluster centers from pts_in_hull.npy (already transposed) -float hull_pts[] = { +static float hull_pts[] = { -90., -90., -90., -90., -90., -80., -80., -80., -80., -80., -80., -80., -80., -70., -70., -70., -70., -70., -70., -70., -70., -70., -70., -60., -60., -60., -60., -60., -60., -60., -60., -60., -60., -60., -60., -50., -50., -50., -50., -50., -50., -50., -50., -50., -50., -50., -50., -50., -50., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -30., @@ -43,54 +41,61 @@ float hull_pts[] = { -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., -90., -80., -70., -60., -50., -40., -30., -20., -10., 0. }; - int main(int argc, char **argv) { - CommandLineParser parser(argc, argv, - "{ help | false | print this help message }" - "{ proto | colorization_deploy_v2.prototxt | model configuration }" - "{ model | colorization_release_v2.caffemodel | model weights }" - "{ image | space_shuttle.jpg | path to image file }" - "{ opencl | false | enable OpenCL }" - ); - - String modelTxt = parser.get("proto"); - String modelBin = parser.get("model"); - String imageFile = parser.get("image"); - if (parser.get("help") || modelTxt.empty() || modelBin.empty() || imageFile.empty()) + const string about = + "This sample demonstrates recoloring grayscale images with dnn.\n" + "This program is based on:\n" + " http://richzhang.github.io/colorization\n" + " https://github.com/richzhang/colorization\n" + "Download caffemodel and prototxt files:\n" + " http://eecs.berkeley.edu/~rich.zhang/projects/2016_colorization/files/demo_v2/colorization_release_v2.caffemodel\n" + " https://raw.githubusercontent.com/richzhang/colorization/master/colorization/models/colorization_deploy_v2.prototxt\n"; + const string keys = + "{ h help | | print this help message }" + "{ proto | colorization_deploy_v2.prototxt | model configuration }" + "{ model | colorization_release_v2.caffemodel | model weights }" + "{ image | space_shuttle.jpg | path to image file }" + "{ opencl | | enable OpenCL }"; + CommandLineParser parser(argc, argv, keys); + parser.about(about); + if (parser.has("help")) { - cout << "A sample app to demonstrate recoloring grayscale images with dnn." << endl; parser.printMessage(); return 0; } - - // fixed input size for the pretrained network - int W_in = 224; - int H_in = 224; - - Net net = dnn::readNetFromCaffe(modelTxt, modelBin); - - // setup additional layers: - int sz[] = {2, 313, 1, 1}; - Mat pts_in_hull(4, sz, CV_32F, hull_pts); - Ptr class8_ab = net.getLayer("class8_ab"); - class8_ab->blobs.push_back(pts_in_hull); - - Ptr conv8_313_rh = net.getLayer("conv8_313_rh"); - conv8_313_rh->blobs.push_back(Mat(1, 313, CV_32F, 2.606f)); - - if (parser.get("opencl")) + string modelTxt = parser.get("proto"); + string modelBin = parser.get("model"); + string imageFile = parser.get("image"); + bool useOpenCL = parser.has("opencl"); + if (!parser.check()) { - net.setPreferableTarget(DNN_TARGET_OPENCL); + parser.printErrors(); + return 1; } Mat img = imread(imageFile); if (img.empty()) { - std::cerr << "Can't read image from the file: " << imageFile << std::endl; - exit(-1); + cout << "Can't read image from file: " << imageFile << endl; + return 2; } + // fixed input size for the pretrained network + const int W_in = 224; + const int H_in = 224; + Net net = dnn::readNetFromCaffe(modelTxt, modelBin); + if (useOpenCL) + net.setPreferableTarget(DNN_TARGET_OPENCL); + + // setup additional layers: + int sz[] = {2, 313, 1, 1}; + const Mat pts_in_hull(4, sz, CV_32F, hull_pts); + Ptr class8_ab = net.getLayer("class8_ab"); + class8_ab->blobs.push_back(pts_in_hull); + Ptr conv8_313_rh = net.getLayer("conv8_313_rh"); + conv8_313_rh->blobs.push_back(Mat(1, 313, CV_32F, Scalar(2.606))); + // extract L channel and subtract mean Mat lab, L, input; img.convertTo(img, CV_32F, 1.0/255); @@ -111,13 +116,11 @@ int main(int argc, char **argv) resize(a, a, img.size()); resize(b, b, img.size()); - // merge, and convert back to bgr + // merge, and convert back to BGR Mat color, chn[] = {L, a, b}; merge(chn, 3, lab); cvtColor(lab, color, COLOR_Lab2BGR); - namedWindow("color", WINDOW_NORMAL); - namedWindow("original", WINDOW_NORMAL); imshow("color", color); imshow("original", img); waitKey(); diff --git a/samples/tapi/dense_optical_flow.cpp b/samples/tapi/dense_optical_flow.cpp new file mode 100644 index 0000000000..27ca2b867a --- /dev/null +++ b/samples/tapi/dense_optical_flow.cpp @@ -0,0 +1,151 @@ +// 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 +#include +#include + +#include "opencv2/core/ocl.hpp" +#include "opencv2/core/utility.hpp" +#include "opencv2/imgcodecs.hpp" +#include "opencv2/videoio.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/video.hpp" + +using namespace std; +using namespace cv; + +static Mat getVisibleFlow(InputArray flow) +{ + vector flow_vec; + split(flow, flow_vec); + UMat magnitude, angle; + cartToPolar(flow_vec[0], flow_vec[1], magnitude, angle, true); + magnitude.convertTo(magnitude, CV_32F, 0.2); + vector hsv_vec; + hsv_vec.push_back(angle); + hsv_vec.push_back(UMat::ones(angle.size(), angle.type())); + hsv_vec.push_back(magnitude); + UMat hsv; + merge(hsv_vec, hsv); + Mat img; + cvtColor(hsv, img, COLOR_HSV2BGR); + return img; +} + +static Size fitSize(const Size & sz, const Size & bounds) +{ + CV_Assert(sz.area() > 0); + if (sz.width > bounds.width || sz.height > bounds.height) + { + double scale = std::min((double)bounds.width / sz.width, (double)bounds.height / sz.height); + return Size(cvRound(sz.width * scale), cvRound(sz.height * scale)); + } + return sz; +} + +int main(int argc, const char* argv[]) +{ + const char* keys = + "{ h help | | print help message }" + "{ c camera | 0 | capture video from camera (device index starting from 0) }" + "{ a algorithm | fb | algorithm (supported: 'fb', 'tvl')}" + "{ m cpu | | run without OpenCL }" + "{ v video | | use video as input }" + "{ o original | | use original frame size (do not resize to 640x480)}" + ; + CommandLineParser parser(argc, argv, keys); + parser.about("This sample demonstrates using of dense optical flow algorithms."); + if (parser.has("help")) + { + parser.printMessage(); + return 0; + } + int camera = parser.get("camera"); + string algorithm = parser.get("algorithm"); + bool useCPU = parser.has("cpu"); + string filename = parser.get("video"); + bool useOriginalSize = parser.has("original"); + if (!parser.check()) + { + parser.printErrors(); + return 1; + } + + VideoCapture cap; + if(filename.empty()) + cap.open(camera); + else + cap.open(filename); + if (!cap.isOpened()) + { + cout << "Can not open video stream: '" << (filename.empty() ? "" : filename) << "'" << endl; + return 2; + } + + cv::Ptr alg; + if (algorithm == "fb") + alg = cv::FarnebackOpticalFlow::create(); + else if (algorithm == "tvl") + alg = cv::DualTVL1OpticalFlow::create(); + else + { + cout << "Invalid algorithm: " << algorithm << endl; + return 3; + } + + ocl::setUseOpenCL(!useCPU); + + cout << "Press 'm' to toggle CPU/GPU processing mode" << endl; + cout << "Press ESC or 'q' to exit" << endl; + + UMat prevFrame, frame, input_frame, flow; + for(;;) + { + if (!cap.read(input_frame) || input_frame.empty()) + { + cout << "Finished reading: empty frame" << endl; + break; + } + Size small_size = fitSize(input_frame.size(), Size(640, 480)); + if (!useOriginalSize && small_size != input_frame.size()) + resize(input_frame, frame, small_size); + else + frame = input_frame; + cvtColor(frame, frame, COLOR_BGR2GRAY); + imshow("frame", frame); + if (!prevFrame.empty()) + { + int64 t = getTickCount(); + alg->calc(prevFrame, frame, flow); + t = getTickCount() - t; + { + Mat img = getVisibleFlow(flow); + ostringstream buf; + buf << "Algo: " << algorithm << " | " + << "Mode: " << (useCPU ? "CPU" : "GPU") << " | " + << "FPS: " << fixed << setprecision(1) << (getTickFrequency() / (double)t); + putText(img, buf.str(), Point(10, 30), FONT_HERSHEY_PLAIN, 2.0, Scalar(0, 0, 255), 2, LINE_AA); + imshow("Dense optical flow field", img); + } + } + frame.copyTo(prevFrame); + + // interact with user + const char key = (char)waitKey(30); + if (key == 27 || key == 'q') // ESC + { + cout << "Exit requested" << endl; + break; + } + else if (key == 'm') + { + useCPU = !useCPU; + ocl::setUseOpenCL(!useCPU); + cout << "Set processing mode to: " << (useCPU ? "CPU" : "GPU") << endl; + } + } + + return 0; +} diff --git a/samples/tapi/opencl_custom_kernel.cpp b/samples/tapi/opencl_custom_kernel.cpp index 87f5b9a24a..2395061a9a 100644 --- a/samples/tapi/opencl_custom_kernel.cpp +++ b/samples/tapi/opencl_custom_kernel.cpp @@ -1,3 +1,7 @@ +// 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 "opencv2/core.hpp" #include "opencv2/core/ocl.hpp" #include "opencv2/highgui.hpp" diff --git a/samples/tapi/tvl1_optical_flow.cpp b/samples/tapi/tvl1_optical_flow.cpp deleted file mode 100644 index 3d301ee033..0000000000 --- a/samples/tapi/tvl1_optical_flow.cpp +++ /dev/null @@ -1,233 +0,0 @@ -#include -#include -#include - -#include "opencv2/core/ocl.hpp" -#include "opencv2/core/utility.hpp" -#include "opencv2/imgcodecs.hpp" -#include "opencv2/videoio.hpp" -#include "opencv2/highgui.hpp" -#include "opencv2/video.hpp" - -using namespace std; -using namespace cv; - -typedef unsigned char uchar; -#define LOOP_NUM 10 -int64 work_begin = 0; -int64 work_end = 0; - -static void workBegin() -{ - work_begin = getTickCount(); -} -static void workEnd() -{ - work_end += (getTickCount() - work_begin); -} -static double getTime() -{ - return work_end * 1000. / getTickFrequency(); -} - -template inline T clamp (T x, T a, T b) -{ - return ((x) > (a) ? ((x) < (b) ? (x) : (b)) : (a)); -} - -template inline T mapValue(T x, T a, T b, T c, T d) -{ - x = ::clamp(x, a, b); - return c + (d - c) * (x - a) / (b - a); -} - -static void getFlowField(const Mat& u, const Mat& v, Mat& flowField) -{ - float maxDisplacement = 1.0f; - - for (int i = 0; i < u.rows; ++i) - { - const float* ptr_u = u.ptr(i); - const float* ptr_v = v.ptr(i); - - for (int j = 0; j < u.cols; ++j) - { - float d = max(fabsf(ptr_u[j]), fabsf(ptr_v[j])); - - if (d > maxDisplacement) - maxDisplacement = d; - } - } - - flowField.create(u.size(), CV_8UC4); - - for (int i = 0; i < flowField.rows; ++i) - { - const float* ptr_u = u.ptr(i); - const float* ptr_v = v.ptr(i); - - - Vec4b* row = flowField.ptr(i); - - for (int j = 0; j < flowField.cols; ++j) - { - row[j][0] = 0; - row[j][1] = static_cast (mapValue (-ptr_v[j], -maxDisplacement, maxDisplacement, 0.0f, 255.0f)); - row[j][2] = static_cast (mapValue ( ptr_u[j], -maxDisplacement, maxDisplacement, 0.0f, 255.0f)); - row[j][3] = 255; - } - } -} - - -int main(int argc, const char* argv[]) -{ - const char* keys = - "{ h help | | print help message }" - "{ l left | | specify left image }" - "{ r right | | specify right image }" - "{ o output | tvl1_output.jpg | specify output save path }" - "{ c camera | 0 | enable camera capturing }" - "{ m cpu_mode | | run without OpenCL }" - "{ v video | | use video as input }"; - - CommandLineParser cmd(argc, argv, keys); - - if (cmd.has("help")) - { - cout << "Usage: pyrlk_optical_flow [options]" << endl; - cout << "Available options:" << endl; - cmd.printMessage(); - return EXIT_SUCCESS; - } - - string fname0 = cmd.get("l"); - string fname1 = cmd.get("r"); - string vdofile = cmd.get("v"); - string outpath = cmd.get("o"); - bool useCPU = cmd.get("m"); - bool useCamera = cmd.get("c"); - int inputName = cmd.get("c"); - - UMat frame0, frame1; - imread(fname0, cv::IMREAD_GRAYSCALE).copyTo(frame0); - imread(fname1, cv::IMREAD_GRAYSCALE).copyTo(frame1); - cv::Ptr alg = cv::createOptFlow_DualTVL1(); - - UMat flow; - Mat show_flow; - vector flow_vec; - if (frame0.empty() || frame1.empty()) - useCamera = true; - - if (useCamera) - { - VideoCapture capture; - UMat frame, frameCopy; - UMat frame0Gray, frame1Gray; - UMat ptr0, ptr1; - - if(vdofile.empty()) - capture.open( inputName ); - else - capture.open(vdofile.c_str()); - - if(!capture.isOpened()) - { - if(vdofile.empty()) - cout << "Capture from CAM " << inputName << " didn't work" << endl; - else - cout << "Capture from file " << vdofile << " failed" <calc(ptr0, ptr1, flow); - split(flow, flow_vec); - - if (i%2 == 1) - frame1.copyTo(frameCopy); - else - frame0.copyTo(frameCopy); - getFlowField(flow_vec[0].getMat(ACCESS_READ), flow_vec[1].getMat(ACCESS_READ), show_flow); - imshow("tvl1 optical flow field", show_flow); - } - - char key = (char)waitKey(10); - if (key == 27) - break; - else if (key == 'm' || key == 'M') - { - ocl::setUseOpenCL(!cv::ocl::useOpenCL()); - cout << "Switched to " << (ocl::useOpenCL() ? "OpenCL" : "CPU") << " mode\n"; - } - } - - capture.release(); - } - else - { -nocamera: - if (cmd.has("cpu_mode")) - { - ocl::setUseOpenCL(false); - std::cout << "OpenCL was disabled" << std::endl; - } - for(int i = 0; i <= LOOP_NUM; i ++) - { - cout << "loop" << i << endl; - - if (i > 0) workBegin(); - - alg->calc(frame0, frame1, flow); - split(flow, flow_vec); - - if (i > 0 && i <= LOOP_NUM) - workEnd(); - - if (i == LOOP_NUM) - { - if (useCPU) - cout << "average CPU time (noCamera) : "; - else - cout << "average GPU time (noCamera) : "; - cout << getTime() / LOOP_NUM << " ms" << endl; - - getFlowField(flow_vec[0].getMat(ACCESS_READ), flow_vec[1].getMat(ACCESS_READ), show_flow); - imshow("PyrLK [Sparse]", show_flow); - imwrite(outpath, show_flow); - } - } - } - - waitKey(); - - return EXIT_SUCCESS; -} From 265f335dae1d78b3e09a5ee21444575b588ba2d1 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Mon, 26 Feb 2018 21:10:21 +0300 Subject: [PATCH 08/36] Add install component for 3rdparty libraries licenses --- 3rdparty/cpufeatures/CMakeLists.txt | 2 ++ 3rdparty/include/opencl/LICENSE.txt | 25 ++++++++++++++ 3rdparty/ittnotify/CMakeLists.txt | 2 ++ 3rdparty/libjasper/CMakeLists.txt | 2 ++ 3rdparty/libjpeg/CMakeLists.txt | 2 ++ 3rdparty/libpng/CMakeLists.txt | 4 ++- 3rdparty/libtiff/CMakeLists.txt | 2 ++ 3rdparty/openexr/CMakeLists.txt | 2 ++ 3rdparty/protobuf/CMakeLists.txt | 2 ++ 3rdparty/tbb/CMakeLists.txt | 2 ++ 3rdparty/zlib/CMakeLists.txt | 2 ++ cmake/OpenCVDetectOpenCL.cmake | 1 + cmake/OpenCVFindIPP.cmake | 1 + cmake/OpenCVFindIPPIW.cmake | 15 ++++++++- cmake/OpenCVUtils.cmake | 12 +++++++ modules/core/3rdparty/SoftFloat/COPYING.txt | 36 +++++++++++++++++++++ modules/core/CMakeLists.txt | 2 ++ 17 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 3rdparty/include/opencl/LICENSE.txt create mode 100644 modules/core/3rdparty/SoftFloat/COPYING.txt diff --git a/3rdparty/cpufeatures/CMakeLists.txt b/3rdparty/cpufeatures/CMakeLists.txt index 6b19574864..92bce6abf8 100644 --- a/3rdparty/cpufeatures/CMakeLists.txt +++ b/3rdparty/cpufeatures/CMakeLists.txt @@ -31,3 +31,5 @@ endif() if(NOT BUILD_SHARED_LIBS) ocv_install_target(${OPENCV_CPUFEATURES_TARGET_NAME} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) endif() + +ocv_install_3rdparty_licenses(cpufeatures LICENSE README.md) diff --git a/3rdparty/include/opencl/LICENSE.txt b/3rdparty/include/opencl/LICENSE.txt new file mode 100644 index 0000000000..020ce65fca --- /dev/null +++ b/3rdparty/include/opencl/LICENSE.txt @@ -0,0 +1,25 @@ +Copyright (c) 2008-2015 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and/or associated documentation files (the +"Materials"), to deal in the Materials without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Materials, and to +permit persons to whom the Materials are furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Materials. + +MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS +KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS +SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + https://www.khronos.org/registry/ + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. diff --git a/3rdparty/ittnotify/CMakeLists.txt b/3rdparty/ittnotify/CMakeLists.txt index e8b2d289ea..2acb5347b4 100644 --- a/3rdparty/ittnotify/CMakeLists.txt +++ b/3rdparty/ittnotify/CMakeLists.txt @@ -60,3 +60,5 @@ endif() if(NOT BUILD_SHARED_LIBS) ocv_install_target(${ITT_LIBRARY} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) endif() + +ocv_install_3rdparty_licenses(ittnotify src/ittnotify/LICENSE.BSD src/ittnotify/LICENSE.GPL) diff --git a/3rdparty/libjasper/CMakeLists.txt b/3rdparty/libjasper/CMakeLists.txt index 13200eb445..29349e0c50 100644 --- a/3rdparty/libjasper/CMakeLists.txt +++ b/3rdparty/libjasper/CMakeLists.txt @@ -47,3 +47,5 @@ endif() if(NOT BUILD_SHARED_LIBS) ocv_install_target(${JASPER_LIBRARY} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) endif() + +ocv_install_3rdparty_licenses(jasper LICENSE README copyright) diff --git a/3rdparty/libjpeg/CMakeLists.txt b/3rdparty/libjpeg/CMakeLists.txt index c5509cac40..f686baf61a 100644 --- a/3rdparty/libjpeg/CMakeLists.txt +++ b/3rdparty/libjpeg/CMakeLists.txt @@ -51,3 +51,5 @@ endif() if(NOT BUILD_SHARED_LIBS) ocv_install_target(${JPEG_LIBRARY} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) endif() + +ocv_install_3rdparty_licenses(libjpeg README) diff --git a/3rdparty/libpng/CMakeLists.txt b/3rdparty/libpng/CMakeLists.txt index b5f36a1875..01ac496976 100644 --- a/3rdparty/libpng/CMakeLists.txt +++ b/3rdparty/libpng/CMakeLists.txt @@ -48,7 +48,7 @@ if(PPC64LE OR PPC64) list(APPEND lib_srcs powerpc/powerpc_init.c powerpc/filter_vsx_intrinsics.c) add_definitions(-DPNG_POWERPC_VSX_OPT=2) else() - add_definitions(-DPNG_POWERPC_VSX_OPT=0) + add_definitions(-DPNG_POWERPC_VSX_OPT=0) endif() endif() @@ -80,3 +80,5 @@ endif() if(NOT BUILD_SHARED_LIBS) ocv_install_target(${PNG_LIBRARY} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) endif() + +ocv_install_3rdparty_licenses(libpng LICENSE README opencv-libpng.patch) diff --git a/3rdparty/libtiff/CMakeLists.txt b/3rdparty/libtiff/CMakeLists.txt index 73717e20c0..9d575bcab9 100644 --- a/3rdparty/libtiff/CMakeLists.txt +++ b/3rdparty/libtiff/CMakeLists.txt @@ -470,3 +470,5 @@ endif() if(NOT BUILD_SHARED_LIBS) ocv_install_target(${TIFF_LIBRARY} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) endif() + +ocv_install_3rdparty_licenses(libtiff COPYRIGHT) diff --git a/3rdparty/openexr/CMakeLists.txt b/3rdparty/openexr/CMakeLists.txt index 7302441d63..730b9a0d7e 100644 --- a/3rdparty/openexr/CMakeLists.txt +++ b/3rdparty/openexr/CMakeLists.txt @@ -76,5 +76,7 @@ if(NOT BUILD_SHARED_LIBS) ocv_install_target(IlmImf EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) endif() +ocv_install_3rdparty_licenses(openexr LICENSE AUTHORS.ilmbase AUTHORS.openexr fix_msvc2013_errors.patch) + set(OPENEXR_INCLUDE_PATHS ${OPENEXR_INCLUDE_PATHS} PARENT_SCOPE) set(OPENEXR_VERSION "1.7.1" PARENT_SCOPE) diff --git a/3rdparty/protobuf/CMakeLists.txt b/3rdparty/protobuf/CMakeLists.txt index a10e20bfd8..f5ca6f1fff 100644 --- a/3rdparty/protobuf/CMakeLists.txt +++ b/3rdparty/protobuf/CMakeLists.txt @@ -150,3 +150,5 @@ set(Protobuf_VERSION ${Protobuf_VERSION} CACHE INTERNAL "" FORCE) if(NOT BUILD_SHARED_LIBS) ocv_install_target(libprotobuf EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) endif() + +ocv_install_3rdparty_licenses(protobuf LICENSE README.md) diff --git a/3rdparty/tbb/CMakeLists.txt b/3rdparty/tbb/CMakeLists.txt index f2b7b286ab..5fe608619e 100644 --- a/3rdparty/tbb/CMakeLists.txt +++ b/3rdparty/tbb/CMakeLists.txt @@ -156,4 +156,6 @@ ocv_install_target(tbb EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev ) +ocv_install_3rdparty_licenses(tbb "${tbb_src_dir}/LICENSE" "${tbb_src_dir}/README") + ocv_tbb_read_version("${tbb_src_dir}/include") diff --git a/3rdparty/zlib/CMakeLists.txt b/3rdparty/zlib/CMakeLists.txt index cd1da16987..8525a11fac 100644 --- a/3rdparty/zlib/CMakeLists.txt +++ b/3rdparty/zlib/CMakeLists.txt @@ -99,3 +99,5 @@ endif() if(NOT BUILD_SHARED_LIBS) ocv_install_target(${ZLIB_LIBRARY} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) endif() + +ocv_install_3rdparty_licenses(zlib README) diff --git a/cmake/OpenCVDetectOpenCL.cmake b/cmake/OpenCVDetectOpenCL.cmake index 433f244fe6..629d44a62d 100644 --- a/cmake/OpenCVDetectOpenCL.cmake +++ b/cmake/OpenCVDetectOpenCL.cmake @@ -5,6 +5,7 @@ if(APPLE) else(APPLE) set(OPENCL_LIBRARY "" CACHE STRING "OpenCL library") set(OPENCL_INCLUDE_DIR "${OpenCV_SOURCE_DIR}/3rdparty/include/opencl/1.2" CACHE PATH "OpenCL include directory") + ocv_install_3rdparty_licenses(opencl-headers "${OpenCV_SOURCE_DIR}/3rdparty/include/opencl/LICENSE.txt") endif(APPLE) mark_as_advanced(OPENCL_INCLUDE_DIR OPENCL_LIBRARY) diff --git a/cmake/OpenCVFindIPP.cmake b/cmake/OpenCVFindIPP.cmake index 068cef71be..52c8d50638 100644 --- a/cmake/OpenCVFindIPP.cmake +++ b/cmake/OpenCVFindIPP.cmake @@ -244,6 +244,7 @@ if(NOT DEFINED IPPROOT) if(NOT IPPROOT) return() endif() + ocv_install_3rdparty_licenses(ippicv "${IPPROOT}/readme.htm" "${IPPROOT}/license/ippEULA.txt") endif() file(TO_CMAKE_PATH "${IPPROOT}" __IPPROOT) diff --git a/cmake/OpenCVFindIPPIW.cmake b/cmake/OpenCVFindIPPIW.cmake index dcc546f29a..3b63aa1a0d 100644 --- a/cmake/OpenCVFindIPPIW.cmake +++ b/cmake/OpenCVFindIPPIW.cmake @@ -136,6 +136,13 @@ if(BUILD_IPP_IW) # local sources ippiw_setup("${OpenCV_SOURCE_DIR}/3rdparty/ippiw" 1) + set(IPPIW_ROOT "${IPPROOT}/../${IW_PACKAGE_SUBDIR}") + ocv_install_3rdparty_licenses(ippiw + "${IPPIW_ROOT}/EULA.txt" + "${IPPIW_ROOT}/redist.txt" + "${IPPIW_ROOT}/support.txt" + "${IPPIW_ROOT}/third-party-programs.txt") + # Package sources get_filename_component(__PATH "${IPPROOT}/../${IW_PACKAGE_SUBDIR}/" ABSOLUTE) ippiw_setup("${__PATH}" 1) @@ -161,9 +168,15 @@ if(NOT HAVE_IPP_ICV AND BUILD_IPP_IW) set(TEMP_ROOT 0) include("${OpenCV_SOURCE_DIR}/3rdparty/ippicv/ippicv.cmake") download_ippicv(TEMP_ROOT) + set(IPPIW_ROOT "${TEMP_ROOT}/../${IW_PACKAGE_SUBDIR}") + ocv_install_3rdparty_licenses(ippiw + "${IPPIW_ROOT}/EULA.txt" + "${IPPIW_ROOT}/redist.txt" + "${IPPIW_ROOT}/support.txt" + "${IPPIW_ROOT}/third-party-programs.txt") # Package sources. Only sources are compatible with regular Intel IPP - ippiw_setup("${TEMP_ROOT}/../${IW_PACKAGE_SUBDIR}/" 1) + ippiw_setup("${IPPIW_ROOT}" 1) endif() diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index ae367d74a3..30f36ac5e0 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -1002,6 +1002,18 @@ function(ocv_install_target) endif() endfunction() +# ocv_install_3rdparty_licenses( [ ..]) +function(ocv_install_3rdparty_licenses library) + foreach(filename ${ARGN}) + get_filename_component(name "${filename}" NAME) + install( + FILES "${filename}" + DESTINATION "${OPENCV_OTHER_INSTALL_PATH}/licenses" + COMPONENT licenses + RENAME "${library}-${name}" + OPTIONAL) + endforeach() +endfunction() # read set of version defines from the header file macro(ocv_parse_header FILENAME FILE_VAR) diff --git a/modules/core/3rdparty/SoftFloat/COPYING.txt b/modules/core/3rdparty/SoftFloat/COPYING.txt new file mode 100644 index 0000000000..e16aa0fd58 --- /dev/null +++ b/modules/core/3rdparty/SoftFloat/COPYING.txt @@ -0,0 +1,36 @@ + +License for Berkeley SoftFloat Release 3c + +John R. Hauser +2017 February 10 + +The following applies to the whole of SoftFloat Release 3c as well as to +each source file individually. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the +University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions 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. + + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. diff --git a/modules/core/CMakeLists.txt b/modules/core/CMakeLists.txt index 4fb12f3c47..2ce93d374b 100644 --- a/modules/core/CMakeLists.txt +++ b/modules/core/CMakeLists.txt @@ -70,3 +70,5 @@ endif() ocv_add_accuracy_tests() ocv_add_perf_tests() + +ocv_install_3rdparty_licenses(SoftFloat "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/SoftFloat/COPYING.txt") From 3b15f3e3b9041ca742822e48c7241d1f39e611b8 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 29 Mar 2018 13:01:46 +0300 Subject: [PATCH 09/36] avoid calling of setNumThreads() to respect user settings --- modules/calib3d/perf/perf_stereosgbm.cpp | 1 - modules/calib3d/test/test_solvepnp_ransac.cpp | 2 ++ modules/imgproc/src/connectedcomponents.cpp | 31 ++++++++----------- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/modules/calib3d/perf/perf_stereosgbm.cpp b/modules/calib3d/perf/perf_stereosgbm.cpp index e74e1da472..2947938d40 100644 --- a/modules/calib3d/perf/perf_stereosgbm.cpp +++ b/modules/calib3d/perf/perf_stereosgbm.cpp @@ -67,7 +67,6 @@ PERF_TEST_P( TestStereoCorresp, DISABLED_TooLongInDebug_SGBM, Combine(Values(Siz MakeArtificialExample(rng,src_left,src_right); - cv::setNumThreads(cv::getNumberOfCPUs()); int wsize = 3; int P1 = 8*src_left.channels()*wsize*wsize; TEST_CYCLE() diff --git a/modules/calib3d/test/test_solvepnp_ransac.cpp b/modules/calib3d/test/test_solvepnp_ransac.cpp index 0a164440a5..8eec7a7167 100644 --- a/modules/calib3d/test/test_solvepnp_ransac.cpp +++ b/modules/calib3d/test/test_solvepnp_ransac.cpp @@ -382,6 +382,7 @@ TEST(Calib3d_SolvePnPRansac, concurrency) Mat rvec1, rvec2; Mat tvec1, tvec2; + int threads = getNumThreads(); { // limit concurrency to get deterministic result theRNG().state = 20121010; @@ -390,6 +391,7 @@ TEST(Calib3d_SolvePnPRansac, concurrency) } { + setNumThreads(threads); Mat rvec; Mat tvec; // parallel executions diff --git a/modules/imgproc/src/connectedcomponents.cpp b/modules/imgproc/src/connectedcomponents.cpp index e0d91aef2b..676afc6e8b 100644 --- a/modules/imgproc/src/connectedcomponents.cpp +++ b/modules/imgproc/src/connectedcomponents.cpp @@ -579,9 +579,6 @@ namespace cv{ CV_Assert(img.cols == imgLabels.cols); CV_Assert(connectivity == 8 || connectivity == 4); - const int nThreads = cv::getNumberOfCPUs(); - cv::setNumThreads(nThreads); - const int h = img.rows; const int w = img.cols; @@ -606,12 +603,13 @@ namespace cv{ P[0] = 0; cv::Range range(0, h); + const double nParallelStripes = std::max(1, std::min(h / 2, getNumThreads()*4)); + LabelT nLabels = 1; if (connectivity == 8){ - //First scan, each thread works with chunk of img.rows/nThreads rows - //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows - cv::parallel_for_(range, FirstScan8Connectivity(img, imgLabels, P, chunksSizeAndLabels), nThreads); + //First scan + cv::parallel_for_(range, FirstScan8Connectivity(img, imgLabels, P, chunksSizeAndLabels), nParallelStripes); //merge labels of different chunks mergeLabels8Connectivity(imgLabels, P, chunksSizeAndLabels); @@ -621,9 +619,8 @@ namespace cv{ } } else{ - //First scan, each thread works with chunk of img.rows/nThreads rows - //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows - cv::parallel_for_(range, FirstScan4Connectivity(img, imgLabels, P, chunksSizeAndLabels), nThreads); + //First scan + cv::parallel_for_(range, FirstScan4Connectivity(img, imgLabels, P, chunksSizeAndLabels), nParallelStripes); //merge labels of different chunks mergeLabels4Connectivity(imgLabels, P, chunksSizeAndLabels); @@ -638,7 +635,7 @@ namespace cv{ sop.init(nLabels); //Second scan - cv::parallel_for_(range, SecondScan(imgLabels, P, sop, sopArray, nLabels), nThreads); + cv::parallel_for_(range, SecondScan(imgLabels, P, sop, sopArray, nLabels), nParallelStripes); StatsOp::mergeStats(imgLabels, sopArray, sop, nLabels); sop.finish(); @@ -2530,9 +2527,6 @@ namespace cv{ CV_Assert(img.cols == imgLabels.cols); CV_Assert(connectivity == 8); - const int nThreads = cv::getNumberOfCPUs(); - cv::setNumThreads(nThreads); - const int h = img.rows; const int w = img.cols; @@ -2556,10 +2550,11 @@ namespace cv{ P[0] = 0; cv::Range range(0, h); + const double nParallelStripes = std::max(1, std::min(h / 2, getNumThreads()*4)); //First scan, each thread works with chunk of img.rows/nThreads rows //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows - cv::parallel_for_(range, FirstScan(img, imgLabels, P, chunksSizeAndLabels), nThreads); + cv::parallel_for_(range, FirstScan(img, imgLabels, P, chunksSizeAndLabels), nParallelStripes); //merge labels of different chunks mergeLabels(img, imgLabels, P, chunksSizeAndLabels); @@ -2574,7 +2569,7 @@ namespace cv{ sop.init(nLabels); //Second scan - cv::parallel_for_(range, SecondScan(img, imgLabels, P, sop, sopArray, nLabels), nThreads); + cv::parallel_for_(range, SecondScan(img, imgLabels, P, sop, sopArray, nLabels), nParallelStripes); StatsOp::mergeStats(imgLabels, sopArray, sop, nLabels); sop.finish(); @@ -3936,12 +3931,12 @@ namespace cv{ int lDepth = L.depth(); int iDepth = I.depth(); const char *currentParallelFramework = cv::currentParallelFramework(); - const int numberOfCPUs = cv::getNumberOfCPUs(); + const int nThreads = cv::getNumThreads(); CV_Assert(iDepth == CV_8U || iDepth == CV_8S); - //Run parallel labeling only if the rows of the image are at least twice the number returned by getNumberOfCPUs - const bool is_parallel = currentParallelFramework != NULL && numberOfCPUs > 1 && L.rows / numberOfCPUs >= 2; + //Run parallel labeling only if the rows of the image are at least twice the number of available threads + const bool is_parallel = currentParallelFramework != NULL && nThreads > 1 && L.rows / nThreads >= 2; if (ccltype == CCL_WU || connectivity == 4){ // Wu algorithm is used From 65c46d0cc6b58dbf86c42efc4bc2d71bec159901 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Wed, 11 Apr 2018 16:49:40 +0300 Subject: [PATCH 10/36] Removed WINRT related code --- modules/videoio/src/cap_msmf.cpp | 666 ------------------------------- modules/videoio/src/cap_msmf.hpp | 609 ---------------------------- 2 files changed, 1275 deletions(-) diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp index d4582d6f5e..eaca0e2cd9 100644 --- a/modules/videoio/src/cap_msmf.cpp +++ b/modules/videoio/src/cap_msmf.cpp @@ -86,36 +86,11 @@ #include -#ifdef WINRT - // for ComPtr usage -#include -#ifdef __cplusplus_winrt -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#ifdef HAVE_CONCURRENCY -#include -#ifndef __cplusplus_winrt -#include "wrl.h" -#endif -#include "ppltasks_winrt.hpp" -#endif -#else #include -#endif struct IMFMediaType; -#ifndef WINRT struct IMFActivate; struct IMFMediaSource; -#endif struct IMFAttributes; namespace @@ -252,43 +227,6 @@ private: ImageGrabberCallback& operator=(const ImageGrabberCallback&); // Declared to fix compilation warning. }; -#ifdef WINRT -extern const __declspec(selectany) WCHAR RuntimeClass_CV_ImageGrabberWinRT[] = L"cv.ImageGrabberWinRT"; - -class ImageGrabberWinRT : - public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>, - IMFSampleGrabberSinkCallback>, public ImageGrabberCallback -{ - InspectableClass(RuntimeClass_CV_ImageGrabberWinRT, BaseTrust) -public: - ImageGrabberWinRT(bool synchronous); - ~ImageGrabberWinRT(void); - - HRESULT initImageGrabber(MAKE_WRL_REF(_MediaCapture) pSource, - GUID VideoFormat); - HRESULT startGrabbing(MAKE_WRL_REF(_AsyncAction)* action); - HRESULT stopGrabbing(MAKE_WRL_REF(_AsyncAction)* action); - // IMFClockStateSink methods - STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) { return ImageGrabberCallback::OnClockStart(hnsSystemTime, llClockStartOffset); } - STDMETHODIMP OnClockStop(MFTIME hnsSystemTime) { return ImageGrabberCallback::OnClockStop(hnsSystemTime); } - STDMETHODIMP OnClockPause(MFTIME hnsSystemTime) { return ImageGrabberCallback::OnClockPause(hnsSystemTime); } - STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime) { return ImageGrabberCallback::OnClockRestart(hnsSystemTime); } - STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate) { return ImageGrabberCallback::OnClockSetRate(hnsSystemTime, flRate); } - // IMFSampleGrabberSinkCallback methods - STDMETHODIMP OnSetPresentationClock(IMFPresentationClock* pClock) { return ImageGrabberCallback::OnSetPresentationClock(pClock); } - STDMETHODIMP OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags, - LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer, - DWORD dwSampleSize) { return ImageGrabberCallback::OnProcessSample(guidMajorMediaType, dwSampleFlags, llSampleTime, llSampleDuration, pSampleBuffer, dwSampleSize); } - STDMETHODIMP OnShutdown() { return ImageGrabberCallback::OnShutdown(); } - // Function of creation of the instance of the class - static HRESULT CreateInstance(ImageGrabberWinRT **ppIG, bool synchronous = false); -private: - MAKE_WRL_AGILE_REF(_MediaCapture) ig_pMedCapSource; - MediaSink* ig_pMediaSink; -}; -#endif - // Class for grabbing image from video stream class ImageGrabber : public ImageGrabberCallback { @@ -395,20 +333,7 @@ public: CamParametrs getParametrs(); void setParametrs(CamParametrs parametrs); void setEmergencyStopEvent(void *userData, void(*func)(int, void *)); -#ifdef WINRT - long readInfoOfDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice, unsigned int Num); - void waitForDevice() - { - if (vd_pAction) { -#ifdef HAVE_CONCURRENCY - CREATE_TASK DEFINE_RET_TYPE(void)(vd_pAction).wait(); -#endif - vd_pAction = nullptr; - } - } -#else long readInfoOfDevice(IMFActivate *pActivate, unsigned int Num); -#endif wchar_t *getName(); int getCountFormats(); unsigned int getWidth(); @@ -441,32 +366,14 @@ private: std::map vd_CaptureFormats; std::vector vd_CurrentFormats; IMFMediaSource *vd_pSource; -#ifdef WINRT - MAKE_WRL_AGILE_REF(_MediaCapture) vd_pMedCap; - EventRegistrationToken vd_cookie; - ImageGrabberWinRT *vd_pImGr; - MAKE_WRL_REF(_AsyncAction) vd_pAction; -#ifdef HAVE_CONCURRENCY - Concurrency::critical_section vd_lock; -#endif -#endif emergensyStopEventCallback vd_func; void *vd_userData; HRESULT enumerateCaptureFormats(IMFMediaSource *pSource); long setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex); void buildLibraryofTypes(); int findType(unsigned int size, unsigned int frameRate = 0); -#ifdef WINRT - HRESULT enumerateCaptureFormats(MAKE_WRL_REF(_MediaCapture) pSource); - long setDeviceFormat(MAKE_WRL_REF(_MediaCapture) pSource, unsigned long dwFormatIndex, MAKE_WRL_REF(_AsyncAction)* pAction); - long resetDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice); -#ifdef HAVE_CONCURRENCY - long checkDevice(_DeviceClass devClass, DEFINE_TASK* pTask, MAKE_WRL_REF(_IDeviceInformation)* ppDevice); -#endif -#else long resetDevice(IMFActivate *pActivate); long checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice); -#endif long initDevice(); }; @@ -475,28 +382,13 @@ class videoDevices { public: ~videoDevices(void); -#ifdef WINRT - long initDevices(_DeviceClass devClass); - void waitInit() { - if (vds_enumTask) { -#ifdef HAVE_CONCURRENCY - CREATE_TASK DEFINE_RET_TYPE(void)(vds_enumTask).wait(); -#endif - vds_enumTask = nullptr; - } - } -#else long initDevices(IMFAttributes *pAttributes); -#endif static videoDevices& getInstance(); videoDevice *getDevice(unsigned int i); unsigned int getCount(); void clearDevices(); private: UINT32 count; -#ifdef WINRT - MAKE_WRL_REF(_AsyncAction) vds_enumTask; -#endif std::vector vds_Devices; videoDevices(void); }; @@ -566,9 +458,6 @@ public: bool setupDevice(int deviceID, unsigned int w, unsigned int h, unsigned int idealFramerate = 30); // Checking of recivig of new frame from video device with deviceID bool isFrameNew(int deviceID); -#ifdef WINRT - void waitForDevice(int deviceID); -#endif // Writing of Raw Data pixels from video device with deviceID with correction of RedAndBlue flipping flipRedAndBlue and vertical flipping flipImage bool getPixels(int deviceID, unsigned char * pixels, bool flipRedAndBlue = false, bool flipImage = false); static void processPixels(unsigned char * src, unsigned char * dst, unsigned int width, unsigned int height, unsigned int bpp, bool bRGB, bool bFlip); @@ -1089,156 +978,6 @@ ImageGrabber::~ImageGrabber(void) DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Destroying instance of the ImageGrabber class\n", ig_DeviceID); } -#ifdef WINRT - -ImageGrabberWinRT::ImageGrabberWinRT(bool synchronous): - ImageGrabberCallback(synchronous), - ig_pMediaSink(NULL) -{ - ig_pMedCapSource = nullptr; -} - -ImageGrabberWinRT::~ImageGrabberWinRT(void) -{ - //stop must already be performed and complete by object owner - if (ig_pMediaSink != NULL) { - ((IMFMediaSink*)ig_pMediaSink)->Shutdown(); - } - SafeRelease(&ig_pMediaSink); - RELEASE_AGILE_WRL(ig_pMedCapSource) - - CloseHandle(ig_hFinish); - - if (ig_Synchronous) - { - CloseHandle(ig_hFrameReady); - CloseHandle(ig_hFrameGrabbed); - } - - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE: Destroying instance of the ImageGrabberWinRT class\n"); -} - -HRESULT ImageGrabberWinRT::initImageGrabber(MAKE_WRL_REF(_MediaCapture) pSource, - GUID VideoFormat) -{ - HRESULT hr; - MAKE_WRL_OBJ(_VideoDeviceController) pDevCont; - WRL_PROP_GET(pSource, VideoDeviceController, pDevCont, hr) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps; - WRL_METHOD(pMedDevCont, GetMediaStreamProperties, pMedEncProps, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview)) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_VideoEncodingProperties, pVidProps, pMedEncProps, hr); - if (FAILED(hr)) return hr; - _ComPtr pType = NULL; - hr = MediaSink::ConvertPropertiesToMediaType(DEREF_AS_NATIVE_WRL_OBJ(ABI::Windows::Media::MediaProperties::IMediaEncodingProperties, pMedEncProps), &pType); - if (FAILED(hr)) return hr; - MediaType MT = FormatReader::Read(pType.Get()); - unsigned int sizeRawImage = 0; - if(VideoFormat == MFVideoFormat_RGB24) - { - sizeRawImage = MT.MF_MT_FRAME_SIZE * 3; - } - else if(VideoFormat == MFVideoFormat_RGB32) - { - sizeRawImage = MT.MF_MT_FRAME_SIZE * 4; - } - sizeRawImage = MT.MF_MT_SAMPLE_SIZE; - CHECK_HR(hr = RawImage::CreateInstance(&ig_RIFirst, sizeRawImage)); - CHECK_HR(hr = RawImage::CreateInstance(&ig_RISecond, sizeRawImage)); - ig_RIOut = ig_RISecond; - ig_pMedCapSource = pSource; -done: - return hr; -} - -HRESULT ImageGrabberWinRT::stopGrabbing(MAKE_WRL_REF(_AsyncAction)* action) -{ - HRESULT hr = S_OK; - if (ig_pMedCapSource != nullptr) { - GET_WRL_OBJ_FROM_REF(_MediaCaptureVideoPreview, imedPrevCap, DEREF_AGILE_WRL_OBJ(ig_pMedCapSource), hr) - if (FAILED(hr)) return hr; - MAKE_WRL_REF(_AsyncAction) pAction; - WRL_METHOD_BASE(imedPrevCap, StopPreviewAsync, pAction, hr) - if (SUCCEEDED(hr)) { -#ifdef HAVE_CONCURRENCY - DEFINE_TASK _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction); - *action = reinterpret_cast(BEGIN_CREATE_ASYNC(void, _task, this) - HRESULT hr = S_OK; - _task.wait(); - SafeRelease(&ig_pMediaSink); - SetEvent(ig_hFinish); - END_CREATE_ASYNC(hr)); -#else - *action = nullptr; -#endif - } - } - return hr; -} - -HRESULT ImageGrabberWinRT::startGrabbing(MAKE_WRL_REF(_AsyncAction)* action) -{ - HRESULT hr = S_OK; - GET_WRL_OBJ_FROM_REF(_MediaCaptureVideoPreview, imedPrevCap, DEREF_AGILE_WRL_OBJ(ig_pMedCapSource), hr) - if (FAILED(hr)) return hr; - ACTIVATE_OBJ(RuntimeClass_Windows_Foundation_Collections_PropertySet, _PropertySet, pSet, hr) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_Map, spSetting, pSet, hr) - if (FAILED(hr)) return hr; - ACTIVATE_STATIC_OBJ(RuntimeClass_Windows_Foundation_PropertyValue, MAKE_WRL_OBJ(_PropertyValueStatics), spPropVal, hr) - if (FAILED(hr)) return hr; - _ObjectObj pVal; - boolean bReplaced; - WRL_METHOD(spPropVal, CreateUInt32, pVal, hr, (unsigned int)WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview)) - if (FAILED(hr)) return hr; - WRL_METHOD(spSetting, Insert, bReplaced, hr, DEREF_WRL_OBJ(_StringReference(MF_PROP_VIDTYPE)), DEREF_WRL_OBJ(pVal)) - if (FAILED(hr)) return hr; - WRL_METHOD(spSetting, Insert, bReplaced, hr, DEREF_WRL_OBJ(_StringReference(MF_PROP_SAMPLEGRABBERCALLBACK)), reinterpret_cast<_Object>(this)) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_VideoDeviceController) pDevCont; - WRL_PROP_GET(ig_pMedCapSource, VideoDeviceController, pDevCont, hr) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps; - WRL_METHOD(pMedDevCont, GetMediaStreamProperties, pMedEncProps, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview)) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_VideoEncodingProperties, pVidProps, pMedEncProps, hr); - if (FAILED(hr)) return hr; - ACTIVATE_OBJ(RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile, _MediaEncodingProfile, pEncProps, hr) - if (FAILED(hr)) return hr; - WRL_PROP_PUT(pEncProps, Video, DEREF_WRL_OBJ(pVidProps), hr) - if (FAILED(hr)) return hr; - WRL_METHOD(spSetting, Insert, bReplaced, hr, DEREF_WRL_OBJ(_StringReference(MF_PROP_VIDENCPROPS)), DEREF_WRL_OBJ(pVidProps)) - if (SUCCEEDED(hr)) { - //can start/stop multiple times with same MediaCapture object if using activatable class - WRL_METHOD(imedPrevCap, _StartPreviewToCustomSinkIdAsync, *action, hr, DEREF_WRL_OBJ(pEncProps), DEREF_WRL_OBJ(_StringReference(RuntimeClass_CV_MediaSink)), DEREF_WRL_OBJ(pSet)) - if (FAILED(hr) && hr == REGDB_E_CLASSNOTREG) { - hr = Microsoft::WRL::Make().CopyTo(&ig_pMediaSink); - if (FAILED(hr)) return hr; - hr = ((ABI::Windows::Media::IMediaExtension*)ig_pMediaSink)->SetProperties(DEREF_AS_NATIVE_WRL_OBJ(ABI::Windows::Foundation::Collections::IPropertySet, pSet)); - if (FAILED(hr)) return hr; - WRL_METHOD(imedPrevCap, StartPreviewToCustomSinkAsync, *action, hr, DEREF_WRL_OBJ(pEncProps), reinterpret_cast(ig_pMediaSink)) - } - } - return hr; -} - -HRESULT ImageGrabberWinRT::CreateInstance(ImageGrabberWinRT **ppIG, bool synchronous) -{ - *ppIG = Microsoft::WRL::Make(synchronous).Detach(); - if (ppIG == NULL) - { - return E_OUTOFMEMORY; - } - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE: Creating instance of ImageGrabberWinRT\n"); - return S_OK; -} -#endif - HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource) { // Clean up. @@ -1811,12 +1550,6 @@ unsigned char * RawImage::getpPixels() videoDevice::videoDevice(void): vd_IsSetuped(false), vd_LockOut(OpenLock), vd_pFriendlyName(NULL), vd_Width(0), vd_Height(0), vd_FrameRate(0), vd_pSource(NULL), vd_pImGrTh(NULL), vd_func(NULL), vd_userData(NULL) { -#ifdef WINRT - vd_pMedCap = nullptr; - vd_cookie.value = 0; - vd_pImGr = NULL; - vd_pAction = nullptr; -#endif } void videoDevice::setParametrs(CamParametrs parametrs) @@ -1899,63 +1632,13 @@ CamParametrs videoDevice::getParametrs() return out; } -#ifdef WINRT -long videoDevice::resetDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice) -#else long videoDevice::resetDevice(IMFActivate *pActivate) -#endif { HRESULT hr = E_FAIL; vd_CurrentFormats.clear(); if(vd_pFriendlyName) CoTaskMemFree(vd_pFriendlyName); vd_pFriendlyName = NULL; -#ifdef WINRT - if (pDevice) - { - ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCapture, _MediaCapture, pIMedCap, hr) - if (FAILED(hr)) return hr; - ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings, _MediaCaptureInitializationSettings, pCapInitSet, hr) - if (FAILED(hr)) return hr; - _StringObj str; - WRL_PROP_GET(pDevice, Name, *REF_WRL_OBJ(str), hr) - if (FAILED(hr)) return hr; - unsigned int length = 0; - PCWSTR wstr = WindowsGetStringRawBuffer(reinterpret_cast(DEREF_WRL_OBJ(str)), &length); - vd_pFriendlyName = (wchar_t*)CoTaskMemAlloc((length + 1) * sizeof(wchar_t)); - wcscpy(vd_pFriendlyName, wstr); - WRL_PROP_GET(pDevice, Id, *REF_WRL_OBJ(str), hr) - if (FAILED(hr)) return hr; - WRL_PROP_PUT(pCapInitSet, VideoDeviceId, DEREF_WRL_OBJ(str), hr) - if (FAILED(hr)) return hr; - WRL_PROP_PUT(pCapInitSet, StreamingCaptureMode, WRL_ENUM_GET(_StreamingCaptureMode, StreamingCaptureMode, Video), hr) - if (FAILED(hr)) return hr; - MAKE_WRL_REF(_AsyncAction) pAction; - WRL_METHOD(DEREF_WRL_OBJ(pIMedCap), _InitializeWithSettingsAsync, pAction, hr, DEREF_WRL_OBJ(pCapInitSet)) -#ifdef HAVE_CONCURRENCY - DEFINE_TASK _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction); - if (FAILED(hr)) return hr; - MAKE_WRL_AGILE_REF(_MediaCapture) pAgileMedCap; - pAgileMedCap = PREPARE_TRANSFER_WRL_OBJ(pIMedCap); - Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); - MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; - SAVE_CURRENT_CONTEXT(context); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, _task, pOldAction, context, &pAgileMedCap, this) - HRESULT hr = S_OK; - if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); - _task.wait(); - if (SUCCEEDED(hr)) { - //all camera capture calls only in original context - BEGIN_CALL_IN_CONTEXT(hr, context, pAgileMedCap, this) - enumerateCaptureFormats(DEREF_AGILE_WRL_OBJ(pAgileMedCap)); - END_CALL_IN_CONTEXT_BASE - } - buildLibraryofTypes(); - RELEASE_AGILE_WRL(pAgileMedCap) - END_CREATE_ASYNC(hr)); -#endif - } -#else if(pActivate) { IMFMediaSource *pSource = NULL; @@ -1981,64 +1664,15 @@ long videoDevice::resetDevice(IMFActivate *pActivate) DebugPrintOut(L"VIDEODEVICE %i: IMFMediaSource interface cannot be created \n", vd_CurrentNumber); } } -#endif return hr; } -#ifdef WINRT -long videoDevice::readInfoOfDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice, unsigned int Num) -{ - HRESULT hr = -1; - vd_CurrentNumber = Num; - hr = resetDevice(pDevice); - return hr; -} -#else long videoDevice::readInfoOfDevice(IMFActivate *pActivate, unsigned int Num) { vd_CurrentNumber = Num; return resetDevice(pActivate); } -#endif -#ifdef WINRT -#ifdef HAVE_CONCURRENCY -long videoDevice::checkDevice(_DeviceClass devClass, DEFINE_TASK* pTask, MAKE_WRL_REF(_IDeviceInformation)* ppDevice) -{ - HRESULT hr = S_OK; - ACTIVATE_STATIC_OBJ(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation, MAKE_WRL_OBJ(_DeviceInformationStatics), pDevStat, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_REF(_AsyncOperation) pAction; - WRL_METHOD(pDevStat, _FindAllAsyncDeviceClass, pAction, hr, devClass) - if (SUCCEEDED(hr)) { - *pTask = CREATE_TASK DEFINE_RET_TYPE(void)([pAction, &ppDevice, this]() -> DEFINE_RET_FORMAL(void) { - HRESULT hr = S_OK; - MAKE_WRL_OBJ(_VectorView) pVector = - CREATE_TASK DEFINE_RET_TYPE(MAKE_WRL_REF(_VectorView))(pAction).get(); - UINT32 count = 0; - if (SUCCEEDED(hr)) WRL_PROP_GET(pVector, Size, count, hr) - if (SUCCEEDED(hr) && count > 0) { - for (UINT32 i = 0; i < count; i++) { - MAKE_WRL_OBJ(_IDeviceInformation) pDevice; - WRL_METHOD(pVector, GetAt, pDevice, hr, i) - if (SUCCEEDED(hr)) { - _StringObj str; - unsigned int length = 0; - WRL_PROP_GET(pDevice, Name, *REF_WRL_OBJ(str), hr) - PCWSTR wstr = WindowsGetStringRawBuffer(reinterpret_cast(DEREF_WRL_OBJ(str)), &length); - if (wcscmp(wstr, vd_pFriendlyName) == 0) { - *ppDevice = PREPARE_TRANSFER_WRL_OBJ(pDevice); - } - } - } - } - RET_VAL_BASE; - }); - } - return hr; -} -#endif -#else long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice) { IMFActivate **ppDevices = NULL; @@ -2095,59 +1729,11 @@ long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice) } return hr; } -#endif long videoDevice::initDevice() { HRESULT hr = S_OK; CoInitialize(NULL); -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); - MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; - SAVE_CURRENT_CONTEXT(context); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, pOldAction, context, this) - HRESULT hr; - if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); - DEFINE_TASK pTask; - MAKE_WRL_OBJ(_IDeviceInformation) pDevInfo; - hr = checkDevice(WRL_ENUM_GET(_DeviceClass, DeviceClass, VideoCapture), &pTask, REF_WRL_OBJ(pDevInfo)); - if (SUCCEEDED(hr)) pTask.wait(); - if (SUCCEEDED(hr)) { - DEFINE_TASK _task; - BEGIN_CALL_IN_CONTEXT(hr, context, pDevInfo, &_task, context, this) - HRESULT hr; - ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCapture, _MediaCapture, pIMedCap, hr) - if (SUCCEEDED(hr)) { - RELEASE_WRL(vd_pMedCap); - vd_pMedCap = PREPARE_TRANSFER_WRL_OBJ(pIMedCap); - ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings, _MediaCaptureInitializationSettings, pCapInitSet, hr) - _StringObj str; - if (SUCCEEDED(hr)) { - WRL_PROP_GET(pDevInfo, Id, *REF_WRL_OBJ(str), hr) - if (SUCCEEDED(hr)) { - WRL_PROP_PUT(pCapInitSet, VideoDeviceId, DEREF_WRL_OBJ(str), hr) - } - } - if (SUCCEEDED(hr)) - WRL_PROP_PUT(pCapInitSet, StreamingCaptureMode, WRL_ENUM_GET(_StreamingCaptureMode, StreamingCaptureMode, Video), hr) - if (SUCCEEDED(hr)) reinterpret_cast(DEREF_AGILE_WRL_OBJ(vd_pMedCap))->add_Failed(Microsoft::WRL::Callback([this, context](ABI::Windows::Media::Capture::IMediaCapture*, ABI::Windows::Media::Capture::IMediaCaptureFailedEventArgs*) -> HRESULT { - HRESULT hr; - BEGIN_CALL_IN_CONTEXT(hr, context, this) - closeDevice(); - END_CALL_IN_CONTEXT_BASE - return hr; - }).Get(), &vd_cookie); - MAKE_WRL_OBJ(_AsyncAction) pAction; - if (SUCCEEDED(hr)) WRL_METHOD(vd_pMedCap, _InitializeWithSettingsAsync, *REF_WRL_OBJ(pAction), hr, DEREF_WRL_OBJ(pCapInitSet)) - if (SUCCEEDED(hr)) _task = CREATE_TASK DEFINE_RET_TYPE(void)(DEREF_WRL_OBJ(pAction)); - } - END_CALL_IN_CONTEXT(hr) - _task.wait(); - } - END_CREATE_ASYNC(hr)); -#endif -#else _ComPtr pAttributes = NULL; IMFActivate *vd_pActivate = NULL; hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1); @@ -2182,7 +1768,6 @@ long videoDevice::initDevice() { DebugPrintOut(L"VIDEODEVICE %i: The attribute of video cameras cannot be getting \n", vd_CurrentNumber); } -#endif return hr; } @@ -2209,31 +1794,6 @@ void videoDevice::closeDevice() { vd_IsSetuped = false; -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - if (DEREF_AGILE_WRL_OBJ(vd_pMedCap)) { - MAKE_WRL_REF(_AsyncAction) action; - Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); - MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; - vd_pImGr->stopGrabbing(&action); - reinterpret_cast(DEREF_AGILE_WRL_OBJ(vd_pMedCap))->remove_Failed(vd_cookie); - vd_cookie.value = 0; - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, action, pOldAction, this) - HRESULT hr = S_OK; - if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); - CREATE_TASK DEFINE_RET_TYPE(void)(action).wait(); - RELEASE_WRL(vd_pMedCap) - if(vd_LockOut == RawDataLock) { - delete vd_pImGr; - } - vd_pImGr = NULL; - vd_LockOut = OpenLock; - END_CREATE_ASYNC(hr)); - return; - } -#endif -#endif - vd_pSource->Shutdown(); SafeRelease(&vd_pSource); if(vd_LockOut == RawDataLock) @@ -2363,26 +1923,6 @@ void videoDevice::buildLibraryofTypes() } } -#ifdef WINRT -long videoDevice::setDeviceFormat(MAKE_WRL_REF(_MediaCapture) pSource, unsigned long dwFormatIndex, MAKE_WRL_REF(_AsyncAction)* pAction) -{ - HRESULT hr; - MAKE_WRL_OBJ(_VideoDeviceController) pDevCont; - WRL_PROP_GET(pSource, VideoDeviceController, pDevCont, hr) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_VectorView) pVector; - WRL_METHOD(pMedDevCont, GetAvailableMediaStreamProperties, pVector, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview)) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps; - WRL_METHOD(pVector, GetAt, pMedEncProps, hr, dwFormatIndex) - if (FAILED(hr)) return hr; - WRL_METHOD(pMedDevCont, SetMediaStreamPropertiesAsync, *pAction, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview), DEREF_WRL_OBJ(pMedEncProps)) - return hr; -} -#endif - long videoDevice::setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex) { _ComPtr pPD = NULL; @@ -2424,9 +1964,6 @@ bool videoDevice::isDeviceSetup() RawImage * videoDevice::getRawImageOut() { if(!vd_IsSetuped) return NULL; -#ifdef WINRT - if(vd_pImGr) return vd_pImGr->getRawImage(); -#endif if(vd_pImGrTh) return vd_pImGrTh->getImageGrabber()->getRawImage(); else @@ -2446,27 +1983,6 @@ bool videoDevice::isFrameNew() vd_LockOut = RawDataLock; //must already be closed -#ifdef WINRT - if (DEREF_AGILE_WRL_OBJ(vd_pMedCap)) { - MAKE_WRL_REF(_AsyncAction) action; - if (FAILED(ImageGrabberWinRT::CreateInstance(&vd_pImGr))) return false; - if (FAILED(vd_pImGr->initImageGrabber(DEREF_AGILE_WRL_OBJ(vd_pMedCap), MFVideoFormat_RGB24)) || FAILED(vd_pImGr->startGrabbing(&action))) { - delete vd_pImGr; - return false; - } -#ifdef HAVE_CONCURRENCY - Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); - MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; - DEFINE_TASK _task = CREATE_TASK DEFINE_RET_TYPE(void)(action); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, _task, pOldAction, this) - HRESULT hr = S_OK; - if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); - _task.wait(); - END_CREATE_ASYNC(hr)); -#endif - return true; - } -#endif HRESULT hr = ImageGrabberThread::CreateInstance(&vd_pImGrTh, vd_pSource, vd_CurrentNumber); if(FAILED(hr)) { @@ -2477,10 +1993,6 @@ bool videoDevice::isFrameNew() vd_pImGrTh->start(); return true; } -#ifdef WINRT - if(vd_pImGr) - return vd_pImGr->getRawImage()->isNew(); -#endif if(vd_pImGrTh) return vd_pImGrTh->getImageGrabber()->getRawImage()->isNew(); } @@ -2506,46 +2018,16 @@ bool videoDevice::setupDevice(unsigned int id) HRESULT hr = initDevice(); if(SUCCEEDED(hr)) { -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); - MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; - SAVE_CURRENT_CONTEXT(context); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, pOldAction, context, id, this) - HRESULT hr; - if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); -#endif -#endif vd_Width = vd_CurrentFormats[id].width; vd_Height = vd_CurrentFormats[id].height; vd_FrameRate = vd_CurrentFormats[id].MF_MT_FRAME_RATE_NUMERATOR / vd_CurrentFormats[id].MF_MT_FRAME_RATE_DENOMINATOR; -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - if (DEREF_AGILE_WRL_OBJ(vd_pMedCap)) { - DEFINE_TASK _task; - BEGIN_CALL_IN_CONTEXT(hr, context, id, &_task, this) - MAKE_WRL_REF(_AsyncAction) pAction; - HRESULT hr = setDeviceFormat(DEREF_AGILE_WRL_OBJ(vd_pMedCap), (DWORD) id, &pAction); - if (SUCCEEDED(hr)) _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction); - END_CALL_IN_CONTEXT(hr) - if (SUCCEEDED(hr)) _task.wait(); - } else -#endif -#endif hr = setDeviceFormat(vd_pSource, (DWORD) id); vd_IsSetuped = (SUCCEEDED(hr)); if(vd_IsSetuped) DebugPrintOut(L"\n\nVIDEODEVICE %i: Device is setuped \n", vd_CurrentNumber); vd_PrevParametrs = getParametrs(); -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - END_CREATE_ASYNC(hr)); -#endif - return true; -#else return vd_IsSetuped; -#endif } else { @@ -2577,43 +2059,11 @@ wchar_t *videoDevice::getName() videoDevice::~videoDevice(void) { closeDevice(); -#ifdef WINRT - RELEASE_WRL(vd_pMedCap) -#endif SafeRelease(&vd_pSource); if(vd_pFriendlyName) CoTaskMemFree(vd_pFriendlyName); } -#ifdef WINRT -HRESULT videoDevice::enumerateCaptureFormats(MAKE_WRL_REF(_MediaCapture) pSource) -{ - HRESULT hr; - MAKE_WRL_OBJ(_VideoDeviceController) pDevCont; - WRL_PROP_GET(pSource, VideoDeviceController, pDevCont, hr) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_VectorView) pVector; - WRL_METHOD(pMedDevCont, GetAvailableMediaStreamProperties, pVector, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview)) - if (FAILED(hr)) return hr; - UINT32 count; - WRL_PROP_GET(pVector, Size, count, hr) - if (FAILED(hr)) return hr; - for (UINT32 i = 0; i < count; i++) { - MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps; - WRL_METHOD(pVector, GetAt, pMedEncProps, hr, i) - if (FAILED(hr)) return hr; - _ComPtr pType = NULL; - hr = MediaSink::ConvertPropertiesToMediaType(DEREF_AS_NATIVE_WRL_OBJ(ABI::Windows::Media::MediaProperties::IMediaEncodingProperties, pMedEncProps), &pType); - if (FAILED(hr)) return hr; - MediaType MT = FormatReader::Read(pType.Get()); - vd_CurrentFormats.push_back(MT); - } - return hr; -} -#endif - HRESULT videoDevice::enumerateCaptureFormats(IMFMediaSource *pSource) { HRESULT hr = S_OK; @@ -2668,9 +2118,6 @@ done: videoDevices::videoDevices(void): count(0) { -#ifdef WINRT - vds_enumTask = nullptr; -#endif } void videoDevices::clearDevices() @@ -2699,41 +2146,6 @@ videoDevice * videoDevices::getDevice(unsigned int i) return vds_Devices[i]; } -#ifdef WINRT -long videoDevices::initDevices(_DeviceClass devClass) -{ - HRESULT hr = S_OK; - ACTIVATE_STATIC_OBJ(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation, MAKE_WRL_OBJ(_DeviceInformationStatics), pDevStat, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_REF(_AsyncOperation) pAction; - WRL_METHOD(pDevStat, _FindAllAsyncDeviceClass, pAction, hr, devClass) - if (SUCCEEDED(hr)) { -#ifdef HAVE_CONCURRENCY - SAVE_CURRENT_CONTEXT(context); - vds_enumTask = reinterpret_cast(BEGIN_CREATE_ASYNC(void, pAction, context, this) - HRESULT hr = S_OK; - MAKE_WRL_OBJ(_VectorView) pVector = - CREATE_TASK DEFINE_RET_TYPE(MAKE_WRL_REF(_VectorView))(pAction).get(); - if (SUCCEEDED(hr)) WRL_PROP_GET(pVector, Size, count, hr) - if (SUCCEEDED(hr) && count > 0) { - for (UINT32 i = 0; i < count; i++) { - videoDevice *vd = new videoDevice; - MAKE_WRL_OBJ(_IDeviceInformation) pDevice; - WRL_METHOD(pVector, GetAt, pDevice, hr, i) - if (SUCCEEDED(hr)) { - BEGIN_CALL_IN_CONTEXT(hr, context, vd, pDevice, i) - vd->readInfoOfDevice(DEREF_WRL_OBJ(pDevice), i); - END_CALL_IN_CONTEXT_BASE - vds_Devices.push_back(vd); - } - } - } - END_CREATE_ASYNC(hr)); -#endif - } - return hr; -} -#else long videoDevices::initDevices(IMFAttributes *pAttributes) { clearDevices(); @@ -2761,7 +2173,6 @@ long videoDevices::initDevices(IMFAttributes *pAttributes) } return hr; } -#endif unsigned int videoDevices::getCount() { @@ -2836,10 +2247,6 @@ videoInput::videoInput(void): MF(Media_Foundation::getInstance()), accessToDevic void videoInput::updateListOfDevices() { HRESULT hr = S_OK; -#ifdef WINRT - videoDevices *vDs = &videoDevices::getInstance(); - hr = vDs->initDevices(WRL_ENUM_GET(_DeviceClass, DeviceClass, VideoCapture)); -#else _ComPtr pAttributes = NULL; CoInitialize(NULL); hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1); @@ -2855,7 +2262,6 @@ void videoInput::updateListOfDevices() videoDevices *vDs = &videoDevices::getInstance(); hr = vDs->initDevices(pAttributes.Get()); } -#endif if (FAILED(hr)) { DebugPrintOut(L"MEDIA FOUNDATION: The access to the video cameras denied\n"); @@ -3059,36 +2465,6 @@ bool videoInput::isFrameNew(int deviceID) return false; } -#ifdef WINRT -void videoInput::waitForDevice(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return; - } - if(accessToDevices) - { - if(!isDeviceSetup(deviceID)) - { - if(isDeviceMediaSource(deviceID)) - return; - } - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - { - VD->waitForDevice(); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return; -} -#endif - unsigned int videoInput::getCountFormats(int deviceID) const { if (deviceID < 0) @@ -3268,9 +2644,6 @@ unsigned int videoInput::listDevices(bool silent) if(accessToDevices) { videoDevices *VDS = &videoDevices::getInstance(); -#ifdef WINRT - VDS->waitInit(); -#endif out = VDS->getCount(); if(!silent) DebugPrintOut(L"\nVIDEOINPUT SPY MODE!\n\n"); if(!silent) DebugPrintOut(L"SETUP: Looking For Capture Devices\n"); @@ -3458,12 +2831,6 @@ protected: int index, width, height, fourcc; IplImage* frame; videoInput VI; -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - DEFINE_TASK openTask; - Concurrency::critical_section lock; -#endif -#endif }; #ifdef _DEBUG @@ -3506,12 +2873,6 @@ void CvCaptureCAM_MSMF::close() // Initialize camera input bool CvCaptureCAM_MSMF::open( int _index ) { -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - SAVE_CURRENT_CONTEXT(context); - auto func = [_index, context, this](DEFINE_RET_VAL(bool)) -> DEFINE_RET_FORMAL(bool) { -#endif -#endif int try_index = _index; int devices = 0; close(); @@ -3519,37 +2880,10 @@ bool CvCaptureCAM_MSMF::open( int _index ) if (devices == 0) return false; try_index = try_index < 0 ? 0 : (try_index > devices-1 ? devices-1 : try_index); -#ifdef WINRT - HRESULT hr; -#ifdef HAVE_CONCURRENCY - BEGIN_CALL_IN_CONTEXT(hr, context, this, try_index) -#endif -#endif VI.setupDevice(try_index, 0, 0, 0); // With maximum frame size. -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - END_CALL_IN_CONTEXT_BASE - VI.waitForDevice(try_index); - BEGIN_CALL_IN_CONTEXT(hr, context, this, try_index) - HRESULT hr = S_OK; -#endif -#endif if( !VI.isFrameNew(try_index) ) -#ifdef WINRT - hr = E_FAIL; -#else return false; -#endif index = try_index; -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - END_CALL_IN_CONTEXT_BASE - RET_VAL(true) - }; - Concurrency::critical_section::scoped_lock _LockHolder(lock); - CREATE_OR_CONTINUE_TASK(openTask, bool, func) -#endif -#endif return true; } diff --git a/modules/videoio/src/cap_msmf.hpp b/modules/videoio/src/cap_msmf.hpp index 2d48f86d94..04aa3b9806 100644 --- a/modules/videoio/src/cap_msmf.hpp +++ b/modules/videoio/src/cap_msmf.hpp @@ -1,9 +1,3 @@ -#ifdef WINRT -#define ICustomStreamSink StreamSink -#ifndef __cplusplus_winrt -#include "wrl.h" -#endif -#else EXTERN_C const IID IID_ICustomStreamSink; class DECLSPEC_UUID("4F8A1939-2FD3-46DB-AE70-DB7E0DD79B73") DECLSPEC_NOVTABLE ICustomStreamSink : public IUnknown @@ -16,7 +10,6 @@ public: virtual HRESULT Restart() = 0; virtual HRESULT Stop() = 0; }; -#endif #define MF_PROP_SAMPLEGRABBERCALLBACK L"samplegrabbercallback" #define MF_PROP_VIDTYPE L"vidtype" @@ -182,219 +175,6 @@ MAKE_ENUM(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypePairs[] = { }; MAKE_MAP(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypeMap(StreamSinkMarkerTypePairs, StreamSinkMarkerTypePairs + sizeof(StreamSinkMarkerTypePairs) / sizeof(StreamSinkMarkerTypePairs[0])); -#ifdef WINRT - -#ifdef __cplusplus_winrt -#define _ContextCallback Concurrency::details::_ContextCallback -#define BEGIN_CALL_IN_CONTEXT(hr, var, ...) hr = S_OK;\ - var._CallInContext([__VA_ARGS__]() { -#define END_CALL_IN_CONTEXT(hr) if (FAILED(hr)) throw Platform::Exception::CreateException(hr);\ -}); -#define END_CALL_IN_CONTEXT_BASE }); -#else -#define _ContextCallback Concurrency_winrt::details::_ContextCallback -#define BEGIN_CALL_IN_CONTEXT(hr, var, ...) hr = var._CallInContext([__VA_ARGS__]() -> HRESULT { -#define END_CALL_IN_CONTEXT(hr) return hr;\ -}); -#define END_CALL_IN_CONTEXT_BASE return S_OK;\ -}); -#endif -#define GET_CURRENT_CONTEXT _ContextCallback::_CaptureCurrent() -#define SAVE_CURRENT_CONTEXT(var) _ContextCallback var = GET_CURRENT_CONTEXT - -#define COMMA , - -#ifdef __cplusplus_winrt -#define _Object Platform::Object^ -#define _ObjectObj Platform::Object^ -#define _String Platform::String^ -#define _StringObj Platform::String^ -#define _StringReference ref new Platform::String -#define _StringReferenceObj Platform::String^ -#define _DeviceInformationCollection Windows::Devices::Enumeration::DeviceInformationCollection -#define _MediaCapture Windows::Media::Capture::MediaCapture -#define _MediaCaptureVideoPreview Windows::Media::Capture::MediaCapture -#define _MediaCaptureInitializationSettings Windows::Media::Capture::MediaCaptureInitializationSettings -#define _VideoDeviceController Windows::Media::Devices::VideoDeviceController -#define _MediaDeviceController Windows::Media::Devices::VideoDeviceController -#define _MediaEncodingProperties Windows::Media::MediaProperties::IMediaEncodingProperties -#define _VideoEncodingProperties Windows::Media::MediaProperties::VideoEncodingProperties -#define _MediaStreamType Windows::Media::Capture::MediaStreamType -#define _AsyncInfo Windows::Foundation::IAsyncInfo -#define _AsyncAction Windows::Foundation::IAsyncAction -#define _AsyncOperation Windows::Foundation::IAsyncOperation -#define _DeviceClass Windows::Devices::Enumeration::DeviceClass -#define _IDeviceInformation Windows::Devices::Enumeration::DeviceInformation -#define _DeviceInformation Windows::Devices::Enumeration::DeviceInformation -#define _DeviceInformationStatics Windows::Devices::Enumeration::DeviceInformation -#define _MediaEncodingProfile Windows::Media::MediaProperties::MediaEncodingProfile -#define _StreamingCaptureMode Windows::Media::Capture::StreamingCaptureMode -#define _PropertySet Windows::Foundation::Collections::PropertySet -#define _Map Windows::Foundation::Collections::PropertySet -#define _PropertyValueStatics Windows::Foundation::PropertyValue -#define _VectorView Windows::Foundation::Collections::IVectorView -#define _StartPreviewToCustomSinkIdAsync StartPreviewToCustomSinkAsync -#define _InitializeWithSettingsAsync InitializeAsync -#define _FindAllAsyncDeviceClass FindAllAsync -#define _MediaExtension Windows::Media::IMediaExtension -#define BEGIN_CREATE_ASYNC(type, ...) (Concurrency::create_async([__VA_ARGS__]() { -#define END_CREATE_ASYNC(hr) if (FAILED(hr)) throw Platform::Exception::CreateException(hr);\ -})) -#define DEFINE_TASK Concurrency::task -#define CREATE_TASK Concurrency::create_task -#define CREATE_OR_CONTINUE_TASK(_task, rettype, func) _task = (_task == Concurrency::task()) ? Concurrency::create_task(func) : _task.then([func](rettype) -> rettype { return func(); }); -#define DEFINE_RET_VAL(x) -#define DEFINE_RET_TYPE(x) -#define DEFINE_RET_FORMAL(x) x -#define RET_VAL(x) return x; -#define RET_VAL_BASE -#define MAKE_STRING(str) str -#define GET_STL_STRING(str) std::wstring(str->Data()) -#define GET_STL_STRING_RAW(str) std::wstring(str->Data()) -#define MAKE_WRL_OBJ(x) x^ -#define MAKE_WRL_REF(x) x^ -#define MAKE_OBJ_REF(x) x^ -#define MAKE_WRL_AGILE_REF(x) Platform::Agile -#define MAKE_PROPERTY_BACKING(Type, PropName) property Type PropName; -#define MAKE_PROPERTY(Type, PropName, PropValue) -#define MAKE_PROPERTY_STRING(Type, PropName, PropValue) -#define MAKE_READONLY_PROPERTY(Type, PropName, PropValue) property Type PropName\ -{\ - Type get() { return PropValue; }\ -} -#define THROW_INVALID_ARG throw ref new Platform::InvalidArgumentException(); -#define RELEASE_AGILE_WRL(x) x = nullptr; -#define RELEASE_WRL(x) x = nullptr; -#define GET_WRL_OBJ_FROM_REF(objtype, obj, orig, hr) objtype^ obj = orig;\ -hr = S_OK; -#define GET_WRL_OBJ_FROM_OBJ(objtype, obj, orig, hr) objtype^ obj = safe_cast(orig);\ -hr = S_OK; -#define WRL_ENUM_GET(obj, prefix, prop) obj::##prop -#define WRL_PROP_GET(obj, prop, arg, hr) arg = obj->##prop;\ -hr = S_OK; -#define WRL_PROP_PUT(obj, prop, arg, hr) obj->##prop = arg;\ -hr = S_OK; -#define WRL_METHOD_BASE(obj, method, ret, hr) ret = obj->##method();\ -hr = S_OK; -#define WRL_METHOD(obj, method, ret, hr, ...) ret = obj->##method(__VA_ARGS__);\ -hr = S_OK; -#define WRL_METHOD_NORET_BASE(obj, method, hr) obj->##method();\ - hr = S_OK; -#define WRL_METHOD_NORET(obj, method, hr, ...) obj->##method(__VA_ARGS__);\ - hr = S_OK; -#define REF_WRL_OBJ(obj) &obj -#define DEREF_WRL_OBJ(obj) obj -#define DEREF_AGILE_WRL_OBJ(obj) obj.Get() -#define DEREF_AS_NATIVE_WRL_OBJ(type, obj) reinterpret_cast(obj) -#define PREPARE_TRANSFER_WRL_OBJ(obj) obj -#define ACTIVATE_LOCAL_OBJ_BASE(objtype) ref new objtype() -#define ACTIVATE_LOCAL_OBJ(objtype, ...) ref new objtype(__VA_ARGS__) -#define ACTIVATE_EVENT_HANDLER(objtype, ...) ref new objtype(__VA_ARGS__) -#define ACTIVATE_OBJ(rtclass, objtype, obj, hr) MAKE_WRL_OBJ(objtype) obj = ref new objtype();\ -hr = S_OK; -#define ACTIVATE_STATIC_OBJ(rtclass, objtype, obj, hr) objtype obj;\ -hr = S_OK; -#else -#define _Object IInspectable* -#define _ObjectObj Microsoft::WRL::ComPtr -#define _String HSTRING -#define _StringObj Microsoft::WRL::Wrappers::HString -#define _StringReference Microsoft::WRL::Wrappers::HStringReference -#define _StringReferenceObj Microsoft::WRL::Wrappers::HStringReference -#define _DeviceInformationCollection ABI::Windows::Devices::Enumeration::DeviceInformationCollection -#define _MediaCapture ABI::Windows::Media::Capture::IMediaCapture -#define _MediaCaptureVideoPreview ABI::Windows::Media::Capture::IMediaCaptureVideoPreview -#define _MediaCaptureInitializationSettings ABI::Windows::Media::Capture::IMediaCaptureInitializationSettings -#define _VideoDeviceController ABI::Windows::Media::Devices::IVideoDeviceController -#define _MediaDeviceController ABI::Windows::Media::Devices::IMediaDeviceController -#define _MediaEncodingProperties ABI::Windows::Media::MediaProperties::IMediaEncodingProperties -#define _VideoEncodingProperties ABI::Windows::Media::MediaProperties::IVideoEncodingProperties -#define _MediaStreamType ABI::Windows::Media::Capture::MediaStreamType -#define _AsyncInfo ABI::Windows::Foundation::IAsyncInfo -#define _AsyncAction ABI::Windows::Foundation::IAsyncAction -#define _AsyncOperation ABI::Windows::Foundation::IAsyncOperation -#define _DeviceClass ABI::Windows::Devices::Enumeration::DeviceClass -#define _IDeviceInformation ABI::Windows::Devices::Enumeration::IDeviceInformation -#define _DeviceInformation ABI::Windows::Devices::Enumeration::DeviceInformation -#define _DeviceInformationStatics ABI::Windows::Devices::Enumeration::IDeviceInformationStatics -#define _MediaEncodingProfile ABI::Windows::Media::MediaProperties::IMediaEncodingProfile -#define _StreamingCaptureMode ABI::Windows::Media::Capture::StreamingCaptureMode -#define _PropertySet ABI::Windows::Foundation::Collections::IPropertySet -#define _Map ABI::Windows::Foundation::Collections::IMap -#define _PropertyValueStatics ABI::Windows::Foundation::IPropertyValueStatics -#define _VectorView ABI::Windows::Foundation::Collections::IVectorView -#define _StartPreviewToCustomSinkIdAsync StartPreviewToCustomSinkIdAsync -#define _InitializeWithSettingsAsync InitializeWithSettingsAsync -#define _FindAllAsyncDeviceClass FindAllAsyncDeviceClass -#define _MediaExtension ABI::Windows::Media::IMediaExtension -#define BEGIN_CREATE_ASYNC(type, ...) Concurrency_winrt::create_async([__VA_ARGS__]() -> HRESULT { -#define END_CREATE_ASYNC(hr) return hr;\ -}) -#define DEFINE_TASK Concurrency_winrt::task -#define CREATE_TASK Concurrency_winrt::create_task -#define CREATE_OR_CONTINUE_TASK(_task, rettype, func) _task = (_task == Concurrency_winrt::task()) ? Concurrency_winrt::create_task(func) : _task.then([func](rettype, rettype* retVal) -> HRESULT { return func(retVal); }); -#define DEFINE_RET_VAL(x) x* retVal -#define DEFINE_RET_TYPE(x) -#define DEFINE_RET_FORMAL(x) HRESULT -#define RET_VAL(x) *retVal = x;\ -return S_OK; -#define RET_VAL_BASE return S_OK; -#define MAKE_STRING(str) Microsoft::WRL::Wrappers::HStringReference(L##str) -#define GET_STL_STRING(str) std::wstring(str.GetRawBuffer(NULL)) -#define GET_STL_STRING_RAW(str) WindowsGetStringRawBuffer(str, NULL) -#define MAKE_WRL_OBJ(x) Microsoft::WRL::ComPtr -#define MAKE_WRL_REF(x) x* -#define MAKE_OBJ_REF(x) x -#define MAKE_WRL_AGILE_REF(x) x* -#define MAKE_PROPERTY_BACKING(Type, PropName) Type PropName; -#define MAKE_PROPERTY(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { *pVal = PropValue; } else { return E_INVALIDARG; } return S_OK; }\ - STDMETHODIMP put_##PropName(Type Val) { PropValue = Val; return S_OK; } -#define MAKE_PROPERTY_STRING(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { return ::WindowsDuplicateString(PropValue.Get(), pVal); } else { return E_INVALIDARG; } }\ - STDMETHODIMP put_##PropName(Type Val) { return PropValue.Set(Val); } -#define MAKE_READONLY_PROPERTY(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { *pVal = PropValue; } else { return E_INVALIDARG; } return S_OK; } -#define THROW_INVALID_ARG RoOriginateError(E_INVALIDARG, nullptr); -#define RELEASE_AGILE_WRL(x) if (x) { (x)->Release(); x = nullptr; } -#define RELEASE_WRL(x) if (x) { (x)->Release(); x = nullptr; } -#define GET_WRL_OBJ_FROM_REF(objtype, obj, orig, hr) Microsoft::WRL::ComPtr obj;\ -hr = orig->QueryInterface(__uuidof(objtype), &obj); -#define GET_WRL_OBJ_FROM_OBJ(objtype, obj, orig, hr) Microsoft::WRL::ComPtr obj;\ -hr = orig.As(&obj); -#define WRL_ENUM_GET(obj, prefix, prop) obj::prefix##_##prop -#define WRL_PROP_GET(obj, prop, arg, hr) hr = obj->get_##prop(&arg); -#define WRL_PROP_PUT(obj, prop, arg, hr) hr = obj->put_##prop(arg); -#define WRL_METHOD_BASE(obj, method, ret, hr) hr = obj->##method(&ret); -#define WRL_METHOD(obj, method, ret, hr, ...) hr = obj->##method(__VA_ARGS__, &ret); -#define WRL_METHOD_NORET_BASE(obj, method, hr) hr = obj->##method(); -#define REF_WRL_OBJ(obj) obj.GetAddressOf() -#define DEREF_WRL_OBJ(obj) obj.Get() -#define DEREF_AGILE_WRL_OBJ(obj) obj -#define DEREF_AS_NATIVE_WRL_OBJ(type, obj) obj.Get() -#define PREPARE_TRANSFER_WRL_OBJ(obj) obj.Detach() -#define ACTIVATE_LOCAL_OBJ_BASE(objtype) Microsoft::WRL::Make() -#define ACTIVATE_LOCAL_OBJ(objtype, ...) Microsoft::WRL::Make(__VA_ARGS__) -#define ACTIVATE_EVENT_HANDLER(objtype, ...) Microsoft::WRL::Callback(__VA_ARGS__).Get() -#define ACTIVATE_OBJ(rtclass, objtype, obj, hr) MAKE_WRL_OBJ(objtype) obj;\ -{\ - Microsoft::WRL::ComPtr objFactory;\ - hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(rtclass).Get(), objFactory.ReleaseAndGetAddressOf());\ - if (SUCCEEDED(hr)) {\ - Microsoft::WRL::ComPtr pInsp;\ - hr = objFactory->ActivateInstance(pInsp.GetAddressOf());\ - if (SUCCEEDED(hr)) hr = pInsp.As(&obj);\ - }\ -} -#define ACTIVATE_STATIC_OBJ(rtclass, objtype, obj, hr) objtype obj;\ -{\ - Microsoft::WRL::ComPtr objFactory;\ - hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(rtclass).Get(), objFactory.ReleaseAndGetAddressOf());\ - if (SUCCEEDED(hr)) {\ - if (SUCCEEDED(hr)) hr = objFactory.As(&obj);\ - }\ -} -#endif - -#define _ComPtr Microsoft::WRL::ComPtr -#else #define _COM_SMARTPTR_DECLARE(T,var) T ## Ptr var @@ -509,7 +289,6 @@ private: }; #define _ComPtr ComPtr -#endif template class CBaseAttributes : public TBase @@ -860,19 +639,10 @@ protected: }; class StreamSink : -#ifdef WINRT - public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::ClassicCom>, - IMFStreamSink, - IMFMediaEventGenerator, - IMFMediaTypeHandler, - CBaseAttributes<> > -#else public IMFStreamSink, public IMFMediaTypeHandler, public CBaseAttributes<>, public ICustomStreamSink -#endif { public: // IUnknown methods @@ -890,9 +660,6 @@ public: if (riid == IID_IMarshal) { return MarshalQI(riid, ppv); } else { -#ifdef WINRT - hr = RuntimeClassT::QueryInterface(riid, ppv); -#else if (riid == IID_IUnknown || riid == IID_IMFStreamSink) { *ppv = static_cast(this); AddRef(); @@ -910,15 +677,11 @@ public: AddRef(); } else hr = E_NOINTERFACE; -#endif } return hr; } -#ifdef WINRT - STDMETHOD(RuntimeClassInitialize)() { return S_OK; } -#else ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&m_cRef); @@ -932,7 +695,6 @@ public: } return cRef; } -#endif HRESULT MarshalQI(REFIID riid, LPVOID* ppv) { HRESULT hr = S_OK; @@ -967,11 +729,7 @@ public: m_StartTime(0), m_fGetStartTimeFromSample(false), m_fWaitingForFirstSample(false), m_state(State_TypeNotSet), m_pParent(nullptr), m_imageWidthInPixels(0), m_imageHeightInPixels(0) { -#ifdef WINRT - m_token.value = 0; -#else m_bConnected = false; -#endif InitializeCriticalSectionEx(&m_critSec, 3000, 0); ZeroMemory(&m_guiCurrentSubtype, sizeof(m_guiCurrentSubtype)); CBaseAttributes::Initialize(0U); @@ -1646,17 +1404,11 @@ public: return hr; } private: -#ifdef WINRT - EventRegistrationToken m_token; -#else bool m_bConnected; -#endif bool m_IsShutdown; // Flag to indicate if Shutdown() method was called. CRITICAL_SECTION m_critSec; -#ifndef WINRT long m_cRef; -#endif IMFAttributes* m_pParent; _ComPtr m_spCurrentType; _ComPtr m_spEventQueue; // Event queue @@ -2174,37 +1926,11 @@ protected: } }; -/* Be sure to declare webcam device capability in manifest - For better media capture support, add the following snippet with correct module name to the project manifest - (videoio needs DLL activation class factoryentry points): - - - - modulename - - - - */ - extern const __declspec(selectany) WCHAR RuntimeClass_CV_MediaSink[] = L"cv.MediaSink"; class MediaSink : -#ifdef WINRT - public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >, - Microsoft::WRL::Implements, - IMFMediaSink, - IMFClockStateSink, - Microsoft::WRL::FtmBase, - CBaseAttributes<>> -#else public IMFMediaSink, public IMFClockStateSink, public CBaseAttributes<> -#endif { -#ifdef WINRT - InspectableClass(RuntimeClass_CV_MediaSink, BaseTrust) -public: -#else public: ULONG STDMETHODCALLTYPE AddRef() { @@ -2246,7 +1972,6 @@ public: return hr; } -#endif MediaSink() : m_IsShutdown(false), m_llStartTime(0) { CBaseAttributes<>::Initialize(0U); InitializeCriticalSectionEx(&m_critSec, 3000, 0); @@ -2269,308 +1994,6 @@ public: return S_OK; } } -#ifdef WINRT - STDMETHODIMP SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration) - { - HRESULT hr = S_OK; - if (pConfiguration) { - Microsoft::WRL::ComPtr spInsp; - Microsoft::WRL::ComPtr> spSetting; - Microsoft::WRL::ComPtr spPropVal; - Microsoft::WRL::ComPtr pMedEncProps; - UINT32 uiType = ABI::Windows::Media::Capture::MediaStreamType_VideoPreview; - - hr = pConfiguration->QueryInterface(IID_PPV_ARGS(&spSetting)); - if (FAILED(hr)) { - hr = E_FAIL; - } - - if (SUCCEEDED(hr)) { - hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_SAMPLEGRABBERCALLBACK).Get(), spInsp.ReleaseAndGetAddressOf()); - if (FAILED(hr)) { - hr = E_INVALIDARG; - } - if (SUCCEEDED(hr)) { - hr = SetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, spInsp.Get()); - } - } - if (SUCCEEDED(hr)) { - hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_VIDTYPE).Get(), spInsp.ReleaseAndGetAddressOf()); - if (FAILED(hr)) { - hr = E_INVALIDARG; - } - if (SUCCEEDED(hr)) { - if (SUCCEEDED(hr = spInsp.As(&spPropVal))) { - hr = spPropVal->GetUInt32(&uiType); - } - } - } - if (SUCCEEDED(hr)) { - hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_VIDENCPROPS).Get(), spInsp.ReleaseAndGetAddressOf()); - if (FAILED(hr)) { - hr = E_INVALIDARG; - } - if (SUCCEEDED(hr)) { - hr = spInsp.As(&pMedEncProps); - } - } - if (SUCCEEDED(hr)) { - hr = SetMediaStreamProperties((ABI::Windows::Media::Capture::MediaStreamType)uiType, pMedEncProps.Get()); - } - } - - return hr; - } - static DWORD GetStreamId(ABI::Windows::Media::Capture::MediaStreamType mediaStreamType) - { - return 3 - mediaStreamType; - } - static HRESULT AddAttribute(_In_ GUID guidKey, _In_ ABI::Windows::Foundation::IPropertyValue *pValue, _In_ IMFAttributes* pAttr) - { - HRESULT hr = S_OK; - PROPVARIANT var; - ABI::Windows::Foundation::PropertyType type; - hr = pValue->get_Type(&type); - ZeroMemory(&var, sizeof(var)); - - if (SUCCEEDED(hr)) - { - switch (type) - { - case ABI::Windows::Foundation::PropertyType_UInt8Array: - { - UINT32 cbBlob; - BYTE *pbBlog = nullptr; - hr = pValue->GetUInt8Array(&cbBlob, &pbBlog); - if (SUCCEEDED(hr)) - { - if (pbBlog == nullptr) - { - hr = E_INVALIDARG; - } - else - { - hr = pAttr->SetBlob(guidKey, pbBlog, cbBlob); - } - } - CoTaskMemFree(pbBlog); - } - break; - - case ABI::Windows::Foundation::PropertyType_Double: - { - DOUBLE value; - hr = pValue->GetDouble(&value); - if (SUCCEEDED(hr)) - { - hr = pAttr->SetDouble(guidKey, value); - } - } - break; - - case ABI::Windows::Foundation::PropertyType_Guid: - { - GUID value; - hr = pValue->GetGuid(&value); - if (SUCCEEDED(hr)) - { - hr = pAttr->SetGUID(guidKey, value); - } - } - break; - - case ABI::Windows::Foundation::PropertyType_String: - { - Microsoft::WRL::Wrappers::HString value; - hr = pValue->GetString(value.GetAddressOf()); - if (SUCCEEDED(hr)) - { - UINT32 len = 0; - LPCWSTR szValue = WindowsGetStringRawBuffer(value.Get(), &len); - hr = pAttr->SetString(guidKey, szValue); - } - } - break; - - case ABI::Windows::Foundation::PropertyType_UInt32: - { - UINT32 value; - hr = pValue->GetUInt32(&value); - if (SUCCEEDED(hr)) - { - pAttr->SetUINT32(guidKey, value); - } - } - break; - - case ABI::Windows::Foundation::PropertyType_UInt64: - { - UINT64 value; - hr = pValue->GetUInt64(&value); - if (SUCCEEDED(hr)) - { - hr = pAttr->SetUINT64(guidKey, value); - } - } - break; - - case ABI::Windows::Foundation::PropertyType_Inspectable: - { - Microsoft::WRL::ComPtr value; - hr = TYPE_E_TYPEMISMATCH; - if (SUCCEEDED(hr)) - { - pAttr->SetUnknown(guidKey, value.Get()); - } - } - break; - - // ignore unknown values - } - } - - return hr; - } - static HRESULT ConvertPropertiesToMediaType(_In_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties *pMEP, _Outptr_ IMFMediaType **ppMT) - { - HRESULT hr = S_OK; - _ComPtr spMT; - Microsoft::WRL::ComPtr> spMap; - Microsoft::WRL::ComPtr*>> spIterable; - Microsoft::WRL::ComPtr*>> spIterator; - - if (pMEP == nullptr || ppMT == nullptr) - { - return E_INVALIDARG; - } - *ppMT = nullptr; - - hr = pMEP->get_Properties(spMap.GetAddressOf()); - - if (SUCCEEDED(hr)) - { - hr = spMap.As(&spIterable); - } - if (SUCCEEDED(hr)) - { - hr = spIterable->First(&spIterator); - } - if (SUCCEEDED(hr)) - { - MFCreateMediaType(spMT.ReleaseAndGetAddressOf()); - } - - boolean hasCurrent = false; - if (SUCCEEDED(hr)) - { - hr = spIterator->get_HasCurrent(&hasCurrent); - } - - while (hasCurrent) - { - Microsoft::WRL::ComPtr > spKeyValuePair; - Microsoft::WRL::ComPtr spValue; - Microsoft::WRL::ComPtr spPropValue; - GUID guidKey; - - hr = spIterator->get_Current(&spKeyValuePair); - if (FAILED(hr)) - { - break; - } - hr = spKeyValuePair->get_Key(&guidKey); - if (FAILED(hr)) - { - break; - } - hr = spKeyValuePair->get_Value(&spValue); - if (FAILED(hr)) - { - break; - } - hr = spValue.As(&spPropValue); - if (FAILED(hr)) - { - break; - } - hr = AddAttribute(guidKey, spPropValue.Get(), spMT.Get()); - if (FAILED(hr)) - { - break; - } - - hr = spIterator->MoveNext(&hasCurrent); - if (FAILED(hr)) - { - break; - } - } - - - if (SUCCEEDED(hr)) - { - Microsoft::WRL::ComPtr spValue; - Microsoft::WRL::ComPtr spPropValue; - GUID guiMajorType; - - hr = spMap->Lookup(MF_MT_MAJOR_TYPE, spValue.GetAddressOf()); - - if (SUCCEEDED(hr)) - { - hr = spValue.As(&spPropValue); - } - if (SUCCEEDED(hr)) - { - hr = spPropValue->GetGuid(&guiMajorType); - } - if (SUCCEEDED(hr)) - { - if (guiMajorType != MFMediaType_Video && guiMajorType != MFMediaType_Audio) - { - hr = E_UNEXPECTED; - } - } - } - - if (SUCCEEDED(hr)) - { - *ppMT = spMT.Detach(); - } - - return hr; - } - //this should be passed through SetProperties! - HRESULT SetMediaStreamProperties(ABI::Windows::Media::Capture::MediaStreamType MediaStreamType, - _In_opt_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties *mediaEncodingProperties) - { - HRESULT hr = S_OK; - _ComPtr spMediaType; - - if (MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_VideoPreview && - MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_VideoRecord && - MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_Audio) - { - return E_INVALIDARG; - } - - RemoveStreamSink(GetStreamId(MediaStreamType)); - - if (mediaEncodingProperties != nullptr) - { - _ComPtr spStreamSink; - hr = ConvertPropertiesToMediaType(mediaEncodingProperties, &spMediaType); - if (SUCCEEDED(hr)) - { - hr = AddStreamSink(GetStreamId(MediaStreamType), nullptr, spStreamSink.GetAddressOf()); - } - if (SUCCEEDED(hr)) { - hr = SetUnknown(MF_MEDIASINK_PREFERREDTYPE, spMediaType.Detach()); - } - } - - return hr; - } -#endif //IMFMediaSink HRESULT STDMETHODCALLTYPE GetCharacteristics( /* [out] */ __RPC__out DWORD *pdwCharacteristics) { @@ -2609,14 +2032,6 @@ public: if (SUCCEEDED(hr)) { -#ifdef WINRT - pStream = Microsoft::WRL::Make(); - if (pStream == nullptr) { - hr = E_OUTOFMEMORY; - } - if (SUCCEEDED(hr)) - hr = pStream.As(&spMFStream); -#else StreamSink* pSink = new StreamSink(); if (pSink) { hr = pSink->QueryInterface(IID_IMFStreamSink, (void**)spMFStream.GetAddressOf()); @@ -2625,7 +2040,6 @@ public: } if (FAILED(hr)) delete pSink; } -#endif } // Initialize the stream. @@ -2721,12 +2135,7 @@ public: { hr = m_streams.Remove(pos, nullptr); _ComPtr spCustomSink; -#ifdef WINRT - spCustomSink = static_cast(spStream.Get()); - hr = S_OK; -#else hr = spStream.As(&spCustomSink); -#endif if (SUCCEEDED(hr)) hr = spCustomSink->Shutdown(); } @@ -2945,12 +2354,8 @@ public: { _ComPtr spCustomSink; HRESULT hr; -#ifdef WINRT - spCustomSink = static_cast(pStream); -#else hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); if (FAILED(hr)) return hr; -#endif hr = spCustomSink->Shutdown(); return hr; } @@ -2968,12 +2373,8 @@ public: { _ComPtr spCustomSink; HRESULT hr; -#ifdef WINRT - spCustomSink = static_cast(pStream); -#else hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); if (FAILED(hr)) return hr; -#endif hr = spCustomSink->Start(_llStartTime); return hr; } @@ -2988,12 +2389,8 @@ public: { _ComPtr spCustomSink; HRESULT hr; -#ifdef WINRT - spCustomSink = static_cast(pStream); -#else hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); if (FAILED(hr)) return hr; -#endif hr = spCustomSink->Stop(); return hr; } @@ -3098,16 +2495,10 @@ public: return hr; } private: -#ifndef WINRT long m_cRef; -#endif CRITICAL_SECTION m_critSec; bool m_IsShutdown; ComPtrList m_streams; _ComPtr m_spClock; LONGLONG m_llStartTime; }; - -#ifdef WINRT -ActivatableClass(MediaSink); -#endif From 44848d3241fa9c2e15311f92149761673effcb5c Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Thu, 12 Apr 2018 15:26:18 +0300 Subject: [PATCH 11/36] MSMF-based CameraCapture reworked to use SourceReader --- modules/videoio/src/cap_msmf.cpp | 1393 ++++++++---------------------- 1 file changed, 379 insertions(+), 1014 deletions(-) diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp index eaca0e2cd9..393aa93b6c 100644 --- a/modules/videoio/src/cap_msmf.cpp +++ b/modules/videoio/src/cap_msmf.cpp @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -106,19 +107,33 @@ template void SafeRelease(T **ppT) } #ifdef _DEBUG -/// Class for printing info into console -class DPO +void DPOprintOut(const wchar_t *format, ...) { -public: - ~DPO(void); - static DPO& getInstance(); - void printOut(const wchar_t *format, ...); - void setVerbose(bool state); - bool verbose; -private: - DPO(void); -}; -#define DebugPrintOut(...) DPO::getInstance().printOut(__VA_ARGS__) + int i = 0; + wchar_t *p = NULL; + va_list args; + va_start(args, format); + if (::IsDebuggerPresent()) + { + WCHAR szMsg[512]; + ::StringCchVPrintfW(szMsg, sizeof(szMsg) / sizeof(szMsg[0]), format, args); + ::OutputDebugStringW(szMsg); + } + else + { + if (wcscmp(format, L"%i")) + { + i = va_arg(args, int); + } + if (wcscmp(format, L"%s")) + { + p = va_arg(args, wchar_t *); + } + wprintf(format, i, p); + } + va_end(args); +} +#define DebugPrintOut(...) DPOprintOut(__VA_ARGS__) #else #define DebugPrintOut(...) void() #endif @@ -334,7 +349,6 @@ public: void setParametrs(CamParametrs parametrs); void setEmergencyStopEvent(void *userData, void(*func)(int, void *)); long readInfoOfDevice(IMFActivate *pActivate, unsigned int Num); - wchar_t *getName(); int getCountFormats(); unsigned int getWidth(); unsigned int getHeight(); @@ -357,7 +371,6 @@ private: } vd_LockOut; wchar_t *vd_pFriendlyName; ImageGrabberThread *vd_pImGrTh; - CamParametrs vd_PrevParametrs; unsigned int vd_Width; unsigned int vd_Height; unsigned int vd_FrameRate; @@ -372,8 +385,7 @@ private: long setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex); void buildLibraryofTypes(); int findType(unsigned int size, unsigned int frameRate = 0); - long resetDevice(IMFActivate *pActivate); - long checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice); + long checkDevice(IMFActivate **pDevice); long initDevice(); }; @@ -382,14 +394,8 @@ class videoDevices { public: ~videoDevices(void); - long initDevices(IMFAttributes *pAttributes); - static videoDevices& getInstance(); - videoDevice *getDevice(unsigned int i); - unsigned int getCount(); - void clearDevices(); + static cv::Ptr getDevice(unsigned int i, bool fallback = false); private: - UINT32 count; - std::vector vds_Devices; videoDevices(void); }; @@ -407,118 +413,6 @@ private: Media_Foundation(void) { CV_Assert(SUCCEEDED(MFStartup(MF_VERSION))); } }; -/// The only visiable class for controlling of video devices in format singelton -class videoInput -{ -public: - virtual ~videoInput(void); - // Getting of static instance of videoInput class - static videoInput& getInstance(); - // Closing video device with deviceID - void closeDevice(int deviceID); - // Setting callback function for emergency events(for example: removing video device with deviceID) with userData - void setEmergencyStopEvent(int deviceID, void *userData, void(*func)(int, void *)); - // Closing all devices - void closeAllDevices(); - // Getting of parametrs of video device with deviceID - CamParametrs getParametrs(int deviceID); - // Setting of parametrs of video device with deviceID - void setParametrs(int deviceID, CamParametrs parametrs); - // Getting numbers of existence videodevices with listing in consol - unsigned int listDevices(bool silent = false); - // Getting numbers of formats, which are supported by videodevice with deviceID - unsigned int getCountFormats(int deviceID) const; - // Getting width of image, which is getting from videodevice with deviceID - unsigned int getWidth(int deviceID) const; - // Getting height of image, which is getting from videodevice with deviceID - unsigned int getHeight(int deviceID) const; - // Getting frame rate, which is getting from videodevice with deviceID - unsigned int getFrameRate(int deviceID) const; - // Getting name of videodevice with deviceID - const wchar_t *getNameVideoDevice(int deviceID); - // Getting interface MediaSource for Media Foundation from videodevice with deviceID - IMFMediaSource *getMediaSource(int deviceID); - // Getting format with id, which is supported by videodevice with deviceID - MediaType getFormat(int deviceID, int unsigned id); - // Checking of existence of the suitable video devices - bool isDevicesAcceable(); - // Checking of using the videodevice with deviceID - bool isDeviceSetup(int deviceID); - // Checking of using MediaSource from videodevice with deviceID - bool isDeviceMediaSource(int deviceID); - // Checking of using Raw Data of pixels from videodevice with deviceID - bool isDeviceRawDataSource(int deviceID); -#ifdef _DEBUG - // Setting of the state of outprinting info in console - static void setVerbose(bool state); -#endif - // Initialization of video device with deviceID by media type with id - bool setupDevice(int deviceID, unsigned int id = 0); - // Initialization of video device with deviceID by wisth w, height h and fps idealFramerate - bool setupDevice(int deviceID, unsigned int w, unsigned int h, unsigned int idealFramerate = 30); - // Checking of recivig of new frame from video device with deviceID - bool isFrameNew(int deviceID); - // Writing of Raw Data pixels from video device with deviceID with correction of RedAndBlue flipping flipRedAndBlue and vertical flipping flipImage - bool getPixels(int deviceID, unsigned char * pixels, bool flipRedAndBlue = false, bool flipImage = false); - static void processPixels(unsigned char * src, unsigned char * dst, unsigned int width, unsigned int height, unsigned int bpp, bool bRGB, bool bFlip); -private: - Media_Foundation& MF; - bool accessToDevices; - videoInput(void); - void updateListOfDevices(); -}; - -#ifdef _DEBUG -DPO::DPO(void):verbose(true) -{ -} - -DPO::~DPO(void) -{ -} - -DPO& DPO::getInstance() -{ - static DPO instance; - return instance; -} - -void DPO::printOut(const wchar_t *format, ...) -{ - if(verbose) - { - int i = 0; - wchar_t *p = NULL; - va_list args; - va_start(args, format); - if( ::IsDebuggerPresent() ) - { - WCHAR szMsg[512]; - ::StringCchVPrintfW(szMsg, sizeof(szMsg)/sizeof(szMsg[0]), format, args); - ::OutputDebugStringW(szMsg); - } - else - { - if(wcscmp(format, L"%i")) - { - i = va_arg (args, int); - } - if(wcscmp(format, L"%s")) - { - p = va_arg (args, wchar_t *); - } - wprintf(format, i,p); - } - va_end (args); - } -} - -void DPO::setVerbose(bool state) -{ - verbose = state; -} -#endif - LPCWSTR GetGUIDNameConstNew(const GUID& guid); HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz); HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index); @@ -1558,6 +1452,7 @@ void videoDevice::setParametrs(CamParametrs parametrs) { if(vd_pSource) { + CamParametrs vd_PrevParametrs = getParametrs(); Parametr *pParametr = (Parametr *)(¶metrs); Parametr *pPrevParametr = (Parametr *)(&vd_PrevParametrs); IAMVideoProcAmp *pProcAmp = NULL; @@ -1632,141 +1527,25 @@ CamParametrs videoDevice::getParametrs() return out; } -long videoDevice::resetDevice(IMFActivate *pActivate) -{ - HRESULT hr = E_FAIL; - vd_CurrentFormats.clear(); - if(vd_pFriendlyName) - CoTaskMemFree(vd_pFriendlyName); - vd_pFriendlyName = NULL; - if(pActivate) - { - IMFMediaSource *pSource = NULL; - hr = pActivate->GetAllocatedString( - MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, - &vd_pFriendlyName, - NULL - ); - if (SUCCEEDED(hr)) - hr = pActivate->ActivateObject( - __uuidof(IMFMediaSource), - (void**)&pSource - ); - if (SUCCEEDED(hr) && pSource) - { - enumerateCaptureFormats(pSource); - buildLibraryofTypes(); - SafeRelease(&pSource); - }//end if (SUCCEEDED(hr) && pSource) - if(FAILED(hr)) - { - vd_pFriendlyName = NULL; - DebugPrintOut(L"VIDEODEVICE %i: IMFMediaSource interface cannot be created \n", vd_CurrentNumber); - } - } - return hr; -} - long videoDevice::readInfoOfDevice(IMFActivate *pActivate, unsigned int Num) { vd_CurrentNumber = Num; - return resetDevice(pActivate); -} - -long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice) -{ - IMFActivate **ppDevices = NULL; - UINT32 count; - wchar_t *newFriendlyName = NULL; - HRESULT hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count); - if (SUCCEEDED(hr)) + HRESULT hr = E_FAIL; + vd_CurrentFormats.clear(); + if (pActivate) { - if(count > 0) + SafeRelease(&vd_pSource); + hr = pActivate->ActivateObject( + __uuidof(IMFMediaSource), + (void**)&vd_pSource + ); + if (SUCCEEDED(hr) && vd_pSource) { - if(count > vd_CurrentNumber) - { - hr = ppDevices[vd_CurrentNumber]->GetAllocatedString( - MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, - &newFriendlyName, - NULL - ); - if (SUCCEEDED(hr)) - { - if(wcscmp(newFriendlyName, vd_pFriendlyName) != 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Chosen device cannot be found \n", vd_CurrentNumber); - hr = E_INVALIDARG; - pDevice = NULL; - } - else - { - *pDevice = ppDevices[vd_CurrentNumber]; - (*pDevice)->AddRef(); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: Name of device cannot be gotten \n", vd_CurrentNumber); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: Number of devices more than corrent number of the device \n", vd_CurrentNumber); - hr = E_INVALIDARG; - } - for(UINT32 i = 0; i < count; i++) - { - SafeRelease(&ppDevices[i]); - } - SafeRelease(ppDevices); - } + enumerateCaptureFormats(vd_pSource); + buildLibraryofTypes(); + }//end if (SUCCEEDED(hr) && pSource) else - hr = E_FAIL; - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: List of DeviceSources cannot be enumerated \n", vd_CurrentNumber); - } - return hr; -} - -long videoDevice::initDevice() -{ - HRESULT hr = S_OK; - CoInitialize(NULL); - _ComPtr pAttributes = NULL; - IMFActivate *vd_pActivate = NULL; - hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1); - if (SUCCEEDED(hr)) - { - hr = pAttributes->SetGUID( - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID - ); - } - if (SUCCEEDED(hr)) - { - hr = checkDevice(pAttributes.Get(), &vd_pActivate); - if (SUCCEEDED(hr) && vd_pActivate) - { - SafeRelease(&vd_pSource); - hr = vd_pActivate->ActivateObject( - __uuidof(IMFMediaSource), - (void**)&vd_pSource - ); - if (SUCCEEDED(hr)) - { - } - SafeRelease(&vd_pActivate); - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: Device there is not \n", vd_CurrentNumber); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: The attribute of video cameras cannot be getting \n", vd_CurrentNumber); + DebugPrintOut(L"VIDEODEVICE %i: IMFMediaSource interface cannot be created \n", vd_CurrentNumber); } return hr; } @@ -1906,7 +1685,7 @@ void videoDevice::buildLibraryofTypes() for(; i != vd_CurrentFormats.end(); i++) { // Count only supported video formats. - if( (*i).MF_MT_SUBTYPE == MFVideoFormat_RGB24 ) + if( (*i).MF_MT_SUBTYPE == MFVideoFormat_RGB24 || (*i).MF_MT_SUBTYPE == MFVideoFormat_NV12 ) { size = (*i).MF_MT_FRAME_SIZE; framerate = (*i).MF_MT_FRAME_RATE_NUMERATOR / (*i).MF_MT_FRAME_RATE_DENOMINATOR; @@ -2015,25 +1794,16 @@ bool videoDevice::setupDevice(unsigned int id) { if(!vd_IsSetuped) { - HRESULT hr = initDevice(); - if(SUCCEEDED(hr)) - { - vd_Width = vd_CurrentFormats[id].width; - vd_Height = vd_CurrentFormats[id].height; - vd_FrameRate = vd_CurrentFormats[id].MF_MT_FRAME_RATE_NUMERATOR / - vd_CurrentFormats[id].MF_MT_FRAME_RATE_DENOMINATOR; - hr = setDeviceFormat(vd_pSource, (DWORD) id); - vd_IsSetuped = (SUCCEEDED(hr)); - if(vd_IsSetuped) - DebugPrintOut(L"\n\nVIDEODEVICE %i: Device is setuped \n", vd_CurrentNumber); - vd_PrevParametrs = getParametrs(); - return vd_IsSetuped; - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: Interface IMFMediaSource cannot be got \n", vd_CurrentNumber); - return false; - } + HRESULT hr; + vd_Width = vd_CurrentFormats[id].width; + vd_Height = vd_CurrentFormats[id].height; + vd_FrameRate = vd_CurrentFormats[id].MF_MT_FRAME_RATE_NUMERATOR / + vd_CurrentFormats[id].MF_MT_FRAME_RATE_DENOMINATOR; + hr = setDeviceFormat(vd_pSource, (DWORD) id); + vd_IsSetuped = (SUCCEEDED(hr)); + if(vd_IsSetuped) + DebugPrintOut(L"\n\nVIDEODEVICE %i: Device is setuped \n", vd_CurrentNumber); + return vd_IsSetuped; } else { @@ -2051,11 +1821,6 @@ bool videoDevice::setupDevice(unsigned int w, unsigned int h, unsigned int ideal return setupDevice(id); } -wchar_t *videoDevice::getName() -{ - return vd_pFriendlyName; -} - videoDevice::~videoDevice(void) { closeDevice(); @@ -2116,73 +1881,60 @@ done: return hr; } -videoDevices::videoDevices(void): count(0) +videoDevices::videoDevices(void) { -} - -void videoDevices::clearDevices() -{ - std::vector::iterator i = vds_Devices.begin(); - for(; i != vds_Devices.end(); ++i) - delete (*i); - vds_Devices.clear(); + DebugPrintOut(L"\n***** VIDEOINPUT LIBRARY - 2013 (Author: Evgeny Pereguda) *****\n\n"); } videoDevices::~videoDevices(void) { - clearDevices(); + DebugPrintOut(L"\n***** CLOSE VIDEOINPUT LIBRARY - 2013 *****\n\n"); } -videoDevice * videoDevices::getDevice(unsigned int i) -{ - if(i >= vds_Devices.size()) - { - return NULL; - } - if(i < 0) - { - return NULL; - } - return vds_Devices[i]; -} - -long videoDevices::initDevices(IMFAttributes *pAttributes) -{ - clearDevices(); - IMFActivate **ppDevices = NULL; - HRESULT hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count); - if (SUCCEEDED(hr)) - { - if(count > 0) - { - for(UINT32 i = 0; i < count; i++) - { - videoDevice *vd = new videoDevice; - vd->readInfoOfDevice(ppDevices[i], i); - vds_Devices.push_back(vd); - SafeRelease(&ppDevices[i]); - } - SafeRelease(ppDevices); - } - else - hr = E_INVALIDARG; - } - else - { - DebugPrintOut(L"VIDEODEVICES: The instances of the videoDevice class cannot be created\n"); - } - return hr; -} - -unsigned int videoDevices::getCount() -{ - return (unsigned int)vds_Devices.size(); -} - -videoDevices& videoDevices::getInstance() +cv::Ptr videoDevices::getDevice(unsigned int i, bool fallback) { static videoDevices instance; - return instance; + + cv::Ptr res; + + _ComPtr pAttributes = NULL; + if (SUCCEEDED(MFCreateAttributes(pAttributes.GetAddressOf(), 1)) && + SUCCEEDED(pAttributes->SetGUID( + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID + ))) + { + IMFActivate **ppDevices = NULL; + UINT32 count; + if (SUCCEEDED(MFEnumDeviceSources(pAttributes.Get(), &ppDevices, &count))) + { + if (count > 0) + { + if (fallback) + i = std::min(std::max(0U, i), count - 1); + + for (UINT32 ind = 0; ind < count; ind++) + { + if (ind == i) + { + res = cv::Ptr(new videoDevice); + res->readInfoOfDevice(ppDevices[ind], ind); + res->setupDevice(0, 0, 0); + if (!res->isDeviceSetup() || !res->isFrameNew()) + res.release(); + } + SafeRelease(&ppDevices[ind]); + } + } + } + else + DebugPrintOut(L"VIDEODEVICES: The instances of the videoDevice class cannot be created\n"); + CoTaskMemFree(ppDevices); + } + + if (res.empty()) + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", i); + return res; } Parametr::Parametr() @@ -2236,581 +1988,6 @@ void MediaType::Clear() memset(&MF_MT_SUBTYPE, 0, sizeof(GUID)); } -videoInput::videoInput(void): MF(Media_Foundation::getInstance()), accessToDevices(false) -{ - DebugPrintOut(L"\n***** VIDEOINPUT LIBRARY - 2013 (Author: Evgeny Pereguda) *****\n\n"); - updateListOfDevices(); - if(!accessToDevices) - DebugPrintOut(L"INITIALIZATION: There is not any suitable video device\n"); -} - -void videoInput::updateListOfDevices() -{ - HRESULT hr = S_OK; - _ComPtr pAttributes = NULL; - CoInitialize(NULL); - hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1); - if (SUCCEEDED(hr)) - { - hr = pAttributes->SetGUID( - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID - ); - } - if (SUCCEEDED(hr)) - { - videoDevices *vDs = &videoDevices::getInstance(); - hr = vDs->initDevices(pAttributes.Get()); - } - if (FAILED(hr)) - { - DebugPrintOut(L"MEDIA FOUNDATION: The access to the video cameras denied\n"); - } - - accessToDevices = (SUCCEEDED(hr)); - - if(!accessToDevices) - DebugPrintOut(L"UPDATING: There is not any suitable video device\n"); -} - -videoInput::~videoInput(void) -{ - DebugPrintOut(L"\n***** CLOSE VIDEOINPUT LIBRARY - 2013 *****\n\n"); -} - -IMFMediaSource *videoInput::getMediaSource(int deviceID) -{ - if(accessToDevices) - { - videoDevice * VD = videoDevices::getInstance().getDevice(deviceID); - if(VD) - { - IMFMediaSource *out = VD->getMediaSource(); - if(!out) - DebugPrintOut(L"VideoDevice %i: There is not any suitable IMFMediaSource interface\n", deviceID); - return out; - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return NULL; -} - -bool videoInput::setupDevice(int deviceID, unsigned int id) -{ - if (deviceID < 0 ) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - { - bool out = VD->setupDevice(id); - if(!out) - DebugPrintOut(L"VIDEODEVICE %i: This device cannot be started\n", deviceID); - return out; - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return false; -} - -bool videoInput::setupDevice(int deviceID, unsigned int w, unsigned int h, unsigned int idealFramerate) -{ - if (deviceID < 0 ) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - { - bool out = VD->setupDevice(w, h, idealFramerate); - if(!out) - DebugPrintOut(L"VIDEODEVICE %i: this device cannot be started\n", deviceID); - return out; - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n", deviceID); - } - return false; -} - -MediaType videoInput::getFormat(int deviceID, unsigned int id) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return MediaType(); - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->getFormat(id); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return MediaType(); -} - -bool videoInput::isDeviceSetup(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->isDeviceSetup(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return false; -} - -bool videoInput::isDeviceMediaSource(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->isDeviceMediaSource(); - } - else - { - DebugPrintOut(L"Device(s): There is not any suitable video device\n"); - } - return false; -} - -bool videoInput::isDeviceRawDataSource(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - { - bool isRaw = VD->isDeviceRawDataSource(); - return isRaw; - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return false; -} - -bool videoInput::isFrameNew(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - if(!isDeviceSetup(deviceID)) - { - if(isDeviceMediaSource(deviceID)) - return false; - } - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - { - return VD->isFrameNew(); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return false; -} - -unsigned int videoInput::getCountFormats(int deviceID) const -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return 0; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->getCountFormats(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return 0; -} - -void videoInput::closeAllDevices() -{ - videoDevices *VDS = &videoDevices::getInstance(); - for(unsigned int i = 0; i < VDS->getCount(); i++) - closeDevice(i); -} - -void videoInput::setParametrs(int deviceID, CamParametrs parametrs) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice *VD = VDS->getDevice(deviceID); - if(VD) - VD->setParametrs(parametrs); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } -} - -CamParametrs videoInput::getParametrs(int deviceID) -{ - CamParametrs out; - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return out; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice *VD = VDS->getDevice(deviceID); - if(VD) - out = VD->getParametrs(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return out; -} - -void videoInput::closeDevice(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice *VD = VDS->getDevice(deviceID); - if(VD) - VD->closeDevice(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } -} - -unsigned int videoInput::getWidth(int deviceID) const -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return 0; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->getWidth(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return 0; -} - -unsigned int videoInput::getHeight(int deviceID) const -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return 0; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->getHeight(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return 0; -} - -unsigned int videoInput::getFrameRate(int deviceID) const -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return 0; - } - if(accessToDevices) - { - videoDevice * VD = videoDevices::getInstance().getDevice(deviceID); - if(VD) - return VD->getFrameRate(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return 0; -} - -const wchar_t *videoInput::getNameVideoDevice(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return NULL; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->getName(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return L"Empty"; -} - -unsigned int videoInput::listDevices(bool silent) -{ - int out = 0; - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - out = VDS->getCount(); - if(!silent) DebugPrintOut(L"\nVIDEOINPUT SPY MODE!\n\n"); - if(!silent) DebugPrintOut(L"SETUP: Looking For Capture Devices\n"); - for(int i = 0; i < out; i++) - { - if(!silent) DebugPrintOut(L"SETUP: %i) %s \n",i, getNameVideoDevice(i)); - } - if(!silent) DebugPrintOut(L"SETUP: %i Device(s) found\n\n", out); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return out; -} - -videoInput& videoInput::getInstance() -{ - static videoInput instance; - return instance; -} - -bool videoInput::isDevicesAcceable() -{ - return accessToDevices; -} - -#ifdef _DEBUG -void videoInput::setVerbose(bool state) -{ - DPO *dpo = &DPO::getInstance(); - dpo->setVerbose(state); -} -#endif - -void videoInput::setEmergencyStopEvent(int deviceID, void *userData, void(*func)(int, void *)) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return; - } - if(accessToDevices) - { - if(func) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - VD->setEmergencyStopEvent(userData, func); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } -} - -bool videoInput::getPixels(int deviceID, unsigned char * dstBuffer, bool flipRedAndBlue, bool flipImage) -{ - bool success = false; - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return success; - } - if(accessToDevices) - { - bool isRaw = isDeviceRawDataSource(deviceID); - if(isRaw) - { - videoDevice *VD = videoDevices::getInstance().getDevice(deviceID); - RawImage *RIOut = VD->getRawImageOut(); - if(RIOut) - { - const unsigned int bytes = 3; - const unsigned int height = VD->getHeight(); - const unsigned int width = VD->getWidth(); - const unsigned int size = bytes * width * height; - if(size == RIOut->getSize()) - { - processPixels(RIOut->getpPixels(), dstBuffer, width, height, bytes, flipRedAndBlue, flipImage); - success = true; - } - else - { - DebugPrintOut(L"ERROR: GetPixels() - bufferSizes do not match!\n"); - } - } - else - { - DebugPrintOut(L"ERROR: GetPixels() - Unable to grab frame for device %i\n", deviceID); - } - } - else - { - DebugPrintOut(L"ERROR: GetPixels() - Not raw data source device %i\n", deviceID); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return success; -} - -void videoInput::processPixels(unsigned char * src, unsigned char * dst, unsigned int width, - unsigned int height, unsigned int bpp, bool bRGB, bool bFlip) -{ - unsigned int widthInBytes = width * bpp; - unsigned int numBytes = widthInBytes * height; - int *dstInt, *srcInt; - if(!bRGB) - { - if(bFlip) - { - for(unsigned int y = 0; y < height; y++) - { - dstInt = (int *)(dst + (y * widthInBytes)); - srcInt = (int *)(src + ( (height -y -1) * widthInBytes)); - memcpy(dstInt, srcInt, widthInBytes); - } - } - else - { - memcpy(dst, src, numBytes); - } - } - else - { - if(bFlip) - { - unsigned int x = 0; - unsigned int y = (height - 1) * widthInBytes; - src += y; - for(unsigned int i = 0; i < numBytes; i+=3) - { - if(x >= width) - { - x = 0; - src -= widthInBytes*2; - } - *dst = *(src+2); - dst++; - *dst = *(src+1); - dst++; - *dst = *src; - dst++; - src+=3; - x++; - } - } - else - { - for(unsigned int i = 0; i < numBytes; i+=3) - { - *dst = *(src+2); - dst++; - *dst = *(src+1); - dst++; - *dst = *src; - dst++; - src+=3; - } - } - } -} } /******* Capturing video from camera via Microsoft Media Foundation **********/ @@ -2827,28 +2004,23 @@ public: virtual IplImage* retrieveFrame(int) CV_OVERRIDE; virtual int getCaptureDomain() CV_OVERRIDE { return CV_CAP_MSMF; } // Return the type of the capture object: CV_CAP_VFW, etc... protected: - void init(); - int index, width, height, fourcc; + double getFramerate(MediaType MT) const; + bool configureOutput(unsigned int width, unsigned int height, unsigned int prefFramerate); + Media_Foundation& MF; + _ComPtr videoFileSource; + DWORD dwStreamIndex; + MediaType captureFormat; + _ComPtr videoSample; IplImage* frame; - videoInput VI; + bool isOpened; }; -#ifdef _DEBUG -struct SuppressVideoInputMessages -{ - SuppressVideoInputMessages() { videoInput::setVerbose(true); } -}; - -static SuppressVideoInputMessages do_it; -#endif - CvCaptureCAM_MSMF::CvCaptureCAM_MSMF(): - index(-1), - width(-1), - height(-1), - fourcc(-1), + MF(Media_Foundation::getInstance()), + videoFileSource(NULL), + videoSample(NULL), frame(NULL), - VI(videoInput::getInstance()) + isOpened(false) { CoInitialize(0); } @@ -2861,108 +2033,302 @@ CvCaptureCAM_MSMF::~CvCaptureCAM_MSMF() void CvCaptureCAM_MSMF::close() { - if( index >= 0 ) + if (isOpened) { - VI.closeDevice(index); - index = -1; - cvReleaseImage(&frame); + isOpened = false; + if (videoSample) + videoSample.Reset(); + if (videoFileSource) + videoFileSource.Reset(); + if (frame) + cvReleaseImage(&frame); } - width = height = -1; +} + +bool CvCaptureCAM_MSMF::configureOutput(unsigned int width, unsigned int height, unsigned int prefFramerate) +{ + HRESULT hr = S_OK; + int dwStreamFallback = -1; + MediaType MTFallback; + int dwStreamBest = -1; + MediaType MTBest; + + DWORD dwMediaTypeTest = 0; + DWORD dwStreamTest = 0; + while (SUCCEEDED(hr)) + { + _ComPtr pType; + hr = videoFileSource->GetNativeMediaType(dwStreamTest, dwMediaTypeTest, &pType); + if (hr == MF_E_NO_MORE_TYPES) + { + hr = S_OK; + ++dwStreamTest; + dwMediaTypeTest = 0; + } + else if (SUCCEEDED(hr)) + { + MediaType MT = FormatReader::Read(pType.Get()); + if (MT.MF_MT_MAJOR_TYPE == MFMediaType_Video) + { + if (dwStreamFallback < 0 || + ((MT.width * MT.height) > (MTFallback.width * MTFallback.height)) || + (((MT.width * MT.height) == (MTFallback.width * MTFallback.height)) && getFramerate(MT) > getFramerate(MTFallback) && (prefFramerate == 0 || getFramerate(MT) <= prefFramerate))) + { + dwStreamFallback = (int)dwStreamTest; + MTFallback = MT; + } + if (MT.width == width && MT.height == height) + { + if (dwStreamBest < 0 || + (getFramerate(MT) > getFramerate(MTBest) && (prefFramerate == 0 || getFramerate(MT) <= prefFramerate))) + { + dwStreamBest = (int)dwStreamTest; + MTBest = MT; + } + } + } + ++dwMediaTypeTest; + } + } + if (dwStreamBest >= 0 || dwStreamFallback >= 0) + { + // Retrieved stream media type + DWORD tryStream = (DWORD)(dwStreamBest >= 0 ? dwStreamBest : dwStreamFallback); + MediaType tryMT = dwStreamBest >= 0 ? MTBest : MTFallback; + _ComPtr mediaTypeOut; + if (// Set the output media type. + SUCCEEDED(MFCreateMediaType(&mediaTypeOut)) && + SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)) && + SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24)) && + SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive)) && + SUCCEEDED(MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1)) && + SUCCEEDED(MFSetAttributeSize(mediaTypeOut.Get(), MF_MT_FRAME_SIZE, tryMT.width, tryMT.height)) && + SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_DEFAULT_STRIDE, 3 * tryMT.width)))//Assume BGR24 input + { + if (SUCCEEDED(videoFileSource->SetStreamSelection((DWORD)MF_SOURCE_READER_ALL_STREAMS, false)) && + SUCCEEDED(videoFileSource->SetStreamSelection(tryStream, true)) && + SUCCEEDED(videoFileSource->SetCurrentMediaType(tryStream, NULL, mediaTypeOut.Get())) + ) + { + dwStreamIndex = tryStream; + captureFormat = tryMT; + return true; + } + else + close(); + } + } + return false; } // Initialize camera input -bool CvCaptureCAM_MSMF::open( int _index ) +bool CvCaptureCAM_MSMF::open(int _index) { - int try_index = _index; - int devices = 0; close(); - devices = VI.listDevices(true); - if (devices == 0) - return false; - try_index = try_index < 0 ? 0 : (try_index > devices-1 ? devices-1 : try_index); - VI.setupDevice(try_index, 0, 0, 0); // With maximum frame size. - if( !VI.isFrameNew(try_index) ) - return false; - index = try_index; - return true; -} + _ComPtr msAttr = NULL; + if (SUCCEEDED(MFCreateAttributes(msAttr.GetAddressOf(), 1)) && + SUCCEEDED(msAttr->SetGUID( + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID + ))) + { + IMFActivate **ppDevices = NULL; + UINT32 count; + if (SUCCEEDED(MFEnumDeviceSources(msAttr.Get(), &ppDevices, &count))) + { + if (count > 0) + { + _index = std::min(std::max(0, _index), (int)count - 1); + for (int ind = 0; ind < (int)count; ind++) + { + if (ind == _index && ppDevices[ind]) + { + // Set source reader parameters + _ComPtr mSrc; + _ComPtr srAttr; + if (SUCCEEDED(ppDevices[ind]->ActivateObject(__uuidof(IMFMediaSource), (void**)&mSrc)) && mSrc && + SUCCEEDED(MFCreateAttributes(&srAttr, 10)) && + SUCCEEDED(srAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, false)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, false)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true)) && + //ToDo: Enable D3D MF_SOURCE_READER_D3D_MANAGER attribute + SUCCEEDED(MFCreateSourceReaderFromMediaSource(mSrc.Get(), srAttr.Get(), &videoFileSource))) + { + isOpened = true; + configureOutput(0, 0, 0); + } + } + SafeRelease(&ppDevices[ind]); + } + } + } + CoTaskMemFree(ppDevices); + } + + return isOpened; +} bool CvCaptureCAM_MSMF::grabFrame() { - while (VI.isDeviceSetup(index) && !VI.isFrameNew(index)) - Sleep(1); - return VI.isDeviceSetup(index); + if (isOpened) + { + DWORD streamIndex, flags; + LONGLONG llTimeStamp; + if (videoSample) + videoSample.Reset(); + HRESULT hr; + while(SUCCEEDED(hr = videoFileSource->ReadSample( + dwStreamIndex, // Stream index. + 0, // Flags. + &streamIndex, // Receives the actual stream index. + &flags, // Receives status flags. + &llTimeStamp, // Receives the time stamp. + &videoSample // Receives the sample or NULL. + )) && + streamIndex == dwStreamIndex && !(flags & (MF_SOURCE_READERF_ERROR|MF_SOURCE_READERF_ALLEFFECTSREMOVED|MF_SOURCE_READERF_ENDOFSTREAM)) && + !videoSample + ) + { + if (flags & MF_SOURCE_READERF_STREAMTICK) + { + DebugPrintOut(L"\tStream tick detected. Retrying to grab the frame\n"); + } + } + + if (SUCCEEDED(hr)) + { + if (streamIndex != dwStreamIndex) + { + DebugPrintOut(L"\tWrong stream readed. Abort capturing\n"); + close(); + } + else if (flags & MF_SOURCE_READERF_ERROR) + { + DebugPrintOut(L"\tStream reading error. Abort capturing\n"); + close(); + } + else if (flags & MF_SOURCE_READERF_ALLEFFECTSREMOVED) + { + DebugPrintOut(L"\tStream decoding error. Abort capturing\n"); + close(); + } + else if (flags & MF_SOURCE_READERF_ENDOFSTREAM) + { + DebugPrintOut(L"\tEnd of stream detected\n"); + } + else + { + if (flags & MF_SOURCE_READERF_NEWSTREAM) + { + DebugPrintOut(L"\tNew stream detected\n"); + } + if (flags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED) + { + DebugPrintOut(L"\tStream native media type changed\n"); + } + if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) + { + DebugPrintOut(L"\tStream current media type changed\n"); + } + return true; + } + } + } + return false; } IplImage* CvCaptureCAM_MSMF::retrieveFrame(int) { - const int w = (int)VI.getWidth(index); - const int h = (int)VI.getHeight(index); - if( !frame || w != frame->width || h != frame->height ) + unsigned int width = captureFormat.width; + unsigned int height = captureFormat.height; + unsigned int bytes = 3; //Suppose output format is BGR24 + if (!frame || (int)width != frame->width || (int)height != frame->height) { if (frame) - cvReleaseImage( &frame ); - frame = cvCreateImage( cvSize(w,h), 8, 3 ); + cvReleaseImage(&frame); + frame = cvCreateImage(cvSize(width, height), 8, bytes); } - VI.getPixels( index, (uchar*)frame->imageData, false, true ); - return frame; + + unsigned int size = bytes * width * height; + DWORD bcnt; + if (videoSample && SUCCEEDED(videoSample->GetBufferCount(&bcnt)) && bcnt > 0) + { + _ComPtr buf = NULL; + if (SUCCEEDED(videoSample->GetBufferByIndex(0, &buf))) + { + DWORD maxsize, cursize; + BYTE* ptr = NULL; + if (SUCCEEDED(buf->Lock(&ptr, &maxsize, &cursize))) + { + if ((unsigned int)cursize == size) + { + memcpy(frame->imageData, ptr, size); + buf->Unlock(); + return frame; + } + buf->Unlock(); + } + } + } + + return NULL; +} + +double CvCaptureCAM_MSMF::getFramerate(MediaType MT) const +{ + if (MT.MF_MT_SUBTYPE == MFVideoFormat_MP43) //Unable to estimate FPS for MP43 + return 0; + return MT.MF_MT_FRAME_RATE_DENOMINATOR != 0 ? ((double)MT.MF_MT_FRAME_RATE_NUMERATOR) / ((double)MT.MF_MT_FRAME_RATE_DENOMINATOR) : 0; } double CvCaptureCAM_MSMF::getProperty( int property_id ) const { - // image format proprrties - switch( property_id ) - { - case CV_CAP_PROP_FRAME_WIDTH: - return VI.getWidth(index); - case CV_CAP_PROP_FRAME_HEIGHT: - return VI.getHeight(index); - case CV_CAP_PROP_FPS: - return VI.getFrameRate(index); - default: - break; - } - return 0; + // image format properties + if (isOpened) + switch (property_id) + { + case CV_CAP_PROP_FRAME_WIDTH: + return captureFormat.width; + case CV_CAP_PROP_FRAME_HEIGHT: + return captureFormat.height; + case CV_CAP_PROP_FOURCC: + return captureFormat.MF_MT_SUBTYPE.Data1; + case CV_CAP_PROP_FPS: + return getFramerate(captureFormat); + } + + return -1; } bool CvCaptureCAM_MSMF::setProperty( int property_id, double value ) { // image capture properties - unsigned int fps = 0; - bool handled = false; - switch( property_id ) + if (isOpened) { - case CV_CAP_PROP_FRAME_WIDTH: - width = cvRound(value); - fps = VI.getFrameRate(index); - handled = true; - break; - case CV_CAP_PROP_FRAME_HEIGHT: - height = cvRound(value); - fps = VI.getFrameRate(index); - handled = true; - break; - case CV_CAP_PROP_FPS: - width = (int)VI.getHeight(index); - height = (int)VI.getWidth(index); - fps = cvRound(value); - break; - } - - if ( handled ) { - if( width > 0 && height > 0 ) + unsigned int width = captureFormat.width; + unsigned int height = captureFormat.height; + unsigned int fps = getProperty(CV_CAP_PROP_FPS); + switch (property_id) { - if( (width != (int)VI.getWidth(index) || height != (int)VI.getHeight(index) || fps != VI.getFrameRate(index)) - && VI.isDeviceSetup(index))//|| fourcc != VI.getFourcc(index) ) - { - VI.closeDevice(index); - VI.setupDevice(index, width, height, fps); - } - width = height = -1; - return VI.isDeviceSetup(index); + case CV_CAP_PROP_FRAME_WIDTH: + width = cvRound(value); + break; + case CV_CAP_PROP_FRAME_HEIGHT: + height = cvRound(value); + break; + case CV_CAP_PROP_FPS: + fps = cvRound(value); + break; } - return true; - } + if (width > 0 && height > 0 && fps >= 0) + { + if (width != captureFormat.width || height != captureFormat.height || fps != getFramerate(captureFormat)) + return configureOutput(width, height, fps); + else + return true; + } + } return false; } @@ -3008,8 +2374,7 @@ CvCaptureFile_MSMF::~CvCaptureFile_MSMF() bool CvCaptureFile_MSMF::open(const char* filename) { - if (isOpened) - close(); + close(); if (!filename) return false; From b0b2d8de4459ee3ce0ea6074b07f17bafa75af94 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Fri, 13 Apr 2018 15:43:41 +0300 Subject: [PATCH 12/36] Remove unused code --- modules/videoio/src/cap_msmf.cpp | 2298 +++++++-------------------- modules/videoio/src/cap_msmf.hpp | 2504 ------------------------------ 2 files changed, 548 insertions(+), 4254 deletions(-) diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp index 393aa93b6c..56ac29e746 100644 --- a/modules/videoio/src/cap_msmf.cpp +++ b/modules/videoio/src/cap_msmf.cpp @@ -52,9 +52,6 @@ #undef WINVER #define WINVER _WIN32_WINNT_WIN8 #endif -#if defined _MSC_VER && _MSC_VER >= 1600 - #define HAVE_CONCURRENCY -#endif #include #include #include @@ -97,15 +94,6 @@ struct IMFAttributes; namespace { -template void SafeRelease(T **ppT) -{ - if (*ppT) - { - (*ppT)->Release(); - *ppT = NULL; - } -} - #ifdef _DEBUG void DPOprintOut(const wchar_t *format, ...) { @@ -138,166 +126,154 @@ void DPOprintOut(const wchar_t *format, ...) #define DebugPrintOut(...) void() #endif -#include "cap_msmf.hpp" +template +class ComPtr +{ +public: + ComPtr() throw() + { + } + ComPtr(T* lp) throw() + { + p = lp; + } + ComPtr(_In_ const ComPtr& lp) throw() + { + p = lp.p; + } + virtual ~ComPtr() + { + } + + T** operator&() throw() + { + assert(p == NULL); + return p.operator&(); + } + T* operator->() const throw() + { + assert(p != NULL); + return p.operator->(); + } + bool operator!() const throw() + { + return p.operator==(NULL); + } + bool operator==(_In_opt_ T* pT) const throw() + { + return p.operator==(pT); + } + bool operator!=(_In_opt_ T* pT) const throw() + { + return p.operator!=(pT); + } + operator bool() + { + return p.operator!=(NULL); + } + + T* const* GetAddressOf() const throw() + { + return &p; + } + + T** GetAddressOf() throw() + { + return &p; + } + + T** ReleaseAndGetAddressOf() throw() + { + p.Release(); + return &p; + } + + T* Get() const throw() + { + return p; + } + + // Attach to an existing interface (does not AddRef) + void Attach(_In_opt_ T* p2) throw() + { + p.Attach(p2); + } + // Detach the interface (does not Release) + T* Detach() throw() + { + return p.Detach(); + } + _Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT) throw() + { + assert(ppT != NULL); + if (ppT == NULL) + return E_POINTER; + *ppT = p; + if (p != NULL) + p->AddRef(); + return S_OK; + } + + void Reset() + { + p.Release(); + } + + // query for U interface + template + HRESULT As(_Inout_ U** lp) const throw() + { + return p->QueryInterface(__uuidof(U), reinterpret_cast(lp)); + } + // query for U interface + template + HRESULT As(_Out_ ComPtr* lp) const throw() + { + return p->QueryInterface(__uuidof(U), reinterpret_cast(lp->ReleaseAndGetAddressOf())); + } +private: + _COM_SMARTPTR_TYPEDEF(T, __uuidof(T)); + TPtr p; +}; + +#define _ComPtr ComPtr // Structure for collecting info about types of video, which are supported by current video device struct MediaType { unsigned int MF_MT_FRAME_SIZE; - unsigned int height; - unsigned int width; + UINT32 height; + UINT32 width; unsigned int MF_MT_YUV_MATRIX; unsigned int MF_MT_VIDEO_LIGHTING; int MF_MT_DEFAULT_STRIDE; // stride is negative if image is bottom-up unsigned int MF_MT_VIDEO_CHROMA_SITING; GUID MF_MT_AM_FORMAT_TYPE; - wchar_t *pMF_MT_AM_FORMAT_TYPEName; + LPCWSTR pMF_MT_AM_FORMAT_TYPEName; unsigned int MF_MT_FIXED_SIZE_SAMPLES; unsigned int MF_MT_VIDEO_NOMINAL_RANGE; - unsigned int MF_MT_FRAME_RATE_NUMERATOR; - unsigned int MF_MT_FRAME_RATE_DENOMINATOR; - unsigned int MF_MT_PIXEL_ASPECT_RATIO; - unsigned int MF_MT_PIXEL_ASPECT_RATIO_low; + UINT32 MF_MT_FRAME_RATE_NUMERATOR; + UINT32 MF_MT_FRAME_RATE_DENOMINATOR; + UINT32 MF_MT_PIXEL_ASPECT_RATIO; + UINT32 MF_MT_PIXEL_ASPECT_RATIO_low; unsigned int MF_MT_ALL_SAMPLES_INDEPENDENT; - unsigned int MF_MT_FRAME_RATE_RANGE_MIN; - unsigned int MF_MT_FRAME_RATE_RANGE_MIN_low; + UINT32 MF_MT_FRAME_RATE_RANGE_MIN; + UINT32 MF_MT_FRAME_RATE_RANGE_MIN_low; unsigned int MF_MT_SAMPLE_SIZE; unsigned int MF_MT_VIDEO_PRIMARIES; unsigned int MF_MT_INTERLACE_MODE; - unsigned int MF_MT_FRAME_RATE_RANGE_MAX; - unsigned int MF_MT_FRAME_RATE_RANGE_MAX_low; + UINT32 MF_MT_FRAME_RATE_RANGE_MAX; + UINT32 MF_MT_FRAME_RATE_RANGE_MAX_low; GUID MF_MT_MAJOR_TYPE; GUID MF_MT_SUBTYPE; - wchar_t *pMF_MT_MAJOR_TYPEName; - wchar_t *pMF_MT_SUBTYPEName; + LPCWSTR pMF_MT_MAJOR_TYPEName; + LPCWSTR pMF_MT_SUBTYPEName; MediaType(); + MediaType(IMFMediaType *pType); ~MediaType(); void Clear(); }; -/// Class for parsing info from IMFMediaType into the local MediaType -class FormatReader -{ -public: - static MediaType Read(IMFMediaType *pType); - ~FormatReader(void); -private: - FormatReader(void); -}; - -DWORD WINAPI MainThreadFunction( LPVOID lpParam ); -typedef void(*emergensyStopEventCallback)(int, void *); - -class RawImage -{ -public: - ~RawImage(void); - // Function of creation of the instance of the class - static long CreateInstance(RawImage **ppRImage,unsigned int size); - void setCopy(const BYTE * pSampleBuffer); - void fastCopy(const BYTE * pSampleBuffer); - unsigned char * getpPixels(); - bool isNew(); - unsigned int getSize(); -private: - bool ri_new; - unsigned int ri_size; - unsigned char *ri_pixels; - RawImage(unsigned int size); -}; - -class ImageGrabberCallback : public IMFSampleGrabberSinkCallback -{ -public: - void pauseGrabbing(); - void resumeGrabbing(); - RawImage *getRawImage(); - // IMFClockStateSink methods - STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset); - STDMETHODIMP OnClockStop(MFTIME hnsSystemTime); - STDMETHODIMP OnClockPause(MFTIME hnsSystemTime); - STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime); - STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate); - // IMFSampleGrabberSinkCallback methods - STDMETHODIMP OnSetPresentationClock(IMFPresentationClock* pClock); - STDMETHODIMP OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags, - LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer, - DWORD dwSampleSize); - STDMETHODIMP OnShutdown(); - - const HANDLE ig_hFrameReady; - const HANDLE ig_hFrameGrabbed; - const HANDLE ig_hFinish; -protected: - ImageGrabberCallback(bool synchronous); - bool ig_RIE; - bool ig_Close; - bool ig_Synchronous; - long m_cRef; - - RawImage *ig_RIFirst; - RawImage *ig_RISecond; - RawImage *ig_RIOut; -private: - ImageGrabberCallback& operator=(const ImageGrabberCallback&); // Declared to fix compilation warning. - }; - -// Class for grabbing image from video stream -class ImageGrabber : public ImageGrabberCallback -{ -public: - ~ImageGrabber(void); - HRESULT initImageGrabber(IMFMediaSource *pSource); - HRESULT startGrabbing(void); - void stopGrabbing(); - // IUnknown methods - STDMETHODIMP QueryInterface(REFIID iid, void** ppv); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - // Function of creation of the instance of the class - static HRESULT CreateInstance(ImageGrabber **ppIG, unsigned int deviceID, bool synchronous = false); - const MediaType* getCaptureFormat() { return &captureFormat; } - -private: - unsigned int ig_DeviceID; - - IMFMediaSource *ig_pSource; - MediaType captureFormat; - IMFMediaSession *ig_pSession; - IMFTopology *ig_pTopology; - ImageGrabber(unsigned int deviceID, bool synchronous); - HRESULT CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo); - HRESULT AddSourceNode(IMFTopology *pTopology, IMFMediaSource *pSource, - IMFPresentationDescriptor *pPD, IMFStreamDescriptor *pSD, IMFTopologyNode **ppNode); - HRESULT AddOutputNode(IMFTopology *pTopology, IMFActivate *pActivate, DWORD dwId, IMFTopologyNode **ppNode); - - ImageGrabber& operator=(const ImageGrabber&); // Declared to fix comiplation error. -}; - -/// Class for controlling of thread of the grabbing raw data from video device -class ImageGrabberThread -{ - friend DWORD WINAPI MainThreadFunction( LPVOID lpParam ); -public: - ~ImageGrabberThread(void); - static HRESULT CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID, bool synchronious = false); - void start(); - void stop(); - void setEmergencyStopEvent(void *userData, void(*func)(int, void *)); - ImageGrabber *getImageGrabber(); -protected: - virtual void run(); -private: - ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID, bool synchronious); - HANDLE igt_Handle; - DWORD igt_ThreadIdArray; - ImageGrabber *igt_pImageGrabber; - emergensyStopEventCallback igt_func; - void *igt_userData; - bool igt_stop; - unsigned int igt_DeviceID; -}; - // Structure for collecting info about one parametr of current video device struct Parametr { @@ -307,97 +283,112 @@ struct Parametr long Step; long Default; long Flag; - Parametr(); + Parametr() + { + CurrentValue = 0; + Min = 0; + Max = 0; + Step = 0; + Default = 0; + Flag = 0; + } }; // Structure for collecting info about 17 parametrs of current video device struct CamParametrs { - Parametr Brightness; - Parametr Contrast; - Parametr Hue; - Parametr Saturation; - Parametr Sharpness; - Parametr Gamma; - Parametr ColorEnable; - Parametr WhiteBalance; - Parametr BacklightCompensation; - Parametr Gain; - Parametr Pan; - Parametr Tilt; - Parametr Roll; - Parametr Zoom; - Parametr Exposure; - Parametr Iris; - Parametr Focus; + Parametr Brightness; + Parametr Contrast; + Parametr Hue; + Parametr Saturation; + Parametr Sharpness; + Parametr Gamma; + Parametr ColorEnable; + Parametr WhiteBalance; + Parametr BacklightCompensation; + Parametr Gain; + Parametr Pan; + Parametr Tilt; + Parametr Roll; + Parametr Zoom; + Parametr Exposure; + Parametr Iris; + Parametr Focus; }; -typedef std::wstring String; -typedef std::vector vectorNum; -typedef std::map SUBTYPEMap; -typedef std::map FrameRateMap; -typedef void(*emergensyStopEventCallback)(int, void *); - -/// Class for controlling of video device -class videoDevice +CamParametrs videoDevice__getParametrs(IMFMediaSource* vd_pSource) { -public: - videoDevice(void); - ~videoDevice(void); - void closeDevice(); - CamParametrs getParametrs(); - void setParametrs(CamParametrs parametrs); - void setEmergencyStopEvent(void *userData, void(*func)(int, void *)); - long readInfoOfDevice(IMFActivate *pActivate, unsigned int Num); - int getCountFormats(); - unsigned int getWidth(); - unsigned int getHeight(); - unsigned int getFrameRate() const; - MediaType getFormat(unsigned int id); - bool setupDevice(unsigned int w, unsigned int h, unsigned int idealFramerate = 0); - bool setupDevice(unsigned int id); - bool isDeviceSetup(); - bool isDeviceMediaSource(); - bool isDeviceRawDataSource(); - bool isFrameNew(); - IMFMediaSource *getMediaSource(); - RawImage *getRawImageOut(); -private: - enum typeLock + CamParametrs out; + if (vd_pSource) { - MediaSourceLock, - RawDataLock, - OpenLock - } vd_LockOut; - wchar_t *vd_pFriendlyName; - ImageGrabberThread *vd_pImGrTh; - unsigned int vd_Width; - unsigned int vd_Height; - unsigned int vd_FrameRate; - unsigned int vd_CurrentNumber; - bool vd_IsSetuped; - std::map vd_CaptureFormats; - std::vector vd_CurrentFormats; - IMFMediaSource *vd_pSource; - emergensyStopEventCallback vd_func; - void *vd_userData; - HRESULT enumerateCaptureFormats(IMFMediaSource *pSource); - long setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex); - void buildLibraryofTypes(); - int findType(unsigned int size, unsigned int frameRate = 0); - long checkDevice(IMFActivate **pDevice); - long initDevice(); -}; + Parametr *pParametr = (Parametr *)(&out); + IAMVideoProcAmp *pProcAmp = NULL; + HRESULT hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcAmp)); + if (SUCCEEDED(hr)) + { + for (unsigned int i = 0; i < 10; i++) + { + Parametr temp; + hr = pProcAmp->GetRange(VideoProcAmp_Brightness + i, &temp.Min, &temp.Max, &temp.Step, &temp.Default, &temp.Flag); + if (SUCCEEDED(hr)) + { + temp.CurrentValue = temp.Default; + pParametr[i] = temp; + } + } + pProcAmp->Release(); + } + IAMCameraControl *pProcControl = NULL; + hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcControl)); + if (SUCCEEDED(hr)) + { + for (unsigned int i = 0; i < 7; i++) + { + Parametr temp; + hr = pProcControl->GetRange(CameraControl_Pan + i, &temp.Min, &temp.Max, &temp.Step, &temp.Default, &temp.Flag); + if (SUCCEEDED(hr)) + { + temp.CurrentValue = temp.Default; + pParametr[10 + i] = temp; + } + } + pProcControl->Release(); + } + } + return out; +} -/// Class for managing of list of video devices -class videoDevices +void videoDevice__setParametrs(IMFMediaSource* vd_pSource, CamParametrs parametrs) { -public: - ~videoDevices(void); - static cv::Ptr getDevice(unsigned int i, bool fallback = false); -private: - videoDevices(void); -}; + if (vd_pSource) + { + CamParametrs vd_PrevParametrs = videoDevice__getParametrs(vd_pSource); + Parametr *pParametr = (Parametr *)(¶metrs); + Parametr *pPrevParametr = (Parametr *)(&vd_PrevParametrs); + IAMVideoProcAmp *pProcAmp = NULL; + HRESULT hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcAmp)); + if (SUCCEEDED(hr)) + { + for (unsigned int i = 0; i < 10; i++) + { + if (pPrevParametr[i].CurrentValue != pParametr[i].CurrentValue || pPrevParametr[i].Flag != pParametr[i].Flag) + hr = pProcAmp->Set(VideoProcAmp_Brightness + i, pParametr[i].CurrentValue, pParametr[i].Flag); + } + pProcAmp->Release(); + } + IAMCameraControl *pProcControl = NULL; + hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcControl)); + if (SUCCEEDED(hr)) + { + for (unsigned int i = 0; i < 7; i++) + { + if (pPrevParametr[10 + i].CurrentValue != pParametr[10 + i].CurrentValue || pPrevParametr[10 + i].Flag != pParametr[10 + i].Flag) + hr = pProcControl->Set(CameraControl_Pan + i, pParametr[10 + i].CurrentValue, pParametr[10 + i].Flag); + } + pProcControl->Release(); + } + } +} // Class for creating of Media Foundation context class Media_Foundation @@ -413,1548 +404,354 @@ private: Media_Foundation(void) { CV_Assert(SUCCEEDED(MFStartup(MF_VERSION))); } }; -LPCWSTR GetGUIDNameConstNew(const GUID& guid); -HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz); -HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index); -HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, MediaType &out); - -unsigned int *GetParametr(GUID guid, MediaType &out) -{ - if(guid == MF_MT_YUV_MATRIX) - return &(out.MF_MT_YUV_MATRIX); - if(guid == MF_MT_VIDEO_LIGHTING) - return &(out.MF_MT_VIDEO_LIGHTING); - if(guid == MF_MT_DEFAULT_STRIDE) - return (unsigned int*)&(out.MF_MT_DEFAULT_STRIDE); - if(guid == MF_MT_VIDEO_CHROMA_SITING) - return &(out.MF_MT_VIDEO_CHROMA_SITING); - if(guid == MF_MT_VIDEO_NOMINAL_RANGE) - return &(out.MF_MT_VIDEO_NOMINAL_RANGE); - if(guid == MF_MT_ALL_SAMPLES_INDEPENDENT) - return &(out.MF_MT_ALL_SAMPLES_INDEPENDENT); - if(guid == MF_MT_FIXED_SIZE_SAMPLES) - return &(out.MF_MT_FIXED_SIZE_SAMPLES); - if(guid == MF_MT_SAMPLE_SIZE) - return &(out.MF_MT_SAMPLE_SIZE); - if(guid == MF_MT_VIDEO_PRIMARIES) - return &(out.MF_MT_VIDEO_PRIMARIES); - if(guid == MF_MT_INTERLACE_MODE) - return &(out.MF_MT_INTERLACE_MODE); - return NULL; -} - -HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, MediaType &out) -{ - WCHAR *pGuidName = NULL; - WCHAR *pGuidValName = NULL; - GUID guid = { 0 }; - PROPVARIANT var; - PropVariantInit(&var); - HRESULT hr = pAttr->GetItemByIndex(index, &guid, &var); - if (FAILED(hr)) - { - goto done; - } - hr = GetGUIDNameNew(guid, &pGuidName); - if (FAILED(hr)) - { - goto done; - } - hr = SpecialCaseAttributeValueNew(guid, var, out); - unsigned int *p; - if (FAILED(hr)) - { - goto done; - } - if (hr == S_FALSE) - { - switch (var.vt) - { - case VT_UI4: - p = GetParametr(guid, out); - if(p) - { - *p = var.ulVal; - } - break; - case VT_UI8: - break; - case VT_R8: - break; - case VT_CLSID: - if(guid == MF_MT_AM_FORMAT_TYPE) - { - hr = GetGUIDNameNew(*var.puuid, &pGuidValName); - if (SUCCEEDED(hr)) - { - out.MF_MT_AM_FORMAT_TYPE = *var.puuid; - out.pMF_MT_AM_FORMAT_TYPEName = pGuidValName; - pGuidValName = NULL; - } - } - if(guid == MF_MT_MAJOR_TYPE) - { - hr = GetGUIDNameNew(*var.puuid, &pGuidValName); - if (SUCCEEDED(hr)) - { - out.MF_MT_MAJOR_TYPE = *var.puuid; - out.pMF_MT_MAJOR_TYPEName = pGuidValName; - pGuidValName = NULL; - } - } - if(guid == MF_MT_SUBTYPE) - { - hr = GetGUIDNameNew(*var.puuid, &pGuidValName); - if (SUCCEEDED(hr)) - { - out.MF_MT_SUBTYPE = *var.puuid; - out.pMF_MT_SUBTYPEName = pGuidValName; - pGuidValName = NULL; - } - } - break; - case VT_LPWSTR: - break; - case VT_VECTOR | VT_UI1: - break; - case VT_UNKNOWN: - break; - default: - break; - } - } -done: - CoTaskMemFree(pGuidName); - CoTaskMemFree(pGuidValName); - PropVariantClear(&var); - return hr; -} - -HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz) -{ - HRESULT hr = S_OK; - WCHAR *pName = NULL; - LPCWSTR pcwsz = GetGUIDNameConstNew(guid); - if (pcwsz) - { - size_t cchLength = 0; - hr = StringCchLengthW(pcwsz, STRSAFE_MAX_CCH, &cchLength); - if (FAILED(hr)) - { - goto done; - } - pName = (WCHAR*)CoTaskMemAlloc((cchLength + 1) * sizeof(WCHAR)); - if (pName == NULL) - { - hr = E_OUTOFMEMORY; - goto done; - } - hr = StringCchCopyW(pName, cchLength + 1, pcwsz); - if (FAILED(hr)) - { - goto done; - } - } - else - { - hr = StringFromCLSID(guid, &pName); - } -done: - if (FAILED(hr)) - { - *ppwsz = NULL; - CoTaskMemFree(pName); - } - else - { - *ppwsz = pName; - } - return hr; -} - -void LogUINT32AsUINT64New(const PROPVARIANT& var, UINT32 &uHigh, UINT32 &uLow) -{ - Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &uHigh, &uLow); -} - -float OffsetToFloatNew(const MFOffset& offset) -{ - return offset.value + (static_cast(offset.fract) / 65536.0f); -} - -HRESULT LogVideoAreaNew(const PROPVARIANT& var) -{ - if (var.caub.cElems < sizeof(MFVideoArea)) - { - return S_OK; - } - return S_OK; -} - -HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, MediaType &out) -{ - if (guid == MF_MT_DEFAULT_STRIDE) - { - out.MF_MT_DEFAULT_STRIDE = var.intVal; - } else - if (guid == MF_MT_FRAME_SIZE) - { - UINT32 uHigh = 0, uLow = 0; - LogUINT32AsUINT64New(var, uHigh, uLow); - out.width = uHigh; - out.height = uLow; - out.MF_MT_FRAME_SIZE = out.width * out.height; - } - else - if (guid == MF_MT_FRAME_RATE) - { - UINT32 uHigh = 0, uLow = 0; - LogUINT32AsUINT64New(var, uHigh, uLow); - out.MF_MT_FRAME_RATE_NUMERATOR = uHigh; - out.MF_MT_FRAME_RATE_DENOMINATOR = uLow; - } - else - if (guid == MF_MT_FRAME_RATE_RANGE_MAX) - { - UINT32 uHigh = 0, uLow = 0; - LogUINT32AsUINT64New(var, uHigh, uLow); - out.MF_MT_FRAME_RATE_RANGE_MAX = uHigh; - out.MF_MT_FRAME_RATE_RANGE_MAX_low = uLow; - } - else - if (guid == MF_MT_FRAME_RATE_RANGE_MIN) - { - UINT32 uHigh = 0, uLow = 0; - LogUINT32AsUINT64New(var, uHigh, uLow); - out.MF_MT_FRAME_RATE_RANGE_MIN = uHigh; - out.MF_MT_FRAME_RATE_RANGE_MIN_low = uLow; - } - else - if (guid == MF_MT_PIXEL_ASPECT_RATIO) - { - UINT32 uHigh = 0, uLow = 0; - LogUINT32AsUINT64New(var, uHigh, uLow); - out.MF_MT_PIXEL_ASPECT_RATIO = uHigh; - out.MF_MT_PIXEL_ASPECT_RATIO_low = uLow; - } - else - { - return S_FALSE; - } - return S_OK; -} - -#ifndef IF_EQUAL_RETURN -#define IF_EQUAL_RETURN(param, val) if(val == param) return L#val +#ifndef IF_GUID_EQUAL_RETURN +#define IF_GUID_EQUAL_RETURN(val) if(val == guid) return L#val #endif - LPCWSTR GetGUIDNameConstNew(const GUID& guid) { - IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE); - IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE); - IF_EQUAL_RETURN(guid, MF_MT_SUBTYPE); - IF_EQUAL_RETURN(guid, MF_MT_ALL_SAMPLES_INDEPENDENT); - IF_EQUAL_RETURN(guid, MF_MT_FIXED_SIZE_SAMPLES); - IF_EQUAL_RETURN(guid, MF_MT_COMPRESSED); - IF_EQUAL_RETURN(guid, MF_MT_SAMPLE_SIZE); - IF_EQUAL_RETURN(guid, MF_MT_WRAPPED_TYPE); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_NUM_CHANNELS); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_SECOND); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_AVG_BYTES_PER_SECOND); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BLOCK_ALIGNMENT); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BITS_PER_SAMPLE); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_VALID_BITS_PER_SAMPLE); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_BLOCK); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_CHANNEL_MASK); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FOLDDOWN_MATRIX); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKREF); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKTARGET); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGREF); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGTARGET); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_PREFER_WAVEFORMATEX); - IF_EQUAL_RETURN(guid, MF_MT_AAC_PAYLOAD_TYPE); - IF_EQUAL_RETURN(guid, MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION); - IF_EQUAL_RETURN(guid, MF_MT_FRAME_SIZE); - IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE); - IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MAX); - IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MIN); - IF_EQUAL_RETURN(guid, MF_MT_PIXEL_ASPECT_RATIO); - IF_EQUAL_RETURN(guid, MF_MT_DRM_FLAGS); - IF_EQUAL_RETURN(guid, MF_MT_PAD_CONTROL_FLAGS); - IF_EQUAL_RETURN(guid, MF_MT_SOURCE_CONTENT_HINT); - IF_EQUAL_RETURN(guid, MF_MT_VIDEO_CHROMA_SITING); - IF_EQUAL_RETURN(guid, MF_MT_INTERLACE_MODE); - IF_EQUAL_RETURN(guid, MF_MT_TRANSFER_FUNCTION); - IF_EQUAL_RETURN(guid, MF_MT_VIDEO_PRIMARIES); - IF_EQUAL_RETURN(guid, MF_MT_CUSTOM_VIDEO_PRIMARIES); - IF_EQUAL_RETURN(guid, MF_MT_YUV_MATRIX); - IF_EQUAL_RETURN(guid, MF_MT_VIDEO_LIGHTING); - IF_EQUAL_RETURN(guid, MF_MT_VIDEO_NOMINAL_RANGE); - IF_EQUAL_RETURN(guid, MF_MT_GEOMETRIC_APERTURE); - IF_EQUAL_RETURN(guid, MF_MT_MINIMUM_DISPLAY_APERTURE); - IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_APERTURE); - IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_ENABLED); - IF_EQUAL_RETURN(guid, MF_MT_AVG_BITRATE); - IF_EQUAL_RETURN(guid, MF_MT_AVG_BIT_ERROR_RATE); - IF_EQUAL_RETURN(guid, MF_MT_MAX_KEYFRAME_SPACING); - IF_EQUAL_RETURN(guid, MF_MT_DEFAULT_STRIDE); - IF_EQUAL_RETURN(guid, MF_MT_PALETTE); - IF_EQUAL_RETURN(guid, MF_MT_USER_DATA); - IF_EQUAL_RETURN(guid, MF_MT_AM_FORMAT_TYPE); - IF_EQUAL_RETURN(guid, MF_MT_MPEG_START_TIME_CODE); - IF_EQUAL_RETURN(guid, MF_MT_MPEG2_PROFILE); - IF_EQUAL_RETURN(guid, MF_MT_MPEG2_LEVEL); - IF_EQUAL_RETURN(guid, MF_MT_MPEG2_FLAGS); - IF_EQUAL_RETURN(guid, MF_MT_MPEG_SEQUENCE_HEADER); - IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_0); - IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_0); - IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_1); - IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_1); - IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_SRC_PACK); - IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_CTRL_PACK); - IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_HEADER); - IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_FORMAT); - IF_EQUAL_RETURN(guid, MF_MT_IMAGE_LOSS_TOLERANT); - IF_EQUAL_RETURN(guid, MF_MT_MPEG4_SAMPLE_DESCRIPTION); - IF_EQUAL_RETURN(guid, MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY); - IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_4CC); - IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_WAVE_FORMAT_TAG); + IF_GUID_EQUAL_RETURN(MF_MT_MAJOR_TYPE); + IF_GUID_EQUAL_RETURN(MF_MT_SUBTYPE); + IF_GUID_EQUAL_RETURN(MF_MT_ALL_SAMPLES_INDEPENDENT); + IF_GUID_EQUAL_RETURN(MF_MT_FIXED_SIZE_SAMPLES); + IF_GUID_EQUAL_RETURN(MF_MT_COMPRESSED); + IF_GUID_EQUAL_RETURN(MF_MT_SAMPLE_SIZE); + IF_GUID_EQUAL_RETURN(MF_MT_WRAPPED_TYPE); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_NUM_CHANNELS); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_SAMPLES_PER_SECOND); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_AVG_BYTES_PER_SECOND); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_BLOCK_ALIGNMENT); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_BITS_PER_SAMPLE); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_VALID_BITS_PER_SAMPLE); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_SAMPLES_PER_BLOCK); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_CHANNEL_MASK); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_FOLDDOWN_MATRIX); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_WMADRC_PEAKREF); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_WMADRC_PEAKTARGET); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_WMADRC_AVGREF); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_WMADRC_AVGTARGET); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_PREFER_WAVEFORMATEX); + IF_GUID_EQUAL_RETURN(MF_MT_AAC_PAYLOAD_TYPE); + IF_GUID_EQUAL_RETURN(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION); + IF_GUID_EQUAL_RETURN(MF_MT_FRAME_SIZE); + IF_GUID_EQUAL_RETURN(MF_MT_FRAME_RATE); + IF_GUID_EQUAL_RETURN(MF_MT_FRAME_RATE_RANGE_MAX); + IF_GUID_EQUAL_RETURN(MF_MT_FRAME_RATE_RANGE_MIN); + IF_GUID_EQUAL_RETURN(MF_MT_PIXEL_ASPECT_RATIO); + IF_GUID_EQUAL_RETURN(MF_MT_DRM_FLAGS); + IF_GUID_EQUAL_RETURN(MF_MT_PAD_CONTROL_FLAGS); + IF_GUID_EQUAL_RETURN(MF_MT_SOURCE_CONTENT_HINT); + IF_GUID_EQUAL_RETURN(MF_MT_VIDEO_CHROMA_SITING); + IF_GUID_EQUAL_RETURN(MF_MT_INTERLACE_MODE); + IF_GUID_EQUAL_RETURN(MF_MT_TRANSFER_FUNCTION); + IF_GUID_EQUAL_RETURN(MF_MT_VIDEO_PRIMARIES); + IF_GUID_EQUAL_RETURN(MF_MT_CUSTOM_VIDEO_PRIMARIES); + IF_GUID_EQUAL_RETURN(MF_MT_YUV_MATRIX); + IF_GUID_EQUAL_RETURN(MF_MT_VIDEO_LIGHTING); + IF_GUID_EQUAL_RETURN(MF_MT_VIDEO_NOMINAL_RANGE); + IF_GUID_EQUAL_RETURN(MF_MT_GEOMETRIC_APERTURE); + IF_GUID_EQUAL_RETURN(MF_MT_MINIMUM_DISPLAY_APERTURE); + IF_GUID_EQUAL_RETURN(MF_MT_PAN_SCAN_APERTURE); + IF_GUID_EQUAL_RETURN(MF_MT_PAN_SCAN_ENABLED); + IF_GUID_EQUAL_RETURN(MF_MT_AVG_BITRATE); + IF_GUID_EQUAL_RETURN(MF_MT_AVG_BIT_ERROR_RATE); + IF_GUID_EQUAL_RETURN(MF_MT_MAX_KEYFRAME_SPACING); + IF_GUID_EQUAL_RETURN(MF_MT_DEFAULT_STRIDE); + IF_GUID_EQUAL_RETURN(MF_MT_PALETTE); + IF_GUID_EQUAL_RETURN(MF_MT_USER_DATA); + IF_GUID_EQUAL_RETURN(MF_MT_AM_FORMAT_TYPE); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG_START_TIME_CODE); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG2_PROFILE); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG2_LEVEL); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG2_FLAGS); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG_SEQUENCE_HEADER); + IF_GUID_EQUAL_RETURN(MF_MT_DV_AAUX_SRC_PACK_0); + IF_GUID_EQUAL_RETURN(MF_MT_DV_AAUX_CTRL_PACK_0); + IF_GUID_EQUAL_RETURN(MF_MT_DV_AAUX_SRC_PACK_1); + IF_GUID_EQUAL_RETURN(MF_MT_DV_AAUX_CTRL_PACK_1); + IF_GUID_EQUAL_RETURN(MF_MT_DV_VAUX_SRC_PACK); + IF_GUID_EQUAL_RETURN(MF_MT_DV_VAUX_CTRL_PACK); + IF_GUID_EQUAL_RETURN(MF_MT_ARBITRARY_HEADER); + IF_GUID_EQUAL_RETURN(MF_MT_ARBITRARY_FORMAT); + IF_GUID_EQUAL_RETURN(MF_MT_IMAGE_LOSS_TOLERANT); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG4_SAMPLE_DESCRIPTION); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY); + IF_GUID_EQUAL_RETURN(MF_MT_ORIGINAL_4CC); + IF_GUID_EQUAL_RETURN(MF_MT_ORIGINAL_WAVE_FORMAT_TAG); // Media types - IF_EQUAL_RETURN(guid, MFMediaType_Audio); - IF_EQUAL_RETURN(guid, MFMediaType_Video); - IF_EQUAL_RETURN(guid, MFMediaType_Protected); - IF_EQUAL_RETURN(guid, MFMediaType_SAMI); - IF_EQUAL_RETURN(guid, MFMediaType_Script); - IF_EQUAL_RETURN(guid, MFMediaType_Image); - IF_EQUAL_RETURN(guid, MFMediaType_HTML); - IF_EQUAL_RETURN(guid, MFMediaType_Binary); - IF_EQUAL_RETURN(guid, MFMediaType_FileTransfer); - IF_EQUAL_RETURN(guid, MFVideoFormat_AI44); // FCC('AI44') - IF_EQUAL_RETURN(guid, MFVideoFormat_ARGB32); // D3DFMT_A8R8G8B8 - IF_EQUAL_RETURN(guid, MFVideoFormat_AYUV); // FCC('AYUV') - IF_EQUAL_RETURN(guid, MFVideoFormat_DV25); // FCC('dv25') - IF_EQUAL_RETURN(guid, MFVideoFormat_DV50); // FCC('dv50') - IF_EQUAL_RETURN(guid, MFVideoFormat_DVH1); // FCC('dvh1') - IF_EQUAL_RETURN(guid, MFVideoFormat_DVSD); // FCC('dvsd') - IF_EQUAL_RETURN(guid, MFVideoFormat_DVSL); // FCC('dvsl') - IF_EQUAL_RETURN(guid, MFVideoFormat_H264); // FCC('H264') - IF_EQUAL_RETURN(guid, MFVideoFormat_I420); // FCC('I420') - IF_EQUAL_RETURN(guid, MFVideoFormat_IYUV); // FCC('IYUV') - IF_EQUAL_RETURN(guid, MFVideoFormat_M4S2); // FCC('M4S2') - IF_EQUAL_RETURN(guid, MFVideoFormat_MJPG); - IF_EQUAL_RETURN(guid, MFVideoFormat_MP43); // FCC('MP43') - IF_EQUAL_RETURN(guid, MFVideoFormat_MP4S); // FCC('MP4S') - IF_EQUAL_RETURN(guid, MFVideoFormat_MP4V); // FCC('MP4V') - IF_EQUAL_RETURN(guid, MFVideoFormat_MPG1); // FCC('MPG1') - IF_EQUAL_RETURN(guid, MFVideoFormat_MSS1); // FCC('MSS1') - IF_EQUAL_RETURN(guid, MFVideoFormat_MSS2); // FCC('MSS2') - IF_EQUAL_RETURN(guid, MFVideoFormat_NV11); // FCC('NV11') - IF_EQUAL_RETURN(guid, MFVideoFormat_NV12); // FCC('NV12') - IF_EQUAL_RETURN(guid, MFVideoFormat_P010); // FCC('P010') - IF_EQUAL_RETURN(guid, MFVideoFormat_P016); // FCC('P016') - IF_EQUAL_RETURN(guid, MFVideoFormat_P210); // FCC('P210') - IF_EQUAL_RETURN(guid, MFVideoFormat_P216); // FCC('P216') - IF_EQUAL_RETURN(guid, MFVideoFormat_RGB24); // D3DFMT_R8G8B8 - IF_EQUAL_RETURN(guid, MFVideoFormat_RGB32); // D3DFMT_X8R8G8B8 - IF_EQUAL_RETURN(guid, MFVideoFormat_RGB555); // D3DFMT_X1R5G5B5 - IF_EQUAL_RETURN(guid, MFVideoFormat_RGB565); // D3DFMT_R5G6B5 - IF_EQUAL_RETURN(guid, MFVideoFormat_RGB8); - IF_EQUAL_RETURN(guid, MFVideoFormat_UYVY); // FCC('UYVY') - IF_EQUAL_RETURN(guid, MFVideoFormat_v210); // FCC('v210') - IF_EQUAL_RETURN(guid, MFVideoFormat_v410); // FCC('v410') - IF_EQUAL_RETURN(guid, MFVideoFormat_WMV1); // FCC('WMV1') - IF_EQUAL_RETURN(guid, MFVideoFormat_WMV2); // FCC('WMV2') - IF_EQUAL_RETURN(guid, MFVideoFormat_WMV3); // FCC('WMV3') - IF_EQUAL_RETURN(guid, MFVideoFormat_WVC1); // FCC('WVC1') - IF_EQUAL_RETURN(guid, MFVideoFormat_Y210); // FCC('Y210') - IF_EQUAL_RETURN(guid, MFVideoFormat_Y216); // FCC('Y216') - IF_EQUAL_RETURN(guid, MFVideoFormat_Y410); // FCC('Y410') - IF_EQUAL_RETURN(guid, MFVideoFormat_Y416); // FCC('Y416') - IF_EQUAL_RETURN(guid, MFVideoFormat_Y41P); - IF_EQUAL_RETURN(guid, MFVideoFormat_Y41T); - IF_EQUAL_RETURN(guid, MFVideoFormat_YUY2); // FCC('YUY2') - IF_EQUAL_RETURN(guid, MFVideoFormat_YV12); // FCC('YV12') - IF_EQUAL_RETURN(guid, MFVideoFormat_YVYU); - IF_EQUAL_RETURN(guid, MFAudioFormat_PCM); // WAVE_FORMAT_PCM - IF_EQUAL_RETURN(guid, MFAudioFormat_Float); // WAVE_FORMAT_IEEE_FLOAT - IF_EQUAL_RETURN(guid, MFAudioFormat_DTS); // WAVE_FORMAT_DTS - IF_EQUAL_RETURN(guid, MFAudioFormat_Dolby_AC3_SPDIF); // WAVE_FORMAT_DOLBY_AC3_SPDIF - IF_EQUAL_RETURN(guid, MFAudioFormat_DRM); // WAVE_FORMAT_DRM - IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV8); // WAVE_FORMAT_WMAUDIO2 - IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV9); // WAVE_FORMAT_WMAUDIO3 - IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudio_Lossless); // WAVE_FORMAT_WMAUDIO_LOSSLESS - IF_EQUAL_RETURN(guid, MFAudioFormat_WMASPDIF); // WAVE_FORMAT_WMASPDIF - IF_EQUAL_RETURN(guid, MFAudioFormat_MSP1); // WAVE_FORMAT_WMAVOICE9 - IF_EQUAL_RETURN(guid, MFAudioFormat_MP3); // WAVE_FORMAT_MPEGLAYER3 - IF_EQUAL_RETURN(guid, MFAudioFormat_MPEG); // WAVE_FORMAT_MPEG - IF_EQUAL_RETURN(guid, MFAudioFormat_AAC); // WAVE_FORMAT_MPEG_HEAAC - IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS); // WAVE_FORMAT_MPEG_ADTS_AAC + IF_GUID_EQUAL_RETURN(MFMediaType_Audio); + IF_GUID_EQUAL_RETURN(MFMediaType_Video); + IF_GUID_EQUAL_RETURN(MFMediaType_Protected); +#ifdef MFMediaType_Perception + IF_GUID_EQUAL_RETURN(MFMediaType_Perception); +#endif + IF_GUID_EQUAL_RETURN(MFMediaType_Stream); + IF_GUID_EQUAL_RETURN(MFMediaType_SAMI); + IF_GUID_EQUAL_RETURN(MFMediaType_Script); + IF_GUID_EQUAL_RETURN(MFMediaType_Image); + IF_GUID_EQUAL_RETURN(MFMediaType_HTML); + IF_GUID_EQUAL_RETURN(MFMediaType_Binary); + IF_GUID_EQUAL_RETURN(MFMediaType_FileTransfer); + IF_GUID_EQUAL_RETURN(MFVideoFormat_AI44); // FCC('AI44') + IF_GUID_EQUAL_RETURN(MFVideoFormat_ARGB32); // D3DFMT_A8R8G8B8 + IF_GUID_EQUAL_RETURN(MFVideoFormat_AYUV); // FCC('AYUV') + IF_GUID_EQUAL_RETURN(MFVideoFormat_DV25); // FCC('dv25') + IF_GUID_EQUAL_RETURN(MFVideoFormat_DV50); // FCC('dv50') + IF_GUID_EQUAL_RETURN(MFVideoFormat_DVH1); // FCC('dvh1') + IF_GUID_EQUAL_RETURN(MFVideoFormat_DVC); + IF_GUID_EQUAL_RETURN(MFVideoFormat_DVHD); + IF_GUID_EQUAL_RETURN(MFVideoFormat_DVSD); // FCC('dvsd') + IF_GUID_EQUAL_RETURN(MFVideoFormat_DVSL); // FCC('dvsl') + IF_GUID_EQUAL_RETURN(MFVideoFormat_H264); // FCC('H264') + IF_GUID_EQUAL_RETURN(MFVideoFormat_I420); // FCC('I420') + IF_GUID_EQUAL_RETURN(MFVideoFormat_IYUV); // FCC('IYUV') + IF_GUID_EQUAL_RETURN(MFVideoFormat_M4S2); // FCC('M4S2') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MJPG); + IF_GUID_EQUAL_RETURN(MFVideoFormat_MP43); // FCC('MP43') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MP4S); // FCC('MP4S') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MP4V); // FCC('MP4V') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MPG1); // FCC('MPG1') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MSS1); // FCC('MSS1') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MSS2); // FCC('MSS2') + IF_GUID_EQUAL_RETURN(MFVideoFormat_NV11); // FCC('NV11') + IF_GUID_EQUAL_RETURN(MFVideoFormat_NV12); // FCC('NV12') + IF_GUID_EQUAL_RETURN(MFVideoFormat_P010); // FCC('P010') + IF_GUID_EQUAL_RETURN(MFVideoFormat_P016); // FCC('P016') + IF_GUID_EQUAL_RETURN(MFVideoFormat_P210); // FCC('P210') + IF_GUID_EQUAL_RETURN(MFVideoFormat_P216); // FCC('P216') + IF_GUID_EQUAL_RETURN(MFVideoFormat_RGB24); // D3DFMT_R8G8B8 + IF_GUID_EQUAL_RETURN(MFVideoFormat_RGB32); // D3DFMT_X8R8G8B8 + IF_GUID_EQUAL_RETURN(MFVideoFormat_RGB555); // D3DFMT_X1R5G5B5 + IF_GUID_EQUAL_RETURN(MFVideoFormat_RGB565); // D3DFMT_R5G6B5 + IF_GUID_EQUAL_RETURN(MFVideoFormat_RGB8); + IF_GUID_EQUAL_RETURN(MFVideoFormat_UYVY); // FCC('UYVY') + IF_GUID_EQUAL_RETURN(MFVideoFormat_v210); // FCC('v210') + IF_GUID_EQUAL_RETURN(MFVideoFormat_v410); // FCC('v410') + IF_GUID_EQUAL_RETURN(MFVideoFormat_WMV1); // FCC('WMV1') + IF_GUID_EQUAL_RETURN(MFVideoFormat_WMV2); // FCC('WMV2') + IF_GUID_EQUAL_RETURN(MFVideoFormat_WMV3); // FCC('WMV3') + IF_GUID_EQUAL_RETURN(MFVideoFormat_WVC1); // FCC('WVC1') + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y210); // FCC('Y210') + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y216); // FCC('Y216') + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y410); // FCC('Y410') + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y416); // FCC('Y416') + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y41P); + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y41T); + IF_GUID_EQUAL_RETURN(MFVideoFormat_YUY2); // FCC('YUY2') + IF_GUID_EQUAL_RETURN(MFVideoFormat_YV12); // FCC('YV12') + IF_GUID_EQUAL_RETURN(MFVideoFormat_YVYU); +#ifdef MFVideoFormat_H263 + IF_GUID_EQUAL_RETURN(MFVideoFormat_H263); +#endif +#ifdef MFVideoFormat_H265 + IF_GUID_EQUAL_RETURN(MFVideoFormat_H265); +#endif +#ifdef MFVideoFormat_H264_ES + IF_GUID_EQUAL_RETURN(MFVideoFormat_H264_ES); +#endif +#ifdef MFVideoFormat_HEVC + IF_GUID_EQUAL_RETURN(MFVideoFormat_HEVC); +#endif +#ifdef MFVideoFormat_HEVC_ES + IF_GUID_EQUAL_RETURN(MFVideoFormat_HEVC_ES); +#endif +#ifdef MFVideoFormat_MPEG2 + IF_GUID_EQUAL_RETURN(MFVideoFormat_MPEG2); +#endif +#ifdef MFVideoFormat_VP80 + IF_GUID_EQUAL_RETURN(MFVideoFormat_VP80); +#endif +#ifdef MFVideoFormat_VP90 + IF_GUID_EQUAL_RETURN(MFVideoFormat_VP90); +#endif +#ifdef MFVideoFormat_420O + IF_GUID_EQUAL_RETURN(MFVideoFormat_420O); +#endif +#ifdef MFVideoFormat_Y42T + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y42T); +#endif +#ifdef MFVideoFormat_YVU9 + IF_GUID_EQUAL_RETURN(MFVideoFormat_YVU9); +#endif +#ifdef MFVideoFormat_v216 + IF_GUID_EQUAL_RETURN(MFVideoFormat_v216); +#endif +#ifdef MFVideoFormat_L8 + IF_GUID_EQUAL_RETURN(MFVideoFormat_L8); +#endif +#ifdef MFVideoFormat_L16 + IF_GUID_EQUAL_RETURN(MFVideoFormat_L16); +#endif +#ifdef MFVideoFormat_D16 + IF_GUID_EQUAL_RETURN(MFVideoFormat_D16); +#endif +#ifdef D3DFMT_X8R8G8B8 + IF_GUID_EQUAL_RETURN(D3DFMT_X8R8G8B8); +#endif +#ifdef D3DFMT_A8R8G8B8 + IF_GUID_EQUAL_RETURN(D3DFMT_A8R8G8B8); +#endif +#ifdef D3DFMT_R8G8B8 + IF_GUID_EQUAL_RETURN(D3DFMT_R8G8B8); +#endif +#ifdef D3DFMT_X1R5G5B5 + IF_GUID_EQUAL_RETURN(D3DFMT_X1R5G5B5); +#endif +#ifdef D3DFMT_A4R4G4B4 + IF_GUID_EQUAL_RETURN(D3DFMT_A4R4G4B4); +#endif +#ifdef D3DFMT_R5G6B5 + IF_GUID_EQUAL_RETURN(D3DFMT_R5G6B5); +#endif +#ifdef D3DFMT_P8 + IF_GUID_EQUAL_RETURN(D3DFMT_P8); +#endif +#ifdef D3DFMT_A2R10G10B10 + IF_GUID_EQUAL_RETURN(D3DFMT_A2R10G10B10); +#endif +#ifdef D3DFMT_A2B10G10R10 + IF_GUID_EQUAL_RETURN(D3DFMT_A2B10G10R10); +#endif +#ifdef D3DFMT_L8 + IF_GUID_EQUAL_RETURN(D3DFMT_L8); +#endif +#ifdef D3DFMT_L16 + IF_GUID_EQUAL_RETURN(D3DFMT_L16); +#endif +#ifdef D3DFMT_D16 + IF_GUID_EQUAL_RETURN(D3DFMT_D16); +#endif +#ifdef MFVideoFormat_A2R10G10B10 + IF_GUID_EQUAL_RETURN(MFVideoFormat_A2R10G10B10); +#endif +#ifdef MFVideoFormat_A16B16G16R16F + IF_GUID_EQUAL_RETURN(MFVideoFormat_A16B16G16R16F); +#endif + IF_GUID_EQUAL_RETURN(MFAudioFormat_PCM); // WAVE_FORMAT_PCM + IF_GUID_EQUAL_RETURN(MFAudioFormat_Float); // WAVE_FORMAT_IEEE_FLOAT + IF_GUID_EQUAL_RETURN(MFAudioFormat_DTS); // WAVE_FORMAT_DTS + IF_GUID_EQUAL_RETURN(MFAudioFormat_Dolby_AC3_SPDIF); // WAVE_FORMAT_DOLBY_AC3_SPDIF + IF_GUID_EQUAL_RETURN(MFAudioFormat_DRM); // WAVE_FORMAT_DRM + IF_GUID_EQUAL_RETURN(MFAudioFormat_WMAudioV8); // WAVE_FORMAT_WMAUDIO2 + IF_GUID_EQUAL_RETURN(MFAudioFormat_WMAudioV9); // WAVE_FORMAT_WMAUDIO3 + IF_GUID_EQUAL_RETURN(MFAudioFormat_WMAudio_Lossless); // WAVE_FORMAT_WMAUDIO_LOSSLESS + IF_GUID_EQUAL_RETURN(MFAudioFormat_WMASPDIF); // WAVE_FORMAT_WMASPDIF + IF_GUID_EQUAL_RETURN(MFAudioFormat_MSP1); // WAVE_FORMAT_WMAVOICE9 + IF_GUID_EQUAL_RETURN(MFAudioFormat_MP3); // WAVE_FORMAT_MPEGLAYER3 + IF_GUID_EQUAL_RETURN(MFAudioFormat_MPEG); // WAVE_FORMAT_MPEG + IF_GUID_EQUAL_RETURN(MFAudioFormat_AAC); // WAVE_FORMAT_MPEG_HEAAC + IF_GUID_EQUAL_RETURN(MFAudioFormat_ADTS); // WAVE_FORMAT_MPEG_ADTS_AAC +#ifdef MFAudioFormat_ALAC + IF_GUID_EQUAL_RETURN(MFAudioFormat_ALAC); +#endif +#ifdef MFAudioFormat_AMR_NB + IF_GUID_EQUAL_RETURN(MFAudioFormat_AMR_NB); +#endif +#ifdef MFAudioFormat_AMR_WB + IF_GUID_EQUAL_RETURN(MFAudioFormat_AMR_WB); +#endif +#ifdef MFAudioFormat_AMR_WP + IF_GUID_EQUAL_RETURN(MFAudioFormat_AMR_WP); +#endif +#ifdef MFAudioFormat_Dolby_AC3 + IF_GUID_EQUAL_RETURN(MFAudioFormat_Dolby_AC3); +#endif +#ifdef MFAudioFormat_Dolby_DDPlus + IF_GUID_EQUAL_RETURN(MFAudioFormat_Dolby_DDPlus); +#endif +#ifdef MFAudioFormat_FLAC + IF_GUID_EQUAL_RETURN(MFAudioFormat_FLAC); +#endif +#ifdef MFAudioFormat_Opus + IF_GUID_EQUAL_RETURN(MFAudioFormat_Opus); +#endif +#ifdef MEDIASUBTYPE_RAW_AAC1 + IF_GUID_EQUAL_RETURN(MEDIASUBTYPE_RAW_AAC1); +#endif +#ifdef MFAudioFormat_Float_SpatialObjects + IF_GUID_EQUAL_RETURN(MFAudioFormat_Float_SpatialObjects); +#endif +#ifdef MFAudioFormat_QCELP + IF_GUID_EQUAL_RETURN(MFAudioFormat_QCELP); +#endif + return NULL; } -FormatReader::FormatReader(void) -{ -} - -MediaType FormatReader::Read(IMFMediaType *pType) -{ - UINT32 count = 0; - MediaType out; - HRESULT hr = pType->LockStore(); - if (FAILED(hr)) - { - return out; - } - hr = pType->GetCount(&count); - if (FAILED(hr)) - { - return out; - } - for (UINT32 i = 0; i < count; i++) - { - hr = LogAttributeValueByIndexNew(pType, i, out); - if (FAILED(hr)) - { - break; - } - } - hr = pType->UnlockStore(); - if (FAILED(hr)) - { - return out; - } - return out; -} - -FormatReader::~FormatReader(void) -{ -} - -#define CHECK_HR(x) if (FAILED(x)) { goto done; } - -ImageGrabberCallback::ImageGrabberCallback(bool synchronous): - m_cRef(1), - ig_RIE(true), - ig_Close(false), - ig_Synchronous(synchronous), - ig_hFrameReady(synchronous ? CreateEvent(NULL, FALSE, FALSE, NULL): 0), - ig_hFrameGrabbed(synchronous ? CreateEvent(NULL, FALSE, FALSE, NULL): 0), - ig_hFinish(CreateEvent(NULL, TRUE, FALSE, NULL)) -{} - -ImageGrabber::ImageGrabber(unsigned int deviceID, bool synchronous): - ImageGrabberCallback(synchronous), - ig_DeviceID(deviceID), - ig_pSource(NULL), - ig_pSession(NULL), - ig_pTopology(NULL) -{} - -ImageGrabber::~ImageGrabber(void) -{ - if (ig_pSession) - { - ig_pSession->Shutdown(); - } - - CloseHandle(ig_hFinish); - - if (ig_Synchronous) - { - CloseHandle(ig_hFrameReady); - CloseHandle(ig_hFrameGrabbed); - } - - SafeRelease(&ig_pSession); - SafeRelease(&ig_pTopology); - - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Destroying instance of the ImageGrabber class\n", ig_DeviceID); -} - -HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource) -{ - // Clean up. - if (ig_pSession) - { - ig_pSession->Shutdown(); - } - SafeRelease(&ig_pSession); - SafeRelease(&ig_pTopology); - - HRESULT hr; - ig_pSource = pSource; - // Configure the media type that the Sample Grabber will receive. - // Setting the major and subtype is usually enough for the topology loader - // to resolve the topology. - _ComPtr pType = NULL; - _ComPtr pSinkActivate = NULL; - CHECK_HR(hr = MFCreateMediaType(pType.GetAddressOf())); - CHECK_HR(hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)); - CHECK_HR(hr = pType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24)); - // Create the sample grabber sink. - CHECK_HR(hr = MFCreateSampleGrabberSinkActivate(pType.Get(), this, pSinkActivate.GetAddressOf())); - // To run as fast as possible, set this attribute (requires Windows 7): - CHECK_HR(hr = pSinkActivate->SetUINT32(MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, TRUE)); - // Create the Media Session. - CHECK_HR(hr = MFCreateMediaSession(NULL, &ig_pSession)); - // Create the topology. - CHECK_HR(hr = CreateTopology(pSource, pSinkActivate.Get(), &ig_pTopology)); - - CHECK_HR(hr = RawImage::CreateInstance(&ig_RIFirst, captureFormat.MF_MT_FRAME_SIZE * 3)); // Expect that output image will be RGB24 thus occupy 3 byte per point - CHECK_HR(hr = RawImage::CreateInstance(&ig_RISecond, captureFormat.MF_MT_FRAME_SIZE * 3)); - ig_RIOut = ig_RISecond; -done: - // Clean up. - if (FAILED(hr)) - { - if (ig_pSession) - { - ig_pSession->Shutdown(); - } - SafeRelease(&ig_pSession); - SafeRelease(&ig_pTopology); - } - return hr; -} - -void ImageGrabber::stopGrabbing() -{ - if(ig_pSession) - ig_pSession->Stop(); - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Stopping of of grabbing of images\n", ig_DeviceID); -} - -HRESULT ImageGrabber::startGrabbing(void) +bool LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, MediaType &out) { PROPVARIANT var; PropVariantInit(&var); - HRESULT hr = ig_pSession->SetTopology(0, ig_pTopology); - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Start Grabbing of the images\n", ig_DeviceID); - hr = ig_pSession->Start(&GUID_NULL, &var); - for(;;) + GUID guid = { 0 }; + if (SUCCEEDED(pAttr->GetItemByIndex(index, &guid, &var))) { - _ComPtr pEvent = NULL; - HRESULT hrStatus = S_OK; - MediaEventType met; - if(!ig_pSession) break; - hr = ig_pSession->GetEvent(0, &pEvent); - if(!SUCCEEDED(hr)) + if (guid == MF_MT_DEFAULT_STRIDE && var.vt == VT_INT) + out.MF_MT_DEFAULT_STRIDE = var.intVal; + else if (guid == MF_MT_FRAME_RATE && var.vt == VT_UI8) + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_FRAME_RATE_NUMERATOR, &out.MF_MT_FRAME_RATE_DENOMINATOR); + else if (guid == MF_MT_FRAME_RATE_RANGE_MAX && var.vt == VT_UI8) + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_FRAME_RATE_RANGE_MAX, &out.MF_MT_FRAME_RATE_RANGE_MAX_low); + else if (guid == MF_MT_FRAME_RATE_RANGE_MIN && var.vt == VT_UI8) + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_FRAME_RATE_RANGE_MIN, &out.MF_MT_FRAME_RATE_RANGE_MIN_low); + else if (guid == MF_MT_PIXEL_ASPECT_RATIO && var.vt == VT_UI8) + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_PIXEL_ASPECT_RATIO, &out.MF_MT_PIXEL_ASPECT_RATIO_low); + else if (guid == MF_MT_YUV_MATRIX && var.vt == VT_UI4) + out.MF_MT_YUV_MATRIX = var.ulVal; + else if (guid == MF_MT_VIDEO_LIGHTING && var.vt == VT_UI4) + out.MF_MT_VIDEO_LIGHTING = var.ulVal; + else if (guid == MF_MT_DEFAULT_STRIDE && var.vt == VT_UI4) + out.MF_MT_DEFAULT_STRIDE = (int)var.ulVal; + else if (guid == MF_MT_VIDEO_CHROMA_SITING && var.vt == VT_UI4) + out.MF_MT_VIDEO_CHROMA_SITING = var.ulVal; + else if (guid == MF_MT_VIDEO_NOMINAL_RANGE && var.vt == VT_UI4) + out.MF_MT_VIDEO_NOMINAL_RANGE = var.ulVal; + else if (guid == MF_MT_ALL_SAMPLES_INDEPENDENT && var.vt == VT_UI4) + out.MF_MT_ALL_SAMPLES_INDEPENDENT = var.ulVal; + else if (guid == MF_MT_FIXED_SIZE_SAMPLES && var.vt == VT_UI4) + out.MF_MT_FIXED_SIZE_SAMPLES = var.ulVal; + else if (guid == MF_MT_SAMPLE_SIZE && var.vt == VT_UI4) + out.MF_MT_SAMPLE_SIZE = var.ulVal; + else if (guid == MF_MT_VIDEO_PRIMARIES && var.vt == VT_UI4) + out.MF_MT_VIDEO_PRIMARIES = var.ulVal; + else if (guid == MF_MT_INTERLACE_MODE && var.vt == VT_UI4) + out.MF_MT_INTERLACE_MODE = var.ulVal; + else if (guid == MF_MT_AM_FORMAT_TYPE && var.vt == VT_CLSID) + out.MF_MT_AM_FORMAT_TYPE = *var.puuid; + else if (guid == MF_MT_MAJOR_TYPE && var.vt == VT_CLSID) + out.pMF_MT_MAJOR_TYPEName = GetGUIDNameConstNew(out.MF_MT_MAJOR_TYPE = *var.puuid); + else if (guid == MF_MT_SUBTYPE && var.vt == VT_CLSID) + out.pMF_MT_SUBTYPEName = GetGUIDNameConstNew(out.MF_MT_SUBTYPE = *var.puuid); + else if (guid == MF_MT_FRAME_SIZE && var.vt == VT_UI8) { - hr = S_OK; - goto done; + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.width, &out.height); + out.MF_MT_FRAME_SIZE = out.width * out.height; } - hr = pEvent->GetStatus(&hrStatus); - if(!SUCCEEDED(hr)) - { - hr = S_OK; - goto done; - } - hr = pEvent->GetType(&met); - if(!SUCCEEDED(hr)) - { - hr = S_OK; - goto done; - } - if (!SUCCEEDED(hrStatus)) - { - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Event Status Error: %u\n", ig_DeviceID, hrStatus); - goto done; - } - if (met == MESessionEnded) - { - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionEnded\n", ig_DeviceID); - ig_pSession->Stop(); - break; - } - if (met == MESessionStopped) - { - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionStopped \n", ig_DeviceID); - break; - } -#if (WINVER >= 0x0602) // Available since Win 8 - if (met == MEVideoCaptureDeviceRemoved) - { - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MEVideoCaptureDeviceRemoved \n", ig_DeviceID); - break; - } -#endif - if ((met == MEError) || (met == MENonFatalError)) - { - pEvent->GetStatus(&hrStatus); - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MEError | MENonFatalError: %u\n", ig_DeviceID, hrStatus); - break; - } - } - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID); - -done: - SetEvent(ig_hFinish); - - return hr; -} - -void ImageGrabberCallback::pauseGrabbing() -{ -} - -void ImageGrabberCallback::resumeGrabbing() -{ -} - -HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo) -{ - HRESULT hr = S_OK; - { // "done:" scope - _ComPtr pPD = NULL; - hr = !pSource ? E_POINTER : S_OK; CHECK_HR(hr); - CHECK_HR(hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf())); - - DWORD cStreams = 0; - CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams)); - DWORD vStream = cStreams; - BOOL vStreamSelected = FALSE; - for (DWORD i = 0; i < cStreams; i++) - { - BOOL fSelected = FALSE; - _ComPtr pSD = NULL; - CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(i, &fSelected, pSD.GetAddressOf())); - - _ComPtr pHandler = NULL; - CHECK_HR(hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf())); - - GUID majorType; - CHECK_HR(hr = pHandler->GetMajorType(&majorType)); - - if (majorType == MFMediaType_Video && !vStreamSelected) - { - if (fSelected) - { - vStream = i; - vStreamSelected = TRUE; - } - else - vStream = i < vStream ? i : vStream; - } - else - { - CHECK_HR(hr = pPD->DeselectStream(i)); - } - } - - if (vStream < cStreams) - { - if (!vStreamSelected) - CHECK_HR(hr = pPD->SelectStream(vStream)); - BOOL fSelected; - _ComPtr pSD = NULL; - CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(vStream, &fSelected, pSD.GetAddressOf())); - - _ComPtr pHandler = NULL; - CHECK_HR(hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf())); - - DWORD cTypes = 0; - CHECK_HR(hr = pHandler->GetMediaTypeCount(&cTypes)); - DWORD j = 0; - for (; j < cTypes; j++) // Iterate throug available video subtypes to find supported and fill MediaType structure - { - _ComPtr pType = NULL; - CHECK_HR(hr = pHandler->GetMediaTypeByIndex(j, pType.GetAddressOf())); - MediaType MT = FormatReader::Read(pType.Get()); - if (MT.MF_MT_MAJOR_TYPE == MFMediaType_Video /*&& MT.MF_MT_SUBTYPE == MFVideoFormat_RGB24*/) - { - captureFormat = MT; - break; - } - } - - if (j < cTypes) // If there is supported video subtype create topology - { - IMFTopology* pTopology = NULL; - _ComPtr pNode1 = NULL; - _ComPtr pNode2 = NULL; - - _ComPtr pNode1c1 = NULL; - _ComPtr pNode1c2 = NULL; - - CHECK_HR(hr = MFCreateTopology(&pTopology)); - CHECK_HR(hr = AddSourceNode(pTopology, pSource, pPD.Get(), pSD.Get(), pNode1.GetAddressOf())); - CHECK_HR(hr = AddOutputNode(pTopology, pSinkActivate, 0, pNode2.GetAddressOf())); - CHECK_HR(hr = pNode1->ConnectOutput(0, pNode2.Get(), 0)); - *ppTopo = pTopology; - (*ppTopo)->AddRef(); - } - else - hr = E_INVALIDARG; - } - else - hr = E_INVALIDARG; - - } // "done:" scope -done: - return hr; -} - -HRESULT ImageGrabber::AddSourceNode( - IMFTopology *pTopology, // Topology. - IMFMediaSource *pSource, // Media source. - IMFPresentationDescriptor *pPD, // Presentation descriptor. - IMFStreamDescriptor *pSD, // Stream descriptor. - IMFTopologyNode **ppNode) // Receives the node pointer. -{ - _ComPtr pNode = NULL; - HRESULT hr = S_OK; - CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, pNode.GetAddressOf())); - CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource)); - CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD)); - CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD)); - CHECK_HR(hr = pTopology->AddNode(pNode.Get())); - // Return the pointer to the caller. - *ppNode = pNode.Get(); - (*ppNode)->AddRef(); - -done: - return hr; -} - -HRESULT ImageGrabber::AddOutputNode( - IMFTopology *pTopology, // Topology. - IMFActivate *pActivate, // Media sink activation object. - DWORD dwId, // Identifier of the stream sink. - IMFTopologyNode **ppNode) // Receives the node pointer. -{ - _ComPtr pNode = NULL; - HRESULT hr = S_OK; - CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, pNode.GetAddressOf())); - CHECK_HR(hr = pNode->SetObject(pActivate)); - CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId)); - CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE)); - CHECK_HR(hr = pTopology->AddNode(pNode.Get())); - // Return the pointer to the caller. - *ppNode = pNode.Get(); - (*ppNode)->AddRef(); - -done: - return hr; -} - -HRESULT ImageGrabber::CreateInstance(ImageGrabber **ppIG, unsigned int deviceID, bool synchronious) -{ - *ppIG = new (std::nothrow) ImageGrabber(deviceID, synchronious); - if (ppIG == NULL) - { - return E_OUTOFMEMORY; - } - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Creating instance of ImageGrabber\n", deviceID); - return S_OK; -} - -STDMETHODIMP ImageGrabber::QueryInterface(REFIID riid, void** ppv) -{ - HRESULT hr = E_NOINTERFACE; - *ppv = NULL; - if(riid == IID_IUnknown || riid == IID_IMFSampleGrabberSinkCallback) - { - *ppv = static_cast(this); - hr = S_OK; - } - if(riid == IID_IMFClockStateSink) - { - *ppv = static_cast(this); - hr = S_OK; - } - if(SUCCEEDED(hr)) - { - reinterpret_cast(*ppv)->AddRef(); - } - return hr; -} - -STDMETHODIMP_(ULONG) ImageGrabber::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - -STDMETHODIMP_(ULONG) ImageGrabber::Release() -{ - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) - { - delete this; - } - return cRef; -} - -STDMETHODIMP ImageGrabberCallback::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) -{ - (void)hnsSystemTime; - (void)llClockStartOffset; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnClockStop(MFTIME hnsSystemTime) -{ - (void)hnsSystemTime; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnClockPause(MFTIME hnsSystemTime) -{ - (void)hnsSystemTime; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnClockRestart(MFTIME hnsSystemTime) -{ - (void)hnsSystemTime; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnClockSetRate(MFTIME hnsSystemTime, float flRate) -{ - (void)flRate; - (void)hnsSystemTime; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnSetPresentationClock(IMFPresentationClock* pClock) -{ - (void)pClock; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags, - LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer, - DWORD dwSampleSize) -{ - (void)guidMajorMediaType; - (void)llSampleTime; - (void)dwSampleFlags; - (void)llSampleDuration; - (void)dwSampleSize; - - HANDLE tmp[] = {ig_hFinish, ig_hFrameGrabbed, NULL}; - - DWORD status = WaitForMultipleObjects(2, tmp, FALSE, INFINITE); - if (status == WAIT_OBJECT_0) - { - DebugPrintOut(L"OnProcessFrame called after ig_hFinish event\n"); - return S_OK; - } - - if(ig_RIE) - { - ig_RIFirst->fastCopy(pSampleBuffer); - ig_RIOut = ig_RIFirst; - } - else - { - ig_RISecond->fastCopy(pSampleBuffer); - ig_RIOut = ig_RISecond; - } - - if (ig_Synchronous) - { - SetEvent(ig_hFrameReady); - } - else - { - ig_RIE = !ig_RIE; - } - - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnShutdown() -{ - SetEvent(ig_hFinish); - return S_OK; -} - -RawImage *ImageGrabberCallback::getRawImage() -{ - return ig_RIOut; -} - -DWORD WINAPI MainThreadFunction( LPVOID lpParam ) -{ - ImageGrabberThread *pIGT = (ImageGrabberThread *)lpParam; - pIGT->run(); - return 0; -} - -HRESULT ImageGrabberThread::CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID, bool synchronious) -{ - *ppIGT = new (std::nothrow) ImageGrabberThread(pSource, deviceID, synchronious); - if (ppIGT == NULL) - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Memory cannot be allocated\n", deviceID); - return E_OUTOFMEMORY; - } - else - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Creating of the instance of ImageGrabberThread\n", deviceID); - return S_OK; -} - -ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID, bool synchronious) : - igt_func(NULL), - igt_Handle(NULL), - igt_stop(false) -{ - HRESULT hr = ImageGrabber::CreateInstance(&igt_pImageGrabber, deviceID, synchronious); - igt_DeviceID = deviceID; - if(SUCCEEDED(hr)) - { - hr = igt_pImageGrabber->initImageGrabber(pSource); - if(!SUCCEEDED(hr)) - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with initialization of the instance of the ImageGrabber class\n", deviceID); - } - else - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Initialization of instance of the ImageGrabber class\n", deviceID); - } - } - else - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with creation of the instance of the ImageGrabber class\n", deviceID); - } -} - -void ImageGrabberThread::setEmergencyStopEvent(void *userData, void(*func)(int, void *)) -{ - if(func) - { - igt_func = func; - igt_userData = userData; - } -} - -ImageGrabberThread::~ImageGrabberThread(void) -{ - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Destroying ImageGrabberThread\n", igt_DeviceID); - if (igt_Handle) - WaitForSingleObject(igt_Handle, INFINITE); - delete igt_pImageGrabber; -} - -void ImageGrabberThread::stop() -{ - igt_stop = true; - if(igt_pImageGrabber) - { - igt_pImageGrabber->stopGrabbing(); - } -} - -void ImageGrabberThread::start() -{ - igt_Handle = CreateThread( - NULL, // default security attributes - 0, // use default stack size - MainThreadFunction, // thread function name - this, // argument to thread function - 0, // use default creation flags - &igt_ThreadIdArray); // returns the thread identifier -} - -void ImageGrabberThread::run() -{ - if(igt_pImageGrabber) - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Thread for grabbing images is started\n", igt_DeviceID); - HRESULT hr = igt_pImageGrabber->startGrabbing(); - if(!SUCCEEDED(hr)) - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with starting the process of grabbing\n", igt_DeviceID); - } - } - else - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i The thread is finished without execution of grabbing\n", igt_DeviceID); - } - if(!igt_stop) - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Emergency Stop thread\n", igt_DeviceID); - if(igt_func) - { - igt_func(igt_DeviceID, igt_userData); - } - } - else - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Finish thread\n", igt_DeviceID); -} - -ImageGrabber *ImageGrabberThread::getImageGrabber() -{ - return igt_pImageGrabber; -} - -RawImage::RawImage(unsigned int size): ri_new(false), ri_pixels(NULL) -{ - ri_size = size; - ri_pixels = new unsigned char[size]; - memset((void *)ri_pixels,0,ri_size); -} - -bool RawImage::isNew() -{ - return ri_new; -} - -unsigned int RawImage::getSize() -{ - return ri_size; -} - -RawImage::~RawImage(void) -{ - delete []ri_pixels; - ri_pixels = NULL; -} - -long RawImage::CreateInstance(RawImage **ppRImage,unsigned int size) -{ - *ppRImage = new (std::nothrow) RawImage(size); - if (ppRImage == NULL) - { - return E_OUTOFMEMORY; - } - return S_OK; -} - -void RawImage::setCopy(const BYTE * pSampleBuffer) -{ - memcpy(ri_pixels, pSampleBuffer, ri_size); - ri_new = true; -} - -void RawImage::fastCopy(const BYTE * pSampleBuffer) -{ - memcpy(ri_pixels, pSampleBuffer, ri_size); - ri_new = true; -} - -unsigned char * RawImage::getpPixels() -{ - ri_new = false; - return ri_pixels; -} - -videoDevice::videoDevice(void): vd_IsSetuped(false), vd_LockOut(OpenLock), vd_pFriendlyName(NULL), - vd_Width(0), vd_Height(0), vd_FrameRate(0), vd_pSource(NULL), vd_pImGrTh(NULL), vd_func(NULL), vd_userData(NULL) -{ -} - -void videoDevice::setParametrs(CamParametrs parametrs) -{ - if(vd_IsSetuped) - { - if(vd_pSource) - { - CamParametrs vd_PrevParametrs = getParametrs(); - Parametr *pParametr = (Parametr *)(¶metrs); - Parametr *pPrevParametr = (Parametr *)(&vd_PrevParametrs); - IAMVideoProcAmp *pProcAmp = NULL; - HRESULT hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcAmp)); - if (SUCCEEDED(hr)) - { - for(unsigned int i = 0; i < 10; i++) - { - if(pPrevParametr[i].CurrentValue != pParametr[i].CurrentValue || pPrevParametr[i].Flag != pParametr[i].Flag) - hr = pProcAmp->Set(VideoProcAmp_Brightness + i, pParametr[i].CurrentValue, pParametr[i].Flag); - } - pProcAmp->Release(); - } - IAMCameraControl *pProcControl = NULL; - hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcControl)); - if (SUCCEEDED(hr)) - { - for(unsigned int i = 0; i < 7; i++) - { - if(pPrevParametr[10 + i].CurrentValue != pParametr[10 + i].CurrentValue || pPrevParametr[10 + i].Flag != pParametr[10 + i].Flag) - hr = pProcControl->Set(CameraControl_Pan+i, pParametr[10 + i].CurrentValue, pParametr[10 + i].Flag); - } - pProcControl->Release(); - } - vd_PrevParametrs = parametrs; - } - } -} - -CamParametrs videoDevice::getParametrs() -{ - CamParametrs out; - if(vd_IsSetuped) - { - if(vd_pSource) - { - Parametr *pParametr = (Parametr *)(&out); - IAMVideoProcAmp *pProcAmp = NULL; - HRESULT hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcAmp)); - if (SUCCEEDED(hr)) - { - for(unsigned int i = 0; i < 10; i++) - { - Parametr temp; - hr = pProcAmp->GetRange(VideoProcAmp_Brightness+i, &temp.Min, &temp.Max, &temp.Step, &temp.Default, &temp.Flag); - if (SUCCEEDED(hr)) - { - temp.CurrentValue = temp.Default; - pParametr[i] = temp; - } - } - pProcAmp->Release(); - } - IAMCameraControl *pProcControl = NULL; - hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcControl)); - if (SUCCEEDED(hr)) - { - for(unsigned int i = 0; i < 7; i++) - { - Parametr temp; - hr = pProcControl->GetRange(CameraControl_Pan+i, &temp.Min, &temp.Max, &temp.Step, &temp.Default, &temp.Flag); - if (SUCCEEDED(hr)) - { - temp.CurrentValue = temp.Default; - pParametr[10 + i] = temp; - } - } - pProcControl->Release(); - } - } - } - return out; -} - -long videoDevice::readInfoOfDevice(IMFActivate *pActivate, unsigned int Num) -{ - vd_CurrentNumber = Num; - HRESULT hr = E_FAIL; - vd_CurrentFormats.clear(); - if (pActivate) - { - SafeRelease(&vd_pSource); - hr = pActivate->ActivateObject( - __uuidof(IMFMediaSource), - (void**)&vd_pSource - ); - if (SUCCEEDED(hr) && vd_pSource) - { - enumerateCaptureFormats(vd_pSource); - buildLibraryofTypes(); - }//end if (SUCCEEDED(hr) && pSource) - else - DebugPrintOut(L"VIDEODEVICE %i: IMFMediaSource interface cannot be created \n", vd_CurrentNumber); - } - return hr; -} - -MediaType videoDevice::getFormat(unsigned int id) -{ - if(id < vd_CurrentFormats.size()) - { - return vd_CurrentFormats[id]; - } - else return MediaType(); -} -int videoDevice::getCountFormats() -{ - return (int)vd_CurrentFormats.size(); -} -void videoDevice::setEmergencyStopEvent(void *userData, void(*func)(int, void *)) -{ - vd_func = func; - vd_userData = userData; -} -void videoDevice::closeDevice() -{ - if(vd_IsSetuped) - { - vd_IsSetuped = false; - - vd_pSource->Shutdown(); - SafeRelease(&vd_pSource); - if(vd_LockOut == RawDataLock) - { - vd_pImGrTh->stop(); - Sleep(500); - delete vd_pImGrTh; - } - vd_pImGrTh = NULL; - vd_LockOut = OpenLock; - DebugPrintOut(L"VIDEODEVICE %i: Device is stopped \n", vd_CurrentNumber); - } -} -unsigned int videoDevice::getWidth() -{ - if(vd_IsSetuped) - return vd_Width; - else - return 0; -} -unsigned int videoDevice::getHeight() -{ - if(vd_IsSetuped) - return vd_Height; - else - return 0; -} - -unsigned int videoDevice::getFrameRate() const -{ - if(vd_IsSetuped) - return vd_FrameRate; - else - return 0; -} - -IMFMediaSource *videoDevice::getMediaSource() -{ - IMFMediaSource *out = NULL; - if(vd_LockOut == OpenLock) - { - vd_LockOut = MediaSourceLock; - out = vd_pSource; - } - return out; -} -int videoDevice::findType(unsigned int size, unsigned int frameRate) -{ - // For required frame size look for the suitable video format. - // If not found, get the format for the largest available frame size. - FrameRateMap FRM; - std::map::const_iterator fmt; - fmt = vd_CaptureFormats.find(size); - if( fmt != vd_CaptureFormats.end() ) - FRM = fmt->second; - else if( !vd_CaptureFormats.empty() ) - FRM = vd_CaptureFormats.rbegin()->second; - - if( FRM.empty() ) - return -1; - - UINT64 frameRateMax = 0; SUBTYPEMap STMMax; - if(frameRate == 0) - { - std::map::iterator f = FRM.begin(); - for(; f != FRM.end(); f++) - { - // Looking for highest possible frame rate. - if((*f).first >= frameRateMax) - { - frameRateMax = (*f).first; - STMMax = (*f).second; - } - } - } - else - { - std::map::iterator f = FRM.begin(); - for(; f != FRM.end(); f++) - { - // Looking for frame rate higher that recently found but not higher then demanded. - if( (*f).first >= frameRateMax && (*f).first <= frameRate ) - { - frameRateMax = (*f).first; - STMMax = (*f).second; - } - } - } - // Get first (default) item from the list if no suitable frame rate found. - if( STMMax.empty() ) - STMMax = FRM.begin()->second; - - // Check if there are any format types on the list. - if( STMMax.empty() ) - return -1; - - vectorNum VN = STMMax.begin()->second; - if( VN.empty() ) - return -1; - - return VN[0]; -} - -void videoDevice::buildLibraryofTypes() -{ - unsigned int size; - unsigned int framerate; - std::vector::iterator i = vd_CurrentFormats.begin(); - int count = 0; - for(; i != vd_CurrentFormats.end(); i++) - { - // Count only supported video formats. - if( (*i).MF_MT_SUBTYPE == MFVideoFormat_RGB24 || (*i).MF_MT_SUBTYPE == MFVideoFormat_NV12 ) - { - size = (*i).MF_MT_FRAME_SIZE; - framerate = (*i).MF_MT_FRAME_RATE_NUMERATOR / (*i).MF_MT_FRAME_RATE_DENOMINATOR; - FrameRateMap FRM = vd_CaptureFormats[size]; - SUBTYPEMap STM = FRM[framerate]; - String subType((*i).pMF_MT_SUBTYPEName); - vectorNum VN = STM[subType]; - VN.push_back(count); - STM[subType] = VN; - FRM[framerate] = STM; - vd_CaptureFormats[size] = FRM; - } - count++; - } -} - -long videoDevice::setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex) -{ - _ComPtr pPD = NULL; - _ComPtr pSD = NULL; - _ComPtr pHandler = NULL; - _ComPtr pType = NULL; - HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - BOOL fSelected; - hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, pSD.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - hr = pHandler->GetMediaTypeByIndex((DWORD)dwFormatIndex, pType.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - hr = pHandler->SetCurrentMediaType(pType.Get()); - -done: - return hr; -} - -bool videoDevice::isDeviceSetup() -{ - return vd_IsSetuped; -} - -RawImage * videoDevice::getRawImageOut() -{ - if(!vd_IsSetuped) return NULL; - if(vd_pImGrTh) - return vd_pImGrTh->getImageGrabber()->getRawImage(); - else - { - DebugPrintOut(L"VIDEODEVICE %i: The instance of ImageGrabberThread class does not exist \n", vd_CurrentNumber); - } - return NULL; -} - -bool videoDevice::isFrameNew() -{ - if(!vd_IsSetuped) return false; - if(vd_LockOut == RawDataLock || vd_LockOut == OpenLock) - { - if(vd_LockOut == OpenLock) - { - vd_LockOut = RawDataLock; - - //must already be closed - HRESULT hr = ImageGrabberThread::CreateInstance(&vd_pImGrTh, vd_pSource, vd_CurrentNumber); - if(FAILED(hr)) - { - DebugPrintOut(L"VIDEODEVICE %i: The instance of ImageGrabberThread class cannot be created.\n", vd_CurrentNumber); - return false; - } - vd_pImGrTh->setEmergencyStopEvent(vd_userData, vd_func); - vd_pImGrTh->start(); - return true; - } - if(vd_pImGrTh) - return vd_pImGrTh->getImageGrabber()->getRawImage()->isNew(); + PropVariantClear(&var); + return true; } return false; } -bool videoDevice::isDeviceMediaSource() -{ - if(vd_LockOut == MediaSourceLock) return true; - return false; -} - -bool videoDevice::isDeviceRawDataSource() -{ - if(vd_LockOut == RawDataLock) return true; - return false; -} - -bool videoDevice::setupDevice(unsigned int id) -{ - if(!vd_IsSetuped) - { - HRESULT hr; - vd_Width = vd_CurrentFormats[id].width; - vd_Height = vd_CurrentFormats[id].height; - vd_FrameRate = vd_CurrentFormats[id].MF_MT_FRAME_RATE_NUMERATOR / - vd_CurrentFormats[id].MF_MT_FRAME_RATE_DENOMINATOR; - hr = setDeviceFormat(vd_pSource, (DWORD) id); - vd_IsSetuped = (SUCCEEDED(hr)); - if(vd_IsSetuped) - DebugPrintOut(L"\n\nVIDEODEVICE %i: Device is setuped \n", vd_CurrentNumber); - return vd_IsSetuped; - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: Device is setuped already \n", vd_CurrentNumber); - return false; - } -} - -bool videoDevice::setupDevice(unsigned int w, unsigned int h, unsigned int idealFramerate) -{ - int id = findType(w * h, idealFramerate); - if( id < 0 ) - return false; - - return setupDevice(id); -} - -videoDevice::~videoDevice(void) -{ - closeDevice(); - SafeRelease(&vd_pSource); - if(vd_pFriendlyName) - CoTaskMemFree(vd_pFriendlyName); -} - -HRESULT videoDevice::enumerateCaptureFormats(IMFMediaSource *pSource) -{ - HRESULT hr = S_OK; - { // "done:" scope - - _ComPtr pPD = NULL; - _ComPtr pSD = NULL; - _ComPtr pHandler = NULL; - _ComPtr pType = NULL; - hr = !pSource ? E_POINTER : S_OK; - if (FAILED(hr)) - { - goto done; - } - hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - BOOL fSelected; - hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, pSD.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - DWORD cTypes = 0; - hr = pHandler->GetMediaTypeCount(&cTypes); - if (FAILED(hr)) - { - goto done; - } - for (DWORD i = 0; i < cTypes; i++) - { - hr = pHandler->GetMediaTypeByIndex(i, pType.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - MediaType MT = FormatReader::Read(pType.Get()); - vd_CurrentFormats.push_back(MT); - } - - } // "done:" scope -done: - return hr; -} - -videoDevices::videoDevices(void) -{ - DebugPrintOut(L"\n***** VIDEOINPUT LIBRARY - 2013 (Author: Evgeny Pereguda) *****\n\n"); -} - -videoDevices::~videoDevices(void) -{ - DebugPrintOut(L"\n***** CLOSE VIDEOINPUT LIBRARY - 2013 *****\n\n"); -} - -cv::Ptr videoDevices::getDevice(unsigned int i, bool fallback) -{ - static videoDevices instance; - - cv::Ptr res; - - _ComPtr pAttributes = NULL; - if (SUCCEEDED(MFCreateAttributes(pAttributes.GetAddressOf(), 1)) && - SUCCEEDED(pAttributes->SetGUID( - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID - ))) - { - IMFActivate **ppDevices = NULL; - UINT32 count; - if (SUCCEEDED(MFEnumDeviceSources(pAttributes.Get(), &ppDevices, &count))) - { - if (count > 0) - { - if (fallback) - i = std::min(std::max(0U, i), count - 1); - - for (UINT32 ind = 0; ind < count; ind++) - { - if (ind == i) - { - res = cv::Ptr(new videoDevice); - res->readInfoOfDevice(ppDevices[ind], ind); - res->setupDevice(0, 0, 0); - if (!res->isDeviceSetup() || !res->isFrameNew()) - res.release(); - } - SafeRelease(&ppDevices[ind]); - } - } - } - else - DebugPrintOut(L"VIDEODEVICES: The instances of the videoDevice class cannot be created\n"); - CoTaskMemFree(ppDevices); - } - - if (res.empty()) - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", i); - return res; -} - -Parametr::Parametr() -{ - CurrentValue = 0; - Min = 0; - Max = 0; - Step = 0; - Default = 0; - Flag = 0; -} - MediaType::MediaType() { - pMF_MT_AM_FORMAT_TYPEName = NULL; pMF_MT_MAJOR_TYPEName = NULL; pMF_MT_SUBTYPEName = NULL; Clear(); } +MediaType::MediaType(IMFMediaType *pType) +{ + UINT32 count = 0; + if (SUCCEEDED(pType->GetCount(&count)) && + SUCCEEDED(pType->LockStore())) + { + for (UINT32 i = 0; i < count; i++) + if (!LogAttributeValueByIndexNew(pType, i, *this)) + break; + pType->UnlockStore(); + } +} + MediaType::~MediaType() { Clear(); @@ -2067,7 +864,7 @@ bool CvCaptureCAM_MSMF::configureOutput(unsigned int width, unsigned int height, } else if (SUCCEEDED(hr)) { - MediaType MT = FormatReader::Read(pType.Get()); + MediaType MT(pType.Get()); if (MT.MF_MT_MAJOR_TYPE == MFMediaType_Video) { if (dwStreamFallback < 0 || @@ -2160,7 +957,8 @@ bool CvCaptureCAM_MSMF::open(int _index) configureOutput(0, 0, 0); } } - SafeRelease(&ppDevices[ind]); + if (ppDevices[ind]) + ppDevices[ind]->Release(); } } } @@ -2407,7 +1205,7 @@ bool CvCaptureFile_MSMF::open(const char* filename) } else if (SUCCEEDED(hr)) { - MediaType MT = FormatReader::Read(pType.Get()); + MediaType MT(pType.Get()); if (MT.MF_MT_MAJOR_TYPE == MFMediaType_Video) { captureFormat = MT; diff --git a/modules/videoio/src/cap_msmf.hpp b/modules/videoio/src/cap_msmf.hpp index 04aa3b9806..e69de29bb2 100644 --- a/modules/videoio/src/cap_msmf.hpp +++ b/modules/videoio/src/cap_msmf.hpp @@ -1,2504 +0,0 @@ -EXTERN_C const IID IID_ICustomStreamSink; - -class DECLSPEC_UUID("4F8A1939-2FD3-46DB-AE70-DB7E0DD79B73") DECLSPEC_NOVTABLE ICustomStreamSink : public IUnknown -{ -public: - virtual HRESULT Initialize() = 0; - virtual HRESULT Shutdown() = 0; - virtual HRESULT Start(MFTIME start) = 0; - virtual HRESULT Pause() = 0; - virtual HRESULT Restart() = 0; - virtual HRESULT Stop() = 0; -}; - -#define MF_PROP_SAMPLEGRABBERCALLBACK L"samplegrabbercallback" -#define MF_PROP_VIDTYPE L"vidtype" -#define MF_PROP_VIDENCPROPS L"videncprops" - -#include - -// MF_MEDIASINK_SAMPLEGRABBERCALLBACK: {26957AA7-AFF4-464c-BB8B-07BA65CE11DF} -// Type: IUnknown* -DEFINE_GUID(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, - 0x26957aa7, 0xaff4, 0x464c, 0xbb, 0x8b, 0x7, 0xba, 0x65, 0xce, 0x11, 0xdf); - -// {4BD133CC-EB9B-496E-8865-0813BFBC6FAA} -DEFINE_GUID(MF_STREAMSINK_ID, 0x4bd133cc, 0xeb9b, 0x496e, 0x88, 0x65, 0x8, 0x13, 0xbf, 0xbc, 0x6f, 0xaa); - -// {C9E22A8C-6A50-4D78-9183-0834A02A3780} -DEFINE_GUID(MF_STREAMSINK_MEDIASINKINTERFACE, - 0xc9e22a8c, 0x6a50, 0x4d78, 0x91, 0x83, 0x8, 0x34, 0xa0, 0x2a, 0x37, 0x80); - -// {DABD13AB-26B7-47C2-97C1-4B04C187B838} -DEFINE_GUID(MF_MEDIASINK_PREFERREDTYPE, - 0xdabd13ab, 0x26b7, 0x47c2, 0x97, 0xc1, 0x4b, 0x4, 0xc1, 0x87, 0xb8, 0x38); - -#include -#ifdef _UNICODE -#define MAKE_MAP(e) std::map -#define MAKE_ENUM(e) std::pair -#define MAKE_ENUM_PAIR(e, str) std::pair(str, L#str) -#else -#define MAKE_MAP(e) std::map -#define MAKE_ENUM(e) std::pair -#define MAKE_ENUM_PAIR(e, str) std::pair(str, #str) -#endif - -MAKE_ENUM(MediaEventType) MediaEventTypePairs[] = { - MAKE_ENUM_PAIR(MediaEventType, MEUnknown), - MAKE_ENUM_PAIR(MediaEventType, MEError), - MAKE_ENUM_PAIR(MediaEventType, MEExtendedType), - MAKE_ENUM_PAIR(MediaEventType, MENonFatalError), - MAKE_ENUM_PAIR(MediaEventType, MEGenericV1Anchor), - MAKE_ENUM_PAIR(MediaEventType, MESessionUnknown), - MAKE_ENUM_PAIR(MediaEventType, MESessionTopologySet), - MAKE_ENUM_PAIR(MediaEventType, MESessionTopologiesCleared), - MAKE_ENUM_PAIR(MediaEventType, MESessionStarted), - MAKE_ENUM_PAIR(MediaEventType, MESessionPaused), - MAKE_ENUM_PAIR(MediaEventType, MESessionStopped), - MAKE_ENUM_PAIR(MediaEventType, MESessionClosed), - MAKE_ENUM_PAIR(MediaEventType, MESessionEnded), - MAKE_ENUM_PAIR(MediaEventType, MESessionRateChanged), - MAKE_ENUM_PAIR(MediaEventType, MESessionScrubSampleComplete), - MAKE_ENUM_PAIR(MediaEventType, MESessionCapabilitiesChanged), - MAKE_ENUM_PAIR(MediaEventType, MESessionTopologyStatus), - MAKE_ENUM_PAIR(MediaEventType, MESessionNotifyPresentationTime), - MAKE_ENUM_PAIR(MediaEventType, MENewPresentation), - MAKE_ENUM_PAIR(MediaEventType, MELicenseAcquisitionStart), - MAKE_ENUM_PAIR(MediaEventType, MELicenseAcquisitionCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEIndividualizationStart), - MAKE_ENUM_PAIR(MediaEventType, MEIndividualizationCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEEnablerProgress), - MAKE_ENUM_PAIR(MediaEventType, MEEnablerCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEPolicyError), - MAKE_ENUM_PAIR(MediaEventType, MEPolicyReport), - MAKE_ENUM_PAIR(MediaEventType, MEBufferingStarted), - MAKE_ENUM_PAIR(MediaEventType, MEBufferingStopped), - MAKE_ENUM_PAIR(MediaEventType, MEConnectStart), - MAKE_ENUM_PAIR(MediaEventType, MEConnectEnd), - MAKE_ENUM_PAIR(MediaEventType, MEReconnectStart), - MAKE_ENUM_PAIR(MediaEventType, MEReconnectEnd), - MAKE_ENUM_PAIR(MediaEventType, MERendererEvent), - MAKE_ENUM_PAIR(MediaEventType, MESessionStreamSinkFormatChanged), - MAKE_ENUM_PAIR(MediaEventType, MESessionV1Anchor), - MAKE_ENUM_PAIR(MediaEventType, MESourceUnknown), - MAKE_ENUM_PAIR(MediaEventType, MESourceStarted), - MAKE_ENUM_PAIR(MediaEventType, MEStreamStarted), - MAKE_ENUM_PAIR(MediaEventType, MESourceSeeked), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSeeked), - MAKE_ENUM_PAIR(MediaEventType, MENewStream), - MAKE_ENUM_PAIR(MediaEventType, MEUpdatedStream), - MAKE_ENUM_PAIR(MediaEventType, MESourceStopped), - MAKE_ENUM_PAIR(MediaEventType, MEStreamStopped), - MAKE_ENUM_PAIR(MediaEventType, MESourcePaused), - MAKE_ENUM_PAIR(MediaEventType, MEStreamPaused), - MAKE_ENUM_PAIR(MediaEventType, MEEndOfPresentation), - MAKE_ENUM_PAIR(MediaEventType, MEEndOfStream), - MAKE_ENUM_PAIR(MediaEventType, MEMediaSample), - MAKE_ENUM_PAIR(MediaEventType, MEStreamTick), - MAKE_ENUM_PAIR(MediaEventType, MEStreamThinMode), - MAKE_ENUM_PAIR(MediaEventType, MEStreamFormatChanged), - MAKE_ENUM_PAIR(MediaEventType, MESourceRateChanged), - MAKE_ENUM_PAIR(MediaEventType, MEEndOfPresentationSegment), - MAKE_ENUM_PAIR(MediaEventType, MESourceCharacteristicsChanged), - MAKE_ENUM_PAIR(MediaEventType, MESourceRateChangeRequested), - MAKE_ENUM_PAIR(MediaEventType, MESourceMetadataChanged), - MAKE_ENUM_PAIR(MediaEventType, MESequencerSourceTopologyUpdated), - MAKE_ENUM_PAIR(MediaEventType, MESourceV1Anchor), - MAKE_ENUM_PAIR(MediaEventType, MESinkUnknown), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkStarted), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkStopped), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkPaused), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkRateChanged), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkRequestSample), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkMarker), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkPrerolled), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkScrubSampleComplete), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkFormatChanged), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkDeviceChanged), - MAKE_ENUM_PAIR(MediaEventType, MEQualityNotify), - MAKE_ENUM_PAIR(MediaEventType, MESinkInvalidated), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionNameChanged), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionVolumeChanged), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionDeviceRemoved), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionServerShutdown), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionGroupingParamChanged), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionIconChanged), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionFormatChanged), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionDisconnected), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionExclusiveModeOverride), - MAKE_ENUM_PAIR(MediaEventType, MESinkV1Anchor), -#if (WINVER >= 0x0602) // Available since Win 8 - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionVolumeChanged), - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionDeviceRemoved), - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionFormatChanged), - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionDisconnected), - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionExclusiveModeOverride), - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionServerShutdown), - MAKE_ENUM_PAIR(MediaEventType, MESinkV2Anchor), -#endif - MAKE_ENUM_PAIR(MediaEventType, METrustUnknown), - MAKE_ENUM_PAIR(MediaEventType, MEPolicyChanged), - MAKE_ENUM_PAIR(MediaEventType, MEContentProtectionMessage), - MAKE_ENUM_PAIR(MediaEventType, MEPolicySet), - MAKE_ENUM_PAIR(MediaEventType, METrustV1Anchor), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseBackupCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseBackupProgress), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseRestoreCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseRestoreProgress), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseAcquisitionCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMIndividualizationCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMIndividualizationProgress), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMProximityCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseStoreCleaned), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMRevocationDownloadCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMV1Anchor), - MAKE_ENUM_PAIR(MediaEventType, METransformUnknown), - MAKE_ENUM_PAIR(MediaEventType, METransformNeedInput), - MAKE_ENUM_PAIR(MediaEventType, METransformHaveOutput), - MAKE_ENUM_PAIR(MediaEventType, METransformDrainComplete), - MAKE_ENUM_PAIR(MediaEventType, METransformMarker), -#if (WINVER >= 0x0602) // Available since Win 8 - MAKE_ENUM_PAIR(MediaEventType, MEByteStreamCharacteristicsChanged), - MAKE_ENUM_PAIR(MediaEventType, MEVideoCaptureDeviceRemoved), - MAKE_ENUM_PAIR(MediaEventType, MEVideoCaptureDevicePreempted), -#endif - MAKE_ENUM_PAIR(MediaEventType, MEReservedMax) -}; -MAKE_MAP(MediaEventType) MediaEventTypeMap(MediaEventTypePairs, MediaEventTypePairs + sizeof(MediaEventTypePairs) / sizeof(MediaEventTypePairs[0])); - -MAKE_ENUM(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypePairs[] = { - MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_DEFAULT), - MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_ENDOFSEGMENT), - MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_TICK), - MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_EVENT) -}; -MAKE_MAP(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypeMap(StreamSinkMarkerTypePairs, StreamSinkMarkerTypePairs + sizeof(StreamSinkMarkerTypePairs) / sizeof(StreamSinkMarkerTypePairs[0])); - - -#define _COM_SMARTPTR_DECLARE(T,var) T ## Ptr var - -template -class ComPtr -{ -public: - ComPtr() throw() - { - } - ComPtr(T* lp) throw() - { - p = lp; - } - ComPtr(_In_ const ComPtr& lp) throw() - { - p = lp.p; - } - virtual ~ComPtr() - { - } - - T** operator&() throw() - { - assert(p == NULL); - return p.operator&(); - } - T* operator->() const throw() - { - assert(p != NULL); - return p.operator->(); - } - bool operator!() const throw() - { - return p.operator==(NULL); - } - bool operator==(_In_opt_ T* pT) const throw() - { - return p.operator==(pT); - } - bool operator!=(_In_opt_ T* pT) const throw() - { - return p.operator!=(pT); - } - operator bool() - { - return p.operator!=(NULL); - } - - T* const* GetAddressOf() const throw() - { - return &p; - } - - T** GetAddressOf() throw() - { - return &p; - } - - T** ReleaseAndGetAddressOf() throw() - { - p.Release(); - return &p; - } - - T* Get() const throw() - { - return p; - } - - // Attach to an existing interface (does not AddRef) - void Attach(_In_opt_ T* p2) throw() - { - p.Attach(p2); - } - // Detach the interface (does not Release) - T* Detach() throw() - { - return p.Detach(); - } - _Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT) throw() - { - assert(ppT != NULL); - if (ppT == NULL) - return E_POINTER; - *ppT = p; - if (p != NULL) - p->AddRef(); - return S_OK; - } - - void Reset() - { - p.Release(); - } - - // query for U interface - template - HRESULT As(_Inout_ U** lp) const throw() - { - return p->QueryInterface(__uuidof(U), reinterpret_cast(lp)); - } - // query for U interface - template - HRESULT As(_Out_ ComPtr* lp) const throw() - { - return p->QueryInterface(__uuidof(U), reinterpret_cast(lp->ReleaseAndGetAddressOf())); - } -private: - _COM_SMARTPTR_TYPEDEF(T, __uuidof(T)); - _COM_SMARTPTR_DECLARE(T, p); -}; - -#define _ComPtr ComPtr - -template -class CBaseAttributes : public TBase -{ -protected: - // This version of the constructor does not initialize the - // attribute store. The derived class must call Initialize() in - // its own constructor. - CBaseAttributes() - { - } - - // This version of the constructor initializes the attribute - // store, but the derived class must pass an HRESULT parameter - // to the constructor. - - CBaseAttributes(HRESULT& hr, UINT32 cInitialSize = 0) - { - hr = Initialize(cInitialSize); - } - - // The next version of the constructor uses a caller-provided - // implementation of IMFAttributes. - - // (Sometimes you want to delegate IMFAttributes calls to some - // other object that implements IMFAttributes, rather than using - // MFCreateAttributes.) - - CBaseAttributes(HRESULT& hr, IUnknown *pUnk) - { - hr = Initialize(pUnk); - } - - virtual ~CBaseAttributes() - { - } - - // Initializes the object by creating the standard Media Foundation attribute store. - HRESULT Initialize(UINT32 cInitialSize = 0) - { - if (_spAttributes.Get() == nullptr) - { - return MFCreateAttributes(&_spAttributes, cInitialSize); - } - else - { - return S_OK; - } - } - - // Initializes this object from a caller-provided attribute store. - // pUnk: Pointer to an object that exposes IMFAttributes. - HRESULT Initialize(IUnknown *pUnk) - { - if (_spAttributes) - { - _spAttributes.Reset(); - _spAttributes = nullptr; - } - - - return pUnk->QueryInterface(IID_PPV_ARGS(&_spAttributes)); - } - -public: - - // IMFAttributes methods - - STDMETHODIMP GetItem(REFGUID guidKey, PROPVARIANT* pValue) - { - assert(_spAttributes); - return _spAttributes->GetItem(guidKey, pValue); - } - - STDMETHODIMP GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType) - { - assert(_spAttributes); - return _spAttributes->GetItemType(guidKey, pType); - } - - STDMETHODIMP CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult) - { - assert(_spAttributes); - return _spAttributes->CompareItem(guidKey, Value, pbResult); - } - - STDMETHODIMP Compare( - IMFAttributes* pTheirs, - MF_ATTRIBUTES_MATCH_TYPE MatchType, - BOOL* pbResult - ) - { - assert(_spAttributes); - return _spAttributes->Compare(pTheirs, MatchType, pbResult); - } - - STDMETHODIMP GetUINT32(REFGUID guidKey, UINT32* punValue) - { - assert(_spAttributes); - return _spAttributes->GetUINT32(guidKey, punValue); - } - - STDMETHODIMP GetUINT64(REFGUID guidKey, UINT64* punValue) - { - assert(_spAttributes); - return _spAttributes->GetUINT64(guidKey, punValue); - } - - STDMETHODIMP GetDouble(REFGUID guidKey, double* pfValue) - { - assert(_spAttributes); - return _spAttributes->GetDouble(guidKey, pfValue); - } - - STDMETHODIMP GetGUID(REFGUID guidKey, GUID* pguidValue) - { - assert(_spAttributes); - return _spAttributes->GetGUID(guidKey, pguidValue); - } - - STDMETHODIMP GetStringLength(REFGUID guidKey, UINT32* pcchLength) - { - assert(_spAttributes); - return _spAttributes->GetStringLength(guidKey, pcchLength); - } - - STDMETHODIMP GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength) - { - assert(_spAttributes); - return _spAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength); - } - - STDMETHODIMP GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength) - { - assert(_spAttributes); - return _spAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength); - } - - STDMETHODIMP GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize) - { - assert(_spAttributes); - return _spAttributes->GetBlobSize(guidKey, pcbBlobSize); - } - - STDMETHODIMP GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize) - { - assert(_spAttributes); - return _spAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize); - } - - STDMETHODIMP GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize) - { - assert(_spAttributes); - return _spAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize); - } - - STDMETHODIMP GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv) - { - assert(_spAttributes); - return _spAttributes->GetUnknown(guidKey, riid, ppv); - } - - STDMETHODIMP SetItem(REFGUID guidKey, REFPROPVARIANT Value) - { - assert(_spAttributes); - return _spAttributes->SetItem(guidKey, Value); - } - - STDMETHODIMP DeleteItem(REFGUID guidKey) - { - assert(_spAttributes); - return _spAttributes->DeleteItem(guidKey); - } - - STDMETHODIMP DeleteAllItems() - { - assert(_spAttributes); - return _spAttributes->DeleteAllItems(); - } - - STDMETHODIMP SetUINT32(REFGUID guidKey, UINT32 unValue) - { - assert(_spAttributes); - return _spAttributes->SetUINT32(guidKey, unValue); - } - - STDMETHODIMP SetUINT64(REFGUID guidKey,UINT64 unValue) - { - assert(_spAttributes); - return _spAttributes->SetUINT64(guidKey, unValue); - } - - STDMETHODIMP SetDouble(REFGUID guidKey, double fValue) - { - assert(_spAttributes); - return _spAttributes->SetDouble(guidKey, fValue); - } - - STDMETHODIMP SetGUID(REFGUID guidKey, REFGUID guidValue) - { - assert(_spAttributes); - return _spAttributes->SetGUID(guidKey, guidValue); - } - - STDMETHODIMP SetString(REFGUID guidKey, LPCWSTR wszValue) - { - assert(_spAttributes); - return _spAttributes->SetString(guidKey, wszValue); - } - - STDMETHODIMP SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize) - { - assert(_spAttributes); - return _spAttributes->SetBlob(guidKey, pBuf, cbBufSize); - } - - STDMETHODIMP SetUnknown(REFGUID guidKey, IUnknown* pUnknown) - { - assert(_spAttributes); - return _spAttributes->SetUnknown(guidKey, pUnknown); - } - - STDMETHODIMP LockStore() - { - assert(_spAttributes); - return _spAttributes->LockStore(); - } - - STDMETHODIMP UnlockStore() - { - assert(_spAttributes); - return _spAttributes->UnlockStore(); - } - - STDMETHODIMP GetCount(UINT32* pcItems) - { - assert(_spAttributes); - return _spAttributes->GetCount(pcItems); - } - - STDMETHODIMP GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue) - { - assert(_spAttributes); - return _spAttributes->GetItemByIndex(unIndex, pguidKey, pValue); - } - - STDMETHODIMP CopyAllItems(IMFAttributes* pDest) - { - assert(_spAttributes); - return _spAttributes->CopyAllItems(pDest); - } - - // Helper functions - - HRESULT SerializeToStream(DWORD dwOptions, IStream* pStm) - // dwOptions: Flags from MF_ATTRIBUTE_SERIALIZE_OPTIONS - { - assert(_spAttributes); - return MFSerializeAttributesToStream(_spAttributes.Get(), dwOptions, pStm); - } - - HRESULT DeserializeFromStream(DWORD dwOptions, IStream* pStm) - { - assert(_spAttributes); - return MFDeserializeAttributesFromStream(_spAttributes.Get(), dwOptions, pStm); - } - - // SerializeToBlob: Stores the attributes in a byte array. - // - // ppBuf: Receives a pointer to the byte array. - // pcbSize: Receives the size of the byte array. - // - // The caller must free the array using CoTaskMemFree. - HRESULT SerializeToBlob(UINT8 **ppBuffer, UINT *pcbSize) - { - assert(_spAttributes); - - if (ppBuffer == NULL) - { - return E_POINTER; - } - if (pcbSize == NULL) - { - return E_POINTER; - } - - HRESULT hr = S_OK; - UINT32 cbSize = 0; - BYTE *pBuffer = NULL; - - CHECK_HR(hr = MFGetAttributesAsBlobSize(_spAttributes.Get(), &cbSize)); - - pBuffer = (BYTE*)CoTaskMemAlloc(cbSize); - if (pBuffer == NULL) - { - CHECK_HR(hr = E_OUTOFMEMORY); - } - - CHECK_HR(hr = MFGetAttributesAsBlob(_spAttributes.Get(), pBuffer, cbSize)); - - *ppBuffer = pBuffer; - *pcbSize = cbSize; - -done: - if (FAILED(hr)) - { - *ppBuffer = NULL; - *pcbSize = 0; - CoTaskMemFree(pBuffer); - } - return hr; - } - - HRESULT DeserializeFromBlob(const UINT8* pBuffer, UINT cbSize) - { - assert(_spAttributes); - return MFInitAttributesFromBlob(_spAttributes.Get(), pBuffer, cbSize); - } - - HRESULT GetRatio(REFGUID guidKey, UINT32* pnNumerator, UINT32* punDenominator) - { - assert(_spAttributes); - return MFGetAttributeRatio(_spAttributes.Get(), guidKey, pnNumerator, punDenominator); - } - - HRESULT SetRatio(REFGUID guidKey, UINT32 unNumerator, UINT32 unDenominator) - { - assert(_spAttributes); - return MFSetAttributeRatio(_spAttributes.Get(), guidKey, unNumerator, unDenominator); - } - - // Gets an attribute whose value represents the size of something (eg a video frame). - HRESULT GetSize(REFGUID guidKey, UINT32* punWidth, UINT32* punHeight) - { - assert(_spAttributes); - return MFGetAttributeSize(_spAttributes.Get(), guidKey, punWidth, punHeight); - } - - // Sets an attribute whose value represents the size of something (eg a video frame). - HRESULT SetSize(REFGUID guidKey, UINT32 unWidth, UINT32 unHeight) - { - assert(_spAttributes); - return MFSetAttributeSize (_spAttributes.Get(), guidKey, unWidth, unHeight); - } - -protected: - _ComPtr _spAttributes; -}; - -class StreamSink : - public IMFStreamSink, - public IMFMediaTypeHandler, - public CBaseAttributes<>, - public ICustomStreamSink -{ -public: - // IUnknown methods -#if defined(_MSC_VER) && _MSC_VER >= 1700 // '_Outptr_result_nullonfailure_' SAL is avaialable since VS 2012 - STDMETHOD(QueryInterface)(REFIID riid, _Outptr_result_nullonfailure_ void **ppv) -#else - STDMETHOD(QueryInterface)(REFIID riid, void **ppv) -#endif - { - if (ppv == nullptr) { - return E_POINTER; - } - (*ppv) = nullptr; - HRESULT hr = S_OK; - if (riid == IID_IMarshal) { - return MarshalQI(riid, ppv); - } else { - if (riid == IID_IUnknown || riid == IID_IMFStreamSink) { - *ppv = static_cast(this); - AddRef(); - } else if (riid == IID_IMFMediaEventGenerator) { - *ppv = static_cast(this); - AddRef(); - } else if (riid == IID_IMFMediaTypeHandler) { - *ppv = static_cast(this); - AddRef(); - } else if (riid == IID_IMFAttributes) { - *ppv = static_cast(this); - AddRef(); - } else if (riid == IID_ICustomStreamSink) { - *ppv = static_cast(this); - AddRef(); - } else - hr = E_NOINTERFACE; - } - - return hr; - } - - ULONG STDMETHODCALLTYPE AddRef() - { - return InterlockedIncrement(&m_cRef); - } - ULONG STDMETHODCALLTYPE Release() - { - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) - { - delete this; - } - return cRef; - } - HRESULT MarshalQI(REFIID riid, LPVOID* ppv) - { - HRESULT hr = S_OK; - if (m_spFTM == nullptr) { - EnterCriticalSection(&m_critSec); - if (m_spFTM == nullptr) { - hr = CoCreateFreeThreadedMarshaler((IMFStreamSink*)this, &m_spFTM); - } - LeaveCriticalSection(&m_critSec); - } - - if (SUCCEEDED(hr)) { - if (m_spFTM == nullptr) { - hr = E_UNEXPECTED; - } - else { - hr = m_spFTM.Get()->QueryInterface(riid, ppv); - } - } - return hr; - } - enum State - { - State_TypeNotSet = 0, // No media type is set - State_Ready, // Media type is set, Start has never been called. - State_Started, - State_Stopped, - State_Paused, - State_Count // Number of states - }; - StreamSink() : m_IsShutdown(false), - m_StartTime(0), m_fGetStartTimeFromSample(false), m_fWaitingForFirstSample(false), - m_state(State_TypeNotSet), m_pParent(nullptr), - m_imageWidthInPixels(0), m_imageHeightInPixels(0) { - m_bConnected = false; - InitializeCriticalSectionEx(&m_critSec, 3000, 0); - ZeroMemory(&m_guiCurrentSubtype, sizeof(m_guiCurrentSubtype)); - CBaseAttributes::Initialize(0U); - DebugPrintOut(L"StreamSink::StreamSink\n"); - } - virtual ~StreamSink() { - DeleteCriticalSection(&m_critSec); - assert(m_IsShutdown); - DebugPrintOut(L"StreamSink::~StreamSink\n"); - } - - HRESULT Initialize() - { - HRESULT hr; - // Create the event queue helper. - hr = MFCreateEventQueue(&m_spEventQueue); - if (SUCCEEDED(hr)) - { - _ComPtr pMedSink; - hr = CBaseAttributes<>::GetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, __uuidof(IMFMediaSink), (LPVOID*)pMedSink.GetAddressOf()); - assert(pMedSink.Get() != NULL); - if (SUCCEEDED(hr)) { - hr = pMedSink.Get()->QueryInterface(IID_PPV_ARGS(&m_pParent)); - } - } - return hr; - } - - HRESULT CheckShutdown() const - { - if (m_IsShutdown) - { - return MF_E_SHUTDOWN; - } - else - { - return S_OK; - } - } - // Called when the presentation clock starts. - HRESULT Start(MFTIME start) - { - HRESULT hr = S_OK; - EnterCriticalSection(&m_critSec); - if (m_state != State_TypeNotSet) { - if (start != PRESENTATION_CURRENT_POSITION) - { - m_StartTime = start; // Cache the start time. - m_fGetStartTimeFromSample = false; - } - else - { - m_fGetStartTimeFromSample = true; - } - m_state = State_Started; - GUID guiMajorType; - m_fWaitingForFirstSample = SUCCEEDED(m_spCurrentType->GetMajorType(&guiMajorType)) && (guiMajorType == MFMediaType_Video); - hr = QueueEvent(MEStreamSinkStarted, GUID_NULL, hr, NULL); - if (SUCCEEDED(hr)) { - hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, hr, NULL); - } - } - else hr = MF_E_NOT_INITIALIZED; - LeaveCriticalSection(&m_critSec); - return hr; - } - - // Called when the presentation clock pauses. - HRESULT Pause() - { - EnterCriticalSection(&m_critSec); - - HRESULT hr = S_OK; - - if (m_state != State_Stopped && m_state != State_TypeNotSet) { - m_state = State_Paused; - hr = QueueEvent(MEStreamSinkPaused, GUID_NULL, hr, NULL); - } else if (hr == State_TypeNotSet) - hr = MF_E_NOT_INITIALIZED; - else - hr = MF_E_INVALIDREQUEST; - LeaveCriticalSection(&m_critSec); - return hr; - } - // Called when the presentation clock restarts. - HRESULT Restart() - { - EnterCriticalSection(&m_critSec); - - HRESULT hr = S_OK; - - if (m_state == State_Paused) { - m_state = State_Started; - hr = QueueEvent(MEStreamSinkStarted, GUID_NULL, hr, NULL); - if (SUCCEEDED(hr)) { - hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, hr, NULL); - } - } else if (hr == State_TypeNotSet) - hr = MF_E_NOT_INITIALIZED; - else - hr = MF_E_INVALIDREQUEST; - LeaveCriticalSection(&m_critSec); - return hr; - } - // Called when the presentation clock stops. - HRESULT Stop() - { - EnterCriticalSection(&m_critSec); - - HRESULT hr = S_OK; - if (m_state != State_TypeNotSet) { - m_state = State_Stopped; - hr = QueueEvent(MEStreamSinkStopped, GUID_NULL, hr, NULL); - } - else hr = MF_E_NOT_INITIALIZED; - LeaveCriticalSection(&m_critSec); - return hr; - } - - // Shuts down the stream sink. - HRESULT Shutdown() - { - _ComPtr pSampleCallback; - HRESULT hr = S_OK; - assert(!m_IsShutdown); - hr = m_pParent->GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - if (SUCCEEDED(hr)) { - hr = pSampleCallback->OnShutdown(); - } - - if (m_spEventQueue) { - hr = m_spEventQueue->Shutdown(); - } - if (m_pParent) - m_pParent->Release(); - m_spCurrentType.Reset(); - m_IsShutdown = TRUE; - - return hr; - } - - //IMFStreamSink - HRESULT STDMETHODCALLTYPE GetMediaSink( - /* [out] */ __RPC__deref_out_opt IMFMediaSink **ppMediaSink) { - if (ppMediaSink == NULL) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - _ComPtr pMedSink; - hr = CBaseAttributes<>::GetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, __uuidof(IMFMediaSink), (LPVOID*)pMedSink.GetAddressOf()); - if (SUCCEEDED(hr)) { - *ppMediaSink = pMedSink.Detach(); - } - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetMediaSink: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetIdentifier( - /* [out] */ __RPC__out DWORD *pdwIdentifier) { - if (pdwIdentifier == NULL) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = GetUINT32(MF_STREAMSINK_ID, (UINT32*)pdwIdentifier); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetIdentifier: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetMediaTypeHandler( - /* [out] */ __RPC__deref_out_opt IMFMediaTypeHandler **ppHandler) { - if (ppHandler == NULL) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - // This stream object acts as its own type handler, so we QI ourselves. - if (SUCCEEDED(hr)) - { - hr = QueryInterface(IID_IMFMediaTypeHandler, (void**)ppHandler); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetMediaTypeHandler: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE ProcessSample(IMFSample *pSample) { - _ComPtr pInput; - _ComPtr pSampleCallback; - BYTE *pSrc = NULL; // Source buffer. - // Stride if the buffer does not support IMF2DBuffer - LONGLONG hnsTime = 0; - LONGLONG hnsDuration = 0; - DWORD cbMaxLength; - DWORD cbCurrentLength = 0; - GUID guidMajorType; - if (pSample == NULL) - { - return E_INVALIDARG; - } - HRESULT hr = S_OK; - - EnterCriticalSection(&m_critSec); - - if (m_state != State_Started && m_state != State_Paused) { - if (m_state == State_TypeNotSet) - hr = MF_E_NOT_INITIALIZED; - else - hr = MF_E_INVALIDREQUEST; - } - if (SUCCEEDED(hr)) - hr = CheckShutdown(); - if (SUCCEEDED(hr)) { - hr = pSample->ConvertToContiguousBuffer(&pInput); - if (SUCCEEDED(hr)) { - hr = pSample->GetSampleTime(&hnsTime); - } - if (SUCCEEDED(hr)) { - hr = pSample->GetSampleDuration(&hnsDuration); - } - if (SUCCEEDED(hr)) { - hr = GetMajorType(&guidMajorType); - } - if (SUCCEEDED(hr)) { - hr = m_pParent->GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - } - if (SUCCEEDED(hr)) { - hr = pInput->Lock(&pSrc, &cbMaxLength, &cbCurrentLength); - } - if (SUCCEEDED(hr)) { - hr = pSampleCallback->OnProcessSample(guidMajorType, 0, hnsTime, hnsDuration, pSrc, cbCurrentLength); - pInput->Unlock(); - } - if (SUCCEEDED(hr)) { - hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL); - } - } - LeaveCriticalSection(&m_critSec); - return hr; - } - - HRESULT STDMETHODCALLTYPE PlaceMarker( - /* [in] */ MFSTREAMSINK_MARKER_TYPE eMarkerType, - /* [in] */ __RPC__in const PROPVARIANT * /*pvarMarkerValue*/, - /* [in] */ __RPC__in const PROPVARIANT * /*pvarContextValue*/) { - eMarkerType; - EnterCriticalSection(&m_critSec); - - HRESULT hr = S_OK; - if (m_state == State_TypeNotSet) - hr = MF_E_NOT_INITIALIZED; - - if (SUCCEEDED(hr)) - hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - //at shutdown will receive MFSTREAMSINK_MARKER_ENDOFSEGMENT - hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::PlaceMarker: HRESULT=%i %s\n", hr, StreamSinkMarkerTypeMap.at(eMarkerType).c_str()); - return hr; - } - - HRESULT STDMETHODCALLTYPE Flush(void) { - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::Flush: HRESULT=%i\n", hr); - return hr; - } - - //IMFMediaEventGenerator - HRESULT STDMETHODCALLTYPE GetEvent( - DWORD dwFlags, IMFMediaEvent **ppEvent) { - // NOTE: - // GetEvent can block indefinitely, so we don't hold the lock. - // This requires some juggling with the event queue pointer. - - HRESULT hr = S_OK; - - _ComPtr pQueue; - - { - EnterCriticalSection(&m_critSec); - - // Check shutdown - hr = CheckShutdown(); - - // Get the pointer to the event queue. - if (SUCCEEDED(hr)) - { - pQueue = m_spEventQueue.Get(); - } - LeaveCriticalSection(&m_critSec); - } - - // Now get the event. - if (SUCCEEDED(hr)) - { - hr = pQueue->GetEvent(dwFlags, ppEvent); - } - MediaEventType meType = MEUnknown; - if (SUCCEEDED(hr) && SUCCEEDED((*ppEvent)->GetType(&meType)) && meType == MEStreamSinkStopped) { - } - HRESULT hrStatus = S_OK; - if (SUCCEEDED(hr)) - hr = (*ppEvent)->GetStatus(&hrStatus); - if (SUCCEEDED(hr)) - DebugPrintOut(L"StreamSink::GetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str()); - else - DebugPrintOut(L"StreamSink::GetEvent: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE BeginGetEvent( - IMFAsyncCallback *pCallback, IUnknown *punkState) { - HRESULT hr = S_OK; - - EnterCriticalSection(&m_critSec); - - hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = m_spEventQueue->BeginGetEvent(pCallback, punkState); - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::BeginGetEvent: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE EndGetEvent( - IMFAsyncResult *pResult, IMFMediaEvent **ppEvent) { - HRESULT hr = S_OK; - - EnterCriticalSection(&m_critSec); - - hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = m_spEventQueue->EndGetEvent(pResult, ppEvent); - } - - MediaEventType meType = MEUnknown; - if (SUCCEEDED(hr) && SUCCEEDED((*ppEvent)->GetType(&meType)) && meType == MEStreamSinkStopped) { - } - - LeaveCriticalSection(&m_critSec); - HRESULT hrStatus = S_OK; - if (SUCCEEDED(hr)) - hr = (*ppEvent)->GetStatus(&hrStatus); - if (SUCCEEDED(hr)) - DebugPrintOut(L"StreamSink::EndGetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str()); - else - DebugPrintOut(L"StreamSink::EndGetEvent: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE QueueEvent( - MediaEventType met, REFGUID guidExtendedType, - HRESULT hrStatus, const PROPVARIANT *pvValue) { - HRESULT hr = S_OK; - - EnterCriticalSection(&m_critSec); - - hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = m_spEventQueue->QueueEventParamVar(met, guidExtendedType, hrStatus, pvValue); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::QueueEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(met).c_str()); - DebugPrintOut(L"StreamSink::QueueEvent: HRESULT=%i\n", hr); - return hr; - } - - /// IMFMediaTypeHandler methods - - // Check if a media type is supported. - STDMETHODIMP IsMediaTypeSupported( - /* [in] */ IMFMediaType *pMediaType, - /* [out] */ IMFMediaType **ppMediaType) - { - if (pMediaType == nullptr) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - GUID majorType = GUID_NULL; - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = pMediaType->GetGUID(MF_MT_MAJOR_TYPE, &majorType); - } - - // First make sure it's video or audio type. - if (SUCCEEDED(hr)) - { - if (majorType != MFMediaType_Video && majorType != MFMediaType_Audio) - { - hr = MF_E_INVALIDTYPE; - } - } - - if (SUCCEEDED(hr) && m_spCurrentType != nullptr) - { - GUID guiNewSubtype; - if (FAILED(pMediaType->GetGUID(MF_MT_SUBTYPE, &guiNewSubtype)) || - guiNewSubtype != m_guiCurrentSubtype) - { - hr = MF_E_INVALIDTYPE; - } - } - // We don't return any "close match" types. - if (ppMediaType) - { - *ppMediaType = nullptr; - } - - if (ppMediaType && SUCCEEDED(hr)) { - _ComPtr pType; - hr = MFCreateMediaType(ppMediaType); - if (SUCCEEDED(hr)) { - hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType); - } - if (SUCCEEDED(hr)) { - hr = pType->LockStore(); - } - bool bLocked = false; - if (SUCCEEDED(hr)) { - bLocked = true; - UINT32 uiCount; - UINT32 uiTotal; - hr = pType->GetCount(&uiTotal); - for (uiCount = 0; SUCCEEDED(hr) && uiCount < uiTotal; uiCount++) { - GUID guid; - PROPVARIANT propval; - hr = pType->GetItemByIndex(uiCount, &guid, &propval); - if (SUCCEEDED(hr) && (guid == MF_MT_FRAME_SIZE || guid == MF_MT_MAJOR_TYPE || guid == MF_MT_PIXEL_ASPECT_RATIO || - guid == MF_MT_ALL_SAMPLES_INDEPENDENT || guid == MF_MT_INTERLACE_MODE || guid == MF_MT_SUBTYPE)) { - hr = (*ppMediaType)->SetItem(guid, propval); - PropVariantClear(&propval); - } - } - } - if (bLocked) { - hr = pType->UnlockStore(); - } - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::IsMediaTypeSupported: HRESULT=%i\n", hr); - return hr; - } - - - // Return the number of preferred media types. - STDMETHODIMP GetMediaTypeCount(DWORD *pdwTypeCount) - { - if (pdwTypeCount == nullptr) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - // We've got only one media type - *pdwTypeCount = 1; - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetMediaTypeCount: HRESULT=%i\n", hr); - return hr; - } - - - // Return a preferred media type by index. - STDMETHODIMP GetMediaTypeByIndex( - /* [in] */ DWORD dwIndex, - /* [out] */ IMFMediaType **ppType) - { - if (ppType == NULL) { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (dwIndex > 0) - { - hr = MF_E_NO_MORE_TYPES; - } else { - //return preferred type based on media capture library 6 elements preferred preview type - //hr = m_spCurrentType.CopyTo(ppType); - if (SUCCEEDED(hr)) { - _ComPtr pType; - hr = MFCreateMediaType(ppType); - if (SUCCEEDED(hr)) { - hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType); - } - if (SUCCEEDED(hr)) { - hr = pType->LockStore(); - } - bool bLocked = false; - if (SUCCEEDED(hr)) { - bLocked = true; - UINT32 uiCount; - UINT32 uiTotal; - hr = pType->GetCount(&uiTotal); - for (uiCount = 0; SUCCEEDED(hr) && uiCount < uiTotal; uiCount++) { - GUID guid; - PROPVARIANT propval; - hr = pType->GetItemByIndex(uiCount, &guid, &propval); - if (SUCCEEDED(hr) && (guid == MF_MT_FRAME_SIZE || guid == MF_MT_MAJOR_TYPE || guid == MF_MT_PIXEL_ASPECT_RATIO || - guid == MF_MT_ALL_SAMPLES_INDEPENDENT || guid == MF_MT_INTERLACE_MODE || guid == MF_MT_SUBTYPE)) { - hr = (*ppType)->SetItem(guid, propval); - PropVariantClear(&propval); - } - } - } - if (bLocked) { - hr = pType->UnlockStore(); - } - } - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetMediaTypeByIndex: HRESULT=%i\n", hr); - return hr; - } - - - // Set the current media type. - STDMETHODIMP SetCurrentMediaType(IMFMediaType *pMediaType) - { - if (pMediaType == NULL) { - return E_INVALIDARG; - } - EnterCriticalSection(&m_critSec); - - HRESULT hr = S_OK; - if (m_state != State_TypeNotSet && m_state != State_Ready) - hr = MF_E_INVALIDREQUEST; - if (SUCCEEDED(hr)) - hr = CheckShutdown(); - - // We don't allow format changes after streaming starts. - - // We set media type already - if (m_state >= State_Ready) - { - if (SUCCEEDED(hr)) - { - hr = IsMediaTypeSupported(pMediaType, NULL); - } - } - - if (SUCCEEDED(hr)) - { - hr = MFCreateMediaType(m_spCurrentType.ReleaseAndGetAddressOf()); - if (SUCCEEDED(hr)) - { - hr = pMediaType->CopyAllItems(m_spCurrentType.Get()); - } - if (SUCCEEDED(hr)) - { - hr = m_spCurrentType->GetGUID(MF_MT_SUBTYPE, &m_guiCurrentSubtype); - } - GUID guid; - if (SUCCEEDED(hr)) { - hr = m_spCurrentType->GetMajorType(&guid); - } - if (SUCCEEDED(hr) && guid == MFMediaType_Video) { - hr = MFGetAttributeSize(m_spCurrentType.Get(), MF_MT_FRAME_SIZE, &m_imageWidthInPixels, &m_imageHeightInPixels); - } - if (SUCCEEDED(hr)) - { - m_state = State_Ready; - } - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::SetCurrentMediaType: HRESULT=%i\n", hr); - return hr; - } - - // Return the current media type, if any. - STDMETHODIMP GetCurrentMediaType(IMFMediaType **ppMediaType) - { - if (ppMediaType == NULL) { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) { - if (m_spCurrentType == nullptr) { - hr = MF_E_NOT_INITIALIZED; - } - } - - if (SUCCEEDED(hr)) { - hr = m_spCurrentType.CopyTo(ppMediaType); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetCurrentMediaType: HRESULT=%i\n", hr); - return hr; - } - - - // Return the major type GUID. - STDMETHODIMP GetMajorType(GUID *pguidMajorType) - { - HRESULT hr; - if (pguidMajorType == nullptr) { - return E_INVALIDARG; - } - - _ComPtr pType; - hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType); - if (SUCCEEDED(hr)) { - hr = pType->GetMajorType(pguidMajorType); - } - DebugPrintOut(L"StreamSink::GetMajorType: HRESULT=%i\n", hr); - return hr; - } -private: - bool m_bConnected; - - bool m_IsShutdown; // Flag to indicate if Shutdown() method was called. - CRITICAL_SECTION m_critSec; - long m_cRef; - IMFAttributes* m_pParent; - _ComPtr m_spCurrentType; - _ComPtr m_spEventQueue; // Event queue - - _ComPtr m_spFTM; - State m_state; - bool m_fGetStartTimeFromSample; - bool m_fWaitingForFirstSample; - MFTIME m_StartTime; // Presentation time when the clock started. - GUID m_guiCurrentSubtype; - UINT32 m_imageWidthInPixels; - UINT32 m_imageHeightInPixels; -}; - -// Notes: -// -// The List class template implements a simple double-linked list. -// It uses STL's copy semantics. - -// There are two versions of the Clear() method: -// Clear(void) clears the list w/out cleaning up the object. -// Clear(FN fn) takes a functor object that releases the objects, if they need cleanup. - -// The List class supports enumeration. Example of usage: -// -// List::POSIITON pos = list.GetFrontPosition(); -// while (pos != list.GetEndPosition()) -// { -// T item; -// hr = list.GetItemPos(&item); -// pos = list.Next(pos); -// } - -// The ComPtrList class template derives from List<> and implements a list of COM pointers. - -template -struct NoOp -{ - void operator()(T& /*t*/) - { - } -}; - -template -class List -{ -protected: - - // Nodes in the linked list - struct Node - { - Node *prev; - Node *next; - T item; - - Node() : prev(nullptr), next(nullptr) - { - } - - Node(T item) : prev(nullptr), next(nullptr) - { - this->item = item; - } - - T Item() const { return item; } - }; - -public: - - // Object for enumerating the list. - class POSITION - { - friend class List; - - public: - POSITION() : pNode(nullptr) - { - } - - bool operator==(const POSITION &p) const - { - return pNode == p.pNode; - } - - bool operator!=(const POSITION &p) const - { - return pNode != p.pNode; - } - - private: - const Node *pNode; - - POSITION(Node *p) : pNode(p) - { - } - }; - -protected: - Node m_anchor; // Anchor node for the linked list. - DWORD m_count; // Number of items in the list. - - Node* Front() const - { - return m_anchor.next; - } - - Node* Back() const - { - return m_anchor.prev; - } - - virtual HRESULT InsertAfter(T item, Node *pBefore) - { - if (pBefore == nullptr) - { - return E_POINTER; - } - - Node *pNode = new Node(item); - if (pNode == nullptr) - { - return E_OUTOFMEMORY; - } - - Node *pAfter = pBefore->next; - - pBefore->next = pNode; - pAfter->prev = pNode; - - pNode->prev = pBefore; - pNode->next = pAfter; - - m_count++; - - return S_OK; - } - - virtual HRESULT GetItem(const Node *pNode, T* ppItem) - { - if (pNode == nullptr || ppItem == nullptr) - { - return E_POINTER; - } - - *ppItem = pNode->item; - return S_OK; - } - - // RemoveItem: - // Removes a node and optionally returns the item. - // ppItem can be nullptr. - virtual HRESULT RemoveItem(Node *pNode, T *ppItem) - { - if (pNode == nullptr) - { - return E_POINTER; - } - - assert(pNode != &m_anchor); // We should never try to remove the anchor node. - if (pNode == &m_anchor) - { - return E_INVALIDARG; - } - - - T item; - - // The next node's previous is this node's previous. - pNode->next->prev = pNode->prev; - - // The previous node's next is this node's next. - pNode->prev->next = pNode->next; - - item = pNode->item; - delete pNode; - - m_count--; - - if (ppItem) - { - *ppItem = item; - } - - return S_OK; - } - -public: - - List() - { - m_anchor.next = &m_anchor; - m_anchor.prev = &m_anchor; - - m_count = 0; - } - - virtual ~List() - { - Clear(); - } - - // Insertion functions - HRESULT InsertBack(T item) - { - return InsertAfter(item, m_anchor.prev); - } - - - HRESULT InsertFront(T item) - { - return InsertAfter(item, &m_anchor); - } - - HRESULT InsertPos(POSITION pos, T item) - { - if (pos.pNode == nullptr) - { - return InsertBack(item); - } - - return InsertAfter(item, pos.pNode->prev); - } - - // RemoveBack: Removes the tail of the list and returns the value. - // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.) - HRESULT RemoveBack(T *ppItem) - { - if (IsEmpty()) - { - return E_FAIL; - } - else - { - return RemoveItem(Back(), ppItem); - } - } - - // RemoveFront: Removes the head of the list and returns the value. - // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.) - HRESULT RemoveFront(T *ppItem) - { - if (IsEmpty()) - { - return E_FAIL; - } - else - { - return RemoveItem(Front(), ppItem); - } - } - - // GetBack: Gets the tail item. - HRESULT GetBack(T *ppItem) - { - if (IsEmpty()) - { - return E_FAIL; - } - else - { - return GetItem(Back(), ppItem); - } - } - - // GetFront: Gets the front item. - HRESULT GetFront(T *ppItem) - { - if (IsEmpty()) - { - return E_FAIL; - } - else - { - return GetItem(Front(), ppItem); - } - } - - - // GetCount: Returns the number of items in the list. - DWORD GetCount() const { return m_count; } - - bool IsEmpty() const - { - return (GetCount() == 0); - } - - // Clear: Takes a functor object whose operator() - // frees the object on the list. - template - void Clear(FN& clear_fn) - { - Node *n = m_anchor.next; - - // Delete the nodes - while (n != &m_anchor) - { - clear_fn(n->item); - - Node *tmp = n->next; - delete n; - n = tmp; - } - - // Reset the anchor to point at itself - m_anchor.next = &m_anchor; - m_anchor.prev = &m_anchor; - - m_count = 0; - } - - // Clear: Clears the list. (Does not delete or release the list items.) - virtual void Clear() - { - NoOp clearOp; - Clear<>(clearOp); - } - - - // Enumerator functions - - POSITION FrontPosition() - { - if (IsEmpty()) - { - return POSITION(nullptr); - } - else - { - return POSITION(Front()); - } - } - - POSITION EndPosition() const - { - return POSITION(); - } - - HRESULT GetItemPos(POSITION pos, T *ppItem) - { - if (pos.pNode) - { - return GetItem(pos.pNode, ppItem); - } - else - { - return E_FAIL; - } - } - - POSITION Next(const POSITION pos) - { - if (pos.pNode && (pos.pNode->next != &m_anchor)) - { - return POSITION(pos.pNode->next); - } - else - { - return POSITION(nullptr); - } - } - - // Remove an item at a position. - // The item is returns in ppItem, unless ppItem is nullptr. - // NOTE: This method invalidates the POSITION object. - HRESULT Remove(POSITION& pos, T *ppItem) - { - if (pos.pNode) - { - // Remove const-ness temporarily... - Node *pNode = const_cast(pos.pNode); - - pos = POSITION(); - - return RemoveItem(pNode, ppItem); - } - else - { - return E_INVALIDARG; - } - } - -}; - - - -// Typical functors for Clear method. - -// ComAutoRelease: Releases COM pointers. -// MemDelete: Deletes pointers to new'd memory. - -class ComAutoRelease -{ -public: - void operator()(IUnknown *p) - { - if (p) - { - p->Release(); - } - } -}; - -class MemDelete -{ -public: - void operator()(void *p) - { - if (p) - { - delete p; - } - } -}; - - -// ComPtrList class -// Derived class that makes it safer to store COM pointers in the List<> class. -// It automatically AddRef's the pointers that are inserted onto the list -// (unless the insertion method fails). -// -// T must be a COM interface type. -// example: ComPtrList -// -// NULLABLE: If true, client can insert nullptr pointers. This means GetItem can -// succeed but return a nullptr pointer. By default, the list does not allow nullptr -// pointers. - -template -class ComPtrList : public List -{ -public: - typedef typename List::Node Node; - typedef T* Ptr; - - void Clear() - { - ComAutoRelease car; - List::Clear(car); - } - - ~ComPtrList() - { - Clear(); - } - -protected: - HRESULT InsertAfter(Ptr item, Node *pBefore) - { - // Do not allow nullptr item pointers unless NULLABLE is true. - if (item == nullptr && !NULLABLE) - { - return E_POINTER; - } - - if (item) - { - item->AddRef(); - } - - HRESULT hr = List::InsertAfter(item, pBefore); - if (FAILED(hr) && item != nullptr) - { - item->Release(); - } - return hr; - } - - HRESULT GetItem(const Node *pNode, Ptr* ppItem) - { - Ptr pItem = nullptr; - - // The base class gives us the pointer without AddRef'ing it. - // If we return the pointer to the caller, we must AddRef(). - HRESULT hr = List::GetItem(pNode, &pItem); - if (SUCCEEDED(hr)) - { - assert(pItem || NULLABLE); - if (pItem) - { - *ppItem = pItem; - (*ppItem)->AddRef(); - } - } - return hr; - } - - HRESULT RemoveItem(Node *pNode, Ptr *ppItem) - { - // ppItem can be nullptr, but we need to get the - // item so that we can release it. - - // If ppItem is not nullptr, we will AddRef it on the way out. - - Ptr pItem = nullptr; - - HRESULT hr = List::RemoveItem(pNode, &pItem); - - if (SUCCEEDED(hr)) - { - assert(pItem || NULLABLE); - if (ppItem && pItem) - { - *ppItem = pItem; - (*ppItem)->AddRef(); - } - - if (pItem) - { - pItem->Release(); - pItem = nullptr; - } - } - - return hr; - } -}; - -extern const __declspec(selectany) WCHAR RuntimeClass_CV_MediaSink[] = L"cv.MediaSink"; - -class MediaSink : - public IMFMediaSink, public IMFClockStateSink, public CBaseAttributes<> -{ -public: - ULONG STDMETHODCALLTYPE AddRef() - { - return InterlockedIncrement(&m_cRef); - } - ULONG STDMETHODCALLTYPE Release() - { - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) - { - delete this; - } - return cRef; - } -#if defined(_MSC_VER) && _MSC_VER >= 1700 // '_Outptr_result_nullonfailure_' SAL is avaialable since VS 2012 - STDMETHOD(QueryInterface)(REFIID riid, _Outptr_result_nullonfailure_ void **ppv) -#else - STDMETHOD(QueryInterface)(REFIID riid, void **ppv) -#endif - { - if (ppv == nullptr) { - return E_POINTER; - } - (*ppv) = nullptr; - HRESULT hr = S_OK; - if (riid == IID_IUnknown || - riid == IID_IMFMediaSink) { - (*ppv) = static_cast(this); - AddRef(); - } else if (riid == IID_IMFClockStateSink) { - (*ppv) = static_cast(this); - AddRef(); - } else if (riid == IID_IMFAttributes) { - (*ppv) = static_cast(this); - AddRef(); - } else { - hr = E_NOINTERFACE; - } - - return hr; - } - MediaSink() : m_IsShutdown(false), m_llStartTime(0) { - CBaseAttributes<>::Initialize(0U); - InitializeCriticalSectionEx(&m_critSec, 3000, 0); - DebugPrintOut(L"MediaSink::MediaSink\n"); - } - - virtual ~MediaSink() { - DebugPrintOut(L"MediaSink::~MediaSink\n"); - DeleteCriticalSection(&m_critSec); - assert(m_IsShutdown); - } - HRESULT CheckShutdown() const - { - if (m_IsShutdown) - { - return MF_E_SHUTDOWN; - } - else - { - return S_OK; - } - } - //IMFMediaSink - HRESULT STDMETHODCALLTYPE GetCharacteristics( - /* [out] */ __RPC__out DWORD *pdwCharacteristics) { - HRESULT hr; - if (pdwCharacteristics == NULL) return E_INVALIDARG; - EnterCriticalSection(&m_critSec); - if (SUCCEEDED(hr = CheckShutdown())) { - //if had an activation object for the sink, shut down would be managed and MF_STREAM_SINK_SUPPORTS_ROTATION appears to be setable to TRUE - *pdwCharacteristics = MEDIASINK_FIXED_STREAMS;// | MEDIASINK_REQUIRE_REFERENCE_MEDIATYPE; - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::GetCharacteristics: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE AddStreamSink( - DWORD dwStreamSinkIdentifier, IMFMediaType * /*pMediaType*/, IMFStreamSink **ppStreamSink) { - _ComPtr spMFStream; - _ComPtr pStream; - EnterCriticalSection(&m_critSec); - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = GetStreamSinkById(dwStreamSinkIdentifier, &spMFStream); - } - - if (SUCCEEDED(hr)) - { - hr = MF_E_STREAMSINK_EXISTS; - } - else - { - hr = S_OK; - } - - if (SUCCEEDED(hr)) - { - StreamSink* pSink = new StreamSink(); - if (pSink) { - hr = pSink->QueryInterface(IID_IMFStreamSink, (void**)spMFStream.GetAddressOf()); - if (SUCCEEDED(hr)) { - hr = spMFStream.As(&pStream); - } - if (FAILED(hr)) delete pSink; - } - } - - // Initialize the stream. - _ComPtr pAttr; - if (SUCCEEDED(hr)) { - hr = pStream.As(&pAttr); - } - if (SUCCEEDED(hr)) { - hr = pAttr->SetUINT32(MF_STREAMSINK_ID, dwStreamSinkIdentifier); - if (SUCCEEDED(hr)) { - hr = pAttr->SetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, (IMFMediaSink*)this); - } - } - if (SUCCEEDED(hr)) { - hr = pStream->Initialize(); - } - - if (SUCCEEDED(hr)) - { - ComPtrList::POSITION pos = m_streams.FrontPosition(); - ComPtrList::POSITION posEnd = m_streams.EndPosition(); - - // Insert in proper position - for (; pos != posEnd; pos = m_streams.Next(pos)) - { - DWORD dwCurrId; - _ComPtr spCurr; - hr = m_streams.GetItemPos(pos, &spCurr); - if (FAILED(hr)) - { - break; - } - hr = spCurr->GetIdentifier(&dwCurrId); - if (FAILED(hr)) - { - break; - } - - if (dwCurrId > dwStreamSinkIdentifier) - { - break; - } - } - - if (SUCCEEDED(hr)) - { - hr = m_streams.InsertPos(pos, spMFStream.Get()); - } - } - - if (SUCCEEDED(hr)) - { - *ppStreamSink = spMFStream.Detach(); - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::AddStreamSink: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE RemoveStreamSink(DWORD dwStreamSinkIdentifier) { - EnterCriticalSection(&m_critSec); - HRESULT hr = CheckShutdown(); - ComPtrList::POSITION pos = m_streams.FrontPosition(); - ComPtrList::POSITION endPos = m_streams.EndPosition(); - _ComPtr spStream; - - if (SUCCEEDED(hr)) - { - for (; pos != endPos; pos = m_streams.Next(pos)) - { - hr = m_streams.GetItemPos(pos, &spStream); - DWORD dwId; - - if (FAILED(hr)) - { - break; - } - - hr = spStream->GetIdentifier(&dwId); - if (FAILED(hr) || dwId == dwStreamSinkIdentifier) - { - break; - } - } - - if (pos == endPos) - { - hr = MF_E_INVALIDSTREAMNUMBER; - } - } - - if (SUCCEEDED(hr)) - { - hr = m_streams.Remove(pos, nullptr); - _ComPtr spCustomSink; - hr = spStream.As(&spCustomSink); - if (SUCCEEDED(hr)) - hr = spCustomSink->Shutdown(); - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::RemoveStreamSink: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetStreamSinkCount(DWORD *pStreamSinkCount) { - if (pStreamSinkCount == NULL) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - *pStreamSinkCount = m_streams.GetCount(); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::GetStreamSinkCount: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetStreamSinkByIndex( - DWORD dwIndex, IMFStreamSink **ppStreamSink) { - if (ppStreamSink == NULL) - { - return E_INVALIDARG; - } - - _ComPtr spStream; - EnterCriticalSection(&m_critSec); - DWORD cStreams = m_streams.GetCount(); - - if (dwIndex >= cStreams) - { - return MF_E_INVALIDINDEX; - } - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - ComPtrList::POSITION pos = m_streams.FrontPosition(); - ComPtrList::POSITION endPos = m_streams.EndPosition(); - DWORD dwCurrent = 0; - - for (; pos != endPos && dwCurrent < dwIndex; pos = m_streams.Next(pos), ++dwCurrent) - { - // Just move to proper position - } - - if (pos == endPos) - { - hr = MF_E_UNEXPECTED; - } - else - { - hr = m_streams.GetItemPos(pos, &spStream); - } - } - - if (SUCCEEDED(hr)) - { - *ppStreamSink = spStream.Detach(); - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::GetStreamSinkByIndex: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetStreamSinkById( - DWORD dwStreamSinkIdentifier, IMFStreamSink **ppStreamSink) { - if (ppStreamSink == NULL) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - HRESULT hr = CheckShutdown(); - _ComPtr spResult; - - if (SUCCEEDED(hr)) - { - ComPtrList::POSITION pos = m_streams.FrontPosition(); - ComPtrList::POSITION endPos = m_streams.EndPosition(); - - for (; pos != endPos; pos = m_streams.Next(pos)) - { - _ComPtr spStream; - hr = m_streams.GetItemPos(pos, &spStream); - DWORD dwId; - - if (FAILED(hr)) - { - break; - } - - hr = spStream->GetIdentifier(&dwId); - if (FAILED(hr)) - { - break; - } - else if (dwId == dwStreamSinkIdentifier) - { - spResult = spStream; - break; - } - } - - if (pos == endPos) - { - hr = MF_E_INVALIDSTREAMNUMBER; - } - } - - if (SUCCEEDED(hr)) - { - assert(spResult); - *ppStreamSink = spResult.Detach(); - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::GetStreamSinkById: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE SetPresentationClock( - IMFPresentationClock *pPresentationClock) { - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - // If we already have a clock, remove ourselves from that clock's - // state notifications. - if (SUCCEEDED(hr)) { - if (m_spClock) { - hr = m_spClock->RemoveClockStateSink(this); - } - } - - // Register ourselves to get state notifications from the new clock. - if (SUCCEEDED(hr)) { - if (pPresentationClock) { - hr = pPresentationClock->AddClockStateSink(this); - } - } - - _ComPtr pSampleCallback; - if (SUCCEEDED(hr)) { - // Release the pointer to the old clock. - // Store the pointer to the new clock. - m_spClock = pPresentationClock; - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - } - LeaveCriticalSection(&m_critSec); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnSetPresentationClock(pPresentationClock); - DebugPrintOut(L"MediaSink::SetPresentationClock: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetPresentationClock( - IMFPresentationClock **ppPresentationClock) { - if (ppPresentationClock == NULL) { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) { - if (!m_spClock) { - hr = MF_E_NO_CLOCK; // There is no presentation clock. - } else { - // Return the pointer to the caller. - hr = m_spClock.CopyTo(ppPresentationClock); - } - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::GetPresentationClock: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE Shutdown(void) { - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) { - ForEach(m_streams, ShutdownFunc()); - m_streams.Clear(); - m_spClock.ReleaseAndGetAddressOf(); - - _ComPtr pType; - hr = CBaseAttributes<>::GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)pType.GetAddressOf()); - if (SUCCEEDED(hr)) { - hr = DeleteItem(MF_MEDIASINK_PREFERREDTYPE); - } - m_IsShutdown = true; - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::Shutdown: HRESULT=%i\n", hr); - return hr; - } - class ShutdownFunc - { - public: - HRESULT operator()(IMFStreamSink *pStream) const - { - _ComPtr spCustomSink; - HRESULT hr; - hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); - if (FAILED(hr)) return hr; - hr = spCustomSink->Shutdown(); - return hr; - } - }; - - class StartFunc - { - public: - StartFunc(LONGLONG llStartTime) - : _llStartTime(llStartTime) - { - } - - HRESULT operator()(IMFStreamSink *pStream) const - { - _ComPtr spCustomSink; - HRESULT hr; - hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); - if (FAILED(hr)) return hr; - hr = spCustomSink->Start(_llStartTime); - return hr; - } - - LONGLONG _llStartTime; - }; - - class StopFunc - { - public: - HRESULT operator()(IMFStreamSink *pStream) const - { - _ComPtr spCustomSink; - HRESULT hr; - hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); - if (FAILED(hr)) return hr; - hr = spCustomSink->Stop(); - return hr; - } - }; - - template - HRESULT ForEach(ComPtrList &col, TFunc fn) - { - ComPtrList::POSITION pos = col.FrontPosition(); - ComPtrList::POSITION endPos = col.EndPosition(); - HRESULT hr = S_OK; - - for (; pos != endPos; pos = col.Next(pos)) - { - _ComPtr spStream; - - hr = col.GetItemPos(pos, &spStream); - if (FAILED(hr)) - { - break; - } - - hr = fn(spStream.Get()); - } - - return hr; - } - //IMFClockStateSink - HRESULT STDMETHODCALLTYPE OnClockStart( - MFTIME hnsSystemTime, - LONGLONG llClockStartOffset) { - EnterCriticalSection(&m_critSec); - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - // Start each stream. - m_llStartTime = llClockStartOffset; - hr = ForEach(m_streams, StartFunc(llClockStartOffset)); - } - _ComPtr pSampleCallback; - if (SUCCEEDED(hr)) - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - LeaveCriticalSection(&m_critSec); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnClockStart(hnsSystemTime, llClockStartOffset); - DebugPrintOut(L"MediaSink::OnClockStart: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE OnClockStop( - MFTIME hnsSystemTime) { - EnterCriticalSection(&m_critSec); - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - // Stop each stream - hr = ForEach(m_streams, StopFunc()); - } - _ComPtr pSampleCallback; - if (SUCCEEDED(hr)) - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - LeaveCriticalSection(&m_critSec); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnClockStop(hnsSystemTime); - DebugPrintOut(L"MediaSink::OnClockStop: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE OnClockPause( - MFTIME hnsSystemTime) { - HRESULT hr; - _ComPtr pSampleCallback; - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnClockPause(hnsSystemTime); - DebugPrintOut(L"MediaSink::OnClockPause: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE OnClockRestart( - MFTIME hnsSystemTime) { - HRESULT hr; - _ComPtr pSampleCallback; - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnClockRestart(hnsSystemTime); - DebugPrintOut(L"MediaSink::OnClockRestart: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE OnClockSetRate( - MFTIME hnsSystemTime, - float flRate) { - HRESULT hr; - _ComPtr pSampleCallback; - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnClockSetRate(hnsSystemTime, flRate); - DebugPrintOut(L"MediaSink::OnClockSetRate: HRESULT=%i\n", hr); - return hr; - } -private: - long m_cRef; - CRITICAL_SECTION m_critSec; - bool m_IsShutdown; - ComPtrList m_streams; - _ComPtr m_spClock; - LONGLONG m_llStartTime; -}; From 916f094ce6a5cca9b1d6468b994d13e1767f83a5 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Thu, 19 Apr 2018 18:24:02 +0300 Subject: [PATCH 13/36] Integrated camera and file MSMF-based VideoCaptures and implemented configuration properties get/set --- modules/videoio/src/cap_msmf.cpp | 1248 ++++++++++++++++++------------ 1 file changed, 746 insertions(+), 502 deletions(-) diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp index 56ac29e746..dfe008224e 100644 --- a/modules/videoio/src/cap_msmf.cpp +++ b/modules/videoio/src/cap_msmf.cpp @@ -249,21 +249,20 @@ struct MediaType int MF_MT_DEFAULT_STRIDE; // stride is negative if image is bottom-up unsigned int MF_MT_VIDEO_CHROMA_SITING; GUID MF_MT_AM_FORMAT_TYPE; - LPCWSTR pMF_MT_AM_FORMAT_TYPEName; unsigned int MF_MT_FIXED_SIZE_SAMPLES; unsigned int MF_MT_VIDEO_NOMINAL_RANGE; UINT32 MF_MT_FRAME_RATE_NUMERATOR; UINT32 MF_MT_FRAME_RATE_DENOMINATOR; - UINT32 MF_MT_PIXEL_ASPECT_RATIO; - UINT32 MF_MT_PIXEL_ASPECT_RATIO_low; + UINT32 MF_MT_PIXEL_ASPECT_RATIO_NUMERATOR; + UINT32 MF_MT_PIXEL_ASPECT_RATIO_DENOMINATOR; unsigned int MF_MT_ALL_SAMPLES_INDEPENDENT; - UINT32 MF_MT_FRAME_RATE_RANGE_MIN; - UINT32 MF_MT_FRAME_RATE_RANGE_MIN_low; + UINT32 MF_MT_FRAME_RATE_RANGE_MIN_NUMERATOR; + UINT32 MF_MT_FRAME_RATE_RANGE_MIN_DENOMINATOR; unsigned int MF_MT_SAMPLE_SIZE; unsigned int MF_MT_VIDEO_PRIMARIES; unsigned int MF_MT_INTERLACE_MODE; - UINT32 MF_MT_FRAME_RATE_RANGE_MAX; - UINT32 MF_MT_FRAME_RATE_RANGE_MAX_low; + UINT32 MF_MT_FRAME_RATE_RANGE_MAX_NUMERATOR; + UINT32 MF_MT_FRAME_RATE_RANGE_MAX_DENOMINATOR; GUID MF_MT_MAJOR_TYPE; GUID MF_MT_SUBTYPE; LPCWSTR pMF_MT_MAJOR_TYPEName; @@ -274,134 +273,18 @@ struct MediaType void Clear(); }; -// Structure for collecting info about one parametr of current video device -struct Parametr -{ - long CurrentValue; - long Min; - long Max; - long Step; - long Default; - long Flag; - Parametr() - { - CurrentValue = 0; - Min = 0; - Max = 0; - Step = 0; - Default = 0; - Flag = 0; - } -}; - -// Structure for collecting info about 17 parametrs of current video device -struct CamParametrs -{ - Parametr Brightness; - Parametr Contrast; - Parametr Hue; - Parametr Saturation; - Parametr Sharpness; - Parametr Gamma; - Parametr ColorEnable; - Parametr WhiteBalance; - Parametr BacklightCompensation; - Parametr Gain; - Parametr Pan; - Parametr Tilt; - Parametr Roll; - Parametr Zoom; - Parametr Exposure; - Parametr Iris; - Parametr Focus; -}; - -CamParametrs videoDevice__getParametrs(IMFMediaSource* vd_pSource) -{ - CamParametrs out; - if (vd_pSource) - { - Parametr *pParametr = (Parametr *)(&out); - IAMVideoProcAmp *pProcAmp = NULL; - HRESULT hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcAmp)); - if (SUCCEEDED(hr)) - { - for (unsigned int i = 0; i < 10; i++) - { - Parametr temp; - hr = pProcAmp->GetRange(VideoProcAmp_Brightness + i, &temp.Min, &temp.Max, &temp.Step, &temp.Default, &temp.Flag); - if (SUCCEEDED(hr)) - { - temp.CurrentValue = temp.Default; - pParametr[i] = temp; - } - } - pProcAmp->Release(); - } - IAMCameraControl *pProcControl = NULL; - hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcControl)); - if (SUCCEEDED(hr)) - { - for (unsigned int i = 0; i < 7; i++) - { - Parametr temp; - hr = pProcControl->GetRange(CameraControl_Pan + i, &temp.Min, &temp.Max, &temp.Step, &temp.Default, &temp.Flag); - if (SUCCEEDED(hr)) - { - temp.CurrentValue = temp.Default; - pParametr[10 + i] = temp; - } - } - pProcControl->Release(); - } - } - return out; -} - -void videoDevice__setParametrs(IMFMediaSource* vd_pSource, CamParametrs parametrs) -{ - if (vd_pSource) - { - CamParametrs vd_PrevParametrs = videoDevice__getParametrs(vd_pSource); - Parametr *pParametr = (Parametr *)(¶metrs); - Parametr *pPrevParametr = (Parametr *)(&vd_PrevParametrs); - IAMVideoProcAmp *pProcAmp = NULL; - HRESULT hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcAmp)); - if (SUCCEEDED(hr)) - { - for (unsigned int i = 0; i < 10; i++) - { - if (pPrevParametr[i].CurrentValue != pParametr[i].CurrentValue || pPrevParametr[i].Flag != pParametr[i].Flag) - hr = pProcAmp->Set(VideoProcAmp_Brightness + i, pParametr[i].CurrentValue, pParametr[i].Flag); - } - pProcAmp->Release(); - } - IAMCameraControl *pProcControl = NULL; - hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcControl)); - if (SUCCEEDED(hr)) - { - for (unsigned int i = 0; i < 7; i++) - { - if (pPrevParametr[10 + i].CurrentValue != pParametr[10 + i].CurrentValue || pPrevParametr[10 + i].Flag != pParametr[10 + i].Flag) - hr = pProcControl->Set(CameraControl_Pan + i, pParametr[10 + i].CurrentValue, pParametr[10 + i].Flag); - } - pProcControl->Release(); - } - } -} - // Class for creating of Media Foundation context class Media_Foundation { public: - ~Media_Foundation(void) { /*CV_Assert(SUCCEEDED(MFShutdown()));*/ } + ~Media_Foundation(void) { /*CV_Assert(SUCCEEDED(MFShutdown()));*/ CoUninitialize(); } static Media_Foundation& getInstance() { static Media_Foundation instance; return instance; } private: - Media_Foundation(void) { CV_Assert(SUCCEEDED(MFStartup(MF_VERSION))); } + Media_Foundation(void) { CoInitialize(0); CV_Assert(SUCCEEDED(MFStartup(MF_VERSION))); } }; #ifndef IF_GUID_EQUAL_RETURN @@ -690,11 +573,11 @@ bool LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, MediaType &o else if (guid == MF_MT_FRAME_RATE && var.vt == VT_UI8) Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_FRAME_RATE_NUMERATOR, &out.MF_MT_FRAME_RATE_DENOMINATOR); else if (guid == MF_MT_FRAME_RATE_RANGE_MAX && var.vt == VT_UI8) - Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_FRAME_RATE_RANGE_MAX, &out.MF_MT_FRAME_RATE_RANGE_MAX_low); + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_FRAME_RATE_RANGE_MAX_NUMERATOR, &out.MF_MT_FRAME_RATE_RANGE_MAX_DENOMINATOR); else if (guid == MF_MT_FRAME_RATE_RANGE_MIN && var.vt == VT_UI8) - Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_FRAME_RATE_RANGE_MIN, &out.MF_MT_FRAME_RATE_RANGE_MIN_low); + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_FRAME_RATE_RANGE_MIN_NUMERATOR, &out.MF_MT_FRAME_RATE_RANGE_MIN_DENOMINATOR); else if (guid == MF_MT_PIXEL_ASPECT_RATIO && var.vt == VT_UI8) - Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_PIXEL_ASPECT_RATIO, &out.MF_MT_PIXEL_ASPECT_RATIO_low); + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_PIXEL_ASPECT_RATIO_NUMERATOR, &out.MF_MT_PIXEL_ASPECT_RATIO_DENOMINATOR); else if (guid == MF_MT_YUV_MATRIX && var.vt == VT_UI4) out.MF_MT_YUV_MATRIX = var.ulVal; else if (guid == MF_MT_VIDEO_LIGHTING && var.vt == VT_UI4) @@ -741,6 +624,9 @@ MediaType::MediaType() MediaType::MediaType(IMFMediaType *pType) { + pMF_MT_MAJOR_TYPEName = NULL; + pMF_MT_SUBTYPEName = NULL; + Clear(); UINT32 count = 0; if (SUCCEEDED(pType->GetCount(&count)) && SUCCEEDED(pType->LockStore())) @@ -770,16 +656,16 @@ void MediaType::Clear() MF_MT_VIDEO_NOMINAL_RANGE = 0; MF_MT_FRAME_RATE_NUMERATOR = 0; MF_MT_FRAME_RATE_DENOMINATOR = 0; - MF_MT_PIXEL_ASPECT_RATIO = 0; - MF_MT_PIXEL_ASPECT_RATIO_low = 0; + MF_MT_PIXEL_ASPECT_RATIO_NUMERATOR = 0; + MF_MT_PIXEL_ASPECT_RATIO_DENOMINATOR = 0; MF_MT_ALL_SAMPLES_INDEPENDENT = 0; - MF_MT_FRAME_RATE_RANGE_MIN = 0; - MF_MT_FRAME_RATE_RANGE_MIN_low = 0; + MF_MT_FRAME_RATE_RANGE_MIN_NUMERATOR = 0; + MF_MT_FRAME_RATE_RANGE_MIN_DENOMINATOR = 0; MF_MT_SAMPLE_SIZE = 0; MF_MT_VIDEO_PRIMARIES = 0; MF_MT_INTERLACE_MODE = 0; - MF_MT_FRAME_RATE_RANGE_MAX = 0; - MF_MT_FRAME_RATE_RANGE_MAX_low = 0; + MF_MT_FRAME_RATE_RANGE_MAX_NUMERATOR = 0; + MF_MT_FRAME_RATE_RANGE_MAX_DENOMINATOR = 0; memset(&MF_MT_MAJOR_TYPE, 0, sizeof(GUID)); memset(&MF_MT_AM_FORMAT_TYPE, 0, sizeof(GUID)); memset(&MF_MT_SUBTYPE, 0, sizeof(GUID)); @@ -787,13 +673,14 @@ void MediaType::Clear() } -/******* Capturing video from camera via Microsoft Media Foundation **********/ -class CvCaptureCAM_MSMF : public CvCapture +/******* Capturing video from camera or file via Microsoft Media Foundation **********/ +class CvCapture_MSMF : public CvCapture { public: - CvCaptureCAM_MSMF(); - virtual ~CvCaptureCAM_MSMF(); - virtual bool open( int index ); + CvCapture_MSMF(); + virtual ~CvCapture_MSMF(); + virtual bool open(int index); + virtual bool open(const char* filename); virtual void close(); virtual double getProperty(int) const CV_OVERRIDE; virtual bool setProperty(int, double) CV_OVERRIDE; @@ -802,33 +689,44 @@ public: virtual int getCaptureDomain() CV_OVERRIDE { return CV_CAP_MSMF; } // Return the type of the capture object: CV_CAP_VFW, etc... protected: double getFramerate(MediaType MT) const; - bool configureOutput(unsigned int width, unsigned int height, unsigned int prefFramerate); + bool configureOutput(UINT32 width, UINT32 height, double prefFramerate, UINT32 aspectRatioN, UINT32 aspectRatioD, int outFormat, bool convertToFormat); + bool setTime(double time, bool rough); + Media_Foundation& MF; _ComPtr videoFileSource; DWORD dwStreamIndex; + MediaType nativeFormat; MediaType captureFormat; + int captureMode; + bool convertFormat; + UINT32 aspectN, aspectD; + MFTIME duration; _ComPtr videoSample; + LONGLONG sampleTime; IplImage* frame; bool isOpened; }; -CvCaptureCAM_MSMF::CvCaptureCAM_MSMF(): +CvCapture_MSMF::CvCapture_MSMF(): MF(Media_Foundation::getInstance()), videoFileSource(NULL), videoSample(NULL), + captureMode(CV_CAP_MODE_BGR), + convertFormat(true), + aspectN(1), + aspectD(1), + sampleTime(0), frame(NULL), isOpened(false) { - CoInitialize(0); } -CvCaptureCAM_MSMF::~CvCaptureCAM_MSMF() +CvCapture_MSMF::~CvCapture_MSMF() { close(); - CoUninitialize(); } -void CvCaptureCAM_MSMF::close() +void CvCapture_MSMF::close() { if (isOpened) { @@ -842,8 +740,13 @@ void CvCaptureCAM_MSMF::close() } } -bool CvCaptureCAM_MSMF::configureOutput(unsigned int width, unsigned int height, unsigned int prefFramerate) +bool CvCapture_MSMF::configureOutput(UINT32 width, UINT32 height, double prefFramerate, UINT32 aspectRatioN, UINT32 aspectRatioD, int outFormat, bool convertToFormat) { + if (width != 0 && height != 0 && + width == captureFormat.width && height == captureFormat.height && prefFramerate == getFramerate(nativeFormat) && + aspectRatioN == aspectN && aspectRatioD == aspectD && outFormat == captureMode && convertToFormat == convertFormat) + return true; + HRESULT hr = S_OK; int dwStreamFallback = -1; MediaType MTFallback; @@ -892,15 +795,35 @@ bool CvCaptureCAM_MSMF::configureOutput(unsigned int width, unsigned int height, // Retrieved stream media type DWORD tryStream = (DWORD)(dwStreamBest >= 0 ? dwStreamBest : dwStreamFallback); MediaType tryMT = dwStreamBest >= 0 ? MTBest : MTFallback; + GUID outSubtype = GUID_NULL; + UINT32 outStride = 0; + if(convertToFormat) + switch (outFormat) + { + case CV_CAP_MODE_BGR: + case CV_CAP_MODE_RGB: + outSubtype = MFVideoFormat_RGB24; + outStride = 3 * tryMT.width; + break; + case CV_CAP_MODE_GRAY: + case CV_CAP_MODE_YUYV: + outSubtype = MFVideoFormat_YUY2; + outStride = 2 * tryMT.width; + break; + default: + return false; + } _ComPtr mediaTypeOut; if (// Set the output media type. SUCCEEDED(MFCreateMediaType(&mediaTypeOut)) && SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)) && - SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24)) && - SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive)) && - SUCCEEDED(MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1)) && + SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_SUBTYPE, convertToFormat ? outSubtype : tryMT.MF_MT_SUBTYPE)) && + SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, convertToFormat ? MFVideoInterlace_Progressive : tryMT.MF_MT_INTERLACE_MODE)) && + SUCCEEDED(MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, aspectRatioN, aspectRatioD)) && SUCCEEDED(MFSetAttributeSize(mediaTypeOut.Get(), MF_MT_FRAME_SIZE, tryMT.width, tryMT.height)) && - SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_DEFAULT_STRIDE, 3 * tryMT.width)))//Assume BGR24 input + SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, convertToFormat ? 1 : tryMT.MF_MT_FIXED_SIZE_SAMPLES)) && + SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_SAMPLE_SIZE, convertToFormat ? outStride * tryMT.height : tryMT.MF_MT_SAMPLE_SIZE)) && + SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_DEFAULT_STRIDE, convertToFormat ? outStride : tryMT.MF_MT_DEFAULT_STRIDE)))//Assume BGR24 input { if (SUCCEEDED(videoFileSource->SetStreamSelection((DWORD)MF_SOURCE_READER_ALL_STREAMS, false)) && SUCCEEDED(videoFileSource->SetStreamSelection(tryStream, true)) && @@ -908,18 +831,24 @@ bool CvCaptureCAM_MSMF::configureOutput(unsigned int width, unsigned int height, ) { dwStreamIndex = tryStream; - captureFormat = tryMT; - return true; + nativeFormat = tryMT; + aspectN = aspectRatioN; + aspectD = aspectRatioD; + captureMode = outFormat; + convertFormat = convertToFormat; + captureFormat = MediaType(mediaTypeOut.Get()); + if (!convertFormat || (captureFormat.MF_MT_FIXED_SIZE_SAMPLES && + captureFormat.MF_MT_SAMPLE_SIZE == ((captureMode == CV_CAP_MODE_GRAY || captureMode == CV_CAP_MODE_YUYV ? 2 : 3) * captureFormat.MF_MT_FRAME_SIZE))) + return true; } - else - close(); + close(); } } return false; } // Initialize camera input -bool CvCaptureCAM_MSMF::open(int _index) +bool CvCapture_MSMF::open(int _index) { close(); @@ -949,12 +878,15 @@ bool CvCaptureCAM_MSMF::open(int _index) SUCCEEDED(srAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)) && SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, false)) && SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, false)) && - SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true)) && - //ToDo: Enable D3D MF_SOURCE_READER_D3D_MANAGER attribute - SUCCEEDED(MFCreateSourceReaderFromMediaSource(mSrc.Get(), srAttr.Get(), &videoFileSource))) + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true))) { - isOpened = true; - configureOutput(0, 0, 0); + //ToDo: Enable D3D MF_SOURCE_READER_D3D_MANAGER attribute + if (SUCCEEDED(MFCreateSourceReaderFromMediaSource(mSrc.Get(), srAttr.Get(), &videoFileSource))) + { + isOpened = true; + duration = 0; + configureOutput(0, 0, 0, aspectN, aspectD, captureMode, convertFormat); + } } } if (ppDevices[ind]) @@ -967,12 +899,53 @@ bool CvCaptureCAM_MSMF::open(int _index) return isOpened; } -bool CvCaptureCAM_MSMF::grabFrame() + +bool CvCapture_MSMF::open(const char* filename) +{ + close(); + if (!filename) + return false; + + // Set source reader parameters + _ComPtr srAttr; + if (SUCCEEDED(MFCreateAttributes(&srAttr, 10)) && + SUCCEEDED(srAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, false)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, false)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true)) + ) + { + //ToDo: Enable D3D MF_SOURCE_READER_D3D_MANAGER attribute + cv::AutoBuffer unicodeFileName(strlen(filename) + 1); + MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, (int)strlen(filename) + 1); + if (SUCCEEDED(MFCreateSourceReaderFromURL(unicodeFileName, srAttr.Get(), &videoFileSource))) + { + isOpened = true; + sampleTime = 0; + if (configureOutput(0, 0, 0, aspectN, aspectD, captureMode, convertFormat)) + { + PROPVARIANT var; + HRESULT hr; + if (SUCCEEDED(hr = videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var)) && + var.vt == VT_UI8) + { + duration = var.uhVal.QuadPart; + PropVariantClear(&var); + } + else + duration = 0; + } + } + } + + return isOpened; +} + +bool CvCapture_MSMF::grabFrame() { if (isOpened) { DWORD streamIndex, flags; - LONGLONG llTimeStamp; if (videoSample) videoSample.Reset(); HRESULT hr; @@ -981,7 +954,7 @@ bool CvCaptureCAM_MSMF::grabFrame() 0, // Flags. &streamIndex, // Receives the actual stream index. &flags, // Receives status flags. - &llTimeStamp, // Receives the time stamp. + &sampleTime, // Receives the time stamp. &videoSample // Receives the sample or NULL. )) && streamIndex == dwStreamIndex && !(flags & (MF_SOURCE_READERF_ERROR|MF_SOURCE_READERF_ALLEFFECTSREMOVED|MF_SOURCE_READERF_ENDOFSTREAM)) && @@ -1036,19 +1009,8 @@ bool CvCaptureCAM_MSMF::grabFrame() return false; } -IplImage* CvCaptureCAM_MSMF::retrieveFrame(int) +IplImage* CvCapture_MSMF::retrieveFrame(int) { - unsigned int width = captureFormat.width; - unsigned int height = captureFormat.height; - unsigned int bytes = 3; //Suppose output format is BGR24 - if (!frame || (int)width != frame->width || (int)height != frame->height) - { - if (frame) - cvReleaseImage(&frame); - frame = cvCreateImage(cvSize(width, height), 8, bytes); - } - - unsigned int size = bytes * width * height; DWORD bcnt; if (videoSample && SUCCEEDED(videoSample->GetBufferCount(&bcnt)) && bcnt > 0) { @@ -1059,13 +1021,47 @@ IplImage* CvCaptureCAM_MSMF::retrieveFrame(int) BYTE* ptr = NULL; if (SUCCEEDED(buf->Lock(&ptr, &maxsize, &cursize))) { - if ((unsigned int)cursize == size) + if (convertFormat) { - memcpy(frame->imageData, ptr, size); - buf->Unlock(); - return frame; + if ((unsigned int)cursize == captureFormat.MF_MT_SAMPLE_SIZE) + { + if (!frame || (int)captureFormat.width != frame->width || (int)captureFormat.height != frame->height) + { + cvReleaseImage(&frame); + unsigned int bytes = captureMode == CV_CAP_MODE_GRAY || !convertFormat ? 1 : captureMode == CV_CAP_MODE_YUYV ? 2 : 3; //Suppose output format is BGR24 + frame = cvCreateImage(cvSize(captureFormat.width, captureFormat.height), 8, bytes); + } + switch (captureMode) + { + case CV_CAP_MODE_YUYV: + case CV_CAP_MODE_BGR: + memcpy(frame->imageData, ptr, cursize); + break; + case CV_CAP_MODE_RGB: + cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC3, ptr), cv::cvarrToMat(frame), cv::COLOR_BGR2RGB); + break; + case CV_CAP_MODE_GRAY: + cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC2, ptr), cv::cvarrToMat(frame), cv::COLOR_YUV2GRAY_YUY2); + break; + default: + cvReleaseImage(&frame); + break; + } + } + else + cvReleaseImage(&frame); + } + else + { + if (!frame || frame->width != (int)cursize || frame->height != 1) + { + cvReleaseImage(&frame); + frame = cvCreateImage(cvSize(cursize, 1), 8, 1); + } + memcpy(frame->imageData, ptr, cursize); } buf->Unlock(); + return frame; } } } @@ -1073,343 +1069,591 @@ IplImage* CvCaptureCAM_MSMF::retrieveFrame(int) return NULL; } -double CvCaptureCAM_MSMF::getFramerate(MediaType MT) const +double CvCapture_MSMF::getFramerate(MediaType MT) const { if (MT.MF_MT_SUBTYPE == MFVideoFormat_MP43) //Unable to estimate FPS for MP43 return 0; return MT.MF_MT_FRAME_RATE_DENOMINATOR != 0 ? ((double)MT.MF_MT_FRAME_RATE_NUMERATOR) / ((double)MT.MF_MT_FRAME_RATE_DENOMINATOR) : 0; } -double CvCaptureCAM_MSMF::getProperty( int property_id ) const +bool CvCapture_MSMF::setTime(double time, bool rough) { - // image format properties - if (isOpened) - switch (property_id) - { - case CV_CAP_PROP_FRAME_WIDTH: - return captureFormat.width; - case CV_CAP_PROP_FRAME_HEIGHT: - return captureFormat.height; - case CV_CAP_PROP_FOURCC: - return captureFormat.MF_MT_SUBTYPE.Data1; - case CV_CAP_PROP_FPS: - return getFramerate(captureFormat); - } - - return -1; -} -bool CvCaptureCAM_MSMF::setProperty( int property_id, double value ) -{ - // image capture properties - if (isOpened) - { - unsigned int width = captureFormat.width; - unsigned int height = captureFormat.height; - unsigned int fps = getProperty(CV_CAP_PROP_FPS); - switch (property_id) - { - case CV_CAP_PROP_FRAME_WIDTH: - width = cvRound(value); - break; - case CV_CAP_PROP_FRAME_HEIGHT: - height = cvRound(value); - break; - case CV_CAP_PROP_FPS: - fps = cvRound(value); - break; - } - - if (width > 0 && height > 0 && fps >= 0) - { - if (width != captureFormat.width || height != captureFormat.height || fps != getFramerate(captureFormat)) - return configureOutput(width, height, fps); - else - return true; - } - } - return false; -} - -class CvCaptureFile_MSMF : public CvCapture -{ -public: - CvCaptureFile_MSMF(); - virtual ~CvCaptureFile_MSMF(); - - virtual bool open( const char* filename ); - virtual void close(); - - virtual double getProperty(int) const; - virtual bool setProperty(int, double); - virtual bool grabFrame(); - virtual IplImage* retrieveFrame(int); - virtual int getCaptureDomain() { return CV_CAP_MSMF; } -protected: - Media_Foundation& MF; - _ComPtr videoFileSource; - DWORD dwStreamIndex; - MediaType captureFormat; - _ComPtr videoSample; - IplImage* frame; - bool isOpened; - - HRESULT getSourceDuration(MFTIME *pDuration) const; -}; - -CvCaptureFile_MSMF::CvCaptureFile_MSMF(): - MF(Media_Foundation::getInstance()), - videoFileSource(NULL), - videoSample(NULL), - frame(NULL), - isOpened(false) -{ -} - -CvCaptureFile_MSMF::~CvCaptureFile_MSMF() -{ - close(); -} - -bool CvCaptureFile_MSMF::open(const char* filename) -{ - close(); - if (!filename) - return false; - - // Set source reader parameters - _ComPtr srAttr; - if (SUCCEEDED(MFCreateAttributes(&srAttr, 10)) && - SUCCEEDED(srAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)) && - SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, false)) && - SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, false)) && - SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true)) - ) - { - //ToDo: Enable D3D MF_SOURCE_READER_D3D_MANAGER attribute - cv::AutoBuffer unicodeFileName(strlen(filename) + 1); - MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, (int)strlen(filename) + 1); - if (SUCCEEDED(MFCreateSourceReaderFromURL(unicodeFileName, srAttr.Get(), &videoFileSource))) - { - HRESULT hr = S_OK; - DWORD dwMediaTypeIndex = 0; - dwStreamIndex = 0; - while (SUCCEEDED(hr)) - { - _ComPtr pType; - hr = videoFileSource->GetNativeMediaType(dwStreamIndex, dwMediaTypeIndex, &pType); - if (hr == MF_E_NO_MORE_TYPES) - { - hr = S_OK; - ++dwStreamIndex; - dwMediaTypeIndex = 0; - } - else if (SUCCEEDED(hr)) - { - MediaType MT(pType.Get()); - if (MT.MF_MT_MAJOR_TYPE == MFMediaType_Video) - { - captureFormat = MT; - break; - } - ++dwMediaTypeIndex; - } - } - - _ComPtr mediaTypeOut; - if (// Retrieved stream media type - SUCCEEDED(hr) && - // Set the output media type. - SUCCEEDED(MFCreateMediaType(&mediaTypeOut)) && - SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)) && - SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24)) && - SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive)) && - SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_DEFAULT_STRIDE, 3 * captureFormat.width)) && //Assume BGR24 input - SUCCEEDED(MFSetAttributeSize(mediaTypeOut.Get(), MF_MT_FRAME_SIZE, captureFormat.width, captureFormat.height)) && - SUCCEEDED(MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1)) && - SUCCEEDED(videoFileSource->SetStreamSelection((DWORD)MF_SOURCE_READER_ALL_STREAMS, false)) && - SUCCEEDED(videoFileSource->SetStreamSelection(dwStreamIndex, true)) && - SUCCEEDED(videoFileSource->SetCurrentMediaType(dwStreamIndex, NULL, mediaTypeOut.Get())) - ) - { - isOpened = true; - return true; - } - } - } - - return false; -} - -void CvCaptureFile_MSMF::close() -{ - if (isOpened) - { - isOpened = false; - if (videoSample) - videoSample.Reset(); - if (videoFileSource) - videoFileSource.Reset(); - if (frame) - cvReleaseImage(&frame); - } -} - -bool CvCaptureFile_MSMF::setProperty(int property_id, double value) -{ - // image capture properties - // FIXME: implement method in VideoInput back end - (void) property_id; - (void) value; - return false; -} - -double CvCaptureFile_MSMF::getProperty(int property_id) const -{ - // image format properties - if (isOpened) - switch( property_id ) - { - case CV_CAP_PROP_FRAME_WIDTH: - return captureFormat.width; - case CV_CAP_PROP_FRAME_HEIGHT: - return captureFormat.height; - case CV_CAP_PROP_FRAME_COUNT: - { - if(captureFormat.MF_MT_SUBTYPE == MFVideoFormat_MP43) //Unable to estimate FPS for MP43 - return 0; - MFTIME duration; - getSourceDuration(&duration); - double fps = ((double)captureFormat.MF_MT_FRAME_RATE_NUMERATOR) / - ((double)captureFormat.MF_MT_FRAME_RATE_DENOMINATOR); - return (double)floor(((double)duration/1e7)*fps+0.5); - } - case CV_CAP_PROP_FOURCC: - return captureFormat.MF_MT_SUBTYPE.Data1; - case CV_CAP_PROP_FPS: - if (captureFormat.MF_MT_SUBTYPE == MFVideoFormat_MP43) //Unable to estimate FPS for MP43 - return 0; - return ((double)captureFormat.MF_MT_FRAME_RATE_NUMERATOR) / - ((double)captureFormat.MF_MT_FRAME_RATE_DENOMINATOR); - } - - return -1; -} - -bool CvCaptureFile_MSMF::grabFrame() -{ - if (isOpened) - { - DWORD streamIndex, flags; - LONGLONG llTimeStamp; - if (videoSample) - videoSample.Reset(); - if (SUCCEEDED(videoFileSource->ReadSample( - dwStreamIndex, // Stream index. - 0, // Flags. - &streamIndex, // Receives the actual stream index. - &flags, // Receives status flags. - &llTimeStamp, // Receives the time stamp. - &videoSample // Receives the sample or NULL. - ))) - { - if (streamIndex != dwStreamIndex) - { - DebugPrintOut(L"\tWrong stream readed. Abort capturing\n"); - close(); - } - else if (flags & MF_SOURCE_READERF_ERROR) - { - DebugPrintOut(L"\tStream reading error. Abort capturing\n"); - close(); - } - else if (flags & MF_SOURCE_READERF_ALLEFFECTSREMOVED) - { - DebugPrintOut(L"\tStream decoding error. Abort capturing\n"); - close(); - } - else if (flags & MF_SOURCE_READERF_ENDOFSTREAM) - { - DebugPrintOut(L"\tEnd of stream detected\n"); - } - else - { - if (flags & MF_SOURCE_READERF_NEWSTREAM) - { - DebugPrintOut(L"\tNew stream detected\n"); - } - if (flags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED) - { - DebugPrintOut(L"\tStream native media type changed\n"); - } - if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) - { - DebugPrintOut(L"\tStream current media type changed\n"); - } - if (flags & MF_SOURCE_READERF_STREAMTICK) - { - DebugPrintOut(L"\tStream tick detected\n"); - } - return true; - } - } - } - return false; -} - -IplImage* CvCaptureFile_MSMF::retrieveFrame(int) -{ - unsigned int width = captureFormat.width; - unsigned int height = captureFormat.height; - unsigned int bytes = 3; //Suppose output format is BGR24 - if( !frame || (int)width != frame->width || (int)height != frame->height ) - { - if (frame) - cvReleaseImage( &frame ); - frame = cvCreateImage( cvSize(width,height), 8, bytes ); - } - - unsigned int size = bytes * width * height; - DWORD bcnt; - if (videoSample && SUCCEEDED(videoSample->GetBufferCount(&bcnt)) && bcnt > 0) - { - _ComPtr buf = NULL; - if (SUCCEEDED(videoSample->GetBufferByIndex(0, &buf))) - { - DWORD maxsize, cursize; - BYTE* ptr = NULL; - if (SUCCEEDED(buf->Lock(&ptr, &maxsize, &cursize))) - { - if ((unsigned int)cursize == size) - { - memcpy(frame->imageData, ptr, size); - buf->Unlock(); - return frame; - } - buf->Unlock(); - } - } - } - - return NULL; -} - -HRESULT CvCaptureFile_MSMF::getSourceDuration(MFTIME *pDuration) const -{ - *pDuration = 0; - PROPVARIANT var; - HRESULT hr = videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var); - if (SUCCEEDED(hr) && var.vt == VT_I8) + if (SUCCEEDED(videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS, &var)) && + var.vt == VT_UI4 && (var.ulVal & MFMEDIASOURCE_CAN_SEEK && (rough || var.ulVal & MFMEDIASOURCE_HAS_SLOW_SEEK))) { - *pDuration = var.hVal.QuadPart; PropVariantClear(&var); + sampleTime = (LONGLONG)floor(time + 0.5); + var.vt = VT_I8; + var.hVal.QuadPart = sampleTime; + HRESULT hr = videoFileSource->SetCurrentPosition(GUID_NULL, var); + if (videoSample) + videoSample.Reset(); + PropVariantClear(&var); + return SUCCEEDED(hr); } - return hr; + return false; +} + +double CvCapture_MSMF::getProperty( int property_id ) const +{ + IAMVideoProcAmp *pProcAmp = NULL; + IAMCameraControl *pProcControl = NULL; + // image format properties + if (property_id == CV_CAP_PROP_FORMAT) + return captureMode; + else if (property_id == CV_CAP_PROP_CONVERT_RGB) + return convertFormat ? 1 : 0; + else if (property_id == CV_CAP_PROP_SAR_NUM) + return aspectN; + else if (property_id == CV_CAP_PROP_SAR_DEN) + return aspectD; + else if (isOpened) + switch (property_id) + { + case CV_CAP_PROP_FRAME_WIDTH: + return captureFormat.width; + case CV_CAP_PROP_FRAME_HEIGHT: + return captureFormat.height; + case CV_CAP_PROP_FOURCC: + return nativeFormat.MF_MT_SUBTYPE.Data1; + case CV_CAP_PROP_FPS: + return getFramerate(nativeFormat); + case CV_CAP_PROP_FRAME_COUNT: + if (duration != 0) + return floor(((double)duration / 1e7)*getFramerate(nativeFormat) + 0.5); + else + break; + case CV_CAP_PROP_POS_FRAMES: + return floor(((double)sampleTime / 1e7)*getFramerate(nativeFormat) + 0.5); + case CV_CAP_PROP_POS_MSEC: + return (double)sampleTime / 1e4; + case CV_CAP_PROP_POS_AVI_RATIO: + if (duration != 0) + return (double)sampleTime / duration; + else + break; + case CV_CAP_PROP_BRIGHTNESS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Brightness, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if(FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Brightness, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_CONTRAST: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Contrast, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Contrast, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_SATURATION: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Saturation, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Saturation, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_HUE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Hue, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Hue, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_GAIN: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Gain, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Gain, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_SHARPNESS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Sharpness, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Sharpness, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_GAMMA: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Gamma, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Gamma, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_BACKLIGHT: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_BacklightCompensation, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_BacklightCompensation, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_MONOCHROME: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_ColorEnable, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_ColorEnable, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal == 0 ? 1 : 0; + } + break; + case CV_CAP_PROP_TEMPERATURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_WhiteBalance, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_WhiteBalance, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: + case CV_CAP_PROP_WHITE_BALANCE_RED_V: + break; + case CV_CAP_PROP_PAN: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Pan, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Pan, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_TILT: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Tilt, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Tilt, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_ROLL: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Roll, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Roll, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_IRIS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Iris, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Iris, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_EXPOSURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Exposure, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Exposure, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + case CV_CAP_PROP_AUTO_EXPOSURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Exposure, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Exposure, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramFlag == VideoProcAmp_Flags_Auto; + } + break; + case CV_CAP_PROP_ZOOM: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Zoom, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Zoom, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_FOCUS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Focus, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Focus, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + case CV_CAP_PROP_AUTOFOCUS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Focus, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Focus, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramFlag == VideoProcAmp_Flags_Auto; + } + break; + case CV_CAP_PROP_MODE: + break; + + case CV_CAP_PROP_RECTIFICATION: + case CV_CAP_PROP_TRIGGER: + case CV_CAP_PROP_TRIGGER_DELAY: + case CV_CAP_PROP_GUID: + case CV_CAP_PROP_ISO_SPEED: + case CV_CAP_PROP_SETTINGS: + case CV_CAP_PROP_BUFFERSIZE: + default: + break; + } + + return -1; +} + +bool CvCapture_MSMF::setProperty( int property_id, double value ) +{ + IAMVideoProcAmp *pProcAmp = NULL; + IAMCameraControl *pProcControl = NULL; + // image capture properties + if (property_id == CV_CAP_PROP_FORMAT) + { + if (isOpened) + return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), aspectN, aspectD, (int)cvRound(value), convertFormat); + else + captureMode = (int)cvRound(value); + return true; + } + else if (property_id == CV_CAP_PROP_CONVERT_RGB) + { + if (isOpened) + return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), aspectN, aspectD, captureMode, value != 0); + else + convertFormat = value != 0; + return true; + } + else if (property_id == CV_CAP_PROP_SAR_NUM && value > 0) + { + if (isOpened) + return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), (UINT32)cvRound(value), aspectD, captureMode, convertFormat); + else + aspectN = (UINT32)cvRound(value); + return true; + } + else if (property_id == CV_CAP_PROP_SAR_DEN && value > 0) + { + if (isOpened) + return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), aspectN, (UINT32)cvRound(value), captureMode, convertFormat); + else + aspectD = (UINT32)cvRound(value); + return true; + } + else if (isOpened) + switch (property_id) + { + case CV_CAP_PROP_FRAME_WIDTH: + if (value > 0) + return configureOutput((UINT32)cvRound(value), captureFormat.height, getFramerate(nativeFormat), aspectN, aspectD, captureMode, convertFormat); + break; + case CV_CAP_PROP_FRAME_HEIGHT: + if (value > 0) + return configureOutput(captureFormat.width, (UINT32)cvRound(value), getFramerate(nativeFormat), aspectN, aspectD, captureMode, convertFormat); + break; + case CV_CAP_PROP_FPS: + if (value >= 0) + return configureOutput(captureFormat.width, captureFormat.height, value, aspectN, aspectD, captureMode, convertFormat); + break; + case CV_CAP_PROP_FOURCC: + break; + case CV_CAP_PROP_FRAME_COUNT: + break; + case CV_CAP_PROP_POS_AVI_RATIO: + if (duration != 0) + return setTime(duration * value, true); + break; + case CV_CAP_PROP_POS_FRAMES: + if (getFramerate(nativeFormat) != 0) + return setTime(value * 1e7 / getFramerate(nativeFormat), false); + break; + case CV_CAP_PROP_POS_MSEC: + return setTime(value * 1e4, true); + case CV_CAP_PROP_BRIGHTNESS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Brightness, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_CONTRAST: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Contrast, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_SATURATION: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Saturation, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_HUE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Hue, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_GAIN: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Gain, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_SHARPNESS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Sharpness, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_GAMMA: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Gamma, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_BACKLIGHT: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_BacklightCompensation, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_MONOCHROME: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = value != 0 ? 0 : 1; + HRESULT hr = pProcAmp->Set(VideoProcAmp_ColorEnable, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_TEMPERATURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_WhiteBalance, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: + case CV_CAP_PROP_WHITE_BALANCE_RED_V: + break; + case CV_CAP_PROP_PAN: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Pan, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_TILT: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Tilt, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_ROLL: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Roll, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_IRIS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Iris, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_EXPOSURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Exposure, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + case CV_CAP_PROP_AUTO_EXPOSURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = 0; + HRESULT hr = pProcControl->Set(CameraControl_Exposure, paramVal, value != 0 ? VideoProcAmp_Flags_Auto : VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_ZOOM: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Zoom, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_FOCUS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Focus, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + case CV_CAP_PROP_AUTOFOCUS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = 0; + HRESULT hr = pProcControl->Set(CameraControl_Focus, paramVal, value != 0 ? VideoProcAmp_Flags_Auto : VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_MODE: + return false; + + case CV_CAP_PROP_RECTIFICATION: + case CV_CAP_PROP_TRIGGER: + case CV_CAP_PROP_TRIGGER_DELAY: + case CV_CAP_PROP_GUID: + case CV_CAP_PROP_ISO_SPEED: + case CV_CAP_PROP_SETTINGS: + case CV_CAP_PROP_BUFFERSIZE: + default: + break; + } + + return false; } CvCapture* cvCreateCameraCapture_MSMF( int index ) { - CvCaptureCAM_MSMF* capture = new CvCaptureCAM_MSMF; + CvCapture_MSMF* capture = new CvCapture_MSMF; try { if( capture->open( index )) @@ -1426,7 +1670,7 @@ CvCapture* cvCreateCameraCapture_MSMF( int index ) CvCapture* cvCreateFileCapture_MSMF (const char* filename) { - CvCaptureFile_MSMF* capture = new CvCaptureFile_MSMF; + CvCapture_MSMF* capture = new CvCapture_MSMF; try { if( capture->open(filename) ) From 80600e5cdcf76bfe9663cc199a8bd3dc77aa8771 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Mon, 23 Apr 2018 16:48:57 +0300 Subject: [PATCH 14/36] Added DXVA hardware acceleration to MSMF-based VideoCapture --- cmake/OpenCVFindLibsVideo.cmake | 7 ++ modules/videoio/CMakeLists.txt | 3 + modules/videoio/src/cap_msmf.cpp | 180 +++++++++++++++++++++++++------ 3 files changed, 156 insertions(+), 34 deletions(-) diff --git a/cmake/OpenCVFindLibsVideo.cmake b/cmake/OpenCVFindLibsVideo.cmake index f7b427bf45..9ed9ceb823 100644 --- a/cmake/OpenCVFindLibsVideo.cmake +++ b/cmake/OpenCVFindLibsVideo.cmake @@ -261,6 +261,13 @@ endif(WITH_DSHOW) ocv_clear_vars(HAVE_MSMF) if(WITH_MSMF) check_include_file(Mfapi.h HAVE_MSMF) + check_include_file(D3D11.h D3D11_found) + check_include_file(D3d11_4.h D3D11_4_found) + if(D3D11_found AND D3D11_4_found) + set(HAVE_DXVA YES) + else() + set(HAVE_DXVA NO) + endif() endif(WITH_MSMF) # --- Extra HighGUI and VideoIO libs on Windows --- diff --git a/modules/videoio/CMakeLists.txt b/modules/videoio/CMakeLists.txt index 3562bfe05f..02d2bd830f 100644 --- a/modules/videoio/CMakeLists.txt +++ b/modules/videoio/CMakeLists.txt @@ -86,6 +86,9 @@ endif() if (WIN32 AND HAVE_MSMF) list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_msmf.hpp) list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_msmf.cpp) + if (HAVE_DXVA) + add_definitions(-DHAVE_DXVA) + endif() endif() if (WIN32 AND HAVE_VFW) diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp index dfe008224e..b43e206591 100644 --- a/modules/videoio/src/cap_msmf.cpp +++ b/modules/videoio/src/cap_msmf.cpp @@ -61,6 +61,10 @@ #include #include #include +#ifdef HAVE_DXVA +#include +#include +#endif #include #include #include @@ -77,6 +81,9 @@ #pragma comment(lib, "mfuuid") #pragma comment(lib, "Strmiids") #pragma comment(lib, "Mfreadwrite") +#ifdef HAVE_DXVA +#pragma comment(lib, "d3d11") +#endif #if (WINVER >= 0x0602) // Available since Win 8 #pragma comment(lib, "MinCore_Downlevel") #endif @@ -677,6 +684,10 @@ void MediaType::Clear() class CvCapture_MSMF : public CvCapture { public: + typedef enum { + MODE_SW = 0, + MODE_HW = 1 + } MSMFCapture_Mode; CvCapture_MSMF(); virtual ~CvCapture_MSMF(); virtual bool open(int index); @@ -691,13 +702,21 @@ protected: double getFramerate(MediaType MT) const; bool configureOutput(UINT32 width, UINT32 height, double prefFramerate, UINT32 aspectRatioN, UINT32 aspectRatioD, int outFormat, bool convertToFormat); bool setTime(double time, bool rough); + bool configureHW(bool enable); Media_Foundation& MF; + cv::String filename; + int camid; + MSMFCapture_Mode captureMode; +#ifdef HAVE_DXVA + _ComPtr D3DDev; + _ComPtr D3DMgr; +#endif _ComPtr videoFileSource; DWORD dwStreamIndex; MediaType nativeFormat; MediaType captureFormat; - int captureMode; + int outputFormat; bool convertFormat; UINT32 aspectN, aspectD; MFTIME duration; @@ -709,9 +728,16 @@ protected: CvCapture_MSMF::CvCapture_MSMF(): MF(Media_Foundation::getInstance()), + filename(""), + camid(-1), + captureMode(MODE_SW), +#ifdef HAVE_DXVA + D3DDev(NULL), + D3DMgr(NULL), +#endif videoFileSource(NULL), videoSample(NULL), - captureMode(CV_CAP_MODE_BGR), + outputFormat(CV_CAP_MODE_BGR), convertFormat(true), aspectN(1), aspectD(1), @@ -737,14 +763,69 @@ void CvCapture_MSMF::close() videoFileSource.Reset(); if (frame) cvReleaseImage(&frame); + camid = -1; + filename = ""; } } +bool CvCapture_MSMF::configureHW(bool enable) +{ +#ifdef HAVE_DXVA + if ((enable && D3DMgr && D3DDev) || (!enable && !D3DMgr && !D3DDev)) + return true; + + bool reopen = isOpened; + int prevcam = camid; + cv::String prevfile = filename; + close(); + if (enable) + { + D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1 }; + if (SUCCEEDED(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_VIDEO_SUPPORT, + levels, sizeof(levels) / sizeof(*levels), D3D11_SDK_VERSION, D3DDev.GetAddressOf(), NULL, NULL))) + { + // NOTE: Getting ready for multi-threaded operation + _ComPtr D3DDevMT; + UINT mgrRToken; + if (SUCCEEDED(D3DDev->QueryInterface(IID_PPV_ARGS(&D3DDevMT)))) + { + D3DDevMT->SetMultithreadProtected(TRUE); + D3DDevMT.Reset(); + if (SUCCEEDED(MFCreateDXGIDeviceManager(&mgrRToken, D3DMgr.GetAddressOf()))) + { + if (SUCCEEDED(D3DMgr->ResetDevice(D3DDev.Get(), mgrRToken))) + { + captureMode = MODE_HW; + return reopen ? camid >= 0 ? open(prevcam) : open(prevfile.c_str()) : true; + } + D3DMgr.Reset(); + } + } + D3DDev.Reset(); + } + return false; + } + else + { + if (D3DMgr) + D3DMgr.Reset(); + if (D3DDev) + D3DDev.Reset(); + captureMode = MODE_SW; + return reopen ? camid >= 0 ? open(prevcam) : open(prevfile.c_str()) : true; + } +#else + return !enable; +#endif +} + bool CvCapture_MSMF::configureOutput(UINT32 width, UINT32 height, double prefFramerate, UINT32 aspectRatioN, UINT32 aspectRatioD, int outFormat, bool convertToFormat) { if (width != 0 && height != 0 && width == captureFormat.width && height == captureFormat.height && prefFramerate == getFramerate(nativeFormat) && - aspectRatioN == aspectN && aspectRatioD == aspectD && outFormat == captureMode && convertToFormat == convertFormat) + aspectRatioN == aspectN && aspectRatioD == aspectD && outFormat == outputFormat && convertToFormat == convertFormat) return true; HRESULT hr = S_OK; @@ -797,18 +878,25 @@ bool CvCapture_MSMF::configureOutput(UINT32 width, UINT32 height, double prefFra MediaType tryMT = dwStreamBest >= 0 ? MTBest : MTFallback; GUID outSubtype = GUID_NULL; UINT32 outStride = 0; + UINT32 outSize = 0; if(convertToFormat) switch (outFormat) { case CV_CAP_MODE_BGR: case CV_CAP_MODE_RGB: - outSubtype = MFVideoFormat_RGB24; - outStride = 3 * tryMT.width; + outSubtype = captureMode == MODE_HW ? MFVideoFormat_RGB32 : MFVideoFormat_RGB24; // HW accelerated mode support only RGB32 + outStride = (captureMode == MODE_HW ? 4 : 3) * tryMT.width; + outSize = outStride * tryMT.height; break; case CV_CAP_MODE_GRAY: + outSubtype = MFVideoFormat_NV12; + outStride = tryMT.width; + outSize = outStride * tryMT.height * 3 / 2; + break; case CV_CAP_MODE_YUYV: outSubtype = MFVideoFormat_YUY2; outStride = 2 * tryMT.width; + outSize = outStride * tryMT.height; break; default: return false; @@ -822,7 +910,7 @@ bool CvCapture_MSMF::configureOutput(UINT32 width, UINT32 height, double prefFra SUCCEEDED(MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, aspectRatioN, aspectRatioD)) && SUCCEEDED(MFSetAttributeSize(mediaTypeOut.Get(), MF_MT_FRAME_SIZE, tryMT.width, tryMT.height)) && SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, convertToFormat ? 1 : tryMT.MF_MT_FIXED_SIZE_SAMPLES)) && - SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_SAMPLE_SIZE, convertToFormat ? outStride * tryMT.height : tryMT.MF_MT_SAMPLE_SIZE)) && + SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_SAMPLE_SIZE, convertToFormat ? outSize : tryMT.MF_MT_SAMPLE_SIZE)) && SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_DEFAULT_STRIDE, convertToFormat ? outStride : tryMT.MF_MT_DEFAULT_STRIDE)))//Assume BGR24 input { if (SUCCEEDED(videoFileSource->SetStreamSelection((DWORD)MF_SOURCE_READER_ALL_STREAMS, false)) && @@ -834,12 +922,10 @@ bool CvCapture_MSMF::configureOutput(UINT32 width, UINT32 height, double prefFra nativeFormat = tryMT; aspectN = aspectRatioN; aspectD = aspectRatioD; - captureMode = outFormat; + outputFormat = outFormat; convertFormat = convertToFormat; captureFormat = MediaType(mediaTypeOut.Get()); - if (!convertFormat || (captureFormat.MF_MT_FIXED_SIZE_SAMPLES && - captureFormat.MF_MT_SAMPLE_SIZE == ((captureMode == CV_CAP_MODE_GRAY || captureMode == CV_CAP_MODE_YUYV ? 2 : 3) * captureFormat.MF_MT_FRAME_SIZE))) - return true; + return true; } close(); } @@ -880,12 +966,16 @@ bool CvCapture_MSMF::open(int _index) SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, false)) && SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true))) { - //ToDo: Enable D3D MF_SOURCE_READER_D3D_MANAGER attribute +#ifdef HAVE_DXVA + if (D3DMgr) + srAttr->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, D3DMgr.Get()); +#endif if (SUCCEEDED(MFCreateSourceReaderFromMediaSource(mSrc.Get(), srAttr.Get(), &videoFileSource))) { isOpened = true; duration = 0; - configureOutput(0, 0, 0, aspectN, aspectD, captureMode, convertFormat); + if (configureOutput(0, 0, 0, aspectN, aspectD, outputFormat, convertFormat)) + camid = _index; } } } @@ -900,10 +990,10 @@ bool CvCapture_MSMF::open(int _index) return isOpened; } -bool CvCapture_MSMF::open(const char* filename) +bool CvCapture_MSMF::open(const char* _filename) { close(); - if (!filename) + if (!_filename) return false; // Set source reader parameters @@ -915,15 +1005,19 @@ bool CvCapture_MSMF::open(const char* filename) SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true)) ) { - //ToDo: Enable D3D MF_SOURCE_READER_D3D_MANAGER attribute - cv::AutoBuffer unicodeFileName(strlen(filename) + 1); - MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, (int)strlen(filename) + 1); +#ifdef HAVE_DXVA + if(D3DMgr) + srAttr->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, D3DMgr.Get()); +#endif + cv::AutoBuffer unicodeFileName(strlen(_filename) + 1); + MultiByteToWideChar(CP_ACP, 0, _filename, -1, unicodeFileName, (int)strlen(_filename) + 1); if (SUCCEEDED(MFCreateSourceReaderFromURL(unicodeFileName, srAttr.Get(), &videoFileSource))) { isOpened = true; sampleTime = 0; - if (configureOutput(0, 0, 0, aspectN, aspectD, captureMode, convertFormat)) + if (configureOutput(0, 0, 0, aspectN, aspectD, outputFormat, convertFormat)) { + filename = _filename; PROPVARIANT var; HRESULT hr; if (SUCCEEDED(hr = videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var)) && @@ -1028,20 +1122,28 @@ IplImage* CvCapture_MSMF::retrieveFrame(int) if (!frame || (int)captureFormat.width != frame->width || (int)captureFormat.height != frame->height) { cvReleaseImage(&frame); - unsigned int bytes = captureMode == CV_CAP_MODE_GRAY || !convertFormat ? 1 : captureMode == CV_CAP_MODE_YUYV ? 2 : 3; //Suppose output format is BGR24 + unsigned int bytes = outputFormat == CV_CAP_MODE_GRAY || !convertFormat ? 1 : outputFormat == CV_CAP_MODE_YUYV ? 2 : 3; frame = cvCreateImage(cvSize(captureFormat.width, captureFormat.height), 8, bytes); } - switch (captureMode) + switch (outputFormat) { case CV_CAP_MODE_YUYV: - case CV_CAP_MODE_BGR: memcpy(frame->imageData, ptr, cursize); break; + case CV_CAP_MODE_BGR: + if (captureMode == MODE_HW) + cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC4, ptr), cv::cvarrToMat(frame), cv::COLOR_BGRA2BGR); + else + memcpy(frame->imageData, ptr, cursize); + break; case CV_CAP_MODE_RGB: - cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC3, ptr), cv::cvarrToMat(frame), cv::COLOR_BGR2RGB); + if (captureMode == MODE_HW) + cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC4, ptr), cv::cvarrToMat(frame), cv::COLOR_BGRA2BGR); + else + cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC3, ptr), cv::cvarrToMat(frame), cv::COLOR_BGR2RGB); break; case CV_CAP_MODE_GRAY: - cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC2, ptr), cv::cvarrToMat(frame), cv::COLOR_YUV2GRAY_YUY2); + memcpy(frame->imageData, ptr, captureFormat.height*captureFormat.width); break; default: cvReleaseImage(&frame); @@ -1101,6 +1203,8 @@ double CvCapture_MSMF::getProperty( int property_id ) const IAMCameraControl *pProcControl = NULL; // image format properties if (property_id == CV_CAP_PROP_FORMAT) + return outputFormat; + else if (property_id == CV_CAP_PROP_MODE) return captureMode; else if (property_id == CV_CAP_PROP_CONVERT_RGB) return convertFormat ? 1 : 0; @@ -1380,8 +1484,6 @@ double CvCapture_MSMF::getProperty( int property_id ) const return paramFlag == VideoProcAmp_Flags_Auto; } break; - case CV_CAP_PROP_MODE: - break; case CV_CAP_PROP_RECTIFICATION: case CV_CAP_PROP_TRIGGER: @@ -1407,13 +1509,25 @@ bool CvCapture_MSMF::setProperty( int property_id, double value ) if (isOpened) return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), aspectN, aspectD, (int)cvRound(value), convertFormat); else - captureMode = (int)cvRound(value); + outputFormat = (int)cvRound(value); return true; } + else if (property_id == CV_CAP_PROP_MODE) + { + switch ((MSMFCapture_Mode)((int)value)) + { + case MODE_SW: + return configureHW(false); + case MODE_HW: + return configureHW(true); + default: + return false; + } + } else if (property_id == CV_CAP_PROP_CONVERT_RGB) { if (isOpened) - return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), aspectN, aspectD, captureMode, value != 0); + return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), aspectN, aspectD, outputFormat, value != 0); else convertFormat = value != 0; return true; @@ -1421,7 +1535,7 @@ bool CvCapture_MSMF::setProperty( int property_id, double value ) else if (property_id == CV_CAP_PROP_SAR_NUM && value > 0) { if (isOpened) - return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), (UINT32)cvRound(value), aspectD, captureMode, convertFormat); + return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), (UINT32)cvRound(value), aspectD, outputFormat, convertFormat); else aspectN = (UINT32)cvRound(value); return true; @@ -1429,7 +1543,7 @@ bool CvCapture_MSMF::setProperty( int property_id, double value ) else if (property_id == CV_CAP_PROP_SAR_DEN && value > 0) { if (isOpened) - return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), aspectN, (UINT32)cvRound(value), captureMode, convertFormat); + return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), aspectN, (UINT32)cvRound(value), outputFormat, convertFormat); else aspectD = (UINT32)cvRound(value); return true; @@ -1439,15 +1553,15 @@ bool CvCapture_MSMF::setProperty( int property_id, double value ) { case CV_CAP_PROP_FRAME_WIDTH: if (value > 0) - return configureOutput((UINT32)cvRound(value), captureFormat.height, getFramerate(nativeFormat), aspectN, aspectD, captureMode, convertFormat); + return configureOutput((UINT32)cvRound(value), captureFormat.height, getFramerate(nativeFormat), aspectN, aspectD, outputFormat, convertFormat); break; case CV_CAP_PROP_FRAME_HEIGHT: if (value > 0) - return configureOutput(captureFormat.width, (UINT32)cvRound(value), getFramerate(nativeFormat), aspectN, aspectD, captureMode, convertFormat); + return configureOutput(captureFormat.width, (UINT32)cvRound(value), getFramerate(nativeFormat), aspectN, aspectD, outputFormat, convertFormat); break; case CV_CAP_PROP_FPS: if (value >= 0) - return configureOutput(captureFormat.width, captureFormat.height, value, aspectN, aspectD, captureMode, convertFormat); + return configureOutput(captureFormat.width, captureFormat.height, value, aspectN, aspectD, outputFormat, convertFormat); break; case CV_CAP_PROP_FOURCC: break; @@ -1634,8 +1748,6 @@ bool CvCapture_MSMF::setProperty( int property_id, double value ) return SUCCEEDED(hr); } break; - case CV_CAP_PROP_MODE: - return false; case CV_CAP_PROP_RECTIFICATION: case CV_CAP_PROP_TRIGGER: From 0bd33c8d1c2270ad4399944e60d84d17180c42b8 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 25 Apr 2018 13:20:03 +0300 Subject: [PATCH 15/36] android: don't use relative paths to contrib modules --- platforms/android/build_sdk.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/platforms/android/build_sdk.py b/platforms/android/build_sdk.py index b40c26069e..463e1036bf 100755 --- a/platforms/android/build_sdk.py +++ b/platforms/android/build_sdk.py @@ -317,6 +317,12 @@ if __name__ == "__main__": if os.path.realpath(args.work_dir) == os.path.realpath(args.opencv_dir): raise Fail("Specify workdir (building from OpenCV source directory is not supported)") + # Relative paths become invalid in sub-directories + if args.opencv_dir is not None and not os.path.isabs(args.opencv_dir): + args.opencv_dir = os.path.abspath(args.opencv_dir) + if args.extra_modules_path is not None and not os.path.isabs(args.extra_modules_path): + args.extra_modules_path = os.path.abspath(args.extra_modules_path) + cpath = args.config if not os.path.exists(cpath): cpath = os.path.join(SCRIPT_DIR, cpath) From 469dc6ac42e67417ba09bd0ab8c9f9da9cf8f7d0 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 25 Apr 2018 16:34:44 +0300 Subject: [PATCH 16/36] imgproc: fix fixed point build avoid using of templated 'operator T ()' --- modules/imgproc/src/fixedpoint.inl.hpp | 44 ++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/modules/imgproc/src/fixedpoint.inl.hpp b/modules/imgproc/src/fixedpoint.inl.hpp index 78ba553307..d153ae9c80 100644 --- a/modules/imgproc/src/fixedpoint.inl.hpp +++ b/modules/imgproc/src/fixedpoint.inl.hpp @@ -91,9 +91,14 @@ public: CV_ALWAYS_INLINE fixedpoint64 operator << (int n) const { return fixedpoint64(val << n); } CV_ALWAYS_INLINE bool operator == (const fixedpoint64& val2) const { return val == val2.val; } template - CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast((int64_t)fixedround((uint64_t)val) >> fixedShift); } + CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast((int64_t)fixedround((uint64_t)val) >> fixedShift); } CV_ALWAYS_INLINE operator double() const { return (double)val / (1LL << fixedShift); } CV_ALWAYS_INLINE operator float() const { return (float)val / (1LL << fixedShift); } + CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast(); } CV_ALWAYS_INLINE bool isZero() { return val == 0; } static CV_ALWAYS_INLINE fixedpoint64 zero() { return fixedpoint64(); } static CV_ALWAYS_INLINE fixedpoint64 one() { return fixedpoint64((int64_t)(1LL << fixedShift)); } @@ -151,9 +156,14 @@ public: CV_ALWAYS_INLINE ufixedpoint64 operator << (int n) const { return ufixedpoint64(val << n); } CV_ALWAYS_INLINE bool operator == (const ufixedpoint64& val2) const { return val == val2.val; } template - CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast(fixedround(val) >> fixedShift); } + CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast(fixedround(val) >> fixedShift); } CV_ALWAYS_INLINE operator double() const { return (double)val / (1LL << fixedShift); } CV_ALWAYS_INLINE operator float() const { return (float)val / (1LL << fixedShift); } + CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast(); } CV_ALWAYS_INLINE bool isZero() { return val == 0; } static CV_ALWAYS_INLINE ufixedpoint64 zero() { return ufixedpoint64(); } static CV_ALWAYS_INLINE ufixedpoint64 one() { return ufixedpoint64((uint64_t)(1ULL << fixedShift)); } @@ -198,10 +208,15 @@ public: CV_ALWAYS_INLINE fixedpoint32 operator << (int n) const { return fixedpoint32(val << n); } CV_ALWAYS_INLINE bool operator == (const fixedpoint32& val2) const { return val == val2.val; } template - CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast((int32_t)fixedround((uint32_t)val) >> fixedShift); } + CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast((int32_t)fixedround((uint32_t)val) >> fixedShift); } CV_ALWAYS_INLINE operator fixedpoint64() const { return (int64_t)val << (fixedpoint64::fixedShift - fixedShift); } CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); } CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); } + CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast(); } CV_ALWAYS_INLINE bool isZero() { return val == 0; } static CV_ALWAYS_INLINE fixedpoint32 zero() { return fixedpoint32(); } static CV_ALWAYS_INLINE fixedpoint32 one() { return fixedpoint32((1 << fixedShift)); } @@ -242,10 +257,15 @@ public: CV_ALWAYS_INLINE ufixedpoint32 operator << (int n) const { return ufixedpoint32(val << n); } CV_ALWAYS_INLINE bool operator == (const ufixedpoint32& val2) const { return val == val2.val; } template - CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast(fixedround(val) >> fixedShift); } + CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast(fixedround(val) >> fixedShift); } CV_ALWAYS_INLINE operator ufixedpoint64() const { return (uint64_t)val << (ufixedpoint64::fixedShift - fixedShift); } CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); } CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); } + CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast(); } CV_ALWAYS_INLINE bool isZero() { return val == 0; } static CV_ALWAYS_INLINE ufixedpoint32 zero() { return ufixedpoint32(); } static CV_ALWAYS_INLINE ufixedpoint32 one() { return ufixedpoint32((1U << fixedShift)); } @@ -284,10 +304,15 @@ public: CV_ALWAYS_INLINE fixedpoint16 operator << (int n) const { return fixedpoint16((int16_t)(val << n)); } CV_ALWAYS_INLINE bool operator == (const fixedpoint16& val2) const { return val == val2.val; } template - CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast((int16_t)fixedround((uint16_t)val) >> fixedShift); } + CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast((int16_t)fixedround((uint16_t)val) >> fixedShift); } CV_ALWAYS_INLINE operator fixedpoint32() const { return (int32_t)val << (fixedpoint32::fixedShift - fixedShift); } CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); } CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); } + CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast(); } CV_ALWAYS_INLINE bool isZero() { return val == 0; } static CV_ALWAYS_INLINE fixedpoint16 zero() { return fixedpoint16(); } static CV_ALWAYS_INLINE fixedpoint16 one() { return fixedpoint16((int16_t)(1 << fixedShift)); } @@ -324,10 +349,15 @@ public: CV_ALWAYS_INLINE ufixedpoint16 operator << (int n) const { return ufixedpoint16((uint16_t)(val << n)); } CV_ALWAYS_INLINE bool operator == (const ufixedpoint16& val2) const { return val == val2.val; } template - CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast(fixedround(val) >> fixedShift); } + CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast(fixedround(val) >> fixedShift); } CV_ALWAYS_INLINE operator ufixedpoint32() const { return (uint32_t)val << (ufixedpoint32::fixedShift - fixedShift); } CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); } CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); } + CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast(); } + CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast(); } CV_ALWAYS_INLINE bool isZero() { return val == 0; } static CV_ALWAYS_INLINE ufixedpoint16 zero() { return ufixedpoint16(); } static CV_ALWAYS_INLINE ufixedpoint16 one() { return ufixedpoint16((uint16_t)(1 << fixedShift)); } @@ -335,4 +365,4 @@ public: } -#endif \ No newline at end of file +#endif From 9166e6052b32b404298e4de0dcec099d580ad666 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 25 Apr 2018 17:18:15 +0300 Subject: [PATCH 17/36] imgproc: fixed fixedpoint coding style - fixed wrong condition (always true) - replaced unnecessary shift operation: '>> 63' to '< 0' - used CV_BIG_INT()/CV_BIG_UINT() macros --- modules/imgproc/src/fixedpoint.inl.hpp | 31 +++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/modules/imgproc/src/fixedpoint.inl.hpp b/modules/imgproc/src/fixedpoint.inl.hpp index d153ae9c80..0878dc456f 100644 --- a/modules/imgproc/src/fixedpoint.inl.hpp +++ b/modules/imgproc/src/fixedpoint.inl.hpp @@ -55,9 +55,11 @@ public: CV_ALWAYS_INLINE fixedpoint64 operator * (const int32_t& val2) const { return operator *(fixedpoint64(val2)); } CV_ALWAYS_INLINE fixedpoint64 operator * (const fixedpoint64& val2) const { - uint64_t uval = (uint64_t)((val ^ (val >> 63)) - (val >> 63)); - uint64_t umul = (uint64_t)((val2.val ^ (val2.val >> 63)) - (val2.val >> 63)); - int64_t ressign = (val >> 63) ^ (val2.val >> 63); + bool sign_val = val < 0; + bool sign_mul = val2.val < 0; + uint64_t uval = sign_val ? (uint64_t)(-val) : (uint64_t)val; + uint64_t umul = sign_mul ? (uint64_t)(-val2.val) : (uint64_t)val2.val; + bool ressign = sign_val ^ sign_mul; uint64_t sh0 = fixedround((uval & 0xFFFFFFFF) * (umul & 0xFFFFFFFF)); uint64_t sh1_0 = (uval >> 32) * (umul & 0xFFFFFFFF); @@ -67,25 +69,24 @@ public: uint64_t val0_h = (sh2 & 0xFFFFFFFF) + (sh1_0 >> 32) + (sh1_1 >> 32) + (val0_l >> 32); val0_l &= 0xFFFFFFFF; - if ( (sh2 >> 32) || (val0_h >> ressign ? 32 : 31) ) - return (ressign ? ~(int64_t)0x7FFFFFFFFFFFFFFF : (int64_t)0x7FFFFFFFFFFFFFFF); + if (sh2 > CV_BIG_INT(0x7FFFFFFF) || val0_h > CV_BIG_INT(0x7FFFFFFF)) + return (int64_t)(ressign ? CV_BIG_UINT(0x8000000000000000) : CV_BIG_INT(0x7FFFFFFFFFFFFFFF)); if (ressign) { - val0_l = (~val0_l + 1) & 0xFFFFFFFF; - val0_h = val0_l ? ~val0_h : (~val0_h + 1); + return -(int64_t)(val0_h << 32 | val0_l); } return (int64_t)(val0_h << 32 | val0_l); } CV_ALWAYS_INLINE fixedpoint64 operator + (const fixedpoint64& val2) const { int64_t res = val + val2.val; - return ((val ^ res) & (val2.val ^ res)) >> 63 ? ~(res & ~0x7FFFFFFFFFFFFFFF) : res; + return (int64_t)(((val ^ res) & (val2.val ^ res)) < 0 ? ~(res & CV_BIG_UINT(0x8000000000000000)) : res); } CV_ALWAYS_INLINE fixedpoint64 operator - (const fixedpoint64& val2) const { int64_t res = val - val2.val; - return ((val ^ val2.val) & (val ^ res)) >> 63 ? ~(res & ~0x7FFFFFFFFFFFFFFF) : res; + return (int64_t)(((val ^ val2.val) & (val ^ res)) < 0 ? ~(res & CV_BIG_UINT(0x8000000000000000)) : res); } CV_ALWAYS_INLINE fixedpoint64 operator >> (int n) const { return fixedpoint64(val >> n); } CV_ALWAYS_INLINE fixedpoint64 operator << (int n) const { return fixedpoint64(val << n); } @@ -138,15 +139,15 @@ public: uint64_t val0_h = (sh2 & 0xFFFFFFFF) + (sh1_0 >> 32) + (sh1_1 >> 32) + (val0_l >> 32); val0_l &= 0xFFFFFFFF; - if ((sh2 >> 32) || (val0_h >> 32)) - return ((uint64_t)0xFFFFFFFFFFFFFFFF); + if (sh2 > CV_BIG_INT(0xFFFFFFFF) || val0_h > CV_BIG_INT(0xFFFFFFFF)) + return (uint64_t)CV_BIG_UINT(0xFFFFFFFFFFFFFFFF); - return val0_h << 32 | val0_l; + return (val0_h << 32 | val0_l); } CV_ALWAYS_INLINE ufixedpoint64 operator + (const ufixedpoint64& val2) const { uint64_t res = val + val2.val; - return (val > res) ? (uint64_t)0xFFFFFFFFFFFFFFFF : res; + return (uint64_t)((val > res) ? CV_BIG_UINT(0xFFFFFFFFFFFFFFFF) : res); } CV_ALWAYS_INLINE ufixedpoint64 operator - (const ufixedpoint64& val2) const { @@ -197,12 +198,12 @@ public: CV_ALWAYS_INLINE fixedpoint32 operator + (const fixedpoint32& val2) const { int32_t res = val + val2.val; - return ((val ^ res) & (val2.val ^ res)) >> 31 ? ~(res & ~0x7FFFFFFF) : res; + return (int64_t)((val ^ res) & (val2.val ^ res)) >> 31 ? ~(res & ~0x7FFFFFFF) : res; } CV_ALWAYS_INLINE fixedpoint32 operator - (const fixedpoint32& val2) const { int32_t res = val - val2.val; - return ((val ^ val2.val) & (val ^ res)) >> 31 ? ~(res & ~0x7FFFFFFF) : res; + return (int64_t)((val ^ val2.val) & (val ^ res)) >> 31 ? ~(res & ~0x7FFFFFFF) : res; } CV_ALWAYS_INLINE fixedpoint32 operator >> (int n) const { return fixedpoint32(val >> n); } CV_ALWAYS_INLINE fixedpoint32 operator << (int n) const { return fixedpoint32(val << n); } From d5b95632639b7203d174effc90cd2c909399a7c9 Mon Sep 17 00:00:00 2001 From: Dmitry Kurtaev Date: Wed, 25 Apr 2018 15:19:02 +0300 Subject: [PATCH 18/36] Custom deep learning layers in Python --- .../dnn_custom_layers/dnn_custom_layers.md | 34 ++++ doc/tutorials/dnn/images/lena_hed.jpg | Bin 0 -> 38925 bytes modules/dnn/misc/python/pyopencv_dnn.hpp | 180 +++++++++++++++++- modules/python/src2/cv2.cpp | 4 + samples/dnn/edge_detection.py | 69 +++++++ 5 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 doc/tutorials/dnn/images/lena_hed.jpg create mode 100644 samples/dnn/edge_detection.py diff --git a/doc/tutorials/dnn/dnn_custom_layers/dnn_custom_layers.md b/doc/tutorials/dnn/dnn_custom_layers/dnn_custom_layers.md index f0e419753a..5b3f3c7347 100644 --- a/doc/tutorials/dnn/dnn_custom_layers/dnn_custom_layers.md +++ b/doc/tutorials/dnn/dnn_custom_layers/dnn_custom_layers.md @@ -190,3 +190,37 @@ In our case resize's output shape will be stored in layer's `blobs[0]`. Next we register a layer and try to import the model. @snippet dnn/custom_layers.cpp Register ResizeBilinearLayer + +## Define a custom layer in Python +The following example shows how to customize OpenCV's layers in Python. + +Let's consider [Holistically-Nested Edge Detection](https://arxiv.org/abs/1504.06375) +deep learning model. That was trained with one and only difference comparing to +a current version of [Caffe framework](http://caffe.berkeleyvision.org/). `Crop` +layers that receive two input blobs and crop the first one to match spatial dimensions +of the second one used to crop from the center. Nowadays Caffe's layer does it +from the top-left corner. So using the latest version of Caffe or OpenCV you'll +get shifted results with filled borders. + +Next we're going to replace OpenCV's `Crop` layer that makes top-left cropping by +a centric one. + +- Create a class with `getMemoryShapes` and `forward` methods + +@snippet dnn/edge_detection.py CropLayer + +@note Both methods should return lists. + +- Register a new layer. + +@snippet dnn/edge_detection.py Register + +That's it! We've replaced an implemented OpenCV's layer to a custom one. +You may find a full script in the [source code](https://github.com/opencv/opencv/tree/master/samples/dnn/edge_detection.py). + + + + + + +
![](js_tutorials/js_assets/lena.jpg)![](images/lena_hed.jpg)
diff --git a/doc/tutorials/dnn/images/lena_hed.jpg b/doc/tutorials/dnn/images/lena_hed.jpg new file mode 100644 index 0000000000000000000000000000000000000000..59d5a6c31ee8bb2d5bc01b0cab02025090f3c155 GIT binary patch literal 38925 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 &blobs, const char *name) //requi return pyopencvVecConverter::to(o, blobs, ArgInfo(name, false)); } -#endif +template +PyObject* pyopencv_from(const dnn::DictValue &dv) +{ + if (dv.size() > 1) + { + std::vector vec(dv.size()); + for (int i = 0; i < dv.size(); ++i) + vec[i] = dv.get(i); + return pyopencv_from_generic_vec(vec); + } + else + return pyopencv_from(dv.get()); +} + +template<> +PyObject* pyopencv_from(const dnn::DictValue &dv) +{ + if (dv.isInt()) return pyopencv_from(dv); + if (dv.isReal()) return pyopencv_from(dv); + if (dv.isString()) return pyopencv_from(dv); + CV_Error(Error::StsNotImplemented, "Unknown value type"); + return NULL; +} + +template<> +PyObject* pyopencv_from(const dnn::LayerParams& lp) +{ + PyObject* dict = PyDict_New(); + for (std::map::const_iterator it = lp.begin(); it != lp.end(); ++it) + { + CV_Assert(!PyDict_SetItemString(dict, it->first.c_str(), pyopencv_from(it->second))); + } + return dict; +} + +class pycvLayer CV_FINAL : public dnn::Layer +{ +public: + pycvLayer(const dnn::LayerParams ¶ms, PyObject* pyLayer) : Layer(params) + { + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); + + PyObject* args = PyTuple_New(2); + CV_Assert(!PyTuple_SetItem(args, 0, pyopencv_from(params))); + CV_Assert(!PyTuple_SetItem(args, 1, pyopencv_from(params.blobs))); + o = PyObject_CallObject(pyLayer, args); + + Py_DECREF(args); + PyGILState_Release(gstate); + if (!o) + CV_Error(Error::StsError, "Failed to create an instance of custom layer"); + } + + static void registerLayer(const std::string& type, PyObject* o) + { + std::map >::iterator it = pyLayers.find(type); + if (it != pyLayers.end()) + it->second.push_back(o); + else + pyLayers[type] = std::vector(1, o); + } + + static void unregisterLayer(const std::string& type) + { + std::map >::iterator it = pyLayers.find(type); + if (it != pyLayers.end()) + { + if (it->second.size() > 1) + it->second.pop_back(); + else + pyLayers.erase(it); + } + } + + static Ptr create(dnn::LayerParams ¶ms) + { + std::map >::iterator it = pyLayers.find(params.type); + if (it == pyLayers.end()) + CV_Error(Error::StsNotImplemented, "Layer with a type \"" + params.type + + "\" is not implemented"); + CV_Assert(!it->second.empty()); + return Ptr(new pycvLayer(params, it->second.back())); + } + + virtual bool getMemoryShapes(const std::vector > &inputs, + const int, + std::vector > &outputs, + std::vector > &) const CV_OVERRIDE + { + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); + + PyObject* args = PyList_New(inputs.size()); + for(size_t i = 0; i < inputs.size(); ++i) + PyList_SET_ITEM(args, i, pyopencv_from_generic_vec(inputs[i])); + + PyObject* res = PyObject_CallMethodObjArgs(o, PyString_FromString("getMemoryShapes"), args, NULL); + Py_DECREF(args); + PyGILState_Release(gstate); + if (!res) + CV_Error(Error::StsNotImplemented, "Failed to call \"getMemoryShapes\" method"); + pyopencv_to_generic_vec(res, outputs, ArgInfo("", 0)); + return false; + } + + virtual void forward(std::vector &inputs, std::vector &outputs, std::vector &) CV_OVERRIDE + { + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); + + std::vector inps(inputs.size()); + for (size_t i = 0; i < inputs.size(); ++i) + inps[i] = *inputs[i]; + + PyObject* args = pyopencv_from(inps); + PyObject* res = PyObject_CallMethodObjArgs(o, PyString_FromString("forward"), args, NULL); + Py_DECREF(args); + PyGILState_Release(gstate); + if (!res) + CV_Error(Error::StsNotImplemented, "Failed to call \"forward\" method"); + + std::vector pyOutputs; + pyopencv_to(res, pyOutputs, ArgInfo("", 0)); + + CV_Assert(pyOutputs.size() == outputs.size()); + for (size_t i = 0; i < outputs.size(); ++i) + { + CV_Assert(pyOutputs[i].size == outputs[i].size); + CV_Assert(pyOutputs[i].type() == outputs[i].type()); + pyOutputs[i].copyTo(outputs[i]); + } + } + + virtual void forward(InputArrayOfArrays, OutputArrayOfArrays, OutputArrayOfArrays) CV_OVERRIDE + { + CV_Error(Error::StsNotImplemented, ""); + } + +private: + // Map layers types to python classes. + static std::map > pyLayers; + PyObject* o; // Instance of implemented python layer. +}; + +std::map > pycvLayer::pyLayers; + +static PyObject *pyopencv_cv_dnn_registerLayer(PyObject*, PyObject *args, PyObject *kw) +{ + const char *keywords[] = { "type", "class", NULL }; + char* layerType; + PyObject *classInstance; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "sO", (char**)keywords, &layerType, &classInstance)) + return NULL; + if (!PyCallable_Check(classInstance)) { + PyErr_SetString(PyExc_TypeError, "class must be callable"); + return NULL; + } + + pycvLayer::registerLayer(layerType, classInstance); + dnn::LayerFactory::registerLayer(layerType, pycvLayer::create); + Py_RETURN_NONE; +} + +static PyObject *pyopencv_cv_dnn_unregisterLayer(PyObject*, PyObject *args, PyObject *kw) +{ + const char *keywords[] = { "type", NULL }; + char* layerType; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "s", (char**)keywords, &layerType)) + return NULL; + + pycvLayer::unregisterLayer(layerType); + dnn::LayerFactory::unregisterLayer(layerType); + Py_RETURN_NONE; +} + +#endif // HAVE_OPENCV_DNN diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index 2c2e9ecf61..4101022ec6 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -1783,6 +1783,10 @@ static PyMethodDef special_methods[] = { {"createTrackbar", pycvCreateTrackbar, METH_VARARGS, "createTrackbar(trackbarName, windowName, value, count, onChange) -> None"}, {"createButton", (PyCFunction)pycvCreateButton, METH_VARARGS | METH_KEYWORDS, "createButton(buttonName, onChange [, userData, buttonType, initialButtonState]) -> None"}, {"setMouseCallback", (PyCFunction)pycvSetMouseCallback, METH_VARARGS | METH_KEYWORDS, "setMouseCallback(windowName, onMouse [, param]) -> None"}, +#endif +#ifdef HAVE_OPENCV_DNN + {"dnn_registerLayer", (PyCFunction)pyopencv_cv_dnn_registerLayer, METH_VARARGS | METH_KEYWORDS, "registerLayer(type, class) -> None"}, + {"dnn_unregisterLayer", (PyCFunction)pyopencv_cv_dnn_unregisterLayer, METH_VARARGS | METH_KEYWORDS, "unregisterLayer(type) -> None"}, #endif {NULL, NULL}, }; diff --git a/samples/dnn/edge_detection.py b/samples/dnn/edge_detection.py new file mode 100644 index 0000000000..26119782db --- /dev/null +++ b/samples/dnn/edge_detection.py @@ -0,0 +1,69 @@ +import cv2 as cv +import argparse + +parser = argparse.ArgumentParser( + description='This sample shows how to define custom OpenCV deep learning layers in Python. ' + 'Holistically-Nested Edge Detection (https://arxiv.org/abs/1504.06375) neural network ' + 'is used as an example model. Find a pre-trained model at https://github.com/s9xie/hed.') +parser.add_argument('--input', help='Path to image or video. Skip to capture frames from camera') +parser.add_argument('--prototxt', help='Path to deploy.prototxt', required=True) +parser.add_argument('--caffemodel', help='Path to hed_pretrained_bsds.caffemodel', required=True) +parser.add_argument('--width', help='Resize input image to a specific width', default=500, type=int) +parser.add_argument('--height', help='Resize input image to a specific height', default=500, type=int) +args = parser.parse_args() + +#! [CropLayer] +class CropLayer(object): + def __init__(self, params, blobs): + self.xstart = 0 + self.xend = 0 + self.ystart = 0 + self.yend = 0 + + # Our layer receives two inputs. We need to crop the first input blob + # to match a shape of the second one (keeping batch size and number of channels) + def getMemoryShapes(self, inputs): + inputShape, targetShape = inputs[0], inputs[1] + batchSize, numChannels = inputShape[0], inputShape[1] + height, width = targetShape[2], targetShape[3] + + self.ystart = (inputShape[2] - targetShape[2]) / 2 + self.xstart = (inputShape[3] - targetShape[3]) / 2 + self.yend = self.ystart + height + self.xend = self.xstart + width + + return [[batchSize, numChannels, height, width]] + + def forward(self, inputs): + return [inputs[0][:,:,self.ystart:self.yend,self.xstart:self.xend]] +#! [CropLayer] + +#! [Register] +cv.dnn_registerLayer('Crop', CropLayer) +#! [Register] + +# Load the model. +net = cv.dnn.readNet(args.prototxt, args.caffemodel) + +kWinName = 'Holistically-Nested Edge Detection' +cv.namedWindow('Input', cv.WINDOW_NORMAL) +cv.namedWindow(kWinName, cv.WINDOW_NORMAL) + +cap = cv.VideoCapture(args.input if args.input else 0) +while cv.waitKey(1) < 0: + hasFrame, frame = cap.read() + if not hasFrame: + cv.waitKey() + break + + cv.imshow('Input', frame) + + inp = cv.dnn.blobFromImage(frame, scalefactor=1.0, size=(args.width, args.height), + mean=(104.00698793, 116.66876762, 122.67891434), + swapRB=False, crop=False) + net.setInput(inp) + + out = net.forward() + out = out[0, 0] + out = cv.resize(out, (frame.shape[1], frame.shape[0])) + cv.imshow(kWinName, out) From dfa04a11bbe6d690c7ff81ee83f7537d0c5d02a0 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 25 Apr 2018 19:32:53 +0300 Subject: [PATCH 19/36] core: norm with mask 16UC3 regression test --- modules/core/test/test_arithm.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp index 5e80a55c65..6c90c1c857 100644 --- a/modules/core/test/test_arithm.cpp +++ b/modules/core/test/test_arithm.cpp @@ -2084,4 +2084,22 @@ TEST(Core_Set, regression_11044) EXPECT_EQ(std::numeric_limits::infinity(), testDouble.at(0, 0)); } +TEST(Core_Norm, IPP_regression_NORM_L1_16UC3_small) +{ + int cn = 3; + Size sz(9, 4); // width < 16 + Mat a(sz, CV_MAKE_TYPE(CV_16U, cn), Scalar::all(1)); + Mat b(sz, CV_MAKE_TYPE(CV_16U, cn), Scalar::all(2)); + uchar mask_[9*4] = { + 255, 255, 255, 0, 255, 255, 0, 255, 0, + 0, 255, 0, 0, 255, 255, 255, 255, 0, + 0, 0, 0, 255, 0, 255, 0, 255, 255, + 0, 0, 255, 0, 255, 255, 255, 0, 255 +}; + Mat mask(sz, CV_8UC1, mask_); + + EXPECT_EQ((double)9*4*cn, cv::norm(a, b, NORM_L1)); // without mask, IPP works well + EXPECT_EQ((double)20*cn, cv::norm(a, b, NORM_L1, mask)); +} + }} // namespace From 57dad685d1f8c37c0c6b49598ac1f83892f63067 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 26 Apr 2018 12:42:37 +0300 Subject: [PATCH 20/36] core: disabled IPP AVX2 normL1(a, b, mask) for cv::Mat with width < 16 --- modules/core/src/norm.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/core/src/norm.cpp b/modules/core/src/norm.cpp index a8d19cb21c..09cd677799 100644 --- a/modules/core/src/norm.cpp +++ b/modules/core/src/norm.cpp @@ -1005,6 +1005,11 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra type == CV_16UC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L2_16u_C3CMR : type == CV_32FC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L2_32f_C3CMR : 0) : 0; + if (cv::ipp::getIppTopFeatures() & ippCPUID_AVX2) // IPP_DISABLE_NORM_16UC3_mask_small (#11399) + { + if (normType == NORM_L1 && type == CV_16UC3 && sz.width < 16) + return false; + } if( ippiNormDiff_C3CMR ) { Ipp64f norm1, norm2, norm3; From 677dc802ae4920a7bd45779eaa729ae008eb65f3 Mon Sep 17 00:00:00 2001 From: Alexander Enaldiev Date: Mon, 23 Apr 2018 15:15:34 +0300 Subject: [PATCH 21/36] protobuf build documenting: move the WITH_PROTOBUF option to the top level --- CMakeLists.txt | 1 + cmake/OpenCVFindProtobuf.cmake | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96d2ef8c1c..6de26879cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -279,6 +279,7 @@ OCV_OPTION(WITH_GDAL "Include GDAL Support" OFF OCV_OPTION(WITH_GPHOTO2 "Include gPhoto2 library support" ON IF (UNIX AND NOT ANDROID AND NOT IOS) ) OCV_OPTION(WITH_LAPACK "Include Lapack library support" (NOT CV_DISABLE_OPTIMIZATION) IF (NOT ANDROID AND NOT IOS) ) OCV_OPTION(WITH_ITT "Include Intel ITT support" ON IF (NOT APPLE_FRAMEWORK) ) +OCV_OPTION(WITH_PROTOBUF "Enable libprotobuf" ON ) # OpenCV build components # =================================================== diff --git a/cmake/OpenCVFindProtobuf.cmake b/cmake/OpenCVFindProtobuf.cmake index 16543fe7e0..b9171f14f0 100644 --- a/cmake/OpenCVFindProtobuf.cmake +++ b/cmake/OpenCVFindProtobuf.cmake @@ -1,15 +1,14 @@ # If protobuf is found - libprotobuf target is available -ocv_option(WITH_PROTOBUF "Enable libprotobuf" ON) -ocv_option(BUILD_PROTOBUF "Force to build libprotobuf from sources" ON) -ocv_option(PROTOBUF_UPDATE_FILES "Force rebuilding .proto files (protoc should be available)" OFF) - set(HAVE_PROTOBUF FALSE) if(NOT WITH_PROTOBUF) return() endif() +ocv_option(BUILD_PROTOBUF "Force to build libprotobuf from sources" ON) +ocv_option(PROTOBUF_UPDATE_FILES "Force rebuilding .proto files (protoc should be available)" OFF) + function(get_protobuf_version version include) file(STRINGS "${include}/google/protobuf/stubs/common.h" ver REGEX "#define GOOGLE_PROTOBUF_VERSION [0-9]+") string(REGEX MATCHALL "[0-9]+" ver ${ver}) From f708a11f0f5160c4f277daea526c7ec039c76505 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 26 Apr 2018 14:13:01 +0300 Subject: [PATCH 22/36] build: fix warnings --- modules/core/src/cuda_gpu_mat.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/modules/core/src/cuda_gpu_mat.cpp b/modules/core/src/cuda_gpu_mat.cpp index 8215dd0694..9514ec2037 100644 --- a/modules/core/src/cuda_gpu_mat.cpp +++ b/modules/core/src/cuda_gpu_mat.cpp @@ -344,13 +344,12 @@ void cv::cuda::ensureSizeIsEnough(int rows, int cols, int type, OutputArray arr) GpuMat cv::cuda::getInputMat(InputArray _src, Stream& stream) { - GpuMat src; - #ifndef HAVE_CUDA (void) _src; (void) stream; throw_no_cuda(); #else + GpuMat src; if (_src.kind() == _InputArray::CUDA_GPU_MAT) { src = _src.getGpuMat(); @@ -361,15 +360,12 @@ GpuMat cv::cuda::getInputMat(InputArray _src, Stream& stream) src = pool.getBuffer(_src.size(), _src.type()); src.upload(_src, stream); } -#endif - return src; +#endif } GpuMat cv::cuda::getOutputMat(OutputArray _dst, int rows, int cols, int type, Stream& stream) { - GpuMat dst; - #ifndef HAVE_CUDA (void) _dst; (void) rows; @@ -378,6 +374,7 @@ GpuMat cv::cuda::getOutputMat(OutputArray _dst, int rows, int cols, int type, St (void) stream; throw_no_cuda(); #else + GpuMat dst; if (_dst.kind() == _InputArray::CUDA_GPU_MAT) { _dst.create(rows, cols, type); @@ -388,9 +385,8 @@ GpuMat cv::cuda::getOutputMat(OutputArray _dst, int rows, int cols, int type, St BufferPool pool(stream); dst = pool.getBuffer(rows, cols, type); } -#endif - return dst; +#endif } void cv::cuda::syncOutput(const GpuMat& dst, OutputArray _dst, Stream& stream) From 8e15c6fd78723bbd98070988e95f6df3853be54d Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 26 Apr 2018 14:16:03 +0300 Subject: [PATCH 23/36] videoio(openni2): fix CV_CAP_PROP_OPENNI2_SYNC property --- modules/videoio/src/cap_openni2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/videoio/src/cap_openni2.cpp b/modules/videoio/src/cap_openni2.cpp index ce380559d0..b4a7808363 100644 --- a/modules/videoio/src/cap_openni2.cpp +++ b/modules/videoio/src/cap_openni2.cpp @@ -490,6 +490,7 @@ double CvCapture_OpenNI2::getCommonProperty( int propIdx ) const break; case CV_CAP_PROP_OPENNI2_SYNC : propValue = const_cast(this)->device.getDepthColorSyncEnabled(); + break; case CV_CAP_PROP_OPENNI2_MIRROR: { bool isMirroring = false; From 2a330e3006f9655fa10948934ea2f96b7447a2ff Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 26 Apr 2018 15:06:59 +0300 Subject: [PATCH 24/36] cuda: eliminate warnings --- cmake/OpenCVDetectCUDA.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/OpenCVDetectCUDA.cmake b/cmake/OpenCVDetectCUDA.cmake index 2d5c8bbbad..d7d085b607 100644 --- a/cmake/OpenCVDetectCUDA.cmake +++ b/cmake/OpenCVDetectCUDA.cmake @@ -200,6 +200,9 @@ if(CUDA_FOUND) string(REPLACE "-frtti" "" ${var} "${${var}}") string(REPLACE "-fvisibility-inlines-hidden" "" ${var} "${${var}}") + + # cc1: warning: command line option '-Wsuggest-override' is valid for C++/ObjC++ but not for C + string(REPLACE "-Wsuggest-override" "" ${var} "${${var}}") endforeach() endmacro() From 1dc73281f8b145627234f011108860f768aea539 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Tue, 24 Apr 2018 16:18:39 +0300 Subject: [PATCH 25/36] Added precise seek to MSMF-based VideoCapture::set(CAP_PROP_POS_FRAMES) --- modules/videoio/src/cap_msmf.cpp | 65 ++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp index b43e206591..fa0c54793d 100644 --- a/modules/videoio/src/cap_msmf.cpp +++ b/modules/videoio/src/cap_msmf.cpp @@ -137,14 +137,14 @@ template class ComPtr { public: - ComPtr() throw() + ComPtr() { } - ComPtr(T* lp) throw() + ComPtr(T* lp) { p = lp; } - ComPtr(_In_ const ComPtr& lp) throw() + ComPtr(_In_ const ComPtr& lp) { p = lp.p; } @@ -152,25 +152,25 @@ public: { } - T** operator&() throw() + T** operator&() { assert(p == NULL); return p.operator&(); } - T* operator->() const throw() + T* operator->() const { assert(p != NULL); return p.operator->(); } - bool operator!() const throw() + bool operator!() const { return p.operator==(NULL); } - bool operator==(_In_opt_ T* pT) const throw() + bool operator==(_In_opt_ T* pT) const { return p.operator==(pT); } - bool operator!=(_In_opt_ T* pT) const throw() + bool operator!=(_In_opt_ T* pT) const { return p.operator!=(pT); } @@ -179,38 +179,38 @@ public: return p.operator!=(NULL); } - T* const* GetAddressOf() const throw() + T* const* GetAddressOf() const { return &p; } - T** GetAddressOf() throw() + T** GetAddressOf() { return &p; } - T** ReleaseAndGetAddressOf() throw() + T** ReleaseAndGetAddressOf() { p.Release(); return &p; } - T* Get() const throw() + T* Get() const { return p; } // Attach to an existing interface (does not AddRef) - void Attach(_In_opt_ T* p2) throw() + void Attach(_In_opt_ T* p2) { p.Attach(p2); } // Detach the interface (does not Release) - T* Detach() throw() + T* Detach() { return p.Detach(); } - _Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT) throw() + _Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT) { assert(ppT != NULL); if (ppT == NULL) @@ -228,13 +228,13 @@ public: // query for U interface template - HRESULT As(_Inout_ U** lp) const throw() + HRESULT As(_Inout_ U** lp) const { return p->QueryInterface(__uuidof(U), reinterpret_cast(lp)); } // query for U interface template - HRESULT As(_Out_ ComPtr* lp) const throw() + HRESULT As(_Out_ ComPtr* lp) const { return p->QueryInterface(__uuidof(U), reinterpret_cast(lp->ReleaseAndGetAddressOf())); } @@ -720,6 +720,7 @@ protected: bool convertFormat; UINT32 aspectN, aspectD; MFTIME duration; + LONGLONG frameStep; _ComPtr videoSample; LONGLONG sampleTime; IplImage* frame; @@ -975,7 +976,11 @@ bool CvCapture_MSMF::open(int _index) isOpened = true; duration = 0; if (configureOutput(0, 0, 0, aspectN, aspectD, outputFormat, convertFormat)) + { + double fps = getFramerate(nativeFormat); + frameStep = (LONGLONG)(fps > 0 ? 1e7 / fps : 0); camid = _index; + } } } } @@ -1017,6 +1022,8 @@ bool CvCapture_MSMF::open(const char* _filename) sampleTime = 0; if (configureOutput(0, 0, 0, aspectN, aspectD, outputFormat, convertFormat)) { + double fps = getFramerate(nativeFormat); + frameStep = (LONGLONG)(fps > 0 ? 1e7 / fps : 0); filename = _filename; PROPVARIANT var; HRESULT hr; @@ -1080,10 +1087,12 @@ bool CvCapture_MSMF::grabFrame() } else if (flags & MF_SOURCE_READERF_ENDOFSTREAM) { + sampleTime += frameStep; DebugPrintOut(L"\tEnd of stream detected\n"); } else { + sampleTime += frameStep; if (flags & MF_SOURCE_READERF_NEWSTREAM) { DebugPrintOut(L"\tNew stream detected\n"); @@ -1182,17 +1191,23 @@ bool CvCapture_MSMF::setTime(double time, bool rough) { PROPVARIANT var; if (SUCCEEDED(videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS, &var)) && - var.vt == VT_UI4 && (var.ulVal & MFMEDIASOURCE_CAN_SEEK && (rough || var.ulVal & MFMEDIASOURCE_HAS_SLOW_SEEK))) + var.vt == VT_UI4 && var.ulVal & MFMEDIASOURCE_CAN_SEEK) { - PropVariantClear(&var); - sampleTime = (LONGLONG)floor(time + 0.5); - var.vt = VT_I8; - var.hVal.QuadPart = sampleTime; - HRESULT hr = videoFileSource->SetCurrentPosition(GUID_NULL, var); if (videoSample) videoSample.Reset(); + bool useGrabbing = time > 0 && !rough && !(var.ulVal & MFMEDIASOURCE_HAS_SLOW_SEEK); PropVariantClear(&var); - return SUCCEEDED(hr); + sampleTime = (useGrabbing && time >= frameStep) ? (LONGLONG)floor(time + 0.5) - frameStep : (LONGLONG)floor(time + 0.5); + var.vt = VT_I8; + var.hVal.QuadPart = sampleTime; + bool resOK = SUCCEEDED(videoFileSource->SetCurrentPosition(GUID_NULL, var)); + PropVariantClear(&var); + if (resOK && useGrabbing) + { + LONGLONG timeborder = (LONGLONG)floor(time + 0.5) - frameStep / 2; + do { resOK = grabFrame(); videoSample.Reset(); } while (resOK && sampleTime < timeborder); + } + return resOK; } return false; } @@ -1576,7 +1591,7 @@ bool CvCapture_MSMF::setProperty( int property_id, double value ) return setTime(value * 1e7 / getFramerate(nativeFormat), false); break; case CV_CAP_PROP_POS_MSEC: - return setTime(value * 1e4, true); + return setTime(value * 1e4, false); case CV_CAP_PROP_BRIGHTNESS: if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { From 56222f35bb8457ecef550c235c4b30dc9322350a Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 26 Apr 2018 16:03:45 +0300 Subject: [PATCH 26/36] cmake: fix CPU_BASELINE_FINAL filling - remove duplicates - restore "always on" missing entries - fix FP16 detection on MSVC --- cmake/OpenCVCompilerOptimizations.cmake | 8 +++++++- cmake/checks/cpu_fp16.cpp | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cmake/OpenCVCompilerOptimizations.cmake b/cmake/OpenCVCompilerOptimizations.cmake index 9190222afc..def96723af 100644 --- a/cmake/OpenCVCompilerOptimizations.cmake +++ b/cmake/OpenCVCompilerOptimizations.cmake @@ -234,6 +234,7 @@ if(X86 OR X86_64) elseif(MSVC) ocv_update(CPU_AVX2_FLAGS_ON "/arch:AVX2") ocv_update(CPU_AVX_FLAGS_ON "/arch:AVX") + ocv_update(CPU_FP16_FLAGS_ON "/arch:AVX") if(NOT MSVC64) # 64-bit MSVC compiler uses SSE/SSE2 by default ocv_update(CPU_SSE_FLAGS_ON "/arch:SSE") @@ -422,6 +423,9 @@ foreach(OPT ${CPU_KNOWN_OPTIMIZATIONS}) if(__is_disabled) set(__is_from_baseline 0) else() + if(CPU_${OPT}_SUPPORTED AND CPU_BASELINE_DETECT) + list(APPEND CPU_BASELINE_FINAL ${OPT}) + endif() ocv_is_optimization_in_list(__is_from_baseline ${OPT} ${CPU_BASELINE_REQUIRE}) if(NOT __is_from_baseline) ocv_is_optimization_in_list(__is_from_baseline ${OPT} ${CPU_BASELINE}) @@ -441,7 +445,9 @@ foreach(OPT ${CPU_KNOWN_OPTIMIZATIONS}) if(";${CPU_DISPATCH};" MATCHES ";${OPT};" AND NOT __is_from_baseline) list(APPEND CPU_DISPATCH_FINAL ${OPT}) elseif(__is_from_baseline) - list(APPEND CPU_BASELINE_FINAL ${OPT}) + if(NOT ";${CPU_BASELINE_FINAL};" MATCHES ";${OPT};") + list(APPEND CPU_BASELINE_FINAL ${OPT}) + endif() ocv_append_optimization_flag(CPU_BASELINE_FLAGS ${OPT}) endif() endif() diff --git a/cmake/checks/cpu_fp16.cpp b/cmake/checks/cpu_fp16.cpp index 6951f1c4f7..f12cb10f4d 100644 --- a/cmake/checks/cpu_fp16.cpp +++ b/cmake/checks/cpu_fp16.cpp @@ -1,6 +1,6 @@ #include -#if defined __F16C__ || (defined _MSC_VER && _MSC_VER >= 1700) || (defined __INTEL_COMPILER && defined __AVX__) +#if defined __F16C__ || (defined _MSC_VER && _MSC_VER >= 1700 && defined __AVX__) || (defined __INTEL_COMPILER && defined __AVX__) #include int test() { From 39e2d64b84a37b97f40fdf0c012d91ee66393254 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 26 Apr 2018 17:46:25 +0300 Subject: [PATCH 27/36] core: fix icc std::exception_ptr detection std::exception_ptr requires enabled C++11 mode --- modules/core/src/parallel.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/core/src/parallel.cpp b/modules/core/src/parallel.cpp index 413b9ee97d..88075a6ce2 100644 --- a/modules/core/src/parallel.cpp +++ b/modules/core/src/parallel.cpp @@ -135,8 +135,6 @@ # define CV__EXCEPTION_PTR 0 // Not supported, details: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58938 # elif defined(CV_CXX11) # define CV__EXCEPTION_PTR 1 -# elif defined(CV_ICC) -# define CV__EXCEPTION_PTR 1 # elif defined(_MSC_VER) # define CV__EXCEPTION_PTR (_MSC_VER >= 1600) # elif defined(__clang__) From 058299cc66adc0bc76b9a37d69626ed5d1733460 Mon Sep 17 00:00:00 2001 From: exoson Date: Wed, 25 Apr 2018 17:04:42 +0300 Subject: [PATCH 28/36] Optimize MultiBandBlender to run faster --- modules/core/include/opencv2/core/mat.hpp | 1 + modules/core/include/opencv2/core/mat.inl.hpp | 1 + .../opencv2/stitching/detail/blenders.hpp | 12 ++ modules/stitching/src/blenders.cpp | 186 +++++++++++++----- modules/stitching/test/test_blenders.cuda.cpp | 14 +- 5 files changed, 164 insertions(+), 50 deletions(-) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index ca1b3aa9b5..6a0cf1cd08 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -240,6 +240,7 @@ public: bool isUMatVector() const; bool isMatx() const; bool isVector() const; + bool isGpuMat() const; bool isGpuMatVector() const; ~_InputArray(); diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index 9b2da34e61..617c61ddad 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -157,6 +157,7 @@ inline bool _InputArray::isMatx() const { return kind() == _InputArray::MATX; } inline bool _InputArray::isVector() const { return kind() == _InputArray::STD_VECTOR || kind() == _InputArray::STD_BOOL_VECTOR || kind() == _InputArray::STD_ARRAY; } +inline bool _InputArray::isGpuMat() const { return kind() == _InputArray::CUDA_GPU_MAT; } inline bool _InputArray::isGpuMatVector() const { return kind() == _InputArray::STD_VECTOR_CUDA_GPU_MAT; } //////////////////////////////////////////////////////////////////////////////////////// diff --git a/modules/stitching/include/opencv2/stitching/detail/blenders.hpp b/modules/stitching/include/opencv2/stitching/detail/blenders.hpp index 07473d459e..4c14340722 100644 --- a/modules/stitching/include/opencv2/stitching/detail/blenders.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/blenders.hpp @@ -145,6 +145,18 @@ private: #if defined(HAVE_OPENCV_CUDAARITHM) && defined(HAVE_OPENCV_CUDAWARPING) std::vector gpu_dst_pyr_laplace_; std::vector gpu_dst_band_weights_; + std::vector gpu_tl_points_; + std::vector gpu_imgs_with_border_; + std::vector > gpu_weight_pyr_gauss_vec_; + std::vector > gpu_src_pyr_laplace_vec_; + std::vector > gpu_ups_; + cuda::GpuMat gpu_dst_mask_; + cuda::GpuMat gpu_mask_; + cuda::GpuMat gpu_img_; + cuda::GpuMat gpu_weight_map_; + cuda::GpuMat gpu_add_mask_; + int gpu_feed_idx_; + bool gpu_initialized_; #endif }; diff --git a/modules/stitching/src/blenders.cpp b/modules/stitching/src/blenders.cpp index 5a7fa856c0..5e9f4133ea 100644 --- a/modules/stitching/src/blenders.cpp +++ b/modules/stitching/src/blenders.cpp @@ -221,6 +221,7 @@ MultiBandBlender::MultiBandBlender(int try_gpu, int num_bands, int weight_type) #if defined(HAVE_OPENCV_CUDAARITHM) && defined(HAVE_OPENCV_CUDAWARPING) can_use_gpu_ = try_gpu && cuda::getCudaEnabledDeviceCount(); + gpu_feed_idx_ = 0; #else (void) try_gpu; can_use_gpu_ = false; @@ -248,6 +249,15 @@ void MultiBandBlender::prepare(Rect dst_roi) #if defined(HAVE_OPENCV_CUDAARITHM) && defined(HAVE_OPENCV_CUDAWARPING) if (can_use_gpu_) { + gpu_initialized_ = false; + gpu_feed_idx_ = 0; + + gpu_tl_points_.clear(); + gpu_weight_pyr_gauss_vec_.clear(); + gpu_src_pyr_laplace_vec_.clear(); + gpu_ups_.clear(); + gpu_imgs_with_border_.clear(); + gpu_dst_pyr_laplace_.resize(num_bands_ + 1); gpu_dst_pyr_laplace_[0].create(dst_roi.size(), CV_16SC3); gpu_dst_pyr_laplace_[0].setTo(Scalar::all(0)); @@ -320,7 +330,37 @@ void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl) int64 t = getTickCount(); #endif - UMat img = _img.getUMat(); + UMat img; + +#if defined(HAVE_OPENCV_CUDAARITHM) && defined(HAVE_OPENCV_CUDAWARPING) + // If using gpu save the top left coordinate when running first time after prepare + if (can_use_gpu_) + { + if (!gpu_initialized_) + { + gpu_tl_points_.push_back(tl); + } + else + { + tl = gpu_tl_points_[gpu_feed_idx_]; + } + } + // If _img is not a GpuMat get it as UMat from the InputArray object. + // If it is GpuMat make a dummy object with right dimensions but no data and + // get _img as a GpuMat + if (!_img.isGpuMat()) +#endif + { + img = _img.getUMat(); + } +#if defined(HAVE_OPENCV_CUDAARITHM) && defined(HAVE_OPENCV_CUDAWARPING) + else + { + gpu_img_ = _img.getGpuMat(); + img = UMat(gpu_img_.rows, gpu_img_.cols, gpu_img_.type()); + } +#endif + CV_Assert(img.type() == CV_16SC3 || img.type() == CV_8UC3); CV_Assert(mask.type() == CV_8U); @@ -357,42 +397,63 @@ void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl) #if defined(HAVE_OPENCV_CUDAARITHM) && defined(HAVE_OPENCV_CUDAWARPING) if (can_use_gpu_) { + if (!gpu_initialized_) + { + gpu_imgs_with_border_.push_back(cuda::GpuMat()); + gpu_weight_pyr_gauss_vec_.push_back(std::vector(num_bands_+1)); + gpu_src_pyr_laplace_vec_.push_back(std::vector(num_bands_+1)); + gpu_ups_.push_back(std::vector(num_bands_)); + } + + // If _img is not GpuMat upload it to gpu else gpu_img_ was set already + if (!_img.isGpuMat()) + { + gpu_img_.upload(img); + } + // Create the source image Laplacian pyramid - cuda::GpuMat gpu_img; - gpu_img.upload(img); - cuda::GpuMat img_with_border; - cuda::copyMakeBorder(gpu_img, img_with_border, top, bottom, left, right, BORDER_REFLECT); - std::vector gpu_src_pyr_laplace(num_bands_ + 1); - img_with_border.convertTo(gpu_src_pyr_laplace[0], CV_16S); + cuda::copyMakeBorder(gpu_img_, gpu_imgs_with_border_[gpu_feed_idx_], top, bottom, + left, right, BORDER_REFLECT); + gpu_imgs_with_border_[gpu_feed_idx_].convertTo(gpu_src_pyr_laplace_vec_[gpu_feed_idx_][0], CV_16S); for (int i = 0; i < num_bands_; ++i) - cuda::pyrDown(gpu_src_pyr_laplace[i], gpu_src_pyr_laplace[i + 1]); + cuda::pyrDown(gpu_src_pyr_laplace_vec_[gpu_feed_idx_][i], + gpu_src_pyr_laplace_vec_[gpu_feed_idx_][i + 1]); for (int i = 0; i < num_bands_; ++i) { - cuda::GpuMat up; - cuda::pyrUp(gpu_src_pyr_laplace[i + 1], up); - cuda::subtract(gpu_src_pyr_laplace[i], up, gpu_src_pyr_laplace[i]); + cuda::pyrUp(gpu_src_pyr_laplace_vec_[gpu_feed_idx_][i + 1], gpu_ups_[gpu_feed_idx_][i]); + cuda::subtract(gpu_src_pyr_laplace_vec_[gpu_feed_idx_][i], + gpu_ups_[gpu_feed_idx_][i], + gpu_src_pyr_laplace_vec_[gpu_feed_idx_][i]); } - // Create the weight map Gaussian pyramid - cuda::GpuMat gpu_mask; - gpu_mask.upload(mask); - cuda::GpuMat weight_map; - std::vector gpu_weight_pyr_gauss(num_bands_ + 1); + // Create the weight map Gaussian pyramid only if not yet initialized + if (!gpu_initialized_) + { + if (mask.isGpuMat()) + { + gpu_mask_ = mask.getGpuMat(); + } + else + { + gpu_mask_.upload(mask); + } - if (weight_type_ == CV_32F) - { - gpu_mask.convertTo(weight_map, CV_32F, 1. / 255.); + if (weight_type_ == CV_32F) + { + gpu_mask_.convertTo(gpu_weight_map_, CV_32F, 1. / 255.); + } + else // weight_type_ == CV_16S + { + gpu_mask_.convertTo(gpu_weight_map_, CV_16S); + cuda::compare(gpu_mask_, 0, gpu_add_mask_, CMP_NE); + cuda::add(gpu_weight_map_, Scalar::all(1), gpu_weight_map_, gpu_add_mask_); + } + cuda::copyMakeBorder(gpu_weight_map_, gpu_weight_pyr_gauss_vec_[gpu_feed_idx_][0], top, + bottom, left, right, BORDER_CONSTANT); + for (int i = 0; i < num_bands_; ++i) + cuda::pyrDown(gpu_weight_pyr_gauss_vec_[gpu_feed_idx_][i], + gpu_weight_pyr_gauss_vec_[gpu_feed_idx_][i + 1]); } - else // weight_type_ == CV_16S - { - gpu_mask.convertTo(weight_map, CV_16S); - cuda::GpuMat add_mask; - cuda::compare(gpu_mask, 0, add_mask, CMP_NE); - cuda::add(weight_map, Scalar::all(1), weight_map, add_mask); - } - cuda::copyMakeBorder(weight_map, gpu_weight_pyr_gauss[0], top, bottom, left, right, BORDER_CONSTANT); - for (int i = 0; i < num_bands_; ++i) - cuda::pyrDown(gpu_weight_pyr_gauss[i], gpu_weight_pyr_gauss[i + 1]); int y_tl = tl_new.y - dst_roi_.y; int y_br = br_new.y - dst_roi_.y; @@ -403,9 +464,9 @@ void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl) for (int i = 0; i <= num_bands_; ++i) { Rect rc(x_tl, y_tl, x_br - x_tl, y_br - y_tl); - cuda::GpuMat &_src_pyr_laplace = gpu_src_pyr_laplace[i]; + cuda::GpuMat &_src_pyr_laplace = gpu_src_pyr_laplace_vec_[gpu_feed_idx_][i]; cuda::GpuMat _dst_pyr_laplace = gpu_dst_pyr_laplace_[i](rc); - cuda::GpuMat &_weight_pyr_gauss = gpu_weight_pyr_gauss[i]; + cuda::GpuMat &_weight_pyr_gauss = gpu_weight_pyr_gauss_vec_[gpu_feed_idx_][i]; cuda::GpuMat _dst_band_weights = gpu_dst_band_weights_[i](rc); using namespace cv::cuda::device::blend; @@ -420,6 +481,7 @@ void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl) x_tl /= 2; y_tl /= 2; x_br /= 2; y_br /= 2; } + ++gpu_feed_idx_; return; } #endif @@ -445,7 +507,7 @@ void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl) UMat weight_map; std::vector weight_pyr_gauss(num_bands_ + 1); - if(weight_type_ == CV_32F) + if (weight_type_ == CV_32F) { mask.getUMat().convertTo(weight_map, CV_32F, 1./255.); } @@ -486,7 +548,7 @@ void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl) Mat _dst_pyr_laplace = dst_pyr_laplace_[i](rc).getMat(ACCESS_RW); Mat _weight_pyr_gauss = weight_pyr_gauss[i].getMat(ACCESS_READ); Mat _dst_band_weights = dst_band_weights_[i](rc).getMat(ACCESS_RW); - if(weight_type_ == CV_32F) + if (weight_type_ == CV_32F) { for (int y = 0; y < rc.height; ++y) { @@ -540,11 +602,15 @@ void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl) void MultiBandBlender::blend(InputOutputArray dst, InputOutputArray dst_mask) { - cv::UMat dst_band_weights_0; Rect dst_rc(0, 0, dst_roi_final_.width, dst_roi_final_.height); #if defined(HAVE_OPENCV_CUDAARITHM) && defined(HAVE_OPENCV_CUDAWARPING) if (can_use_gpu_) { + if (!gpu_initialized_) + { + gpu_ups_.push_back(std::vector(num_bands_+1)); + } + for (int i = 0; i <= num_bands_; ++i) { cuda::GpuMat dst_i = gpu_dst_pyr_laplace_[i]; @@ -564,20 +630,50 @@ void MultiBandBlender::blend(InputOutputArray dst, InputOutputArray dst_mask) // Restore image from Laplacian pyramid for (size_t i = num_bands_; i > 0; --i) { - cuda::GpuMat up; - cuda::pyrUp(gpu_dst_pyr_laplace_[i], up); - cuda::add(up, gpu_dst_pyr_laplace_[i - 1], gpu_dst_pyr_laplace_[i - 1]); + cuda::pyrUp(gpu_dst_pyr_laplace_[i], gpu_ups_[gpu_ups_.size()-1][num_bands_-i]); + cuda::add(gpu_ups_[gpu_ups_.size()-1][num_bands_-i], + gpu_dst_pyr_laplace_[i - 1], + gpu_dst_pyr_laplace_[i - 1]); } - gpu_dst_pyr_laplace_[0](dst_rc).download(dst_); - gpu_dst_band_weights_[0].download(dst_band_weights_0); + // If dst is GpuMat do masking on gpu and return dst as a GpuMat + // else download the image to cpu and return it as an ordinary Mat + if (dst.isGpuMat()) + { + cuda::GpuMat &gpu_dst = dst.getGpuMatRef(); - gpu_dst_pyr_laplace_.clear(); - gpu_dst_band_weights_.clear(); + cuda::compare(gpu_dst_band_weights_[0](dst_rc), WEIGHT_EPS, gpu_dst_mask_, CMP_GT); + + cuda::compare(gpu_dst_mask_, 0, gpu_mask_, CMP_EQ); + + gpu_dst_pyr_laplace_[0](dst_rc).setTo(Scalar::all(0), gpu_mask_); + gpu_dst_pyr_laplace_[0](dst_rc).convertTo(gpu_dst, CV_16S); + + } + else + { + gpu_dst_pyr_laplace_[0](dst_rc).download(dst_); + Mat dst_band_weights_0; + gpu_dst_band_weights_[0].download(dst_band_weights_0); + + compare(dst_band_weights_0(dst_rc), WEIGHT_EPS, dst_mask_, CMP_GT); + Blender::blend(dst, dst_mask); + } + + // Set destination Mats to 0 so new image can be blended + for (size_t i = 0; i < num_bands_ + 1; ++i) + { + gpu_dst_band_weights_[i].setTo(0); + gpu_dst_pyr_laplace_[i].setTo(Scalar::all(0)); + } + gpu_feed_idx_ = 0; + gpu_initialized_ = true; } else #endif { + cv::UMat dst_band_weights_0; + for (int i = 0; i <= num_bands_; ++i) normalizeUsingWeightMap(dst_band_weights_[i], dst_pyr_laplace_[i]); @@ -588,11 +684,11 @@ void MultiBandBlender::blend(InputOutputArray dst, InputOutputArray dst_mask) dst_pyr_laplace_.clear(); dst_band_weights_.clear(); + + compare(dst_band_weights_0(dst_rc), WEIGHT_EPS, dst_mask_, CMP_GT); + + Blender::blend(dst, dst_mask); } - - compare(dst_band_weights_0(dst_rc), WEIGHT_EPS, dst_mask_, CMP_GT); - - Blender::blend(dst, dst_mask); } diff --git a/modules/stitching/test/test_blenders.cuda.cpp b/modules/stitching/test/test_blenders.cuda.cpp index 5d556febe9..0a3f61e2e4 100644 --- a/modules/stitching/test/test_blenders.cuda.cpp +++ b/modules/stitching/test/test_blenders.cuda.cpp @@ -50,12 +50,16 @@ namespace opencv_test { namespace { detail::MultiBandBlender blender(try_cuda, 5); blender.prepare(Rect(0, 0, max(im1.cols, im2.cols), max(im1.rows, im2.rows))); - blender.feed(im1, mask1, Point(0,0)); - blender.feed(im2, mask2, Point(0,0)); - Mat result_s, result_mask; - blender.blend(result_s, result_mask); - result_s.convertTo(result, CV_8U); + // If using cuda try blending multiple times without calling prepare inbetween + for (int i = 0; i < (try_cuda ? 10 : 1); ++i) { + blender.feed(im1, mask1, Point(0, 0)); + blender.feed(im2, mask2, Point(0, 0)); + + Mat result_s, result_mask; + blender.blend(result_s, result_mask); + result_s.convertTo(result, CV_8U); + } } TEST(CUDA_MultiBandBlender, Accuracy) From 856a07711bc679851d1f66d848c0a33a65a80699 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Fri, 27 Apr 2018 12:56:42 +0300 Subject: [PATCH 29/36] core: disabled IPP AVX512 normL1(a, b, mask) for cv::Mat with type=16UC3 and width < 16 --- modules/core/src/norm.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/core/src/norm.cpp b/modules/core/src/norm.cpp index 09cd677799..d12dfc742d 100644 --- a/modules/core/src/norm.cpp +++ b/modules/core/src/norm.cpp @@ -1005,7 +1005,12 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra type == CV_16UC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L2_16u_C3CMR : type == CV_32FC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L2_32f_C3CMR : 0) : 0; - if (cv::ipp::getIppTopFeatures() & ippCPUID_AVX2) // IPP_DISABLE_NORM_16UC3_mask_small (#11399) + if (cv::ipp::getIppTopFeatures() & ( +#if IPP_VERSION_X100 >= 201700 + ippCPUID_AVX512F | +#endif + ippCPUID_AVX2) + ) // IPP_DISABLE_NORM_16UC3_mask_small (#11399) { if (normType == NORM_L1 && type == CV_16UC3 && sz.width < 16) return false; From 87a4f4ab3afc1eaed05480f16bbae570a3d33254 Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Fri, 27 Apr 2018 22:41:56 +0900 Subject: [PATCH 30/36] Merge pull request #11409 from tomoaki0705/fixCLAHEfailure Arm: fix the test failure of OCL_Imgproc/CLAHETest.Accuracy on ODROID-XU4 (#11409) * fix the test failure of OCL_Imgproc/CLAHETest.Accuracy on ODROID-XU4 * avoid the race condition in the reduce * imgproc(ocl): simplify CLAHE code * remove unused class --- modules/imgproc/src/clahe.cpp | 11 +---- modules/imgproc/src/opencl/clahe.cl | 74 +++++++---------------------- 2 files changed, 17 insertions(+), 68 deletions(-) diff --git a/modules/imgproc/src/clahe.cpp b/modules/imgproc/src/clahe.cpp index 7a96da62aa..fffc194ff7 100644 --- a/modules/imgproc/src/clahe.cpp +++ b/modules/imgproc/src/clahe.cpp @@ -54,16 +54,7 @@ namespace clahe const int tilesX, const int tilesY, const cv::Size tileSize, const int clipLimit, const float lutScale) { - cv::ocl::Kernel _k("calcLut", cv::ocl::imgproc::clahe_oclsrc); - - bool is_cpu = cv::ocl::Device::getDefault().type() == cv::ocl::Device::TYPE_CPU; - cv::String opts; - if(is_cpu) - opts = "-D CPU "; - else - opts = cv::format("-D WAVE_SIZE=%d", _k.preferedWorkGroupSizeMultiple()); - - cv::ocl::Kernel k("calcLut", cv::ocl::imgproc::clahe_oclsrc, opts); + cv::ocl::Kernel k("calcLut", cv::ocl::imgproc::clahe_oclsrc); if(k.empty()) return false; diff --git a/modules/imgproc/src/opencl/clahe.cl b/modules/imgproc/src/opencl/clahe.cl index ba69085634..1c806e9b6a 100644 --- a/modules/imgproc/src/opencl/clahe.cl +++ b/modules/imgproc/src/opencl/clahe.cl @@ -43,10 +43,6 @@ // //M*/ -#ifndef WAVE_SIZE -#define WAVE_SIZE 1 -#endif - inline int calc_lut(__local int* smem, int val, int tid) { smem[tid] = val; @@ -60,8 +56,7 @@ inline int calc_lut(__local int* smem, int val, int tid) return smem[tid]; } -#ifdef CPU -inline void reduce(volatile __local int* smem, int val, int tid) +inline int reduce(__local volatile int* smem, int val, int tid) { smem[tid] = val; barrier(CLK_LOCAL_MEM_FENCE); @@ -75,69 +70,39 @@ inline void reduce(volatile __local int* smem, int val, int tid) barrier(CLK_LOCAL_MEM_FENCE); if (tid < 32) + { smem[tid] += smem[tid + 32]; + } barrier(CLK_LOCAL_MEM_FENCE); if (tid < 16) + { smem[tid] += smem[tid + 16]; + } barrier(CLK_LOCAL_MEM_FENCE); if (tid < 8) + { smem[tid] += smem[tid + 8]; + } barrier(CLK_LOCAL_MEM_FENCE); if (tid < 4) + { smem[tid] += smem[tid + 4]; - barrier(CLK_LOCAL_MEM_FENCE); - - if (tid < 2) - smem[tid] += smem[tid + 2]; - barrier(CLK_LOCAL_MEM_FENCE); - - if (tid < 1) - smem[256] = smem[tid] + smem[tid + 1]; - barrier(CLK_LOCAL_MEM_FENCE); -} - -#else - -inline void reduce(__local volatile int* smem, int val, int tid) -{ - smem[tid] = val; - barrier(CLK_LOCAL_MEM_FENCE); - - if (tid < 128) - smem[tid] = val += smem[tid + 128]; - barrier(CLK_LOCAL_MEM_FENCE); - - if (tid < 64) - smem[tid] = val += smem[tid + 64]; - barrier(CLK_LOCAL_MEM_FENCE); - - if (tid < 32) - { - smem[tid] += smem[tid + 32]; -#if WAVE_SIZE < 32 - } barrier(CLK_LOCAL_MEM_FENCE); - - if (tid < 16) - { -#endif - smem[tid] += smem[tid + 16]; -#if WAVE_SIZE < 16 } barrier(CLK_LOCAL_MEM_FENCE); - if (tid < 8) + if (tid == 0) { -#endif - smem[tid] += smem[tid + 8]; - smem[tid] += smem[tid + 4]; - smem[tid] += smem[tid + 2]; - smem[tid] += smem[tid + 1]; + smem[0] = (smem[0] + smem[1]) + (smem[2] + smem[3]); } + barrier(CLK_LOCAL_MEM_FENCE); + + val = smem[0]; + barrier(CLK_LOCAL_MEM_FENCE); + return val; } -#endif __kernel void calcLut(__global __const uchar * src, const int srcStep, const int src_offset, __global uchar * lut, @@ -179,14 +144,7 @@ __kernel void calcLut(__global __const uchar * src, const int srcStep, } // find number of overall clipped samples - reduce(smem, clipped, tid); - barrier(CLK_LOCAL_MEM_FENCE); -#ifdef CPU - clipped = smem[256]; -#else - clipped = smem[0]; -#endif - barrier(CLK_LOCAL_MEM_FENCE); + clipped = reduce(smem, clipped, tid); // redistribute clipped samples evenly int redistBatch = clipped / 256; From 8c349ff8ffad16b1920491902a5b4464a0b5cad0 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 26 Apr 2018 18:54:43 +0300 Subject: [PATCH 31/36] core: added MatSize::dims() method to avoid accessing of 'p[-1]' (static code analysers dislike this) --- .../core/include/opencv2/core/cvstd.inl.hpp | 4 ++-- modules/core/include/opencv2/core/mat.hpp | 3 ++- modules/core/include/opencv2/core/mat.inl.hpp | 20 ++++++++++++++++--- .../dnn/include/opencv2/dnn/shape_utils.hpp | 2 +- modules/dnn/src/layers/slice_layer.cpp | 4 ++-- modules/dnn/src/op_halide.cpp | 5 +++-- 6 files changed, 27 insertions(+), 11 deletions(-) diff --git a/modules/core/include/opencv2/core/cvstd.inl.hpp b/modules/core/include/opencv2/core/cvstd.inl.hpp index 85230f595d..f1637c44f0 100644 --- a/modules/core/include/opencv2/core/cvstd.inl.hpp +++ b/modules/core/include/opencv2/core/cvstd.inl.hpp @@ -265,10 +265,10 @@ std::ostream& operator << (std::ostream& out, const Rect_<_Tp>& rect) static inline std::ostream& operator << (std::ostream& out, const MatSize& msize) { - int i, dims = msize.p[-1]; + int i, dims = msize.dims(); for( i = 0; i < dims; i++ ) { - out << msize.p[i]; + out << msize[i]; if( i < dims-1 ) out << " x "; } diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index ca1b3aa9b5..9f0a448c87 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -548,10 +548,11 @@ struct CV_EXPORTS UMatData struct CV_EXPORTS MatSize { explicit MatSize(int* _p); + int dims() const; Size operator()() const; const int& operator[](int i) const; int& operator[](int i); - operator const int*() const; + operator const int*() const; // TODO OpenCV 4.0: drop this bool operator == (const MatSize& sz) const; bool operator != (const MatSize& sz) const; diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index 9b2da34e61..f0c18584fd 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -1411,22 +1411,36 @@ inline MatSize::MatSize(int* _p) : p(_p) {} +inline +int MatSize::dims() const +{ + return (p - 1)[0]; +} + inline Size MatSize::operator()() const { - CV_DbgAssert(p[-1] <= 2); + CV_DbgAssert(dims() <= 2); return Size(p[1], p[0]); } inline const int& MatSize::operator[](int i) const { + CV_DbgAssert(i < dims()); +#ifdef __OPENCV_BUILD + CV_DbgAssert(i >= 0); +#endif return p[i]; } inline int& MatSize::operator[](int i) { + CV_DbgAssert(i < dims()); +#ifdef __OPENCV_BUILD + CV_DbgAssert(i >= 0); +#endif return p[i]; } @@ -1439,8 +1453,8 @@ MatSize::operator const int*() const inline bool MatSize::operator == (const MatSize& sz) const { - int d = p[-1]; - int dsz = sz.p[-1]; + int d = dims(); + int dsz = sz.dims(); if( d != dsz ) return false; if( d == 2 ) diff --git a/modules/dnn/include/opencv2/dnn/shape_utils.hpp b/modules/dnn/include/opencv2/dnn/shape_utils.hpp index c8da7f8057..1e2332cf10 100644 --- a/modules/dnn/include/opencv2/dnn/shape_utils.hpp +++ b/modules/dnn/include/opencv2/dnn/shape_utils.hpp @@ -134,7 +134,7 @@ static inline MatShape shape(const Mat& mat) static inline MatShape shape(const MatSize& sz) { - return shape(sz.p, sz[-1]); + return shape(sz.p, sz.dims()); } static inline MatShape shape(const UMat& mat) diff --git a/modules/dnn/src/layers/slice_layer.cpp b/modules/dnn/src/layers/slice_layer.cpp index 222ebf6be8..826c640b5f 100644 --- a/modules/dnn/src/layers/slice_layer.cpp +++ b/modules/dnn/src/layers/slice_layer.cpp @@ -161,14 +161,14 @@ public: for (int i = 0; i < outputs.size(); ++i) { - CV_Assert(sliceRanges[i].size() <= inpShape[-1]); + CV_Assert(sliceRanges[i].size() <= inpShape.dims()); // Clamp. for (int j = 0; j < sliceRanges[i].size(); ++j) { sliceRanges[i][j] = clamp(sliceRanges[i][j], inpShape[j]); } // Fill the rest of ranges. - for (int j = sliceRanges[i].size(); j < inpShape[-1]; ++j) + for (int j = sliceRanges[i].size(); j < inpShape.dims(); ++j) { sliceRanges[i].push_back(Range::all()); } diff --git a/modules/dnn/src/op_halide.cpp b/modules/dnn/src/op_halide.cpp index 9287c496d8..c96971bc6a 100644 --- a/modules/dnn/src/op_halide.cpp +++ b/modules/dnn/src/op_halide.cpp @@ -6,6 +6,7 @@ // Third party copyrights are property of their respective owners. #include "precomp.hpp" +#include #include "op_halide.hpp" #ifdef HAVE_HALIDE @@ -36,7 +37,7 @@ static MatShape getBufferShape(const MatShape& shape) static MatShape getBufferShape(const MatSize& size) { - return getBufferShape(MatShape(size.p, size.p + size[-1])); + return getBufferShape(shape(size)); } Halide::Buffer wrapToHalideBuffer(const Mat& mat) @@ -160,7 +161,7 @@ void HalideBackendWrapper::setHostDirty() void getCanonicalSize(const MatSize& size, int* w, int* h, int* c, int* n) { - getCanonicalSize(MatShape(size.p, size.p + size[-1]), w, h, c, n); + getCanonicalSize(shape(size), w, h, c, n); } void getCanonicalSize(const MatShape& shape, int* width, int* height, From 4934f7c5a409553d24074d5b05a91d1e3c635fd5 Mon Sep 17 00:00:00 2001 From: yuki takehara Date: Sat, 28 Apr 2018 20:14:10 +0900 Subject: [PATCH 32/36] Merge pull request #11285 from take1014:core_6125 * Resolves 6125 * Fix test code * Delete unnecessary code --- modules/core/src/convert_scale.cpp | 17 ++++++++++++----- modules/core/test/test_arithm.cpp | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/modules/core/src/convert_scale.cpp b/modules/core/src/convert_scale.cpp index 74cf98b8b0..ff8398a27b 100644 --- a/modules/core/src/convert_scale.cpp +++ b/modules/core/src/convert_scale.cpp @@ -1885,13 +1885,24 @@ void cv::normalize( InputArray _src, InputOutputArray _dst, double a, double b, CV_INSTRUMENT_REGION() double scale = 1, shift = 0; + int type = _src.type(), depth = CV_MAT_DEPTH(type); + + if( rtype < 0 ) + rtype = _dst.fixedType() ? _dst.depth() : depth; + if( norm_type == CV_MINMAX ) { double smin = 0, smax = 0; double dmin = MIN( a, b ), dmax = MAX( a, b ); minMaxIdx( _src, &smin, &smax, 0, 0, _mask ); scale = (dmax - dmin)*(smax - smin > DBL_EPSILON ? 1./(smax - smin) : 0); - shift = dmin - smin*scale; + if( rtype == CV_32F ) + { + scale = (float)scale; + shift = (float)dmin - (float)(smin*scale); + } + else + shift = dmin - smin*scale; } else if( norm_type == CV_L2 || norm_type == CV_L1 || norm_type == CV_C ) { @@ -1902,10 +1913,6 @@ void cv::normalize( InputArray _src, InputOutputArray _dst, double a, double b, else CV_Error( CV_StsBadArg, "Unknown/unsupported norm type" ); - int type = _src.type(), depth = CV_MAT_DEPTH(type); - if( rtype < 0 ) - rtype = _dst.fixedType() ? _dst.depth() : depth; - CV_OCL_RUN(_dst.isUMat(), ocl_normalize(_src, _dst, _mask, rtype, scale, shift)) diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp index 6c90c1c857..dd2ed9a86e 100644 --- a/modules/core/test/test_arithm.cpp +++ b/modules/core/test/test_arithm.cpp @@ -1918,6 +1918,25 @@ TEST(Normalize, regression_5876_inplace_change_type) EXPECT_EQ(0, cvtest::norm(m, result, NORM_INF)); } +TEST(Normalize, regression_6125) +{ + float initial_values[] = { + 1888, 1692, 369, 263, 199, + 280, 326, 129, 143, 126, + 233, 221, 130, 126, 150, + 249, 575, 574, 63, 12 + }; + + Mat src(Size(20, 1), CV_32F, initial_values); + float min = 0., max = 400.; + normalize(src, src, 0, 400, NORM_MINMAX, CV_32F); + for(int i = 0; i < 20; i++) + { + EXPECT_GE(src.at(i), min) << "Value should be >= 0"; + EXPECT_LE(src.at(i), max) << "Value should be <= 400"; + } +} + TEST(MinMaxLoc, regression_4955_nans) { cv::Mat one_mat(2, 2, CV_32F, cv::Scalar(1)); From 65b0b319eb538d67d9e7a9cab8e790b72bdd564c Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sat, 28 Apr 2018 14:17:10 +0300 Subject: [PATCH 33/36] eliminate MSVS2017 build warning modules\dnn\src\layers\prior_box_layer.cpp(208): warning C4834: discarding return value of function with 'nodiscard' attribute --- modules/dnn/src/layers/prior_box_layer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/dnn/src/layers/prior_box_layer.cpp b/modules/dnn/src/layers/prior_box_layer.cpp index 6c02b939cf..81a7392376 100644 --- a/modules/dnn/src/layers/prior_box_layer.cpp +++ b/modules/dnn/src/layers/prior_box_layer.cpp @@ -205,7 +205,9 @@ public: if (_explicitSizes) { - CV_Assert(_aspectRatios.empty(), !params.has("min_size"), !params.has("max_size")); + CV_Assert(_aspectRatios.empty()); + CV_Assert(!params.has("min_size")); + CV_Assert(!params.has("max_size")); _boxWidths = widths; _boxHeights = heights; } From 80934dc48850d4c8483b3b11f31e17b5cf6d21dd Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sat, 28 Apr 2018 15:46:56 +0300 Subject: [PATCH 34/36] cmake: update 'git describe' information --- CMakeLists.txt | 25 ++----------------------- cmake/OpenCVUtils.cmake | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6de26879cc..d50c92b954 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -526,16 +526,7 @@ set(OPENCV_EXTRA_MODULES_PATH "" CACHE PATH "Where to look for additional OpenCV find_host_package(Git QUIET) if(NOT DEFINED OPENCV_VCSVERSION AND GIT_FOUND) - execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --always --dirty --match "[0-9].[0-9].[0-9]*" - WORKING_DIRECTORY "${OpenCV_SOURCE_DIR}" - OUTPUT_VARIABLE OPENCV_VCSVERSION - RESULT_VARIABLE GIT_RESULT - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(NOT GIT_RESULT EQUAL 0) - set(OPENCV_VCSVERSION "unknown") - endif() + ocv_git_describe(OPENCV_VCSVERSION "${OpenCV_SOURCE_DIR}") elseif(NOT DEFINED OPENCV_VCSVERSION) # We don't have git: set(OPENCV_VCSVERSION "unknown") @@ -931,19 +922,7 @@ if(OPENCV_EXTRA_MODULES_PATH AND NOT BUILD_INFO_SKIP_EXTRA_MODULES) else() status("") endif() - set(EXTRA_MODULES_VCSVERSION "unknown") - if(GIT_FOUND) - execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --always --dirty --match "[0-9].[0-9].[0-9]*" - WORKING_DIRECTORY "${p}" - OUTPUT_VARIABLE EXTRA_MODULES_VCSVERSION - RESULT_VARIABLE GIT_RESULT - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(NOT GIT_RESULT EQUAL 0) - set(EXTRA_MODULES_VCSVERSION "unknown") - endif() - endif() + ocv_git_describe(EXTRA_MODULES_VCSVERSION "${p}") status(" Location (extra):" ${p}) status(" Version control (extra):" ${EXTRA_MODULES_VCSVERSION}) endif() diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index be79111423..65029ddbff 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -1620,3 +1620,40 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.1) else() set(compatible_MESSAGE_NEVER "") endif() + + +macro(ocv_git_describe var_name path) + if(GIT_FOUND) + execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --tags --exact-match --dirty + WORKING_DIRECTORY "${path}" + OUTPUT_VARIABLE ${var_name} + RESULT_VARIABLE GIT_RESULT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(NOT GIT_RESULT EQUAL 0) + execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --always --dirty --match "[0-9].[0-9].[0-9]*" --exclude "[^-]*-cvsdk" + WORKING_DIRECTORY "${path}" + OUTPUT_VARIABLE ${var_name} + RESULT_VARIABLE GIT_RESULT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(NOT GIT_RESULT EQUAL 0) # --exclude is not supported by 'git' + # match only tags with complete OpenCV versions (ignores -alpha/-beta/-rc suffixes) + execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --always --dirty --match "[0-9].[0-9]*[0-9]" + WORKING_DIRECTORY "${path}" + OUTPUT_VARIABLE ${var_name} + RESULT_VARIABLE GIT_RESULT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(NOT GIT_RESULT EQUAL 0) + set(${var_name} "unknown") + endif() + endif() + endif() + else() + set(${var_name} "unknown") + endif() +endmacro() From 788d6a7105d00dd4b06e9121d7d101e563c5527c Mon Sep 17 00:00:00 2001 From: Sayed Adel Date: Wed, 2 May 2018 08:19:50 +0000 Subject: [PATCH 35/36] cmake: Disable -Wsuggest-override option in case of using PCH #11433 --- cmake/OpenCVCompilerOptions.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/OpenCVCompilerOptions.cmake b/cmake/OpenCVCompilerOptions.cmake index 774103af3a..d83777fe4b 100644 --- a/cmake/OpenCVCompilerOptions.cmake +++ b/cmake/OpenCVCompilerOptions.cmake @@ -104,7 +104,7 @@ if(CV_GCC OR CV_CLANG) add_extra_compiler_option(-Wuninitialized) add_extra_compiler_option(-Winit-self) if(HAVE_CXX11) - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT ENABLE_PRECOMPILED_HEADERS) add_extra_compiler_option(-Wsuggest-override) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") add_extra_compiler_option(-Winconsistent-missing-override) From 4ff6a1bc7b0c224014a8bde1b1c670627c530704 Mon Sep 17 00:00:00 2001 From: zuoshaobo Date: Thu, 3 May 2018 18:36:49 +0800 Subject: [PATCH 36/36] Merge pull request #11425 from zuoshaobo:relu_negative_slope * FIX INF_ENGINE RELU ERROR * set slope to variable * tab in indentwq --- modules/dnn/src/layers/elementwise_layers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/dnn/src/layers/elementwise_layers.cpp b/modules/dnn/src/layers/elementwise_layers.cpp index 1b8b2c7935..8600967de4 100644 --- a/modules/dnn/src/layers/elementwise_layers.cpp +++ b/modules/dnn/src/layers/elementwise_layers.cpp @@ -329,6 +329,7 @@ struct ReLUFunctor { lp.type = "ReLU"; std::shared_ptr ieLayer(new InferenceEngine::ReLULayer(lp)); + ieLayer->negative_slope = slope; return ieLayer; } #endif // HAVE_INF_ENGINE