Merge pull request #2508 from akarsakov:fix_erode_intel
authorAndrey Pavlenko <andrey.pavlenko@itseez.com>
Fri, 21 Mar 2014 14:25:11 +0000 (18:25 +0400)
committerOpenCV Buildbot <buildbot@opencv.org>
Fri, 21 Mar 2014 14:25:12 +0000 (18:25 +0400)
103 files changed:
cmake/OpenCVDetectVTK.cmake
cmake/OpenCVModule.cmake
doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.rst
doc/py_tutorials/py_video/py_meanshift/py_meanshift.rst
modules/calib3d/perf/opencl/perf_stereobm.cpp [new file with mode: 0644]
modules/calib3d/src/opencl/stereobm.cl [new file with mode: 0644]
modules/calib3d/src/precomp.hpp
modules/calib3d/src/stereobm.cpp
modules/calib3d/test/opencl/test_stereobm.cpp [new file with mode: 0644]
modules/core/doc/basic_structures.rst
modules/core/include/opencv2/core/mat.hpp
modules/core/include/opencv2/core/mat.inl.hpp
modules/core/include/opencv2/core/ocl.hpp
modules/core/perf/opencl/perf_arithm.cpp
modules/core/src/arithm.cpp
modules/core/src/convert.cpp
modules/core/src/copy.cpp
modules/core/src/mathfuncs.cpp
modules/core/src/matrix.cpp
modules/core/src/ocl.cpp
modules/core/src/opencl/arithm.cl
modules/core/src/opencl/copymakeborder.cl
modules/core/src/opencl/flip.cl
modules/core/src/opencl/set_identity.cl
modules/core/src/opencl/split_merge.cl
modules/core/src/umatrix.cpp
modules/core/test/ocl/test_arithm.cpp
modules/core/test/ocl/test_channels.cpp
modules/core/test/ocl/test_dft.cpp
modules/core/test/ocl/test_gemm.cpp
modules/core/test/ocl/test_matrix_operation.cpp
modules/features2d/perf/perf_orb.cpp
modules/features2d/src/fast.cpp
modules/features2d/src/opencl/fast.cl [new file with mode: 0644]
modules/features2d/src/opencl/orb.cl [new file with mode: 0644]
modules/features2d/src/orb.cpp
modules/highgui/CMakeLists.txt
modules/highgui/src/cap_msmf.cpp
modules/highgui/src/cap_msmf.hpp [new file with mode: 0644]
modules/highgui/src/ppltasks_winrt.h [new file with mode: 0644]
modules/imgproc/perf/opencl/perf_3vs4.cpp [new file with mode: 0644]
modules/imgproc/perf/opencl/perf_imgproc.cpp
modules/imgproc/src/morph.cpp
modules/imgproc/src/opencl/morph.cl
modules/imgproc/test/ocl/test_accumulate.cpp
modules/imgproc/test/ocl/test_blend.cpp
modules/imgproc/test/ocl/test_boxfilter.cpp
modules/imgproc/test/ocl/test_canny.cpp
modules/imgproc/test/ocl/test_color.cpp
modules/imgproc/test/ocl/test_filter2d.cpp
modules/imgproc/test/ocl/test_filters.cpp
modules/imgproc/test/ocl/test_gftt.cpp
modules/imgproc/test/ocl/test_histogram.cpp
modules/imgproc/test/ocl/test_imgproc.cpp
modules/imgproc/test/ocl/test_match_template.cpp
modules/imgproc/test/ocl/test_medianfilter.cpp
modules/imgproc/test/ocl/test_pyramids.cpp
modules/imgproc/test/ocl/test_sepfilter2D.cpp
modules/imgproc/test/ocl/test_warp.cpp
modules/objdetect/perf/opencl/perf_cascades.cpp
modules/objdetect/src/cascadedetect.cpp
modules/objdetect/src/hog.cpp
modules/objdetect/src/opencl/objdetect_hog.cl
modules/objdetect/test/opencl/test_hogdetector.cpp
modules/photo/src/denoising.cpp
modules/photo/src/fast_nlmeans_denoising_opencl.hpp
modules/photo/test/ocl/test_denoising.cpp
modules/ts/include/opencv2/ts/ocl_test.hpp
modules/ts/src/ocl_test.cpp
modules/video/test/ocl/test_bgfg_mog2.cpp
modules/video/test/ocl/test_motempl.cpp
modules/video/test/ocl/test_optflow_farneback.cpp
modules/videostab/src/deblurring.cpp
modules/viz/CMakeLists.txt
modules/viz/doc/widget.rst
modules/viz/include/opencv2/viz/types.hpp
modules/viz/include/opencv2/viz/viz3d.hpp
modules/viz/include/opencv2/viz/widgets.hpp
modules/viz/src/clouds.cpp
modules/viz/src/interactor_style.cpp [deleted file]
modules/viz/src/precomp.hpp
modules/viz/src/shapes.cpp
modules/viz/src/viz3d.cpp
modules/viz/src/vizcore.cpp
modules/viz/src/vizimpl.cpp
modules/viz/src/vizimpl.hpp
modules/viz/src/vtk/vtkCloudMatSink.cpp
modules/viz/src/vtk/vtkCloudMatSink.h
modules/viz/src/vtk/vtkCloudMatSource.cpp
modules/viz/src/vtk/vtkCocoaInteractorFix.mm [new file with mode: 0644]
modules/viz/src/vtk/vtkOBJWriter.cpp
modules/viz/src/vtk/vtkOBJWriter.h
modules/viz/src/vtk/vtkTrajectorySource.cpp
modules/viz/src/vtk/vtkVizInteractorStyle.cpp [new file with mode: 0644]
modules/viz/src/vtk/vtkVizInteractorStyle.hpp [moved from modules/viz/src/interactor_style.hpp with 61% similarity]
modules/viz/src/vtk/vtkXYZReader.cpp [new file with mode: 0644]
modules/viz/src/vtk/vtkXYZReader.h [new file with mode: 0644]
modules/viz/src/vtk/vtkXYZWriter.cpp
modules/viz/src/vtk/vtkXYZWriter.h
modules/viz/test/test_precomp.hpp
modules/viz/test/test_tutorial3.cpp
modules/viz/test/test_viz3d.cpp
modules/viz/test/tests_simple.cpp

index 78d1a73..2b55a9c 100644 (file)
@@ -2,25 +2,52 @@ if(NOT WITH_VTK OR ANDROID OR IOS)
   return()
 endif()
 
-if (HAVE_QT5)
-  message(STATUS "VTK is disabled because OpenCV is linked with Q5. Some VTK disributives are compiled with Q4 and therefore can't be linked together Qt5.")
+# VTK 6.x components
+find_package(VTK QUIET COMPONENTS vtkRenderingOpenGL vtkInteractionStyle vtkRenderingLOD vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport NO_MODULE)
+
+# VTK 5.x components
+if(NOT VTK_FOUND)
+  find_package(VTK QUIET COMPONENTS vtkCommon NO_MODULE)
+endif()
+
+if(NOT VTK_FOUND)
+  set(HAVE_VTK OFF)
+  message(STATUS "VTK is not found. Please set -DVTK_DIR in CMake to VTK build directory, or to VTK install subdirectory with VTKConfig.cmake file")
   return()
 endif()
 
-find_package(VTK 6.0 QUIET COMPONENTS vtkRenderingCore vtkInteractionWidgets vtkInteractionStyle vtkIOLegacy vtkIOPLY vtkRenderingFreeType vtkRenderingLOD vtkFiltersTexture vtkIOExport NO_MODULE)
+# Don't support ealier VTKs
+if(${VTK_VERSION} VERSION_LESS "5.8.0")
+  message(STATUS "VTK support is disabled. VTK ver. 5.8.0 is minimum required, but found VTK ver. ${VTK_VERSION}")
+  return()
+endif()
 
-if(NOT DEFINED VTK_FOUND OR NOT VTK_FOUND)
-  find_package(VTK 5.10 QUIET COMPONENTS vtkCommon vtkFiltering vtkRendering vtkWidgets vtkImaging NO_MODULE)
+# Different Qt versions can't be linked together
+if(HAVE_QT5 AND ${VTK_VERSION} VERSION_LESS "6.0.0")
+  if(VTK_USE_QT)
+    message(STATUS "VTK support is disabled. Incompatible combination: OpenCV + Qt5 and VTK ver.${VTK_VERSION} + Qt4")
+  endif()
 endif()
 
-if(NOT DEFINED VTK_FOUND OR NOT VTK_FOUND)
-  find_package(VTK 5.8 QUIET COMPONENTS vtkCommon vtkFiltering vtkRendering vtkWidgets vtkImaging NO_MODULE)
+# Different Qt versions can't be linked together. VTK 6.0.0 doesn't provide a way to get Qt version it was linked with
+if(HAVE_QT5 AND ${VTK_VERSION} VERSION_EQUAL "6.0.0" AND NOT DEFINED FORCE_VTK)
+  message(STATUS "VTK support is disabled. Possible incompatible combination: OpenCV+Qt5, and VTK ver.${VTK_VERSION} with Qt4")
+  message(STATUS "If it is known that VTK was compiled without Qt4, please define '-DFORCE_VTK=TRUE' flag in CMake")
+  return()
 endif()
 
-if(VTK_FOUND)
-  set(HAVE_VTK ON)
-  message(STATUS "Found VTK ver. ${VTK_VERSION} (usefile: ${VTK_USE_FILE})")
-else()
-  set(HAVE_VTK OFF)
-  message(STATUS "VTK is not found. Please set -DVTK_DIR in CMake to VTK build directory, or set $VTK_DIR enviroment variable to VTK install subdirectory with VTKConfig.cmake file (for windows)")
+# Different Qt versions can't be linked together
+if(HAVE_QT AND ${VTK_VERSION} VERSION_GREATER "6.0.0" AND NOT ${VTK_QT_VERSION} STREQUAL "")
+  if(HAVE_QT5 AND ${VTK_QT_VERSION} EQUAL "4")
+    message(STATUS "VTK support is disabled. Incompatible combination: OpenCV + Qt5 and VTK ver.${VTK_VERSION} + Qt4")
+    return()
+  endif()
+
+  if(NOT HAVE_QT5 AND ${VTK_QT_VERSION} EQUAL "5")
+    message(STATUS "VTK support is disabled. Incompatible combination: OpenCV + Qt4 and VTK ver.${VTK_VERSION} + Qt5")
+    return()
+  endif()
 endif()
+
+set(HAVE_VTK ON)
+message(STATUS "Found VTK ver. ${VTK_VERSION} (usefile: ${VTK_USE_FILE})")
index 19c2857..372d450 100644 (file)
@@ -484,6 +484,10 @@ macro(ocv_glob_module_sources)
   file(GLOB_RECURSE lib_int_hdrs "src/*.hpp" "src/*.h")
   file(GLOB lib_hdrs     "include/opencv2/*.hpp" "include/opencv2/${name}/*.hpp" "include/opencv2/${name}/*.h")
   file(GLOB lib_hdrs_detail "include/opencv2/${name}/detail/*.hpp" "include/opencv2/${name}/detail/*.h")
+  file(GLOB_RECURSE lib_srcs_apple "src/*.mm")
+  if (APPLE)
+    list(APPEND lib_srcs ${lib_srcs_apple})
+  endif()
 
   ocv_source_group("Src" DIRBASE "${CMAKE_CURRENT_SOURCE_DIR}/src" FILES ${lib_srcs} ${lib_int_hdrs})
   ocv_source_group("Include" DIRBASE "${CMAKE_CURRENT_SOURCE_DIR}/include" FILES ${lib_hdrs} ${lib_hdrs_detail})
@@ -750,8 +754,8 @@ function(ocv_add_accuracy_tests)
       endif()
 
       get_native_precompiled_header(${the_target} test_precomp.hpp)
-
       add_executable(${the_target} ${OPENCV_TEST_${the_module}_SOURCES} ${${the_target}_pch})
+
       target_link_libraries(${the_target} ${OPENCV_MODULE_${the_module}_DEPS} ${test_deps} ${OPENCV_LINKER_LIBS})
       add_dependencies(opencv_tests ${the_target})
 
index 6b7c661..8220fb5 100644 (file)
@@ -123,7 +123,7 @@ Let (x,y) be the top-left coordinate of the rectangle and (w,h) be its width and
 
 7.b. Rotated Rectangle
 -----------------------
-Here, bounding rectangle is drawn with minimum area, so it considers the rotation also. The function used is **cv2.minAreaRect()**. It returns a Box2D structure which contains following detals - ( top-left corner(x,y), (width, height), angle of rotation ). But to draw this rectangle, we need 4 corners of the rectangle. It is obtained by the function **cv2.boxPoints()**
+Here, bounding rectangle is drawn with minimum area, so it considers the rotation also. The function used is **cv2.minAreaRect()**. It returns a Box2D structure which contains following detals - ( center (x,y), (width, height), angle of rotation ). But to draw this rectangle, we need 4 corners of the rectangle. It is obtained by the function **cv2.boxPoints()**
 ::
 
     rect = cv2.minAreaRect(cnt)
index a111311..87ece69 100644 (file)
@@ -52,7 +52,7 @@ To use meanshift in OpenCV, first we need to setup the target, find its histogra
 
     # set up the ROI for tracking
     roi = frame[r:r+h, c:c+w]
-    hsv_roi =  cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
+    hsv_roi =  cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
     mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
     roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180])
     cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX)
@@ -127,7 +127,7 @@ It is almost same as meanshift, but it returns a rotated rectangle (that is our
 
     # set up the ROI for tracking
     roi = frame[r:r+h, c:c+w]
-    hsv_roi =  cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
+    hsv_roi =  cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
     mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
     roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180])
     cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX)
diff --git a/modules/calib3d/perf/opencl/perf_stereobm.cpp b/modules/calib3d/perf/opencl/perf_stereobm.cpp
new file mode 100644 (file)
index 0000000..8fca1b8
--- /dev/null
@@ -0,0 +1,77 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
+// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors as is and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "perf_precomp.hpp"
+#include "opencv2/ts/ocl_perf.hpp"
+
+#ifdef HAVE_OPENCL
+
+namespace cvtest {
+namespace ocl {
+
+typedef std::tr1::tuple<int, int> StereoBMFixture_t;
+typedef TestBaseWithParam<StereoBMFixture_t> StereoBMFixture;
+
+OCL_PERF_TEST_P(StereoBMFixture, StereoBM, ::testing::Combine(OCL_PERF_ENUM(32, 64, 128), OCL_PERF_ENUM(11,21) ) )
+{
+    const int n_disp = get<0>(GetParam()), winSize = get<1>(GetParam());
+    UMat left, right, disp;
+
+    imread(getDataPath("gpu/stereobm/aloe-L.png"), IMREAD_GRAYSCALE).copyTo(left);
+    imread(getDataPath("gpu/stereobm/aloe-R.png"), IMREAD_GRAYSCALE).copyTo(right);
+    ASSERT_FALSE(left.empty());
+    ASSERT_FALSE(right.empty());
+
+    declare.in(left, right);
+
+    Ptr<StereoBM> bm = createStereoBM( n_disp, winSize );
+    bm->setPreFilterType(bm->PREFILTER_XSOBEL);
+    bm->setTextureThreshold(0);
+
+    OCL_TEST_CYCLE() bm->compute(left, right, disp);
+
+    SANITY_CHECK(disp, 1e-3, ERROR_RELATIVE);
+}
+
+}//ocl
+}//cvtest
+#endif
diff --git a/modules/calib3d/src/opencl/stereobm.cl b/modules/calib3d/src/opencl/stereobm.cl
new file mode 100644 (file)
index 0000000..a746c89
--- /dev/null
@@ -0,0 +1,297 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
+// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors as is and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////// stereoBM //////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef csize
+
+#define MAX_VAL 32767
+
+void calcDisp(__local short * cost, __global short * disp, int uniquenessRatio, int mindisp, int ndisp, int w,
+              __local int * bestDisp, __local int * bestCost, int d, int x, int y, int cols, int rows, int wsz2)
+{
+    short FILTERED = (mindisp - 1)<<4;
+    int best_disp = *bestDisp, best_cost = *bestCost, best_disp_back = ndisp - best_disp - 1;
+
+    short c = cost[0];
+
+    int thresh = best_cost + (best_cost * uniquenessRatio/100);
+    bool notUniq = ( (c <= thresh) && (d < (best_disp_back - 1) || d > (best_disp_back + 1) ) );
+
+    if(notUniq)
+        *bestCost = FILTERED;
+    barrier(CLK_LOCAL_MEM_FENCE);
+
+    if( *bestCost != FILTERED && x < cols-wsz2-mindisp && y < rows-wsz2 && d == best_disp_back)
+    {
+        int y3 = (best_disp_back > 0) ? cost[-w] : cost[w],
+            y2 = c,
+            y1 = (best_disp_back < ndisp-1) ? cost[w] : cost[-w];
+        int d_aprox = y3+y1-2*y2 + abs(y3-y1);
+        disp[0] = (short)(((best_disp_back + mindisp)*256 + (d_aprox != 0 ? (y3-y1)*256/d_aprox : 0) + 15) >> 4);
+    }
+}
+
+int calcLocalIdx(int x, int y, int d, int w)
+{
+    return d*2*w + (w - 1 - y + x);
+}
+
+void calcNewCoordinates(int * x, int * y, int nthread)
+{
+    int oldX = *x - (1-nthread), oldY = *y;
+    *x = (oldX == oldY) ? (0*nthread + (oldX + 2)*(1-nthread) ) : (oldX+1)*(1-nthread) + (oldX+1)*nthread;
+    *y = (oldX == oldY) ? (0*(1-nthread) + (oldY + 1)*nthread) : oldY + 1*(1-nthread);
+}
+
+short calcCostBorder(__global const uchar * leftptr, __global const uchar * rightptr, int x, int y, int nthread,
+                     int wsz2, short * costbuf, int * h, int cols, int d, short cost, int winsize)
+{
+    int head = (*h)%wsz;
+    __global const uchar * left, * right;
+    int idx = mad24(y+wsz2*(2*nthread-1), cols, x+wsz2*(1-2*nthread));
+    left = leftptr + idx;
+    right = rightptr + (idx - d);
+    int shift = 1*nthread + cols*(1-nthread);
+
+    short costdiff = 0;
+    for(int i = 0; i < winsize; i++)
+    {
+        costdiff += abs( left[0] - right[0] );
+        left += shift;
+        right += shift;
+    }
+    cost += costdiff - costbuf[head];
+    costbuf[head] = costdiff;
+    (*h) = (*h)%wsz + 1;
+    return cost;
+}
+
+short calcCostInside(__global const uchar * leftptr, __global const uchar * rightptr, int x, int y,
+                     int wsz2, int cols, int d, short cost_up_left, short cost_up, short cost_left,
+                     int winsize)
+{
+    __global const uchar * left, * right;
+    int idx = mad24(y-wsz2-1, cols, x-wsz2-1);
+    left = leftptr + idx;
+    right = rightptr + (idx - d);
+    int idx2 = winsize*cols;
+
+    uchar corrner1 = abs(left[0] - right[0]),
+          corrner2 = abs(left[winsize] - right[winsize]),
+          corrner3 = abs(left[idx2] - right[idx2]),
+          corrner4 = abs(left[idx2 + winsize] - right[idx2 + winsize]);
+
+    return cost_up + cost_left - cost_up_left + corrner1 -
+        corrner2 - corrner3 + corrner4;
+}
+
+__kernel void stereoBM(__global const uchar * leftptr, __global const uchar * rightptr, __global uchar * dispptr,
+                       int disp_step, int disp_offset, int rows, int cols, int mindisp, int ndisp,
+                       int preFilterCap, int textureTreshold, int uniquenessRatio, int sizeX, int sizeY, int winsize)
+{
+    int gx = get_global_id(0)*sizeX;
+    int gy = get_global_id(1)*sizeY;
+    int lz = get_local_id(2);
+
+    int nthread = lz/ndisp;
+    int d = lz%ndisp;
+    int wsz2 = wsz/2;
+
+    __global short * disp;
+    __global const uchar * left, * right;
+
+    __local short costFunc[csize];
+    __local short * cost;
+    __local int best_disp[2];
+    __local int best_cost[2];
+    best_cost[nthread] = MAX_VAL;
+
+    short costbuf[wsz];
+    int head = 0;
+
+    int shiftX = wsz2 + ndisp + mindisp - 1;
+    int shiftY = wsz2;
+
+    int x = gx + shiftX, y = gy + shiftY, lx = 0, ly = 0;
+
+    int costIdx = calcLocalIdx(lx, ly, d, sizeY);
+    cost = costFunc + costIdx;
+
+    short tempcost = 0;
+    if(x < cols-wsz2-mindisp && y < rows-wsz2)
+    {
+        int shift = 1*nthread + cols*(1-nthread);
+        for(int i = 0; i < winsize; i++)
+        {
+            int idx = mad24(y-wsz2+i*nthread, cols, x-wsz2+i*(1-nthread));
+            left = leftptr + idx;
+            right = rightptr + (idx - d);
+            short costdiff = 0;
+            for(int j = 0; j < winsize; j++)
+            {
+                costdiff += abs( left[0] - right[0] );
+                left += shift;
+                right += shift;
+            }
+            if(nthread==1)
+            {
+                tempcost += costdiff;
+            }
+            costbuf[head] = costdiff;
+            head++;
+        }
+    }
+    if(nthread==1)
+    {
+        cost[0] = tempcost;
+        atomic_min(best_cost+nthread, tempcost);
+    }
+    barrier(CLK_LOCAL_MEM_FENCE);
+
+    if(best_cost[1] == tempcost)
+        best_disp[1] = ndisp - d - 1;
+    barrier(CLK_LOCAL_MEM_FENCE);
+
+    int dispIdx = mad24(gy, disp_step, disp_offset + gx*(int)sizeof(short));
+    disp = (__global short *)(dispptr + dispIdx);
+    calcDisp(cost, disp, uniquenessRatio, mindisp, ndisp, 2*sizeY,
+        best_disp + 1, best_cost+1, d, x, y, cols, rows, wsz2);
+    barrier(CLK_LOCAL_MEM_FENCE);
+
+    lx = 1 - nthread;
+    ly = nthread;
+
+    for(int i = 0; i < sizeY*sizeX/2; i++)
+    {
+        x = (lx < sizeX) ? gx + shiftX + lx : cols;
+        y = (ly < sizeY) ? gy + shiftY + ly : rows;
+
+        best_cost[nthread] = MAX_VAL;
+        barrier(CLK_LOCAL_MEM_FENCE);
+
+        costIdx = calcLocalIdx(lx, ly, d, sizeY);
+        cost = costFunc + costIdx;
+
+        if(x < cols-wsz2-mindisp && y < rows-wsz2 )
+        {
+            tempcost = ( ly*(1-nthread) + lx*nthread == 0 ) ?
+                calcCostBorder(leftptr, rightptr, x, y, nthread, wsz2, costbuf, &head, cols, d,
+                    cost[2*nthread-1], winsize) :
+                calcCostInside(leftptr, rightptr, x, y, wsz2, cols, d,
+                    cost[0], cost[1], cost[-1], winsize);
+        }
+        cost[0] = tempcost;
+        atomic_min(best_cost + nthread, tempcost);
+        barrier(CLK_LOCAL_MEM_FENCE);
+
+        if(best_cost[nthread] == tempcost)
+            best_disp[nthread] = ndisp - d - 1;
+        barrier(CLK_LOCAL_MEM_FENCE);
+
+        int dispIdx = mad24(gy+ly, disp_step, disp_offset + (gx+lx)*(int)sizeof(short));
+        disp = (__global short *)(dispptr + dispIdx);
+
+        calcDisp(cost, disp, uniquenessRatio, mindisp, ndisp, 2*sizeY,
+            best_disp + nthread, best_cost + nthread, d, x, y, cols, rows, wsz2);
+        barrier(CLK_LOCAL_MEM_FENCE);
+
+        calcNewCoordinates(&lx, &ly, nthread);
+    }
+}
+
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////// Norm Prefiler ////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+__kernel void prefilter_norm(__global unsigned char *input, __global unsigned char *output,
+                               int rows, int cols, int prefilterCap, int winsize, int scale_g, int scale_s)
+{
+    int x = get_global_id(0);
+    int y = get_global_id(1);
+    int wsz2 = winsize/2;
+
+    if(x < cols && y < rows)
+    {
+        int cov1 =                                   input[   max(y-1, 0)   * cols + x] * 1 +
+                  input[y * cols + max(x-1,0)] * 1 + input[      y          * cols + x] * 4 + input[y * cols + min(x+1, cols-1)] * 1 +
+                                                     input[min(y+1, rows-1) * cols + x] * 1;
+        int cov2 = 0;
+        for(int i = -wsz2; i < wsz2+1; i++)
+            for(int j = -wsz2; j < wsz2+1; j++)
+                cov2 += input[clamp(y+i, 0, rows-1) * cols + clamp(x+j, 0, cols-1)];
+
+        int res = (cov1*scale_g - cov2*scale_s)>>10;
+        res = min(clamp(res, -prefilterCap, prefilterCap) + prefilterCap, 255);
+        output[y * cols + x] = res & 0xFF;
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////// Sobel Prefiler ////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+__kernel void prefilter_xsobel(__global unsigned char *input, __global unsigned char *output,
+                               int rows, int cols, int prefilterCap)
+{
+    int x = get_global_id(0);
+    int y = get_global_id(1);
+    if(x < cols && y < rows)
+    {
+            output[y * cols + x] = min(prefilterCap, 255) & 0xFF;
+    }
+
+    if(x < cols && y < rows && x > 0 && !((y == rows-1)&(rows%2==1) ) )
+    {
+        int cov = input[ ((y > 0) ? y-1 : y+1)  * cols + (x-1)] * (-1) + input[ ((y > 0) ? y-1 : y+1)  * cols + ((x<cols-1) ? x+1 : x-1)] * (1) +
+                  input[              (y)       * cols + (x-1)] * (-2) + input[        (y)             * cols + ((x<cols-1) ? x+1 : x-1)] * (2) +
+                  input[((y<rows-1)?(y+1):(y-1))* cols + (x-1)] * (-1) + input[((y<rows-1)?(y+1):(y-1))* cols + ((x<cols-1) ? x+1 : x-1)] * (1);
+
+        cov = min(clamp(cov, -prefilterCap, prefilterCap) + prefilterCap, 255);
+        output[y * cols + x] = cov & 0xFF;
+    }
+}
index 12885f3..e8a8112 100644 (file)
@@ -49,6 +49,8 @@
 
 #include "opencv2/core/private.hpp"
 
+#include "opencv2/core/ocl.hpp"
+
 #ifdef HAVE_TEGRA_OPTIMIZATION
 #include "opencv2/calib3d/calib3d_tegra.hpp"
 #else
index b9328e8..7c06deb 100644 (file)
@@ -48,6 +48,7 @@
 #include "precomp.hpp"
 #include <stdio.h>
 #include <limits>
+#include "opencl_kernels.hpp"
 
 namespace cv
 {
@@ -85,6 +86,26 @@ struct StereoBMParams
     int dispType;
 };
 
+static bool ocl_prefilter_norm(InputArray _input, OutputArray _output, int winsize, int prefilterCap)
+{
+    ocl::Kernel k("prefilter_norm", ocl::calib3d::stereobm_oclsrc);
+    if(k.empty())
+        return false;
+
+    int scale_g = winsize*winsize/8, scale_s = (1024 + scale_g)/(scale_g*2);
+    scale_g *= scale_s;
+
+    UMat input = _input.getUMat(), output;
+    _output.create(input.size(), input.type());
+    output = _output.getUMat();
+
+    size_t globalThreads[3] = { input.cols, input.rows, 1 };
+
+    k.args(ocl::KernelArg::PtrReadOnly(input), ocl::KernelArg::PtrWriteOnly(output), input.rows, input.cols,
+        prefilterCap, winsize, scale_g, scale_s);
+
+    return k.run(2, globalThreads, NULL, false);
+}
 
 static void prefilterNorm( const Mat& src, Mat& dst, int winsize, int ftzero, uchar* buf )
 {
@@ -149,6 +170,22 @@ static void prefilterNorm( const Mat& src, Mat& dst, int winsize, int ftzero, uc
     }
 }
 
+static bool ocl_prefilter_xsobel(InputArray _input, OutputArray _output, int prefilterCap)
+{
+    ocl::Kernel k("prefilter_xsobel", ocl::calib3d::stereobm_oclsrc);
+    if(k.empty())
+        return false;
+
+    UMat input = _input.getUMat(), output;
+    _output.create(input.size(), input.type());
+    output = _output.getUMat();
+
+    size_t globalThreads[3] = { input.cols, input.rows, 1 };
+
+    k.args(ocl::KernelArg::PtrReadOnly(input), ocl::KernelArg::PtrWriteOnly(output), input.rows, input.cols, prefilterCap);
+
+    return k.run(2, globalThreads, NULL, false);
+}
 
 static void
 prefilterXSobel( const Mat& src, Mat& dst, int ftzero )
@@ -534,7 +571,6 @@ findStereoCorrespondenceBM( const Mat& left, const Mat& right,
         hsad = hsad0 - dy0*ndisp; cbuf = cbuf0 + (x + wsz2 + 1)*cstep - dy0*ndisp;
         lptr = lptr0 + std::min(std::max(x, -lofs), width-lofs-1) - dy0*sstep;
         rptr = rptr0 + std::min(std::max(x, -rofs), width-rofs-1) - dy0*sstep;
-
         for( y = -dy0; y < height + dy1; y++, hsad += ndisp, cbuf += ndisp, lptr += sstep, rptr += sstep )
         {
             int lval = lptr[0];
@@ -617,6 +653,7 @@ findStereoCorrespondenceBM( const Mat& left, const Mat& right,
                     mind = d;
                 }
             }
+
             tsum += htext[y + wsz2] - htext[y - wsz2 - 1];
             if( tsum < textureThreshold )
             {
@@ -651,6 +688,25 @@ findStereoCorrespondenceBM( const Mat& left, const Mat& right,
     }
 }
 
+static bool ocl_prefiltering(InputArray left0, InputArray right0, OutputArray left, OutputArray right, StereoBMParams* state)
+{
+    if( state->preFilterType == StereoBM::PREFILTER_NORMALIZED_RESPONSE )
+    {
+        if(!ocl_prefilter_norm( left0, left, state->preFilterSize, state->preFilterCap))
+            return false;
+        if(!ocl_prefilter_norm( right0, right, state->preFilterSize, state->preFilterCap))
+            return false;
+    }
+    else
+    {
+        if(!ocl_prefilter_xsobel( left0, left, state->preFilterCap ))
+            return false;
+        if(!ocl_prefilter_xsobel( right0, right, state->preFilterCap))
+            return false;
+    }
+    return true;
+}
+
 struct PrefilterInvoker : public ParallelLoopBody
 {
     PrefilterInvoker(const Mat& left0, const Mat& right0, Mat& left, Mat& right,
@@ -679,6 +735,51 @@ struct PrefilterInvoker : public ParallelLoopBody
     StereoBMParams* state;
 };
 
+static bool ocl_stereobm( InputArray _left, InputArray _right,
+                       OutputArray _disp, StereoBMParams* state)
+{
+    int ndisp = state->numDisparities;
+    int mindisp = state->minDisparity;
+    int wsz = state->SADWindowSize;
+    int wsz2 = wsz/2;
+
+    int sizeX = std::max(11, 27 - ocl::Device::getDefault().maxComputeUnits() ), sizeY = sizeX-1, N = ndisp*2;
+
+    ocl::Kernel k("stereoBM", ocl::calib3d::stereobm_oclsrc, cv::format("-D csize=%d -D wsz=%d", (2*sizeY)*ndisp, wsz) );
+    if(k.empty())
+        return false;
+
+    UMat left = _left.getUMat(), right = _right.getUMat();
+    int cols = left.cols, rows = left.rows;
+
+    _disp.create(_left.size(), CV_16S);
+    _disp.setTo((mindisp - 1)<<4);
+    Rect roi = Rect(Point(wsz2 + mindisp + ndisp - 1, wsz2), Point(cols-wsz2-mindisp, rows-wsz2) );
+    UMat disp = (_disp.getUMat())(roi);
+
+    int globalX = disp.cols/sizeX, globalY = disp.rows/sizeY;
+    globalX += (disp.cols%sizeX) > 0 ? 1 : 0;
+    globalY += (disp.rows%sizeY) > 0 ? 1 : 0;
+    size_t globalThreads[3] = { globalX, globalY, N};
+    size_t localThreads[3] = {1, 1, N};
+
+    int idx = 0;
+    idx = k.set(idx, ocl::KernelArg::PtrReadOnly(left));
+    idx = k.set(idx, ocl::KernelArg::PtrReadOnly(right));
+    idx = k.set(idx, ocl::KernelArg::WriteOnlyNoSize(disp));
+    idx = k.set(idx, rows);
+    idx = k.set(idx, cols);
+    idx = k.set(idx, mindisp);
+    idx = k.set(idx, ndisp);
+    idx = k.set(idx, state->preFilterCap);
+    idx = k.set(idx, state->textureThreshold);
+    idx = k.set(idx, state->uniquenessRatio);
+    idx = k.set(idx, sizeX);
+    idx = k.set(idx, sizeY);
+    idx = k.set(idx, wsz);
+
+    return k.run(3, globalThreads, localThreads, false);
+}
 
 struct FindStereoCorrespInvoker : public ParallelLoopBody
 {
@@ -776,21 +877,18 @@ public:
 
     void compute( InputArray leftarr, InputArray rightarr, OutputArray disparr )
     {
-        Mat left0 = leftarr.getMat(), right0 = rightarr.getMat();
         int dtype = disparr.fixedType() ? disparr.type() : params.dispType;
+        Size leftsize = leftarr.size();
 
-        if (left0.size() != right0.size())
+        if (leftarr.size() != rightarr.size())
             CV_Error( Error::StsUnmatchedSizes, "All the images must have the same size" );
 
-        if (left0.type() != CV_8UC1 || right0.type() != CV_8UC1)
+        if (leftarr.type() != CV_8UC1 || rightarr.type() != CV_8UC1)
             CV_Error( Error::StsUnsupportedFormat, "Both input images must have CV_8UC1" );
 
         if (dtype != CV_16SC1 && dtype != CV_32FC1)
             CV_Error( Error::StsUnsupportedFormat, "Disparity image must have CV_16SC1 or CV_32FC1 format" );
 
-        disparr.create(left0.size(), dtype);
-        Mat disp0 = disparr.getMat();
-
         if( params.preFilterType != PREFILTER_NORMALIZED_RESPONSE &&
             params.preFilterType != PREFILTER_XSOBEL )
             CV_Error( Error::StsOutOfRange, "preFilterType must be = CV_STEREO_BM_NORMALIZED_RESPONSE" );
@@ -802,7 +900,7 @@ public:
             CV_Error( Error::StsOutOfRange, "preFilterCap must be within 1..63" );
 
         if( params.SADWindowSize < 5 || params.SADWindowSize > 255 || params.SADWindowSize % 2 == 0 ||
-            params.SADWindowSize >= std::min(left0.cols, left0.rows) )
+            params.SADWindowSize >= std::min(leftsize.width, leftsize.height) )
             CV_Error( Error::StsOutOfRange, "SADWindowSize must be odd, be within 5..255 and be not larger than image width or height" );
 
         if( params.numDisparities <= 0 || params.numDisparities % 16 != 0 )
@@ -814,6 +912,28 @@ public:
         if( params.uniquenessRatio < 0 )
             CV_Error( Error::StsOutOfRange, "uniqueness ratio must be non-negative" );
 
+        int FILTERED = (params.minDisparity - 1) << DISPARITY_SHIFT;
+
+        if(ocl::useOpenCL() && disparr.isUMat() && params.textureThreshold == 0)
+        {
+            UMat left, right;
+            if(ocl_prefiltering(leftarr, rightarr, left, right, &params))
+            {
+                if(ocl_stereobm(left, right, disparr, &params))
+                {
+                    if( params.speckleRange >= 0 && params.speckleWindowSize > 0 )
+                        filterSpeckles(disparr.getMat(), FILTERED, params.speckleWindowSize, params.speckleRange, slidingSumBuf);
+                    if (dtype == CV_32F)
+                        disparr.getUMat().convertTo(disparr, CV_32FC1, 1./(1 << DISPARITY_SHIFT), 0);
+                    return;
+                }
+            }
+        }
+
+        Mat left0 = leftarr.getMat(), right0 = rightarr.getMat();
+        disparr.create(left0.size(), dtype);
+        Mat disp0 = disparr.getMat();
+
         preFilteredImg0.create( left0.size(), CV_8U );
         preFilteredImg1.create( left0.size(), CV_8U );
         cost.create( left0.size(), CV_16S );
@@ -828,7 +948,6 @@ public:
         int lofs = std::max(ndisp - 1 + mindisp, 0);
         int rofs = -std::min(ndisp - 1 + mindisp, 0);
         int width1 = width - rofs - ndisp + 1;
-        int FILTERED = (params.minDisparity - 1) << DISPARITY_SHIFT;
 
         if( lofs >= width || rofs >= width || width1 < 1 )
         {
@@ -870,6 +989,7 @@ public:
             slidingSumBuf.create( 1, bufSize, CV_8U );
 
         uchar *_buf = slidingSumBuf.data;
+
         parallel_for_(Range(0, 2), PrefilterInvoker(left0, right0, left, right, _buf, _buf + bufSize1, &params), 1);
 
         Rect validDisparityRect(0, 0, width, height), R1 = params.roi1, R2 = params.roi2;
diff --git a/modules/calib3d/test/opencl/test_stereobm.cpp b/modules/calib3d/test/opencl/test_stereobm.cpp
new file mode 100644 (file)
index 0000000..636d76c
--- /dev/null
@@ -0,0 +1,97 @@
+///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
+// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include "cvconfig.h"
+#include "opencv2/ts/ocl_test.hpp"
+
+#ifdef HAVE_OPENCL
+
+namespace cvtest {
+namespace ocl {
+
+PARAM_TEST_CASE(StereoBMFixture, int, int)
+{
+    int n_disp;
+    int winSize;
+    Mat left, right, disp;
+    UMat uleft, uright, udisp;
+
+    virtual void SetUp()
+    {
+        n_disp  = GET_PARAM(0);
+        winSize = GET_PARAM(1);
+
+        left  = readImage("gpu/stereobm/aloe-L.png", IMREAD_GRAYSCALE);
+        right = readImage("gpu/stereobm/aloe-R.png", IMREAD_GRAYSCALE);
+
+        ASSERT_FALSE(left.empty());
+        ASSERT_FALSE(right.empty());
+
+        left.copyTo(uleft);
+        right.copyTo(uright);
+    }
+
+    void Near(double eps = 0.0)
+    {
+        EXPECT_MAT_NEAR_RELATIVE(disp, udisp, eps);
+    }
+};
+
+OCL_TEST_P(StereoBMFixture, StereoBM)
+{
+    Ptr<StereoBM> bm = createStereoBM( n_disp, winSize);
+    bm->setPreFilterType(bm->PREFILTER_XSOBEL);
+    bm->setTextureThreshold(0);
+
+    OCL_OFF(bm->compute(left, right, disp));
+    OCL_ON(bm->compute(uleft, uright, udisp));
+
+    Near(1e-3);
+}
+
+OCL_INSTANTIATE_TEST_CASE_P(StereoMatcher, StereoBMFixture, testing::Combine(testing::Values(32, 64, 128),
+                                       testing::Values(11, 21)));
+}//ocl
+}//cvtest
+
+#endif //HAVE_OPENCL
index bd29b82..459a6a9 100644 (file)
@@ -1615,7 +1615,7 @@ Copies the matrix to another one.
 
 The method copies the matrix data to another matrix. Before copying the data, the method invokes ::
 
-    m.create(this->size(), this->type);
+    m.create(this->size(), this->type());
 
 
 so that the destination matrix is reallocated if needed. While ``m.copyTo(m);`` works flawlessly, the function does not handle the case of a partial overlap between the source and the destination matrices.
@@ -1710,7 +1710,7 @@ Transposes a matrix.
 
 The method performs matrix transposition by means of matrix expressions. It does not perform the actual transposition but returns a temporary matrix transposition object that can be further used as a part of more complex matrix expressions or can be assigned to a matrix: ::
 
-    Mat A1 = A + Mat::eye(A.size(), A.type)*lambda;
+    Mat A1 = A + Mat::eye(A.size(), A.type())*lambda;
     Mat C = A1.t()*A1; // compute (A + lambda*I)^t * (A + lamda*I)
 
 
index eb206fc..33167fa 100644 (file)
@@ -135,7 +135,7 @@ public:
     bool isUMat() const;
     bool isMatVector() const;
     bool isUMatVector() const;
-    bool isMatx();
+    bool isMatx() const;
 
     virtual ~_InputArray();
 
index d289e3a..d463eec 100644 (file)
@@ -112,7 +112,7 @@ inline bool _InputArray::isMat() const { return kind() == _InputArray::MAT; }
 inline bool _InputArray::isUMat() const  { return kind() == _InputArray::UMAT; }
 inline bool _InputArray::isMatVector() const { return kind() == _InputArray::STD_VECTOR_MAT; }
 inline bool _InputArray::isUMatVector() const  { return kind() == _InputArray::STD_VECTOR_UMAT; }
-inline bool _InputArray::isMatx()  { return kind() == _InputArray::MATX; }
+inline bool _InputArray::isMatx() const { return kind() == _InputArray::MATX; }
 
 ////////////////////////////////////////////////////////////////////////////////////////
 
index 5db8ef7..fb9ec24 100644 (file)
@@ -169,6 +169,10 @@ public:
         VENDOR_NVIDIA=3
     };
     int vendorID() const;
+    // FIXIT
+    // dev.isAMD() doesn't work for OpenCL CPU devices from AMD OpenCL platform.
+    // This method should use platform name instead of vendor name.
+    // After fix restore code in arithm.cpp: ocl_compare()
     inline bool isAMD() const { return vendorID() == VENDOR_AMD; }
     inline bool isIntel() const { return vendorID() == VENDOR_INTEL; }
 
index f4680aa..7e0e00e 100644 (file)
@@ -540,7 +540,7 @@ typedef TestBaseWithParam<CompareParams> CompareFixture;
 
 OCL_PERF_TEST_P(CompareFixture, Compare,
             ::testing::Combine(OCL_TEST_SIZES,
-                               OCL_TEST_TYPES, CmpCode::all()))
+                               OCL_TEST_TYPES_134, CmpCode::all()))
 {
     const CompareParams params = GetParam();
     const Size srcSize = get<0>(params);
@@ -549,7 +549,7 @@ OCL_PERF_TEST_P(CompareFixture, Compare,
 
     checkDeviceMaxMemoryAllocSize(srcSize, type);
 
-    UMat src1(srcSize, type), src2(srcSize, type), dst(srcSize, CV_8UC1);
+    UMat src1(srcSize, type), src2(srcSize, type), dst(srcSize, CV_8UC(CV_MAT_CN(type)));
     declare.in(src1, src2, WARMUP_RNG).out(dst);
 
     OCL_TEST_CYCLE() cv::compare(src1, src2, dst, cmpCode);
@@ -557,6 +557,26 @@ OCL_PERF_TEST_P(CompareFixture, Compare,
     SANITY_CHECK(dst);
 }
 
+OCL_PERF_TEST_P(CompareFixture, CompareScalar,
+            ::testing::Combine(OCL_TEST_SIZES,
+                               OCL_PERF_ENUM((MatType)CV_32FC1), // TODO: OCL_TEST_TYPES_134
+                               CmpCode::all()))
+{
+    const CompareParams params = GetParam();
+    const Size srcSize = get<0>(params);
+    const int type = get<1>(params);
+    const int cmpCode = get<2>(params);
+
+    checkDeviceMaxMemoryAllocSize(srcSize, type);
+
+    UMat src1(srcSize, type), dst(srcSize, CV_8UC(CV_MAT_CN(type)));
+    declare.in(src1, WARMUP_RNG).out(dst);
+
+    OCL_TEST_CYCLE() cv::compare(src1, 32, dst, cmpCode);
+
+    SANITY_CHECK(dst);
+}
+
 ///////////// pow ////////////////////////
 
 typedef Size_MatType PowFixture;
index 436239c..f59eefd 100644 (file)
@@ -1299,7 +1299,7 @@ static bool ocl_arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
     int type1 = _src1.type(), depth1 = CV_MAT_DEPTH(type1), cn = CV_MAT_CN(type1);
     bool haveMask = !_mask.empty();
 
-    if( ((haveMask || haveScalar) && cn > 4) )
+    if ( (haveMask || haveScalar) && cn > 4 )
         return false;
 
     int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype), wdepth = std::max(CV_32S, CV_MAT_DEPTH(wtype));
@@ -1320,14 +1320,11 @@ static bool ocl_arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
             "-D convertToWT2=%s -D convertToDT=%s%s -D cn=%d",
             (haveMask ? "MASK_" : ""), (haveScalar ? "UNARY_OP" : "BINARY_OP"),
             oclop2str[oclop], ocl::typeToStr(CV_MAKETYPE(depth1, kercn)),
-            ocl::typeToStr(CV_MAKETYPE(depth1, 1)),
-            ocl::typeToStr(CV_MAKETYPE(depth2, kercn)),
-            ocl::typeToStr(CV_MAKETYPE(depth2, 1)),
-            ocl::typeToStr(CV_MAKETYPE(ddepth, kercn)),
-            ocl::typeToStr(CV_MAKETYPE(ddepth, 1)),
-            ocl::typeToStr(CV_MAKETYPE(wdepth, kercn)),
+            ocl::typeToStr(depth1), ocl::typeToStr(CV_MAKETYPE(depth2, kercn)),
+            ocl::typeToStr(depth2), ocl::typeToStr(CV_MAKETYPE(ddepth, kercn)),
+            ocl::typeToStr(ddepth), ocl::typeToStr(CV_MAKETYPE(wdepth, kercn)),
             ocl::typeToStr(CV_MAKETYPE(wdepth, scalarcn)),
-            ocl::typeToStr(CV_MAKETYPE(wdepth, 1)), wdepth,
+            ocl::typeToStr(wdepth), wdepth,
             ocl::convertTypeStr(depth1, wdepth, kercn, cvtstr[0]),
             ocl::convertTypeStr(depth2, wdepth, kercn, cvtstr[1]),
             ocl::convertTypeStr(wdepth, ddepth, kercn, cvtstr[2]),
@@ -1347,7 +1344,7 @@ static bool ocl_arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
     }
 
     ocl::Kernel k("KF", ocl::core::arithm_oclsrc, opts);
-    if( k.empty() )
+    if (k.empty())
         return false;
 
     UMat src1 = _src1.getUMat(), src2;
@@ -1388,12 +1385,12 @@ static bool ocl_arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
 
         if( !haveMask )
         {
-            if(n == 0)
+            if (n == 0)
                 k.args(src1arg, src2arg, dstarg);
-            else if(n == 1)
+            else if (n == 1)
                 k.args(src1arg, src2arg, dstarg,
                        ocl::KernelArg(0, 0, 0, 0, usrdata_p, usrdata_esz));
-            else if(n == 3)
+            else if (n == 3)
                 k.args(src1arg, src2arg, dstarg,
                        ocl::KernelArg(0, 0, 0, 0, usrdata_p, usrdata_esz),
                        ocl::KernelArg(0, 0, 0, 0, usrdata_p + usrdata_esz, usrdata_esz),
@@ -2617,44 +2614,90 @@ static double getMaxVal(int depth)
 
 #ifdef HAVE_OPENCL
 
-static bool ocl_compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op)
+static bool ocl_compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op, bool haveScalar)
 {
-    if ( !((_src1.isMat() || _src1.isUMat()) && (_src2.isMat() || _src2.isUMat())) )
-        return false;
+    const ocl::Device& dev = ocl::Device::getDefault();
+    bool doubleSupport = dev.doubleFPConfig() > 0;
+    int type1 = _src1.type(), depth1 = CV_MAT_DEPTH(type1), cn = CV_MAT_CN(type1);
+    int type2 = _src2.type();
 
-    bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0;
-    int type = _src1.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type), type2 = _src2.type();
-    if ( (!doubleSupport && (depth == CV_64F || _src2.depth() == CV_64F)) ||
-        !_src1.sameSize(_src2) || type != type2)
+    if (!haveScalar)
+    {
+        if ( (!doubleSupport && (depth1 == CV_64F || _src2.depth() == CV_64F)) ||
+            !_src1.sameSize(_src2) || type1 != type2)
+            return false;
+    }
+    else
+    {
+        if (cn > 1 || depth1 <= CV_32S) // FIXIT: if (cn > 4): Need to clear CPU-based compare behavior
+            return false;
+    }
+
+    if (!doubleSupport && depth1 == CV_64F)
         return false;
 
-    int kercn = ocl::predictOptimalVectorWidth(_src1, _src2, _dst);
+    int kercn = haveScalar ? cn : ocl::predictOptimalVectorWidth(_src1, _src2, _dst);
+    // Workaround for bug with "?:" operator in AMD OpenCL compiler
+    bool workaroundForAMD = /*dev.isAMD() &&*/
+            (
+                (depth1 != CV_8U && depth1 != CV_8S)
+            );
+    if (workaroundForAMD)
+        kercn = 1;
+
+    int scalarcn = kercn == 3 ? 4 : kercn;
+
     const char * const operationMap[] = { "==", ">", ">=", "<", "<=", "!=" };
     char cvt[40];
 
-    ocl::Kernel k("KF", ocl::core::arithm_oclsrc,
-                  format("-D BINARY_OP -D srcT1=%s -D dstT=%s -D workT=srcT1 -D cn=%d"
-                         " -D convertToDT=%s -D OP_CMP -D CMP_OPERATOR=%s%s -D srcT1_C1=%s"
-                         " -D srcT2_C1=%s -D dstT_C1=%s",
-                         ocl::typeToStr(CV_MAKE_TYPE(depth, kercn)),
-                         ocl::typeToStr(CV_8UC(kercn)), kercn,
-                         ocl::convertTypeStr(depth, CV_8U, kercn, cvt),
-                         operationMap[op], doubleSupport ? " -D DOUBLE_SUPPORT" : "",
-                         ocl::typeToStr(depth), ocl::typeToStr(depth), ocl::typeToStr(CV_8U)));
+    String buildOptions = format(
+            "-D %s -D srcT1=%s -D dstT=%s -D workT=srcT1 -D cn=%d"
+            " -D convertToDT=%s -D OP_CMP -D CMP_OPERATOR=%s -D srcT1_C1=%s"
+            " -D srcT2_C1=%s -D dstT_C1=%s -D workST=%s%s",
+            (haveScalar ? "UNARY_OP" : "BINARY_OP"),
+            ocl::typeToStr(CV_MAKE_TYPE(depth1, kercn)),
+            ocl::typeToStr(CV_8UC(kercn)), kercn,
+            ocl::convertTypeStr(depth1, CV_8U, kercn, cvt),
+            operationMap[op],
+            ocl::typeToStr(depth1), ocl::typeToStr(depth1), ocl::typeToStr(CV_8U),
+            ocl::typeToStr(CV_MAKE_TYPE(depth1, scalarcn)),
+            doubleSupport ? " -D DOUBLE_SUPPORT" : ""
+            );
+
+    ocl::Kernel k("KF", ocl::core::arithm_oclsrc, buildOptions);
     if (k.empty())
         return false;
 
-    CV_Assert(type == type2);
-    UMat src1 = _src1.getUMat(), src2 = _src2.getUMat();
+    UMat src1 = _src1.getUMat();
     Size size = src1.size();
-    CV_Assert(size == src2.size());
-
     _dst.create(size, CV_8UC(cn));
     UMat dst = _dst.getUMat();
 
-    k.args(ocl::KernelArg::ReadOnlyNoSize(src1),
-           ocl::KernelArg::ReadOnlyNoSize(src2),
-           ocl::KernelArg::WriteOnly(dst, cn, kercn));
+    if (haveScalar)
+    {
+        size_t esz = CV_ELEM_SIZE1(type1)*scalarcn;
+        double buf[4]={0,0,0,0};
+        Mat src2sc = _src2.getMat();
+
+        if (!src2sc.empty())
+            convertAndUnrollScalar(src2sc, type1, (uchar*)buf, 1);
+
+        ocl::KernelArg scalararg = ocl::KernelArg(0, 0, 0, 0, buf, esz);
+
+        k.args(ocl::KernelArg::ReadOnlyNoSize(src1, cn, kercn),
+               ocl::KernelArg::WriteOnly(dst, cn, kercn),
+               scalararg);
+    }
+    else
+    {
+        CV_DbgAssert(type1 == type2);
+        UMat src2 = _src2.getUMat();
+        CV_DbgAssert(size == src2.size());
+
+        k.args(ocl::KernelArg::ReadOnlyNoSize(src1),
+               ocl::KernelArg::ReadOnlyNoSize(src2),
+               ocl::KernelArg::WriteOnly(dst, cn, kercn));
+    }
 
     size_t globalsize[2] = { dst.cols * cn / kercn, dst.rows };
     return k.run(2, globalsize, NULL, false);
@@ -2669,8 +2712,29 @@ void cv::compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op)
     CV_Assert( op == CMP_LT || op == CMP_LE || op == CMP_EQ ||
                op == CMP_NE || op == CMP_GE || op == CMP_GT );
 
+    bool haveScalar = false;
+
+    if ((_src1.isMatx() + _src2.isMatx()) == 1
+            || !_src1.sameSize(_src2)
+            || _src1.type() != _src2.type())
+    {
+        if (checkScalar(_src1, _src2.type(), _src1.kind(), _src2.kind()))
+        {
+            op = op == CMP_LT ? CMP_GT : op == CMP_LE ? CMP_GE :
+                op == CMP_GE ? CMP_LE : op == CMP_GT ? CMP_LT : op;
+            // src1 is a scalar; swap it with src2
+            compare(_src2, _src1, _dst, op);
+            return;
+        }
+        else if( !checkScalar(_src2, _src1.type(), _src2.kind(), _src1.kind()) )
+            CV_Error( CV_StsUnmatchedSizes,
+                     "The operation is neither 'array op array' (where arrays have the same size and the same type), "
+                     "nor 'array op scalar', nor 'scalar op array'" );
+        haveScalar = true;
+    }
+
     CV_OCL_RUN(_src1.dims() <= 2 && _src2.dims() <= 2 && _dst.isUMat(),
-               ocl_compare(_src1, _src2, _dst, op))
+               ocl_compare(_src1, _src2, _dst, op, haveScalar))
 
     int kind1 = _src1.kind(), kind2 = _src2.kind();
     Mat src1 = _src1.getMat(), src2 = _src2.getMat();
@@ -2685,26 +2749,6 @@ void cv::compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op)
         return;
     }
 
-    bool haveScalar = false;
-
-    if( (kind1 == _InputArray::MATX) + (kind2 == _InputArray::MATX) == 1 ||
-        src1.size != src2.size || src1.type() != src2.type() )
-    {
-        if( checkScalar(src1, src2.type(), kind1, kind2) )
-        {
-            // src1 is a scalar; swap it with src2
-            swap(src1, src2);
-            op = op == CMP_LT ? CMP_GT : op == CMP_LE ? CMP_GE :
-                op == CMP_GE ? CMP_LE : op == CMP_GT ? CMP_LT : op;
-        }
-        else if( !checkScalar(src2, src1.type(), kind2, kind1) )
-            CV_Error( CV_StsUnmatchedSizes,
-                     "The operation is neither 'array op array' (where arrays have the same size and the same type), "
-                     "nor 'array op scalar', nor 'scalar op array'" );
-        haveScalar = true;
-    }
-
-
     int cn = src1.channels(), depth1 = src1.depth(), depth2 = src2.depth();
 
     _dst.create(src1.dims, src1.size, CV_8UC(cn));
index 0139f6a..cd5cf9b 100644 (file)
@@ -415,42 +415,54 @@ namespace cv {
 
 static bool ocl_merge( InputArrayOfArrays _mv, OutputArray _dst )
 {
-    std::vector<UMat> src;
+    std::vector<UMat> src, ksrc;
     _mv.getUMatVector(src);
     CV_Assert(!src.empty());
 
     int type = src[0].type(), depth = CV_MAT_DEPTH(type);
     Size size = src[0].size();
 
-    size_t srcsize = src.size();
-    for (size_t i = 0; i < srcsize; ++i)
+    for (size_t i = 0, srcsize = src.size(); i < srcsize; ++i)
     {
-        int itype = src[i].type(), icn = CV_MAT_CN(itype), idepth = CV_MAT_DEPTH(itype);
-        if (src[i].dims > 2 || icn != 1)
+        int itype = src[i].type(), icn = CV_MAT_CN(itype), idepth = CV_MAT_DEPTH(itype),
+                esz1 = CV_ELEM_SIZE1(idepth);
+        if (src[i].dims > 2)
             return false;
+
         CV_Assert(size == src[i].size() && depth == idepth);
+
+        for (int cn = 0; cn < icn; ++cn)
+        {
+            UMat tsrc = src[i];
+            tsrc.offset += cn * esz1;
+            ksrc.push_back(tsrc);
+        }
     }
+    int dcn = (int)ksrc.size();
 
-    String srcargs, srcdecl, processelem;
-    for (size_t i = 0; i < srcsize; ++i)
+    String srcargs, srcdecl, processelem, cndecl;
+    for (int i = 0; i < dcn; ++i)
     {
         srcargs += format("DECLARE_SRC_PARAM(%d)", i);
         srcdecl += format("DECLARE_DATA(%d)", i);
         processelem += format("PROCESS_ELEM(%d)", i);
+        cndecl += format(" -D scn%d=%d", i, ksrc[i].channels());
     }
 
     ocl::Kernel k("merge", ocl::core::split_merge_oclsrc,
-                  format("-D OP_MERGE -D cn=%d -D T=%s -D DECLARE_SRC_PARAMS_N=%s -D DECLARE_DATA_N=%s -D PROCESS_ELEMS_N=%s",
-                         (int)srcsize, ocl::memopTypeToStr(depth), srcargs.c_str(), srcdecl.c_str(), processelem.c_str()));
+                  format("-D OP_MERGE -D cn=%d -D T=%s -D DECLARE_SRC_PARAMS_N=%s"
+                         " -D DECLARE_DATA_N=%s -D PROCESS_ELEMS_N=%s%s",
+                         dcn, ocl::memopTypeToStr(depth), srcargs.c_str(),
+                         srcdecl.c_str(), processelem.c_str(), cndecl.c_str()));
     if (k.empty())
         return false;
 
-    _dst.create(size, CV_MAKE_TYPE(depth, (int)srcsize));
+    _dst.create(size, CV_MAKE_TYPE(depth, dcn));
     UMat dst = _dst.getUMat();
 
     int argidx = 0;
-    for (size_t i = 0; i < srcsize; ++i)
-        argidx = k.set(argidx, ocl::KernelArg::ReadOnlyNoSize(src[i]));
+    for (int i = 0; i < dcn; ++i)
+        argidx = k.set(argidx, ocl::KernelArg::ReadOnlyNoSize(ksrc[i]));
     k.set(argidx, ocl::KernelArg::WriteOnly(dst));
 
     size_t globalsize[2] = { dst.cols, dst.rows };
index 2e72d0d..5ac5f22 100644 (file)
@@ -482,9 +482,9 @@ enum { FLIP_COLS = 1 << 0, FLIP_ROWS = 1 << 1, FLIP_BOTH = FLIP_ROWS | FLIP_COLS
 static bool ocl_flip(InputArray _src, OutputArray _dst, int flipCode )
 {
     CV_Assert(flipCode >= - 1 && flipCode <= 1);
-    int type = _src.type(), cn = CV_MAT_CN(type), flipType;
+    int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type), flipType;
 
-    if (cn > 4 || cn == 3)
+    if (cn > 4)
         return false;
 
     const char * kernelName;
@@ -506,7 +506,8 @@ static bool ocl_flip(InputArray _src, OutputArray _dst, int flipCode )
     }
 
     ocl::Kernel k(kernelName, ocl::core::flip_oclsrc,
-        format( "-D type=%s", ocl::memopTypeToStr(type)));
+        format( "-D T=%s -D T1=%s -D cn=%d", ocl::memopTypeToStr(type),
+                ocl::memopTypeToStr(depth), cn));
     if (k.empty())
         return false;
 
@@ -782,18 +783,26 @@ namespace cv {
 static bool ocl_copyMakeBorder( InputArray _src, OutputArray _dst, int top, int bottom,
                                 int left, int right, int borderType, const Scalar& value )
 {
-    int type = _src.type(), cn = CV_MAT_CN(type);
+    int type = _src.type(), cn = CV_MAT_CN(type), depth = CV_MAT_DEPTH(type);
     bool isolated = (borderType & BORDER_ISOLATED) != 0;
     borderType &= ~cv::BORDER_ISOLATED;
 
     if ( !(borderType == BORDER_CONSTANT || borderType == BORDER_REPLICATE || borderType == BORDER_REFLECT ||
            borderType == BORDER_WRAP || borderType == BORDER_REFLECT_101) ||
-         cn == 3 || cn > 4)
+         cn > 4)
         return false;
 
     const char * const borderMap[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT", "BORDER_WRAP", "BORDER_REFLECT_101" };
-    ocl::Kernel k("copyMakeBorder", ocl::core::copymakeborder_oclsrc,
-                  format("-D T=%s -D %s", ocl::memopTypeToStr(type), borderMap[borderType]));
+    int scalarcn = cn == 3 ? 4 : cn;
+    int sctype = CV_MAKETYPE(depth, scalarcn);
+    String buildOptions = format(
+            "-D T=%s -D %s "
+            "-D T1=%s -D cn=%d -D ST=%s",
+            ocl::memopTypeToStr(type), borderMap[borderType],
+            ocl::memopTypeToStr(depth), cn, ocl::memopTypeToStr(sctype)
+    );
+
+    ocl::Kernel k("copyMakeBorder", ocl::core::copymakeborder_oclsrc, buildOptions);
     if (k.empty())
         return false;
 
@@ -825,7 +834,7 @@ static bool ocl_copyMakeBorder( InputArray _src, OutputArray _dst, int top, int
     }
 
     k.args(ocl::KernelArg::ReadOnly(src), ocl::KernelArg::WriteOnly(dst),
-           top, left, ocl::KernelArg::Constant(Mat(1, 1, type, value)));
+           top, left, ocl::KernelArg::Constant(Mat(1, 1, sctype, value)));
 
     size_t globalsize[2] = { dst.cols, dst.rows };
     return k.run(2, globalsize, NULL, false);
index 095460c..16df02c 100644 (file)
@@ -2041,7 +2041,7 @@ static bool ocl_pow(InputArray _src, double power, OutputArray _dst,
     const char * const op = issqrt ? "OP_SQRT" : is_ipower ? "OP_POWN" : "OP_POW";
 
     ocl::Kernel k("KF", ocl::core::arithm_oclsrc,
-                  format("-D dstT=%s -D %s -D UNARY_OP%s", ocl::typeToStr(CV_MAKE_TYPE(depth, 1)),
+                  format("-D dstT=%s -D %s -D UNARY_OP%s", ocl::typeToStr(depth),
                          op, doubleSupport ? " -D DOUBLE_SUPPORT" : ""));
     if (k.empty())
         return false;
@@ -2081,7 +2081,7 @@ void pow( InputArray _src, double power, OutputArray _dst )
     {
         if( ipower < 0 )
         {
-            divide( 1., _src, _dst );
+            divide( Scalar::all(1), _src, _dst );
             if( ipower == -1 )
                 return;
             ipower = -ipower;
@@ -2115,10 +2115,7 @@ void pow( InputArray _src, double power, OutputArray _dst )
 
     Mat src, dst;
     if (same)
-    {
-        dst = _dst.getMat();
-        src = dst;
-    }
+        src = dst = _dst.getMat();
     else
     {
         src = _src.getMat();
index db1ce76..82d177e 100644 (file)
@@ -2679,17 +2679,17 @@ namespace cv {
 
 static bool ocl_setIdentity( InputOutputArray _m, const Scalar& s )
 {
-    int type = _m.type(), cn = CV_MAT_CN(type);
-    if (cn == 3)
-        return false;
+    int type = _m.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type),
+            sctype = CV_MAKE_TYPE(depth, cn == 3 ? 4 : cn);
 
     ocl::Kernel k("setIdentity", ocl::core::set_identity_oclsrc,
-                  format("-D T=%s", ocl::memopTypeToStr(type)));
+                  format("-D T=%s -D T1=%s -D cn=%d -D ST=%s", ocl::memopTypeToStr(type),
+                         ocl::memopTypeToStr(depth), cn, ocl::memopTypeToStr(sctype)));
     if (k.empty())
         return false;
 
     UMat m = _m.getUMat();
-    k.args(ocl::KernelArg::WriteOnly(m), ocl::KernelArg::Constant(Mat(1, 1, type, s)));
+    k.args(ocl::KernelArg::WriteOnly(m), ocl::KernelArg::Constant(Mat(1, 1, sctype, s)));
 
     size_t globalsize[2] = { m.cols, m.rows };
     return k.run(2, globalsize, NULL, false);
index 7c4f8de..c6e0c40 100644 (file)
@@ -1410,7 +1410,7 @@ bool useOpenCL()
 {
     CoreTLSData* data = coreTlsData.get();
     if( data->useOpenCL < 0 )
-        data->useOpenCL = (int)haveOpenCL();
+        data->useOpenCL = (int)haveOpenCL() && Device::getDefault().ptr() != NULL;
     return data->useOpenCL > 0;
 }
 
@@ -1419,7 +1419,7 @@ void setUseOpenCL(bool flag)
     if( haveOpenCL() )
     {
         CoreTLSData* data = coreTlsData.get();
-        data->useOpenCL = flag ? 1 : 0;
+        data->useOpenCL = (flag && Device::getDefault().ptr() != NULL) ? 1 : 0;
     }
 }
 
@@ -2245,6 +2245,7 @@ not_found:
         std::cerr << deviceTypes[t] << " ";
 
     std::cerr << std::endl << "    Device name: " << (deviceName.length() == 0 ? "any" : deviceName) << std::endl;
+    CV_Error(CL_INVALID_DEVICE, "Requested OpenCL device is not found");
     return NULL;
 }
 
@@ -4347,7 +4348,7 @@ int predictOptimalVectorWidth(InputArray src1, InputArray src2, InputArray src3,
                               InputArray src4, InputArray src5, InputArray src6,
                               InputArray src7, InputArray src8, InputArray src9)
 {
-    int type = src1.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+    int type = src1.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type), esz = CV_ELEM_SIZE(depth);
     Size ssize = src1.size();
     const ocl::Device & d = ocl::Device::getDefault();
 
@@ -4371,7 +4372,8 @@ int predictOptimalVectorWidth(InputArray src1, InputArray src2, InputArray src3,
     PROCESS_SRC(src9);
 
     size_t size = offsets.size();
-    std::vector<int> dividers(size, width);
+    int wsz = width * esz;
+    std::vector<int> dividers(size, wsz);
 
     for (size_t i = 0; i < size; ++i)
         while (offsets[i] % dividers[i] != 0 || steps[i] % dividers[i] != 0 || cols[i] % dividers[i] != 0)
@@ -4379,7 +4381,7 @@ int predictOptimalVectorWidth(InputArray src1, InputArray src2, InputArray src3,
 
     // default strategy
     for (size_t i = 0; i < size; ++i)
-        if (dividers[i] != width)
+        if (dividers[i] != wsz)
         {
             width = 1;
             break;
index 865b433..5faf7de 100644 (file)
 
 #elif defined OP_CMP
 #define srcT2 srcT1
+#ifndef convertToWT1
 #define convertToWT1
-#define PROCESS_ELEM storedst(convertToDT(srcelem1 CMP_OPERATOR srcelem2 ? (dstT)(255) : (dstT)(0)))
+#endif
+#define PROCESS_ELEM \
+    workT __s1 = srcelem1; \
+    workT __s2 = srcelem2; \
+    storedst(((__s1 CMP_OPERATOR __s2) ? (dstT)(255) : (dstT)(0)))
 
 #elif defined OP_CONVERT_SCALE_ABS
 #undef EXTRA_PARAMS
index dbb00b9..55239ce 100644 (file)
 #endif
 #endif
 
+#if cn != 3
+#define loadpix(addr)  *(__global const T*)(addr)
+#define storepix(val, addr)  *(__global T*)(addr) = val
+#define TSIZE ((int)sizeof(T))
+#define convertScalar(a) (a)
+#else
+#define loadpix(addr)  vload3(0, (__global const T1*)(addr))
+#define storepix(val, addr) vstore3(val, 0, (__global T1*)(addr))
+#define TSIZE ((int)sizeof(T1)*3)
+#define convertScalar(a) (T)(a.x, a.y, a.z)
+#endif
+
 #ifdef BORDER_CONSTANT
 #define EXTRAPOLATE(x, y, v) v = scalar;
 #elif defined BORDER_REPLICATE
@@ -49,7 +61,7 @@
     { \
         x = clamp(x, 0, src_cols - 1); \
         y = clamp(y, 0, src_rows - 1); \
-        v = *(__global const T *)(srcptr + mad24(y, src_step, mad24(x, (int)sizeof(T), src_offset))); \
+        v = loadpix(srcptr + mad24(y, src_step, mad24(x, TSIZE, src_offset))); \
     }
 #elif defined BORDER_WRAP
 #define EXTRAPOLATE(x, y, v) \
@@ -63,7 +75,7 @@
             y -= ((y - src_rows + 1) / src_rows) * src_rows; \
         if( y >= src_rows ) \
             y %= src_rows; \
-        v = *(__global const T *)(srcptr + mad24(y, src_step, mad24(x, (int)sizeof(T), src_offset))); \
+        v = loadpix(srcptr + mad24(y, src_step, mad24(x, TSIZE, src_offset))); \
     }
 #elif defined(BORDER_REFLECT) || defined(BORDER_REFLECT_101)
 #ifdef BORDER_REFLECT
                     y = src_rows - 1 - (y - src_rows) - delta; \
             } \
             while (y >= src_rows || y < 0); \
-        v = *(__global const T *)(srcptr + mad24(y, src_step, mad24(x, (int)sizeof(T), src_offset))); \
+        v = loadpix(srcptr + mad24(y, src_step, mad24(x, TSIZE, src_offset))); \
     }
 #else
 #error No extrapolation method
 
 __kernel void copyMakeBorder(__global const uchar * srcptr, int src_step, int src_offset, int src_rows, int src_cols,
                              __global uchar * dstptr, int dst_step, int dst_offset, int dst_rows, int dst_cols,
-                             int top, int left, T scalar)
+                             int top, int left, ST nVal)
 {
     int x = get_global_id(0);
     int y = get_global_id(1);
 
+#ifdef BORDER_CONSTANT
+    T scalar = convertScalar(nVal);
+#endif
+
     if (x < dst_cols && y < dst_rows)
     {
         int src_x = x - left;
         int src_y = y - top;
 
-        int dst_index = mad24(y, dst_step, mad24(x, (int)sizeof(T), dst_offset));
+        int dst_index = mad24(y, dst_step, mad24(x, (int)TSIZE, dst_offset));
         __global T * dst = (__global T *)(dstptr + dst_index);
 
+        T v;
         if (NEED_EXTRAPOLATION(src_x, src_y))
-            EXTRAPOLATE(src_x, src_y, dst[0])
+        {
+            EXTRAPOLATE(src_x, src_y, v)
+        }
         else
         {
-            int src_index = mad24(src_y, src_step, mad24(src_x, (int)sizeof(T), src_offset));
-            __global const T * src = (__global const T *)(srcptr + src_index);
-            dst[0] = src[0];
+            int src_index = mad24(src_y, src_step, mad24(src_x, TSIZE, src_offset));
+            v = loadpix(srcptr + src_index);
         }
+        storepix(v, dst);
     }
 }
index 0c874db..bacfe7a 100644 (file)
 //
 //M*/
 
-#define sizeoftype ((int)sizeof(type))
+#if cn != 3
+#define loadpix(addr) *(__global const T *)(addr)
+#define storepix(val, addr)  *(__global T *)(addr) = val
+#define TSIZE (int)sizeof(T)
+#else
+#define loadpix(addr) vload3(0, (__global const T1 *)(addr))
+#define storepix(val, addr) vstore3(val, 0, (__global T1 *)(addr))
+#define TSIZE ((int)sizeof(T1)*3)
+#endif
 
-__kernel void arithm_flip_rows(__global const uchar* srcptr, int srcstep, int srcoffset,
-                               __global uchar* dstptr, int dststep, int dstoffset,
+__kernel void arithm_flip_rows(__global const uchar * srcptr, int src_step, int src_offset,
+                               __global uchar * dstptr, int dst_step, int dst_offset,
                                int rows, int cols, int thread_rows, int thread_cols)
 {
     int x = get_global_id(0);
@@ -50,19 +58,16 @@ __kernel void arithm_flip_rows(__global const uchar* srcptr, int srcstep, int sr
 
     if (x < cols && y < thread_rows)
     {
-        __global const type* src0 = (__global const type*)(srcptr + mad24(y, srcstep, mad24(x, sizeoftype, srcoffset)));
-        __global const type* src1 = (__global const type*)(srcptr + mad24(rows - y - 1, srcstep, mad24(x, sizeoftype, srcoffset)));
+        T src0 = loadpix(srcptr + mad24(y, src_step, mad24(x, TSIZE, src_offset)));
+        T src1 = loadpix(srcptr + mad24(rows - y - 1, src_step, mad24(x, TSIZE, src_offset)));
 
-        __global type* dst0 = (__global type*)(dstptr + mad24(y, dststep, mad24(x, sizeoftype, dstoffset)));
-        __global type* dst1 = (__global type*)(dstptr + mad24(rows - y - 1, dststep, mad24(x, sizeoftype, dstoffset)));
-
-        dst0[0] = src1[0];
-        dst1[0] = src0[0];
+        storepix(src1, dstptr + mad24(y, dst_step, mad24(x, TSIZE, dst_offset)));
+        storepix(src0, dstptr + mad24(rows - y - 1, dst_step, mad24(x, TSIZE, dst_offset)));
     }
 }
 
-__kernel void arithm_flip_rows_cols(__global const uchar* srcptr, int srcstep, int srcoffset,
-                                    __global uchar* dstptr, int dststep, int dstoffset,
+__kernel void arithm_flip_rows_cols(__global const uchar * srcptr, int src_step, int src_offset,
+                                    __global uchar * dstptr, int dst_step, int dst_offset,
                                     int rows, int cols, int thread_rows, int thread_cols)
 {
     int x = get_global_id(0);
@@ -71,19 +76,16 @@ __kernel void arithm_flip_rows_cols(__global const uchar* srcptr, int srcstep, i
     if (x < cols && y < thread_rows)
     {
         int x1 = cols - x - 1;
-        __global const type* src0 = (__global const type*)(srcptr + mad24(y, srcstep, mad24(x, sizeoftype, srcoffset)));
-        __global const type* src1 = (__global const type*)(srcptr + mad24(rows - y - 1, srcstep, mad24(x1, sizeoftype, srcoffset)));
-
-        __global type* dst0 = (__global type*)(dstptr + mad24(rows - y - 1, dststep, mad24(x1, sizeoftype, dstoffset)));
-        __global type* dst1 = (__global type*)(dstptr + mad24(y, dststep, mad24(x, sizeoftype, dstoffset)));
+        T src0 = loadpix(srcptr + mad24(y, src_step, mad24(x, TSIZE, src_offset)));
+        T src1 = loadpix(srcptr + mad24(rows - y - 1, src_step, mad24(x1, TSIZE, src_offset)));
 
-        dst0[0] = src0[0];
-        dst1[0] = src1[0];
+        storepix(src0, dstptr + mad24(rows - y - 1, dst_step, mad24(x1, TSIZE, dst_offset)));
+        storepix(src1, dstptr + mad24(y, dst_step, mad24(x, TSIZE, dst_offset)));
     }
 }
 
-__kernel void arithm_flip_cols(__global const uchar* srcptr, int srcstep, int srcoffset,
-                               __global uchar* dstptr, int dststep, int dstoffset,
+__kernel void arithm_flip_cols(__global const uchar * srcptr, int src_step, int src_offset,
+                               __global uchar * dstptr, int dst_step, int dst_offset,
                                int rows, int cols, int thread_rows, int thread_cols)
 {
     int x = get_global_id(0);
@@ -92,13 +94,10 @@ __kernel void arithm_flip_cols(__global const uchar* srcptr, int srcstep, int sr
     if (x < thread_cols && y < rows)
     {
         int x1 = cols - x - 1;
-        __global const type* src0 = (__global const type*)(srcptr + mad24(y, srcstep, mad24(x, sizeoftype, srcoffset)));
-        __global const type* src1 = (__global const type*)(srcptr + mad24(y, srcstep, mad24(x1, sizeoftype, srcoffset)));
-
-        __global type* dst0 = (__global type*)(dstptr + mad24(y, dststep, mad24(x1, sizeoftype, dstoffset)));
-        __global type* dst1 = (__global type*)(dstptr + mad24(y, dststep, mad24(x, sizeoftype, dstoffset)));
+        T src0 = loadpix(srcptr + mad24(y, src_step, mad24(x, TSIZE, src_offset)));
+        T src1 = loadpix(srcptr + mad24(y, src_step, mad24(x1, TSIZE, src_offset)));
 
-        dst1[0] = src1[0];
-        dst0[0] = src0[0];
+        storepix(src0, dstptr + mad24(y, dst_step, mad24(x1, TSIZE, dst_offset)));
+        storepix(src1, dstptr + mad24(y, dst_step, mad24(x, TSIZE, dst_offset)));
     }
 }
index d63ce79..0e8f142 100644 (file)
 //
 //M*/
 
+#if cn != 3
+#define loadpix(addr) *(__global const T *)(addr)
+#define storepix(val, addr)  *(__global T *)(addr) = val
+#define TSIZE (int)sizeof(T)
+#define scalar scalar_
+#else
+#define loadpix(addr) vload3(0, (__global const T1 *)(addr))
+#define storepix(val, addr) vstore3(val, 0, (__global T1 *)(addr))
+#define TSIZE ((int)sizeof(T1)*3)
+#define scalar (T)(scalar_.x, scalar_.y, scalar_.z)
+#endif
+
 __kernel void setIdentity(__global uchar * srcptr, int src_step, int src_offset, int rows, int cols,
-                          T scalar)
+                          ST scalar_)
 {
     int x = get_global_id(0);
     int y = get_global_id(1);
 
     if (x < cols && y < rows)
     {
-        int src_index = mad24(y, src_step, mad24(x, (int)sizeof(T), src_offset));
-        __global T * src = (__global T *)(srcptr + src_index);
+        int src_index = mad24(y, src_step, mad24(x, TSIZE, src_offset));
 
-        src[0] = x == y ? scalar : (T)(0);
+        storepix(x == y ? scalar : (T)(0), srcptr + src_index);
     }
 }
index 8a1bc49..7d27705 100644 (file)
@@ -45,7 +45,7 @@
 
 #define DECLARE_SRC_PARAM(index) __global const uchar * src##index##ptr, int src##index##_step, int src##index##_offset,
 #define DECLARE_DATA(index) __global const T * src##index = \
-    (__global T *)(src##index##ptr + mad24(src##index##_step, y, mad24(x, (int)sizeof(T), src##index##_offset)));
+    (__global T *)(src##index##ptr + mad24(src##index##_step, y, mad24(x, (int)sizeof(T) * scn##index, src##index##_offset)));
 #define PROCESS_ELEM(index) dst[index] = src##index[0];
 
 __kernel void merge(DECLARE_SRC_PARAMS_N
index 44cb3f4..d88dda2 100644 (file)
@@ -88,7 +88,7 @@ void UMatData::unlock()
 
 MatAllocator* UMat::getStdAllocator()
 {
-    if( ocl::haveOpenCL() )
+    if( ocl::haveOpenCL() && ocl::useOpenCL() )
         return ocl::getOpenCLAllocator();
     return Mat::getStdAllocator();
 }
index e6bcf4e..d2b26e1 100644 (file)
@@ -57,9 +57,9 @@ PARAM_TEST_CASE(Lut, MatDepth, MatDepth, Channels, bool, bool)
     int cn;
     bool use_roi, same_cn;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_INPUT_PARAMETER(lut)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_INPUT_PARAMETER(lut);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -87,14 +87,14 @@ PARAM_TEST_CASE(Lut, MatDepth, MatDepth, Channels, bool, bool)
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, dst_type, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_INPUT_PARAMETER(lut)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_INPUT_PARAMETER(lut);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double threshold = 0.)
     {
-        OCL_EXPECT_MATS_NEAR(dst, threshold)
+        OCL_EXPECT_MATS_NEAR(dst, threshold);
     }
 };
 
@@ -119,12 +119,13 @@ PARAM_TEST_CASE(ArithmTestBase, MatDepth, Channels, bool)
     int cn;
     bool use_roi;
     cv::Scalar val;
+    cv::Scalar val_in_range;
 
-    TEST_DECLARE_INPUT_PARAMETER(src1)
-    TEST_DECLARE_INPUT_PARAMETER(src2)
-    TEST_DECLARE_INPUT_PARAMETER(mask)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst1)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst2)
+    TEST_DECLARE_INPUT_PARAMETER(src1);
+    TEST_DECLARE_INPUT_PARAMETER(src2);
+    TEST_DECLARE_INPUT_PARAMETER(mask);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst1);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst2);
 
     virtual void SetUp()
     {
@@ -133,16 +134,19 @@ PARAM_TEST_CASE(ArithmTestBase, MatDepth, Channels, bool)
         use_roi = GET_PARAM(2);
     }
 
-    virtual void generateTestData()
+    virtual void generateTestData(bool with_val_in_range = false)
     {
         const int type = CV_MAKE_TYPE(depth, cn);
 
+        double minV = getMinVal(type);
+        double maxV = getMaxVal(type);
+
         Size roiSize = randomSize(1, MAX_VALUE);
         Border src1Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
-        randomSubMat(src1, src1_roi, roiSize, src1Border, type, 2, 11);
+        randomSubMat(src1, src1_roi, roiSize, src1Border, type, 2, 11); // FIXIT: Test with minV, maxV
 
         Border src2Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
-        randomSubMat(src2, src2_roi, roiSize, src2Border, type, -1540, 1740);
+        randomSubMat(src2, src2_roi, roiSize, src2Border, type, std::max(-1540., minV), std::min(1740., maxV));
 
         Border dst1Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst1, dst1_roi, roiSize, dst1Border, type, 5, 16);
@@ -157,21 +161,27 @@ PARAM_TEST_CASE(ArithmTestBase, MatDepth, Channels, bool)
         val = cv::Scalar(rng.uniform(-100.0, 100.0), rng.uniform(-100.0, 100.0),
                          rng.uniform(-100.0, 100.0), rng.uniform(-100.0, 100.0));
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src1)
-        UMAT_UPLOAD_INPUT_PARAMETER(src2)
-        UMAT_UPLOAD_INPUT_PARAMETER(mask)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst1)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst2)
+        if (with_val_in_range)
+        {
+            val_in_range = cv::Scalar(rng.uniform(minV, maxV), rng.uniform(minV, maxV),
+                                      rng.uniform(minV, maxV), rng.uniform(minV, maxV));
+        }
+
+        UMAT_UPLOAD_INPUT_PARAMETER(src1);
+        UMAT_UPLOAD_INPUT_PARAMETER(src2);
+        UMAT_UPLOAD_INPUT_PARAMETER(mask);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst1);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst2);
     }
 
     void Near(double threshold = 0.)
     {
-        OCL_EXPECT_MATS_NEAR(dst1, threshold)
+        OCL_EXPECT_MATS_NEAR(dst1, threshold);
     }
 
     void Near1(double threshold = 0.)
     {
-        OCL_EXPECT_MATS_NEAR(dst2, threshold)
+        OCL_EXPECT_MATS_NEAR(dst2, threshold);
     }
 };
 
@@ -546,6 +556,12 @@ OCL_TEST_P(Transpose, Mat)
     {
         generateTestData();
 
+        Size roiSize = src1_roi.size();
+        Border dst1Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
+        randomSubMat(dst1, dst1_roi, Size(roiSize.height, roiSize.width), dst1Border, src1.type(), 5, 16);
+
+        UMAT_UPLOAD_INPUT_PARAMETER(dst1);
+
         OCL_OFF(cv::transpose(src1_roi, dst1_roi));
         OCL_ON(cv::transpose(usrc1_roi, udst1_roi));
 
@@ -570,7 +586,7 @@ OCL_TEST_P(Transpose, SquareInplace)
         OCL_OFF(cv::transpose(src1_roi, src1_roi));
         OCL_ON(cv::transpose(usrc1_roi, usrc1_roi));
 
-        OCL_EXPECT_MATS_NEAR(src1, 0)
+        OCL_EXPECT_MATS_NEAR(src1, 0);
     }
 }
 
@@ -750,12 +766,15 @@ OCL_TEST_P(Bitwise_not, Mat)
 
 typedef ArithmTestBase Compare;
 
+static const int cmp_codes[] = { CMP_EQ, CMP_GT, CMP_GE, CMP_LT, CMP_LE, CMP_NE };
+static const char * cmp_strs[] = { "CMP_EQ", "CMP_GT", "CMP_GE", "CMP_LT", "CMP_LE", "CMP_NE" };
+static const int cmp_num = sizeof(cmp_codes) / sizeof(int);
+
 OCL_TEST_P(Compare, Mat)
 {
-    int cmp_codes[] = { CMP_EQ, CMP_GT, CMP_GE, CMP_LT, CMP_LE, CMP_NE };
-    int cmp_num = sizeof(cmp_codes) / sizeof(int);
-
     for (int i = 0; i < cmp_num; ++i)
+    {
+        SCOPED_TRACE(cmp_strs[i]);
         for (int j = 0; j < test_loop_times; j++)
         {
             generateTestData();
@@ -765,6 +784,41 @@ OCL_TEST_P(Compare, Mat)
 
             Near(0);
         }
+    }
+}
+
+OCL_TEST_P(Compare, Scalar)
+{
+    for (int i = 0; i < cmp_num; ++i)
+    {
+        SCOPED_TRACE(cmp_strs[i]);
+        for (int j = 0; j < test_loop_times; j++)
+        {
+            generateTestData(true);
+
+            OCL_OFF(cv::compare(src1_roi, val_in_range, dst1_roi, cmp_codes[i]));
+            OCL_ON(cv::compare(usrc1_roi, val_in_range, udst1_roi, cmp_codes[i]));
+
+            Near(0);
+        }
+    }
+}
+
+OCL_TEST_P(Compare, Scalar2)
+{
+    for (int i = 0; i < cmp_num; ++i)
+    {
+        SCOPED_TRACE(cmp_strs[i]);
+        for (int j = 0; j < test_loop_times; j++)
+        {
+            generateTestData(true);
+
+            OCL_OFF(cv::compare(val_in_range, src1_roi, dst1_roi, cmp_codes[i]));
+            OCL_ON(cv::compare(val_in_range, usrc1_roi, udst1_roi, cmp_codes[i]));
+
+            Near(0);
+        }
+    }
 }
 
 //////////////////////////////// Pow /////////////////////////////////////////////////
@@ -778,12 +832,14 @@ OCL_TEST_P(Pow, Mat)
     for (int j = 0; j < test_loop_times; j++)
         for (int k = 0, size = sizeof(pows) / sizeof(double); k < size; ++k)
         {
+            SCOPED_TRACE(pows[k]);
+
             generateTestData();
 
             OCL_OFF(cv::pow(src1_roi, pows[k], dst1_roi));
             OCL_ON(cv::pow(usrc1_roi, pows[k], udst1_roi));
 
-            Near(1);
+            OCL_EXPECT_MATS_NEAR_RELATIVE(dst1, 1e-5);
         }
 }
 
@@ -845,8 +901,8 @@ struct RepeatTestCase :
         Border dst1Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst1, dst1_roi, dstRoiSize, dst1Border, type, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src1)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst1)
+        UMAT_UPLOAD_INPUT_PARAMETER(src1);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst1);
     }
 };
 
@@ -1402,10 +1458,10 @@ PARAM_TEST_CASE(InRange, MatDepth, Channels, bool /*Scalar or not*/, bool /*Roi*
     bool scalars, use_roi;
     cv::Scalar val1, val2;
 
-    TEST_DECLARE_INPUT_PARAMETER(src1)
-    TEST_DECLARE_INPUT_PARAMETER(src2)
-    TEST_DECLARE_INPUT_PARAMETER(src3)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src1);
+    TEST_DECLARE_INPUT_PARAMETER(src2);
+    TEST_DECLARE_INPUT_PARAMETER(src3);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -1437,15 +1493,15 @@ PARAM_TEST_CASE(InRange, MatDepth, Channels, bool /*Scalar or not*/, bool /*Roi*
         val2 = cv::Scalar(rng.uniform(-100.0, 100.0), rng.uniform(-100.0, 100.0),
                           rng.uniform(-100.0, 100.0), rng.uniform(-100.0, 100.0));
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src1)
-        UMAT_UPLOAD_INPUT_PARAMETER(src2)
-        UMAT_UPLOAD_INPUT_PARAMETER(src3)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src1);
+        UMAT_UPLOAD_INPUT_PARAMETER(src2);
+        UMAT_UPLOAD_INPUT_PARAMETER(src3);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near()
     {
-        OCL_EXPECT_MATS_NEAR(dst, 0)
+        OCL_EXPECT_MATS_NEAR(dst, 0);
     }
 };
 
@@ -1517,7 +1573,7 @@ PARAM_TEST_CASE(PatchNaNs, Channels, bool)
     bool use_roi;
     double value;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
+    TEST_DECLARE_INPUT_PARAMETER(src);
 
     virtual void SetUp()
     {
@@ -1544,12 +1600,12 @@ PARAM_TEST_CASE(PatchNaNs, Channels, bool)
 
         value = randomDouble(-100, 100);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
     }
 
     void Near()
     {
-        OCL_EXPECT_MATS_NEAR(src, 0)
+        OCL_EXPECT_MATS_NEAR(src, 0);
     }
 };
 
@@ -1592,8 +1648,8 @@ PARAM_TEST_CASE(Reduce, std::pair<MatDepth, MatDepth>, Channels, int, bool)
     int sdepth, ddepth, cn, dim, dtype;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -1618,8 +1674,8 @@ PARAM_TEST_CASE(Reduce, std::pair<MatDepth, MatDepth>, Channels, int, bool)
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, dstRoiSize, dstBorder, dtype, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 };
 
@@ -1635,7 +1691,7 @@ OCL_TEST_P(ReduceSum, Mat)
         OCL_ON(cv::reduce(usrc_roi, udst_roi, dim, CV_REDUCE_SUM, dtype));
 
         double eps = ddepth <= CV_32S ? 1 : 1e-4;
-        OCL_EXPECT_MATS_NEAR(dst, eps)
+        OCL_EXPECT_MATS_NEAR(dst, eps);
     }
 }
 
@@ -1650,7 +1706,7 @@ OCL_TEST_P(ReduceMax, Mat)
         OCL_OFF(cv::reduce(src_roi, dst_roi, dim, CV_REDUCE_MAX, dtype));
         OCL_ON(cv::reduce(usrc_roi, udst_roi, dim, CV_REDUCE_MAX, dtype));
 
-        OCL_EXPECT_MATS_NEAR(dst, 0)
+        OCL_EXPECT_MATS_NEAR(dst, 0);
     }
 }
 
@@ -1665,7 +1721,7 @@ OCL_TEST_P(ReduceMin, Mat)
         OCL_OFF(cv::reduce(src_roi, dst_roi, dim, CV_REDUCE_MIN, dtype));
         OCL_ON(cv::reduce(usrc_roi, udst_roi, dim, CV_REDUCE_MIN, dtype));
 
-        OCL_EXPECT_MATS_NEAR(dst, 0)
+        OCL_EXPECT_MATS_NEAR(dst, 0);
     }
 }
 
@@ -1681,7 +1737,7 @@ OCL_TEST_P(ReduceAvg, Mat)
         OCL_ON(cv::reduce(usrc_roi, udst_roi, dim, CV_REDUCE_AVG, dtype));
 
         double eps = ddepth <= CV_32S ? 1 : 5e-6;
-        OCL_EXPECT_MATS_NEAR(dst, eps)
+        OCL_EXPECT_MATS_NEAR(dst, eps);
     }
 }
 
index f0dc102..7565273 100644 (file)
@@ -54,16 +54,16 @@ namespace ocl {
 
 //////////////////////////////////////// Merge ///////////////////////////////////////////////
 
-PARAM_TEST_CASE(Merge, MatDepth, Channels, bool)
+PARAM_TEST_CASE(Merge, MatDepth, int, bool)
 {
-    int depth, cn;
+    int depth, nsrc;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src1)
-    TEST_DECLARE_INPUT_PARAMETER(src2)
-    TEST_DECLARE_INPUT_PARAMETER(src3)
-    TEST_DECLARE_INPUT_PARAMETER(src4)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src1);
+    TEST_DECLARE_INPUT_PARAMETER(src2);
+    TEST_DECLARE_INPUT_PARAMETER(src3);
+    TEST_DECLARE_INPUT_PARAMETER(src4);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     std::vector<Mat> src_roi;
     std::vector<UMat> usrc_roi;
@@ -71,10 +71,15 @@ PARAM_TEST_CASE(Merge, MatDepth, Channels, bool)
     virtual void SetUp()
     {
         depth = GET_PARAM(0);
-        cn = GET_PARAM(1);
+        nsrc = GET_PARAM(1);
         use_roi = GET_PARAM(2);
 
-        CV_Assert(cn >= 1 && cn <= 4);
+        CV_Assert(nsrc >= 1 && nsrc <= 4);
+    }
+
+    int type()
+    {
+        return CV_MAKE_TYPE(depth, randomInt(1, 3));
     }
 
     void generateTestData()
@@ -83,34 +88,39 @@ PARAM_TEST_CASE(Merge, MatDepth, Channels, bool)
 
         {
             Border src1Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
-            randomSubMat(src1, src1_roi, roiSize, src1Border, depth, 2, 11);
+            randomSubMat(src1, src1_roi, roiSize, src1Border, type(), 2, 11);
 
             Border src2Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
-            randomSubMat(src2, src2_roi, roiSize, src2Border, depth, -1540, 1740);
+            randomSubMat(src2, src2_roi, roiSize, src2Border, type(), -1540, 1740);
 
             Border src3Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
-            randomSubMat(src3, src3_roi, roiSize, src3Border, depth, -1540, 1740);
+            randomSubMat(src3, src3_roi, roiSize, src3Border, type(), -1540, 1740);
 
             Border src4Border = randomBorder(0, use_roi ? MAX_VALUE : 0);
-            randomSubMat(src4, src4_roi, roiSize, src4Border, depth, -1540, 1740);
+            randomSubMat(src4, src4_roi, roiSize, src4Border, type(), -1540, 1740);
         }
 
-        Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
-        randomSubMat(dst, dst_roi, roiSize, dstBorder, CV_MAKE_TYPE(depth, cn), 5, 16);
-
-        UMAT_UPLOAD_INPUT_PARAMETER(src1)
-        UMAT_UPLOAD_INPUT_PARAMETER(src2)
-        UMAT_UPLOAD_INPUT_PARAMETER(src3)
-        UMAT_UPLOAD_INPUT_PARAMETER(src4)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src1);
+        UMAT_UPLOAD_INPUT_PARAMETER(src2);
+        UMAT_UPLOAD_INPUT_PARAMETER(src3);
+        UMAT_UPLOAD_INPUT_PARAMETER(src4);
 
         src_roi.push_back(src1_roi), usrc_roi.push_back(usrc1_roi);
-        if (cn >= 2)
+        if (nsrc >= 2)
             src_roi.push_back(src2_roi), usrc_roi.push_back(usrc2_roi);
-        if (cn >= 3)
+        if (nsrc >= 3)
             src_roi.push_back(src3_roi), usrc_roi.push_back(usrc3_roi);
-        if (cn >= 4)
+        if (nsrc >= 4)
             src_roi.push_back(src4_roi), usrc_roi.push_back(usrc4_roi);
+
+        int dcn = 0;
+        for (int i = 0; i < nsrc; ++i)
+            dcn += src_roi[i].channels();
+
+        Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
+        randomSubMat(dst, dst_roi, roiSize, dstBorder, CV_MAKE_TYPE(depth, dcn), 5, 16);
+
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double threshold = 0.)
@@ -139,11 +149,11 @@ PARAM_TEST_CASE(Split, MatType, Channels, bool)
     int depth, cn;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst1)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst2)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst3)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst4)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst1);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst2);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst3);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst4);
 
     std::vector<Mat> dst_roi, dst;
     std::vector<UMat> udst_roi, udst;
@@ -177,11 +187,11 @@ PARAM_TEST_CASE(Split, MatType, Channels, bool)
             randomSubMat(dst4, dst4_roi, roiSize, dst4Border, depth, -1540, 1740);
         }
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst1)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst2)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst3)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst4)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst1);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst2);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst3);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst4);
 
         dst_roi.push_back(dst1_roi), udst_roi.push_back(udst1_roi),
                 dst.push_back(dst1), udst.push_back(udst1);
@@ -221,14 +231,14 @@ PARAM_TEST_CASE(MixChannels, MatType, bool)
     int depth;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src1)
-    TEST_DECLARE_INPUT_PARAMETER(src2)
-    TEST_DECLARE_INPUT_PARAMETER(src3)
-    TEST_DECLARE_INPUT_PARAMETER(src4)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst1)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst2)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst3)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst4)
+    TEST_DECLARE_INPUT_PARAMETER(src1);
+    TEST_DECLARE_INPUT_PARAMETER(src2);
+    TEST_DECLARE_INPUT_PARAMETER(src3);
+    TEST_DECLARE_INPUT_PARAMETER(src4);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst1);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst2);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst3);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst4);
 
     std::vector<Mat> src_roi, dst_roi, dst;
     std::vector<UMat> usrc_roi, udst_roi, udst;
@@ -287,15 +297,15 @@ PARAM_TEST_CASE(MixChannels, MatType, bool)
             randomSubMat(dst4, dst4_roi, roiSize, dst4Border, type(), -1540, 1740);
         }
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src1)
-        UMAT_UPLOAD_INPUT_PARAMETER(src2)
-        UMAT_UPLOAD_INPUT_PARAMETER(src3)
-        UMAT_UPLOAD_INPUT_PARAMETER(src4)
+        UMAT_UPLOAD_INPUT_PARAMETER(src1);
+        UMAT_UPLOAD_INPUT_PARAMETER(src2);
+        UMAT_UPLOAD_INPUT_PARAMETER(src3);
+        UMAT_UPLOAD_INPUT_PARAMETER(src4);
 
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst1)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst2)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst3)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst4)
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst1);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst2);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst3);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst4);
 
         int nsrc = randomInt(1, 5), ndst = randomInt(1, 5);
 
@@ -360,8 +370,8 @@ PARAM_TEST_CASE(InsertChannel, MatDepth, Channels, bool)
     int depth, cn, coi;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -381,8 +391,8 @@ PARAM_TEST_CASE(InsertChannel, MatDepth, Channels, bool)
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, CV_MAKE_TYPE(depth, cn), 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 };
 
@@ -406,8 +416,8 @@ PARAM_TEST_CASE(ExtractChannel, MatDepth, Channels, bool)
     int depth, cn, coi;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -427,8 +437,8 @@ PARAM_TEST_CASE(ExtractChannel, MatDepth, Channels, bool)
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, depth, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 };
 
@@ -447,7 +457,7 @@ OCL_TEST_P(ExtractChannel, Accuracy)
 
 //////////////////////////////////////// Instantiation ///////////////////////////////////////////////
 
-OCL_INSTANTIATE_TEST_CASE_P(Channels, Merge, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));
+OCL_INSTANTIATE_TEST_CASE_P(Channels, Merge, Combine(OCL_ALL_DEPTHS, Values(1, 2, 3, 4), Bool()));
 OCL_INSTANTIATE_TEST_CASE_P(Channels, Split, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));
 OCL_INSTANTIATE_TEST_CASE_P(Channels, MixChannels, Combine(OCL_ALL_DEPTHS, Bool()));
 OCL_INSTANTIATE_TEST_CASE_P(Channels, InsertChannel, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));
index cc9b06d..1f0e43b 100644 (file)
@@ -60,8 +60,8 @@ PARAM_TEST_CASE(Dft, cv::Size, MatDepth, bool, bool, bool, bool)
     int        dft_flags, depth;
     bool inplace;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -106,9 +106,9 @@ PARAM_TEST_CASE(MulSpectrums, bool, bool)
 {
     bool ccorr, useRoi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src1)
-    TEST_DECLARE_INPUT_PARAMETER(src2)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src1);
+    TEST_DECLARE_INPUT_PARAMETER(src2);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -129,9 +129,9 @@ PARAM_TEST_CASE(MulSpectrums, bool, bool)
         Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, srcRoiSize, dstBorder, CV_32FC2, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src1)
-        UMAT_UPLOAD_INPUT_PARAMETER(src2)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src1);
+        UMAT_UPLOAD_INPUT_PARAMETER(src2);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 };
 
index 4d453f3..e92fc2a 100644 (file)
@@ -67,10 +67,10 @@ PARAM_TEST_CASE(Gemm,
 
     double alpha, beta;
 
-    TEST_DECLARE_INPUT_PARAMETER(A)
-    TEST_DECLARE_INPUT_PARAMETER(B)
-    TEST_DECLARE_INPUT_PARAMETER(C)
-    TEST_DECLARE_OUTPUT_PARAMETER(D)
+    TEST_DECLARE_INPUT_PARAMETER(A);
+    TEST_DECLARE_INPUT_PARAMETER(B);
+    TEST_DECLARE_INPUT_PARAMETER(C);
+    TEST_DECLARE_OUTPUT_PARAMETER(D);
 
     virtual void SetUp()
     {
@@ -119,10 +119,10 @@ PARAM_TEST_CASE(Gemm,
         alpha = randomDouble(-4, 4);
         beta = randomDouble(-4, 4);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(A)
-        UMAT_UPLOAD_INPUT_PARAMETER(B)
-        UMAT_UPLOAD_INPUT_PARAMETER(C)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(D)
+        UMAT_UPLOAD_INPUT_PARAMETER(A);
+        UMAT_UPLOAD_INPUT_PARAMETER(B);
+        UMAT_UPLOAD_INPUT_PARAMETER(C);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(D);
     }
 };
 
index 77c5dad..9016095 100644 (file)
@@ -59,8 +59,8 @@ PARAM_TEST_CASE(ConvertTo, MatDepth, MatDepth, Channels, bool)
     int src_depth, cn, dstType;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -80,8 +80,8 @@ PARAM_TEST_CASE(ConvertTo, MatDepth, MatDepth, Channels, bool)
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, dstType, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 };
 
@@ -108,9 +108,9 @@ PARAM_TEST_CASE(CopyTo, MatDepth, Channels, bool, bool)
     int depth, cn;
     bool use_roi, use_mask;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_INPUT_PARAMETER(mask)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_INPUT_PARAMETER(mask);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -139,10 +139,10 @@ PARAM_TEST_CASE(CopyTo, MatDepth, Channels, bool, bool)
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, type, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
         if (use_mask)
-            UMAT_UPLOAD_INPUT_PARAMETER(mask)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+            UMAT_UPLOAD_INPUT_PARAMETER(mask);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 };
 
@@ -169,7 +169,7 @@ OCL_TEST_P(CopyTo, Accuracy)
 }
 
 OCL_INSTANTIATE_TEST_CASE_P(MatrixOperation, ConvertTo, Combine(
-                            OCL_ALL_DEPTHS, OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));
+                                OCL_ALL_DEPTHS, OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool()));
 
 OCL_INSTANTIATE_TEST_CASE_P(MatrixOperation, CopyTo, Combine(
                                 OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool(), Bool()));
index 63de12e..1c181c4 100644 (file)
@@ -28,7 +28,7 @@ PERF_TEST_P(orb, detect, testing::Values(ORB_IMAGES))
     TEST_CYCLE() detector(frame, mask, points);
 
     sort(points.begin(), points.end(), comparators::KeypointGreater());
-    SANITY_CHECK_KEYPOINTS(points);
+    SANITY_CHECK_KEYPOINTS(points, 1e-5);
 }
 
 PERF_TEST_P(orb, extract, testing::Values(ORB_IMAGES))
@@ -72,6 +72,6 @@ PERF_TEST_P(orb, full, testing::Values(ORB_IMAGES))
     TEST_CYCLE() detector(frame, mask, points, descriptors, false);
 
     perf::sort(points, descriptors);
-    SANITY_CHECK_KEYPOINTS(points);
+    SANITY_CHECK_KEYPOINTS(points, 1e-5);
     SANITY_CHECK(descriptors);
 }
index b3335a0..c01cbba 100644 (file)
@@ -43,6 +43,7 @@ The references are:
 
 #include "precomp.hpp"
 #include "fast_score.hpp"
+#include "opencl_kernels.hpp"
 
 #if defined _MSC_VER
 # pragma warning( disable : 4127)
@@ -249,8 +250,90 @@ void FAST_t(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bo
     }
 }
 
+template<typename pt>
+struct cmp_pt
+{
+    bool operator ()(const pt& a, const pt& b) const { return a.y < b.y || (a.y == b.y && a.x < b.x); }
+};
+
+static bool ocl_FAST( InputArray _img, std::vector<KeyPoint>& keypoints,
+                     int threshold, bool nonmax_suppression, int maxKeypoints )
+{
+    UMat img = _img.getUMat();
+    if( img.cols < 7 || img.rows < 7 )
+        return false;
+    size_t globalsize[] = { img.cols-6, img.rows-6 };
+
+    ocl::Kernel fastKptKernel("FAST_findKeypoints", ocl::features2d::fast_oclsrc);
+    if (fastKptKernel.empty())
+        return false;
+
+    UMat kp1(1, maxKeypoints*2+1, CV_32S);
+
+    UMat ucounter1(kp1, Rect(0,0,1,1));
+    ucounter1.setTo(Scalar::all(0));
+
+    if( !fastKptKernel.args(ocl::KernelArg::ReadOnly(img),
+                            ocl::KernelArg::PtrReadWrite(kp1),
+                            maxKeypoints, threshold).run(2, globalsize, 0, true))
+        return false;
+
+    Mat mcounter;
+    ucounter1.copyTo(mcounter);
+    int i, counter = mcounter.at<int>(0);
+    counter = std::min(counter, maxKeypoints);
+
+    keypoints.clear();
+
+    if( counter == 0 )
+        return true;
+
+    if( !nonmax_suppression )
+    {
+        Mat m;
+        kp1(Rect(0, 0, counter*2+1, 1)).copyTo(m);
+        const Point* pt = (const Point*)(m.ptr<int>() + 1);
+        for( i = 0; i < counter; i++ )
+            keypoints.push_back(KeyPoint((float)pt[i].x, (float)pt[i].y, 7.f, -1, 1.f));
+    }
+    else
+    {
+        UMat kp2(1, maxKeypoints*3+1, CV_32S);
+        UMat ucounter2 = kp2(Rect(0,0,1,1));
+        ucounter2.setTo(Scalar::all(0));
+
+        ocl::Kernel fastNMSKernel("FAST_nonmaxSupression", ocl::features2d::fast_oclsrc);
+        if (fastNMSKernel.empty())
+            return false;
+
+        size_t globalsize_nms[] = { counter };
+        if( !fastNMSKernel.args(ocl::KernelArg::PtrReadOnly(kp1),
+                                ocl::KernelArg::PtrReadWrite(kp2),
+                                ocl::KernelArg::ReadOnly(img),
+                                counter, counter).run(1, globalsize_nms, 0, true))
+            return false;
+
+        Mat m2;
+        kp2(Rect(0, 0, counter*3+1, 1)).copyTo(m2);
+        Point3i* pt2 = (Point3i*)(m2.ptr<int>() + 1);
+        int newcounter = std::min(m2.at<int>(0), counter);
+
+        std::sort(pt2, pt2 + newcounter, cmp_pt<Point3i>());
+
+        for( i = 0; i < newcounter; i++ )
+            keypoints.push_back(KeyPoint((float)pt2[i].x, (float)pt2[i].y, 7.f, -1, (float)pt2[i].z));
+    }
+
+    return true;
+}
+
+
 void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression, int type)
 {
+  if( ocl::useOpenCL() && _img.isUMat() && type == FastFeatureDetector::TYPE_9_16 &&
+      ocl_FAST(_img, keypoints, threshold, nonmax_suppression, 10000))
+      return;
+
   switch(type) {
     case FastFeatureDetector::TYPE_5_8:
       FAST_t<8>(_img, keypoints, threshold, nonmax_suppression);
@@ -268,6 +351,7 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
   }
 }
 
+
 void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression)
 {
     FAST(_img, keypoints, threshold, nonmax_suppression, FastFeatureDetector::TYPE_9_16);
@@ -285,10 +369,16 @@ FastFeatureDetector::FastFeatureDetector( int _threshold, bool _nonmaxSuppressio
 
 void FastFeatureDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) const
 {
-    Mat image = _image.getMat(), mask = _mask.getMat(), grayImage = image;
-    if( image.type() != CV_8U )
-        cvtColor( image, grayImage, COLOR_BGR2GRAY );
-    FAST( grayImage, keypoints, threshold, nonmaxSuppression, type );
+    Mat mask = _mask.getMat(), grayImage;
+    UMat ugrayImage;
+    _InputArray gray = _image;
+    if( _image.type() != CV_8U )
+    {
+        _OutputArray ogray = _image.isUMat() ? _OutputArray(ugrayImage) : _OutputArray(grayImage);
+        cvtColor( _image, ogray, COLOR_BGR2GRAY );
+        gray = ogray;
+    }
+    FAST( gray, keypoints, threshold, nonmaxSuppression, type );
     KeyPointsFilter::runByPixelsMask( keypoints, mask );
 }
 
diff --git a/modules/features2d/src/opencl/fast.cl b/modules/features2d/src/opencl/fast.cl
new file mode 100644 (file)
index 0000000..84ca39a
--- /dev/null
@@ -0,0 +1,162 @@
+// OpenCL port of the FAST corner detector.
+// Copyright (C) 2014, Itseez Inc. See the license at http://opencv.org
+
+inline int cornerScore(__global const uchar* img, int step)
+{
+    int k, tofs, v = img[0], a0 = 0, b0;
+    int d[16];
+    #define LOAD2(idx, ofs) \
+        tofs = ofs; d[idx] = (short)(v - img[tofs]); d[idx+8] = (short)(v - img[-tofs])
+    LOAD2(0, 3);
+    LOAD2(1, -step+3);
+    LOAD2(2, -step*2+2);
+    LOAD2(3, -step*3+1);
+    LOAD2(4, -step*3);
+    LOAD2(5, -step*3-1);
+    LOAD2(6, -step*2-2);
+    LOAD2(7, -step-3);
+
+    #pragma unroll
+    for( k = 0; k < 16; k += 2 )
+    {
+        int a = min((int)d[(k+1)&15], (int)d[(k+2)&15]);
+        a = min(a, (int)d[(k+3)&15]);
+        a = min(a, (int)d[(k+4)&15]);
+        a = min(a, (int)d[(k+5)&15]);
+        a = min(a, (int)d[(k+6)&15]);
+        a = min(a, (int)d[(k+7)&15]);
+        a = min(a, (int)d[(k+8)&15]);
+        a0 = max(a0, min(a, (int)d[k&15]));
+        a0 = max(a0, min(a, (int)d[(k+9)&15]));
+    }
+
+    b0 = -a0;
+    #pragma unroll
+    for( k = 0; k < 16; k += 2 )
+    {
+        int b = max((int)d[(k+1)&15], (int)d[(k+2)&15]);
+        b = max(b, (int)d[(k+3)&15]);
+        b = max(b, (int)d[(k+4)&15]);
+        b = max(b, (int)d[(k+5)&15]);
+        b = max(b, (int)d[(k+6)&15]);
+        b = max(b, (int)d[(k+7)&15]);
+        b = max(b, (int)d[(k+8)&15]);
+
+        b0 = min(b0, max(b, (int)d[k]));
+        b0 = min(b0, max(b, (int)d[(k+9)&15]));
+    }
+
+    return -b0-1;
+}
+
+__kernel
+void FAST_findKeypoints(
+    __global const uchar * _img, int step, int img_offset,
+    int img_rows, int img_cols,
+    volatile __global int* kp_loc,
+    int max_keypoints, int threshold )
+{
+    int j = get_global_id(0) + 3;
+    int i = get_global_id(1) + 3;
+
+    if (i < img_rows - 3 && j < img_cols - 3)
+    {
+        __global const uchar* img = _img + mad24(i, step, j + img_offset);
+        int v = img[0], t0 = v - threshold, t1 = v + threshold;
+        int k, tofs, v0, v1;
+        int m0 = 0, m1 = 0;
+
+        #define UPDATE_MASK(idx, ofs) \
+            tofs = ofs; v0 = img[tofs]; v1 = img[-tofs]; \
+            m0 |= ((v0 < t0) << idx) | ((v1 < t0) << (8 + idx)); \
+            m1 |= ((v0 > t1) << idx) | ((v1 > t1) << (8 + idx))
+
+        UPDATE_MASK(0, 3);
+        if( (m0 | m1) == 0 )
+            return;
+
+        UPDATE_MASK(2, -step*2+2);
+        UPDATE_MASK(4, -step*3);
+        UPDATE_MASK(6, -step*2-2);
+
+        #define EVEN_MASK (1+4+16+64)
+
+        if( ((m0 | (m0 >> 8)) & EVEN_MASK) != EVEN_MASK &&
+            ((m1 | (m1 >> 8)) & EVEN_MASK) != EVEN_MASK )
+            return;
+
+        UPDATE_MASK(1, -step+3);
+        UPDATE_MASK(3, -step*3+1);
+        UPDATE_MASK(5, -step*3-1);
+        UPDATE_MASK(7, -step-3);
+        if( ((m0 | (m0 >> 8)) & 255) != 255 &&
+            ((m1 | (m1 >> 8)) & 255) != 255 )
+            return;
+
+        m0 |= m0 << 16;
+        m1 |= m1 << 16;
+
+        #define CHECK0(i) ((m0 & (511 << i)) == (511 << i))
+        #define CHECK1(i) ((m1 & (511 << i)) == (511 << i))
+
+        if( CHECK0(0) + CHECK0(1) + CHECK0(2) + CHECK0(3) +
+            CHECK0(4) + CHECK0(5) + CHECK0(6) + CHECK0(7) +
+            CHECK0(8) + CHECK0(9) + CHECK0(10) + CHECK0(11) +
+            CHECK0(12) + CHECK0(13) + CHECK0(14) + CHECK0(15) +
+
+            CHECK1(0) + CHECK1(1) + CHECK1(2) + CHECK1(3) +
+            CHECK1(4) + CHECK1(5) + CHECK1(6) + CHECK1(7) +
+            CHECK1(8) + CHECK1(9) + CHECK1(10) + CHECK1(11) +
+            CHECK1(12) + CHECK1(13) + CHECK1(14) + CHECK1(15) == 0 )
+            return;
+
+        {
+            int idx = atomic_inc(kp_loc);
+            if( idx < max_keypoints )
+            {
+                kp_loc[1 + 2*idx] = j;
+                kp_loc[2 + 2*idx] = i;
+            }
+        }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// nonmaxSupression
+
+__kernel
+void FAST_nonmaxSupression(
+    __global const int* kp_in, volatile __global int* kp_out,
+    __global const uchar * _img, int step, int img_offset,
+    int rows, int cols, int counter, int max_keypoints)
+{
+    const int idx = get_global_id(0);
+
+    if (idx < counter)
+    {
+        int x = kp_in[1 + 2*idx];
+        int y = kp_in[2 + 2*idx];
+        __global const uchar* img = _img + mad24(y, step, x + img_offset);
+
+        int s = cornerScore(img, step);
+
+        if( (x < 4 || s > cornerScore(img-1, step)) +
+            (y < 4 || s > cornerScore(img-step, step)) != 2 )
+            return;
+        if( (x >= cols - 4 || s > cornerScore(img+1, step)) +
+            (y >= rows - 4 || s > cornerScore(img+step, step)) +
+            (x < 4 || y < 4 || s > cornerScore(img-step-1, step)) +
+            (x >= cols - 4 || y < 4 || s > cornerScore(img-step+1, step)) +
+            (x < 4 || y >= rows - 4 || s > cornerScore(img+step-1, step)) +
+            (x >= cols - 4 || y >= rows - 4 || s > cornerScore(img+step+1, step)) == 6)
+        {
+            int new_idx = atomic_inc(kp_out);
+            if( new_idx < max_keypoints )
+            {
+                kp_out[1 + 3*new_idx] = x;
+                kp_out[2 + 3*new_idx] = y;
+                kp_out[3 + 3*new_idx] = s;
+            }
+        }
+    }
+}
diff --git a/modules/features2d/src/opencl/orb.cl b/modules/features2d/src/opencl/orb.cl
new file mode 100644 (file)
index 0000000..ba5ec6f
--- /dev/null
@@ -0,0 +1,254 @@
+// OpenCL port of the ORB feature detector and descriptor extractor
+// Copyright (C) 2014, Itseez Inc. See the license at http://opencv.org
+//
+// The original code has been contributed by Peter Andreas Entschev, peter@entschev.com
+
+#define LAYERINFO_SIZE 1
+#define LAYERINFO_OFS 0
+#define KEYPOINT_SIZE 3
+#define ORIENTED_KEYPOINT_SIZE 4
+#define KEYPOINT_X 0
+#define KEYPOINT_Y 1
+#define KEYPOINT_Z 2
+#define KEYPOINT_ANGLE 3
+
+/////////////////////////////////////////////////////////////
+
+#ifdef ORB_RESPONSES
+
+__kernel void
+ORB_HarrisResponses(__global const uchar* imgbuf, int imgstep, int imgoffset0,
+                    __global const int* layerinfo, __global const int* keypoints,
+                    __global float* responses, int nkeypoints )
+{
+    int idx = get_global_id(0);
+    if( idx < nkeypoints )
+    {
+        __global const int* kpt = keypoints + idx*KEYPOINT_SIZE;
+        __global const int* layer = layerinfo + kpt[KEYPOINT_Z]*LAYERINFO_SIZE;
+        __global const uchar* img = imgbuf + imgoffset0 + layer[LAYERINFO_OFS] +
+            (kpt[KEYPOINT_Y] - blockSize/2)*imgstep + (kpt[KEYPOINT_X] - blockSize/2);
+
+        int i, j;
+        int a = 0, b = 0, c = 0;
+        for( i = 0; i < blockSize; i++, img += imgstep-blockSize )
+        {
+            for( j = 0; j < blockSize; j++, img++ )
+            {
+                int Ix = (img[1] - img[-1])*2 + img[-imgstep+1] - img[-imgstep-1] + img[imgstep+1] - img[imgstep-1];
+                int Iy = (img[imgstep] - img[-imgstep])*2 + img[imgstep-1] - img[-imgstep-1] + img[imgstep+1] - img[-imgstep+1];
+                a += Ix*Ix;
+                b += Iy*Iy;
+                c += Ix*Iy;
+            }
+        }
+        responses[idx] = ((float)a * b - (float)c * c - HARRIS_K * (float)(a + b) * (a + b))*scale_sq_sq;
+    }
+}
+
+#endif
+
+/////////////////////////////////////////////////////////////
+
+#ifdef ORB_ANGLES
+
+#define _DBL_EPSILON 2.2204460492503131e-16f
+#define atan2_p1 (0.9997878412794807f*57.29577951308232f)
+#define atan2_p3 (-0.3258083974640975f*57.29577951308232f)
+#define atan2_p5 (0.1555786518463281f*57.29577951308232f)
+#define atan2_p7 (-0.04432655554792128f*57.29577951308232f)
+
+inline float fastAtan2( float y, float x )
+{
+    float ax = fabs(x), ay = fabs(y);
+    float a, c, c2;
+    if( ax >= ay )
+    {
+        c = ay/(ax + _DBL_EPSILON);
+        c2 = c*c;
+        a = (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
+    }
+    else
+    {
+        c = ax/(ay + _DBL_EPSILON);
+        c2 = c*c;
+        a = 90.f - (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
+    }
+    if( x < 0 )
+        a = 180.f - a;
+    if( y < 0 )
+        a = 360.f - a;
+    return a;
+}
+
+
+__kernel void
+ORB_ICAngle(__global const uchar* imgbuf, int imgstep, int imgoffset0,
+            __global const int* layerinfo, __global const int* keypoints,
+            __global float* responses, const __global int* u_max,
+            int nkeypoints, int half_k )
+{
+    int idx = get_global_id(0);
+    if( idx < nkeypoints )
+    {
+        __global const int* kpt = keypoints + idx*KEYPOINT_SIZE;
+
+        __global const int* layer = layerinfo + kpt[KEYPOINT_Z]*LAYERINFO_SIZE;
+        __global const uchar* center = imgbuf + imgoffset0 + layer[LAYERINFO_OFS] +
+            kpt[KEYPOINT_Y]*imgstep + kpt[KEYPOINT_X];
+
+        int u, v, m_01 = 0, m_10 = 0;
+
+        // Treat the center line differently, v=0
+        for( u = -half_k; u <= half_k; u++ )
+            m_10 += u * center[u];
+
+        // Go line by line in the circular patch
+        for( v = 1; v <= half_k; v++ )
+        {
+            // Proceed over the two lines
+            int v_sum = 0;
+            int d = u_max[v];
+            for( u = -d; u <= d; u++ )
+            {
+                int val_plus = center[u + v*imgstep], val_minus = center[u - v*imgstep];
+                v_sum += (val_plus - val_minus);
+                m_10 += u * (val_plus + val_minus);
+            }
+            m_01 += v * v_sum;
+        }
+
+        // we do not use OpenCL's atan2 intrinsic,
+        // because we want to get _exactly_ the same results as the CPU version
+        responses[idx] = fastAtan2((float)m_01, (float)m_10);
+    }
+}
+
+#endif
+
+/////////////////////////////////////////////////////////////
+
+#ifdef ORB_DESCRIPTORS
+
+__kernel void
+ORB_computeDescriptor(__global const uchar* imgbuf, int imgstep, int imgoffset0,
+                      __global const int* layerinfo, __global const int* keypoints,
+                      __global uchar* _desc, const __global int* pattern,
+                      int nkeypoints, int dsize )
+{
+    int idx = get_global_id(0);
+    if( idx < nkeypoints )
+    {
+        int i;
+        __global const int* kpt = keypoints + idx*ORIENTED_KEYPOINT_SIZE;
+
+        __global const int* layer = layerinfo + kpt[KEYPOINT_Z]*LAYERINFO_SIZE;
+        __global const uchar* center = imgbuf + imgoffset0 + layer[LAYERINFO_OFS] +
+                                kpt[KEYPOINT_Y]*imgstep + kpt[KEYPOINT_X];
+        float angle = as_float(kpt[KEYPOINT_ANGLE]);
+        angle *= 0.01745329251994329547f;
+
+        float sina = sin(angle);
+        float cosa = cos(angle);
+
+        __global uchar* desc = _desc + idx*dsize;
+
+        #define GET_VALUE(idx) \
+            center[mad24(convert_int_rte(pattern[(idx)*2] * sina + pattern[(idx)*2+1] * cosa), imgstep, \
+                        convert_int_rte(pattern[(idx)*2] * cosa - pattern[(idx)*2+1] * sina))]
+
+        for( i = 0; i < dsize; i++ )
+        {
+            int val;
+        #if WTA_K == 2
+            int t0, t1;
+
+            t0 = GET_VALUE(0); t1 = GET_VALUE(1);
+            val = t0 < t1;
+
+            t0 = GET_VALUE(2); t1 = GET_VALUE(3);
+            val |= (t0 < t1) << 1;
+
+            t0 = GET_VALUE(4); t1 = GET_VALUE(5);
+            val |= (t0 < t1) << 2;
+
+            t0 = GET_VALUE(6); t1 = GET_VALUE(7);
+            val |= (t0 < t1) << 3;
+
+            t0 = GET_VALUE(8); t1 = GET_VALUE(9);
+            val |= (t0 < t1) << 4;
+
+            t0 = GET_VALUE(10); t1 = GET_VALUE(11);
+            val |= (t0 < t1) << 5;
+
+            t0 = GET_VALUE(12); t1 = GET_VALUE(13);
+            val |= (t0 < t1) << 6;
+
+            t0 = GET_VALUE(14); t1 = GET_VALUE(15);
+            val |= (t0 < t1) << 7;
+
+            pattern += 16*2;
+
+        #elif WTA_K == 3
+            int t0, t1, t2;
+
+            t0 = GET_VALUE(0); t1 = GET_VALUE(1); t2 = GET_VALUE(2);
+            val = t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0);
+
+            t0 = GET_VALUE(3); t1 = GET_VALUE(4); t2 = GET_VALUE(5);
+            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 2;
+
+            t0 = GET_VALUE(6); t1 = GET_VALUE(7); t2 = GET_VALUE(8);
+            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 4;
+
+            t0 = GET_VALUE(9); t1 = GET_VALUE(10); t2 = GET_VALUE(11);
+            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 6;
+
+            pattern += 12*2;
+
+        #elif WTA_K == 4
+            int t0, t1, t2, t3, k, val;
+            int a, b;
+
+            t0 = GET_VALUE(0); t1 = GET_VALUE(1);
+            t2 = GET_VALUE(2); t3 = GET_VALUE(3);
+            a = 0, b = 2;
+            if( t1 > t0 ) t0 = t1, a = 1;
+            if( t3 > t2 ) t2 = t3, b = 3;
+            k = t0 > t2 ? a : b;
+            val = k;
+
+            t0 = GET_VALUE(4); t1 = GET_VALUE(5);
+            t2 = GET_VALUE(6); t3 = GET_VALUE(7);
+            a = 0, b = 2;
+            if( t1 > t0 ) t0 = t1, a = 1;
+            if( t3 > t2 ) t2 = t3, b = 3;
+            k = t0 > t2 ? a : b;
+            val |= k << 2;
+
+            t0 = GET_VALUE(8); t1 = GET_VALUE(9);
+            t2 = GET_VALUE(10); t3 = GET_VALUE(11);
+            a = 0, b = 2;
+            if( t1 > t0 ) t0 = t1, a = 1;
+            if( t3 > t2 ) t2 = t3, b = 3;
+            k = t0 > t2 ? a : b;
+            val |= k << 4;
+
+            t0 = GET_VALUE(12); t1 = GET_VALUE(13);
+            t2 = GET_VALUE(14); t3 = GET_VALUE(15);
+            a = 0, b = 2;
+            if( t1 > t0 ) t0 = t1, a = 1;
+            if( t3 > t2 ) t2 = t3, b = 3;
+            k = t0 > t2 ? a : b;
+            val |= k << 6;
+
+            pattern += 16*2;
+        #else
+            #error "unknown/undefined WTA_K value; should be 2, 3 or 4"
+        #endif
+            desc[i] = (uchar)val;
+        }
+    }
+}
+
+#endif
index b72a6db..4fe9cbc 100644 (file)
@@ -35,6 +35,7 @@
 /** Authors: Ethan Rublee, Vincent Rabaud, Gary Bradski */
 
 #include "precomp.hpp"
+#include "opencl_kernels.hpp"
 #include <iterator>
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -43,14 +44,86 @@ namespace cv
 {
 
 const float HARRIS_K = 0.04f;
-const int DESCRIPTOR_SIZE = 32;
+
+template<typename _Tp> inline void copyVectorToUMat(const std::vector<_Tp>& v, OutputArray um)
+{
+    if(v.empty())
+        um.release();
+    Mat(1, (int)(v.size()*sizeof(v[0])), CV_8U, (void*)&v[0]).copyTo(um);
+}
+
+static bool
+ocl_HarrisResponses(const UMat& imgbuf,
+                    const UMat& layerinfo,
+                    const UMat& keypoints,
+                    UMat& responses,
+                    int nkeypoints, int blockSize, float harris_k)
+{
+    size_t globalSize[] = {nkeypoints};
+
+    float scale = 1.f/((1 << 2) * blockSize * 255.f);
+    float scale_sq_sq = scale * scale * scale * scale;
+
+    ocl::Kernel hr_ker("ORB_HarrisResponses", ocl::features2d::orb_oclsrc,
+                format("-D ORB_RESPONSES -D blockSize=%d -D scale_sq_sq=%.12ef -D HARRIS_K=%.12ff", blockSize, scale_sq_sq, harris_k));
+    if( hr_ker.empty() )
+        return false;
+
+    return hr_ker.args(ocl::KernelArg::ReadOnlyNoSize(imgbuf),
+                ocl::KernelArg::PtrReadOnly(layerinfo),
+                ocl::KernelArg::PtrReadOnly(keypoints),
+                ocl::KernelArg::PtrWriteOnly(responses),
+                nkeypoints).run(1, globalSize, 0, true);
+}
+
+static bool
+ocl_ICAngles(const UMat& imgbuf, const UMat& layerinfo,
+             const UMat& keypoints, UMat& responses,
+             const UMat& umax, int nkeypoints, int half_k)
+{
+    size_t globalSize[] = {nkeypoints};
+
+    ocl::Kernel icangle_ker("ORB_ICAngle", ocl::features2d::orb_oclsrc, "-D ORB_ANGLES");
+    if( icangle_ker.empty() )
+        return false;
+
+    return icangle_ker.args(ocl::KernelArg::ReadOnlyNoSize(imgbuf),
+                ocl::KernelArg::PtrReadOnly(layerinfo),
+                ocl::KernelArg::PtrReadOnly(keypoints),
+                ocl::KernelArg::PtrWriteOnly(responses),
+                ocl::KernelArg::PtrReadOnly(umax),
+                nkeypoints, half_k).run(1, globalSize, 0, true);
+}
+
+
+static bool
+ocl_computeOrbDescriptors(const UMat& imgbuf, const UMat& layerInfo,
+                          const UMat& keypoints, UMat& desc, const UMat& pattern,
+                          int nkeypoints, int dsize, int WTA_K)
+{
+    size_t globalSize[] = {nkeypoints};
+
+    ocl::Kernel desc_ker("ORB_computeDescriptor", ocl::features2d::orb_oclsrc,
+                         format("-D ORB_DESCRIPTORS -D WTA_K=%d", WTA_K));
+    if( desc_ker.empty() )
+        return false;
+
+    return desc_ker.args(ocl::KernelArg::ReadOnlyNoSize(imgbuf),
+                         ocl::KernelArg::PtrReadOnly(layerInfo),
+                         ocl::KernelArg::PtrReadOnly(keypoints),
+                         ocl::KernelArg::PtrWriteOnly(desc),
+                         ocl::KernelArg::PtrReadOnly(pattern),
+                         nkeypoints, dsize).run(1, globalSize, 0, true);
+}
+
 
 /**
  * Function that computes the Harris responses in a
- * blockSize x blockSize patch at given points in an image
+ * blockSize x blockSize patch at given points in the image
  */
 static void
-HarrisResponses(const Mat& img, std::vector<KeyPoint>& pts, int blockSize, float harris_k)
+HarrisResponses(const Mat& img, const std::vector<Rect>& layerinfo,
+                std::vector<KeyPoint>& pts, int blockSize, float harris_k)
 {
     CV_Assert( img.type() == CV_8UC1 && blockSize*blockSize <= 2048 );
 
@@ -60,8 +133,7 @@ HarrisResponses(const Mat& img, std::vector<KeyPoint>& pts, int blockSize, float
     int step = (int)(img.step/img.elemSize1());
     int r = blockSize/2;
 
-    float scale = (1 << 2) * blockSize * 255.0f;
-    scale = 1.0f / scale;
+    float scale = 1.f/((1 << 2) * blockSize * 255.f);
     float scale_sq_sq = scale * scale * scale * scale;
 
     AutoBuffer<int> ofsbuf(blockSize*blockSize);
@@ -72,10 +144,11 @@ HarrisResponses(const Mat& img, std::vector<KeyPoint>& pts, int blockSize, float
 
     for( ptidx = 0; ptidx < ptsize; ptidx++ )
     {
-        int x0 = cvRound(pts[ptidx].pt.x - r);
-        int y0 = cvRound(pts[ptidx].pt.y - r);
+        int x0 = cvRound(pts[ptidx].pt.x);
+        int y0 = cvRound(pts[ptidx].pt.y);
+        int z = pts[ptidx].octave;
 
-        const uchar* ptr0 = ptr00 + y0*step + x0;
+        const uchar* ptr0 = ptr00 + (y0 - r + layerinfo[z].y)*step + x0 - r + layerinfo[z].x;
         int a = 0, b = 0, c = 0;
 
         for( int k = 0; k < blockSize*blockSize; k++ )
@@ -94,158 +167,175 @@ HarrisResponses(const Mat& img, std::vector<KeyPoint>& pts, int blockSize, float
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-static float IC_Angle(const Mat& image, const int half_k, Point2f pt,
-                      const std::vector<int> & u_max)
+static void ICAngles(const Mat& img, const std::vector<Rect>& layerinfo,
+                     std::vector<KeyPoint>& pts, const std::vector<int> & u_max, int half_k)
 {
-    int m_01 = 0, m_10 = 0;
+    int step = (int)img.step1();
+    size_t ptidx, ptsize = pts.size();
 
-    const uchar* center = &image.at<uchar> (cvRound(pt.y), cvRound(pt.x));
+    for( ptidx = 0; ptidx < ptsize; ptidx++ )
+    {
+        const Rect& layer = layerinfo[pts[ptidx].octave];
+        const uchar* center = &img.at<uchar>(cvRound(pts[ptidx].pt.y) + layer.y, cvRound(pts[ptidx].pt.x) + layer.x);
 
-    // Treat the center line differently, v=0
-    for (int u = -half_k; u <= half_k; ++u)
-        m_10 += u * center[u];
+        int m_01 = 0, m_10 = 0;
 
-    // Go line by line in the circular patch
-    int step = (int)image.step1();
-    for (int v = 1; v <= half_k; ++v)
-    {
-        // Proceed over the two lines
-        int v_sum = 0;
-        int d = u_max[v];
-        for (int u = -d; u <= d; ++u)
+        // Treat the center line differently, v=0
+        for (int u = -half_k; u <= half_k; ++u)
+            m_10 += u * center[u];
+
+        // Go line by line in the circular patch
+        for (int v = 1; v <= half_k; ++v)
         {
-            int val_plus = center[u + v*step], val_minus = center[u - v*step];
-            v_sum += (val_plus - val_minus);
-            m_10 += u * (val_plus + val_minus);
+            // Proceed over the two lines
+            int v_sum = 0;
+            int d = u_max[v];
+            for (int u = -d; u <= d; ++u)
+            {
+                int val_plus = center[u + v*step], val_minus = center[u - v*step];
+                v_sum += (val_plus - val_minus);
+                m_10 += u * (val_plus + val_minus);
+            }
+            m_01 += v * v_sum;
         }
-        m_01 += v * v_sum;
-    }
 
-    return fastAtan2((float)m_01, (float)m_10);
+        pts[ptidx].angle = fastAtan2((float)m_01, (float)m_10);
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-static void computeOrbDescriptor(const KeyPoint& kpt,
-                                 const Mat& img, const Point* pattern,
-                                 uchar* desc, int dsize, int WTA_K)
+static void
+computeOrbDescriptors( const Mat& imagePyramid, const std::vector<Rect>& layerInfo,
+                       const std::vector<float>& layerScale, std::vector<KeyPoint>& keypoints,
+                       Mat& descriptors, const std::vector<Point>& _pattern, int dsize, int WTA_K )
 {
-    float angle = kpt.angle;
-    //angle = cvFloor(angle/12)*12.f;
-    angle *= (float)(CV_PI/180.f);
-    float a = (float)cos(angle), b = (float)sin(angle);
-
-    const uchar* center = &img.at<uchar>(cvRound(kpt.pt.y), cvRound(kpt.pt.x));
-    int step = (int)img.step;
-
-    float x, y;
-    int ix, iy;
-#if 1
-    #define GET_VALUE(idx) \
-           (x = pattern[idx].x*a - pattern[idx].y*b, \
-            y = pattern[idx].x*b + pattern[idx].y*a, \
-            ix = cvRound(x), \
-            iy = cvRound(y), \
-            *(center + iy*step + ix) )
-#else
-    #define GET_VALUE(idx) \
-        (x = pattern[idx].x*a - pattern[idx].y*b, \
-        y = pattern[idx].x*b + pattern[idx].y*a, \
-        ix = cvFloor(x), iy = cvFloor(y), \
-        x -= ix, y -= iy, \
-        cvRound(center[iy*step + ix]*(1-x)*(1-y) + center[(iy+1)*step + ix]*(1-x)*y + \
-                center[iy*step + ix+1]*x*(1-y) + center[(iy+1)*step + ix+1]*x*y))
-#endif
-
-    if( WTA_K == 2 )
+    int step = (int)imagePyramid.step;
+    int j, i, nkeypoints = (int)keypoints.size();
+
+    for( j = 0; j < nkeypoints; j++ )
     {
-        for (int i = 0; i < dsize; ++i, pattern += 16)
+        const KeyPoint& kpt = keypoints[j];
+        const Rect& layer = layerInfo[kpt.octave];
+        float scale = 1.f/layerScale[kpt.octave];
+        float angle = kpt.angle;
+
+        angle *= (float)(CV_PI/180.f);
+        float a = (float)cos(angle), b = (float)sin(angle);
+
+        const uchar* center = &imagePyramid.at<uchar>(cvRound(kpt.pt.y*scale) + layer.y,
+                                                      cvRound(kpt.pt.x*scale) + layer.x);
+        float x, y;
+        int ix, iy;
+        const Point* pattern = &_pattern[0];
+        uchar* desc = descriptors.ptr<uchar>(j);
+
+    #if 1
+        #define GET_VALUE(idx) \
+               (x = pattern[idx].x*a - pattern[idx].y*b, \
+                y = pattern[idx].x*b + pattern[idx].y*a, \
+                ix = cvRound(x), \
+                iy = cvRound(y), \
+                *(center + iy*step + ix) )
+    #else
+        #define GET_VALUE(idx) \
+            (x = pattern[idx].x*a - pattern[idx].y*b, \
+            y = pattern[idx].x*b + pattern[idx].y*a, \
+            ix = cvFloor(x), iy = cvFloor(y), \
+            x -= ix, y -= iy, \
+            cvRound(center[iy*step + ix]*(1-x)*(1-y) + center[(iy+1)*step + ix]*(1-x)*y + \
+                    center[iy*step + ix+1]*x*(1-y) + center[(iy+1)*step + ix+1]*x*y))
+    #endif
+
+        if( WTA_K == 2 )
         {
-            int t0, t1, val;
-            t0 = GET_VALUE(0); t1 = GET_VALUE(1);
-            val = t0 < t1;
-            t0 = GET_VALUE(2); t1 = GET_VALUE(3);
-            val |= (t0 < t1) << 1;
-            t0 = GET_VALUE(4); t1 = GET_VALUE(5);
-            val |= (t0 < t1) << 2;
-            t0 = GET_VALUE(6); t1 = GET_VALUE(7);
-            val |= (t0 < t1) << 3;
-            t0 = GET_VALUE(8); t1 = GET_VALUE(9);
-            val |= (t0 < t1) << 4;
-            t0 = GET_VALUE(10); t1 = GET_VALUE(11);
-            val |= (t0 < t1) << 5;
-            t0 = GET_VALUE(12); t1 = GET_VALUE(13);
-            val |= (t0 < t1) << 6;
-            t0 = GET_VALUE(14); t1 = GET_VALUE(15);
-            val |= (t0 < t1) << 7;
-
-            desc[i] = (uchar)val;
+            for (i = 0; i < dsize; ++i, pattern += 16)
+            {
+                int t0, t1, val;
+                t0 = GET_VALUE(0); t1 = GET_VALUE(1);
+                val = t0 < t1;
+                t0 = GET_VALUE(2); t1 = GET_VALUE(3);
+                val |= (t0 < t1) << 1;
+                t0 = GET_VALUE(4); t1 = GET_VALUE(5);
+                val |= (t0 < t1) << 2;
+                t0 = GET_VALUE(6); t1 = GET_VALUE(7);
+                val |= (t0 < t1) << 3;
+                t0 = GET_VALUE(8); t1 = GET_VALUE(9);
+                val |= (t0 < t1) << 4;
+                t0 = GET_VALUE(10); t1 = GET_VALUE(11);
+                val |= (t0 < t1) << 5;
+                t0 = GET_VALUE(12); t1 = GET_VALUE(13);
+                val |= (t0 < t1) << 6;
+                t0 = GET_VALUE(14); t1 = GET_VALUE(15);
+                val |= (t0 < t1) << 7;
+
+                desc[i] = (uchar)val;
+            }
         }
-    }
-    else if( WTA_K == 3 )
-    {
-        for (int i = 0; i < dsize; ++i, pattern += 12)
+        else if( WTA_K == 3 )
         {
-            int t0, t1, t2, val;
-            t0 = GET_VALUE(0); t1 = GET_VALUE(1); t2 = GET_VALUE(2);
-            val = t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0);
+            for (i = 0; i < dsize; ++i, pattern += 12)
+            {
+                int t0, t1, t2, val;
+                t0 = GET_VALUE(0); t1 = GET_VALUE(1); t2 = GET_VALUE(2);
+                val = t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0);
 
-            t0 = GET_VALUE(3); t1 = GET_VALUE(4); t2 = GET_VALUE(5);
-            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 2;
+                t0 = GET_VALUE(3); t1 = GET_VALUE(4); t2 = GET_VALUE(5);
+                val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 2;
 
-            t0 = GET_VALUE(6); t1 = GET_VALUE(7); t2 = GET_VALUE(8);
-            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 4;
+                t0 = GET_VALUE(6); t1 = GET_VALUE(7); t2 = GET_VALUE(8);
+                val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 4;
 
-            t0 = GET_VALUE(9); t1 = GET_VALUE(10); t2 = GET_VALUE(11);
-            val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 6;
+                t0 = GET_VALUE(9); t1 = GET_VALUE(10); t2 = GET_VALUE(11);
+                val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 6;
 
-            desc[i] = (uchar)val;
+                desc[i] = (uchar)val;
+            }
         }
-    }
-    else if( WTA_K == 4 )
-    {
-        for (int i = 0; i < dsize; ++i, pattern += 16)
+        else if( WTA_K == 4 )
         {
-            int t0, t1, t2, t3, u, v, k, val;
-            t0 = GET_VALUE(0); t1 = GET_VALUE(1);
-            t2 = GET_VALUE(2); t3 = GET_VALUE(3);
-            u = 0, v = 2;
-            if( t1 > t0 ) t0 = t1, u = 1;
-            if( t3 > t2 ) t2 = t3, v = 3;
-            k = t0 > t2 ? u : v;
-            val = k;
-
-            t0 = GET_VALUE(4); t1 = GET_VALUE(5);
-            t2 = GET_VALUE(6); t3 = GET_VALUE(7);
-            u = 0, v = 2;
-            if( t1 > t0 ) t0 = t1, u = 1;
-            if( t3 > t2 ) t2 = t3, v = 3;
-            k = t0 > t2 ? u : v;
-            val |= k << 2;
-
-            t0 = GET_VALUE(8); t1 = GET_VALUE(9);
-            t2 = GET_VALUE(10); t3 = GET_VALUE(11);
-            u = 0, v = 2;
-            if( t1 > t0 ) t0 = t1, u = 1;
-            if( t3 > t2 ) t2 = t3, v = 3;
-            k = t0 > t2 ? u : v;
-            val |= k << 4;
-
-            t0 = GET_VALUE(12); t1 = GET_VALUE(13);
-            t2 = GET_VALUE(14); t3 = GET_VALUE(15);
-            u = 0, v = 2;
-            if( t1 > t0 ) t0 = t1, u = 1;
-            if( t3 > t2 ) t2 = t3, v = 3;
-            k = t0 > t2 ? u : v;
-            val |= k << 6;
-
-            desc[i] = (uchar)val;
+            for (i = 0; i < dsize; ++i, pattern += 16)
+            {
+                int t0, t1, t2, t3, u, v, k, val;
+                t0 = GET_VALUE(0); t1 = GET_VALUE(1);
+                t2 = GET_VALUE(2); t3 = GET_VALUE(3);
+                u = 0, v = 2;
+                if( t1 > t0 ) t0 = t1, u = 1;
+                if( t3 > t2 ) t2 = t3, v = 3;
+                k = t0 > t2 ? u : v;
+                val = k;
+
+                t0 = GET_VALUE(4); t1 = GET_VALUE(5);
+                t2 = GET_VALUE(6); t3 = GET_VALUE(7);
+                u = 0, v = 2;
+                if( t1 > t0 ) t0 = t1, u = 1;
+                if( t3 > t2 ) t2 = t3, v = 3;
+                k = t0 > t2 ? u : v;
+                val |= k << 2;
+
+                t0 = GET_VALUE(8); t1 = GET_VALUE(9);
+                t2 = GET_VALUE(10); t3 = GET_VALUE(11);
+                u = 0, v = 2;
+                if( t1 > t0 ) t0 = t1, u = 1;
+                if( t3 > t2 ) t2 = t3, v = 3;
+                k = t0 > t2 ? u : v;
+                val |= k << 4;
+
+                t0 = GET_VALUE(12); t1 = GET_VALUE(13);
+                t2 = GET_VALUE(14); t3 = GET_VALUE(15);
+                u = 0, v = 2;
+                if( t1 > t0 ) t0 = t1, u = 1;
+                if( t3 > t2 ) t2 = t3, v = 3;
+                k = t0 > t2 ? u : v;
+                val |= k << 6;
+
+                desc[i] = (uchar)val;
+            }
         }
+        else
+            CV_Error( Error::StsBadSize, "Wrong WTA_K. It can be only 2, 3 or 4." );
+        #undef GET_VALUE
     }
-    else
-        CV_Error( Error::StsBadSize, "Wrong WTA_K. It can be only 2, 3 or 4." );
-
-    #undef GET_VALUE
 }
 
 
@@ -591,21 +681,37 @@ void ORB::operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& k
 }
 
 
-/** Compute the ORB keypoint orientations
- * @param image the image to compute the features and descriptors on
- * @param integral_image the integral image of the iamge (can be empty, but the computation will be slower)
- * @param scale the scale at which we compute the orientation
- * @param keypoints the resulting keypoints
- */
-static void computeOrientation(const Mat& image, std::vector<KeyPoint>& keypoints,
-                               int halfPatchSize, const std::vector<int>& umax)
+static void uploadORBKeypoints(const std::vector<KeyPoint>& src, std::vector<Vec3i>& buf, OutputArray dst)
+{
+    size_t i, n = src.size();
+    buf.resize(std::max(buf.size(), n));
+    for( i = 0; i < n; i++ )
+        buf[i] = Vec3i(cvRound(src[i].pt.x), cvRound(src[i].pt.y), src[i].octave);
+    copyVectorToUMat(buf, dst);
+}
+
+typedef union if32_t
 {
-    // Process each keypoint
-    for (std::vector<KeyPoint>::iterator keypoint = keypoints.begin(),
-         keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
+    int i;
+    float f;
+}
+if32_t;
+
+static void uploadORBKeypoints(const std::vector<KeyPoint>& src,
+                               const std::vector<float>& layerScale,
+                               std::vector<Vec4i>& buf, OutputArray dst)
+{
+    size_t i, n = src.size();
+    buf.resize(std::max(buf.size(), n));
+    for( i = 0; i < n; i++ )
     {
-        keypoint->angle = IC_Angle(image, halfPatchSize, keypoint->pt, umax);
+        int z = src[i].octave;
+        float scale = 1.f/layerScale[z];
+        if32_t angle;
+        angle.f = src[i].angle;
+        buf[i] = Vec4i(cvRound(src[i].pt.x*scale), cvRound(src[i].pt.y*scale), z, angle.i);
     }
+    copyVectorToUMat(buf, dst);
 }
 
 
@@ -614,13 +720,18 @@ static void computeOrientation(const Mat& image, std::vector<KeyPoint>& keypoint
  * @param mask_pyramid the masks to apply at every level
  * @param keypoints the resulting keypoints, clustered per level
  */
-static void computeKeyPoints(const std::vector<Mat>& imagePyramid,
-                             const std::vector<Mat>& maskPyramid,
-                             std::vector<std::vector<KeyPoint> >& allKeypoints,
-                             int nfeatures, int firstLevel, double scaleFactor,
-                             int edgeThreshold, int patchSize, int scoreType )
+static void computeKeyPoints(const Mat& imagePyramid,
+                             const UMat& uimagePyramid,
+                             const Mat& maskPyramid,
+                             const std::vector<Rect>& layerInfo,
+                             const UMat& ulayerInfo,
+                             const std::vector<float>& layerScale,
+                             std::vector<KeyPoint>& allKeypoints,
+                             int nfeatures, double scaleFactor,
+                             int edgeThreshold, int patchSize, int scoreType,
+                             bool useOCL )
 {
-    int nlevels = (int)imagePyramid.size();
+    int i, nkeypoints, level, nlevels = (int)layerInfo.size();
     std::vector<int> nfeaturesPerLevel(nlevels);
 
     // fill the extractors and descriptors for the corresponding scales
@@ -628,7 +739,7 @@ static void computeKeyPoints(const std::vector<Mat>& imagePyramid,
     float ndesiredFeaturesPerScale = nfeatures*(1 - factor)/(1 - (float)std::pow((double)factor, (double)nlevels));
 
     int sumFeatures = 0;
-    for( int level = 0; level < nlevels-1; level++ )
+    for( level = 0; level < nlevels-1; level++ )
     {
         nfeaturesPerLevel[level] = cvRound(ndesiredFeaturesPerScale);
         sumFeatures += nfeaturesPerLevel[level];
@@ -657,66 +768,116 @@ static void computeKeyPoints(const std::vector<Mat>& imagePyramid,
         ++v0;
     }
 
-    allKeypoints.resize(nlevels);
+    allKeypoints.clear();
+    std::vector<KeyPoint> keypoints;
+    std::vector<int> counters(nlevels);
+    keypoints.reserve(nfeaturesPerLevel[0]*2);
 
-    for (int level = 0; level < nlevels; ++level)
+    for( level = 0; level < nlevels; level++ )
     {
         int featuresNum = nfeaturesPerLevel[level];
-        allKeypoints[level].reserve(featuresNum*2);
-
-        std::vector<KeyPoint> & keypoints = allKeypoints[level];
+        Mat img = imagePyramid(layerInfo[level]);
+        Mat mask = maskPyramid.empty() ? Mat() : maskPyramid(layerInfo[level]);
 
         // Detect FAST features, 20 is a good threshold
         FastFeatureDetector fd(20, true);
-        fd.detect(imagePyramid[level], keypoints, maskPyramid[level]);
+        fd.detect(img, keypoints, mask);
 
         // Remove keypoints very close to the border
-        KeyPointsFilter::runByImageBorder(keypoints, imagePyramid[level].size(), edgeThreshold);
+        KeyPointsFilter::runByImageBorder(keypoints, img.size(), edgeThreshold);
 
-        if( scoreType == ORB::HARRIS_SCORE )
-        {
-            // Keep more points than necessary as FAST does not give amazing corners
-            KeyPointsFilter::retainBest(keypoints, 2 * featuresNum);
+        // Keep more points than necessary as FAST does not give amazing corners
+        KeyPointsFilter::retainBest(keypoints, scoreType == ORB::HARRIS_SCORE ? 2 * featuresNum : featuresNum);
+
+        nkeypoints = (int)keypoints.size();
+        counters[level] = nkeypoints;
 
-            // Compute the Harris cornerness (better scoring than FAST)
-            HarrisResponses(imagePyramid[level], keypoints, 7, HARRIS_K);
+        float sf = layerScale[level];
+        for( i = 0; i < nkeypoints; i++ )
+        {
+            keypoints[i].octave = level;
+            keypoints[i].size = patchSize*sf;
         }
 
-        //cull to the final desired level, using the new Harris scores or the original FAST scores.
-        KeyPointsFilter::retainBest(keypoints, featuresNum);
+        std::copy(keypoints.begin(), keypoints.end(), std::back_inserter(allKeypoints));
+    }
+
+    std::vector<Vec3i> ukeypoints_buf;
 
-        float sf = getScale(level, firstLevel, scaleFactor);
+    nkeypoints = (int)allKeypoints.size();
+    Mat responses;
+    UMat ukeypoints, uresponses(1, nkeypoints, CV_32F);
 
-        // Set the level of the coordinates
-        for (std::vector<KeyPoint>::iterator keypoint = keypoints.begin(),
-             keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
+    // Select best features using the Harris cornerness (better scoring than FAST)
+    if( scoreType == ORB::HARRIS_SCORE )
+    {
+        if( useOCL )
         {
-            keypoint->octave = level;
-            keypoint->size = patchSize*sf;
+            uploadORBKeypoints(allKeypoints, ukeypoints_buf, ukeypoints);
+            useOCL = ocl_HarrisResponses( uimagePyramid, ulayerInfo, ukeypoints,
+                                          uresponses, nkeypoints, 7, HARRIS_K );
+            if( useOCL )
+            {
+                uresponses.copyTo(responses);
+                for( i = 0; i < nkeypoints; i++ )
+                    allKeypoints[i].response = responses.at<float>(i);
+            }
         }
 
-        computeOrientation(imagePyramid[level], keypoints, halfPatchSize, umax);
+        if( !useOCL )
+            HarrisResponses(imagePyramid, layerInfo, allKeypoints, 7, HARRIS_K);
+
+        std::vector<KeyPoint> newAllKeypoints;
+        newAllKeypoints.reserve(nfeaturesPerLevel[0]*nlevels);
+
+        int offset = 0;
+        for( level = 0; level < nlevels; level++ )
+        {
+            int featuresNum = nfeaturesPerLevel[level];
+            nkeypoints = counters[level];
+            keypoints.resize(nkeypoints);
+            std::copy(allKeypoints.begin() + offset,
+                      allKeypoints.begin() + offset + nkeypoints,
+                      keypoints.begin());
+            offset += nkeypoints;
+
+            //cull to the final desired level, using the new Harris scores.
+            KeyPointsFilter::retainBest(keypoints, featuresNum);
+
+            std::copy(keypoints.begin(), keypoints.end(), std::back_inserter(newAllKeypoints));
+        }
+        std::swap(allKeypoints, newAllKeypoints);
     }
-}
 
+    nkeypoints = (int)allKeypoints.size();
+    if( useOCL )
+    {
+        UMat uumax;
+        if( useOCL )
+            copyVectorToUMat(umax, uumax);
 
-/** Compute the ORB decriptors
- * @param image the image to compute the features and descriptors on
- * @param integral_image the integral image of the image (can be empty, but the computation will be slower)
- * @param level the scale at which we compute the orientation
- * @param keypoints the keypoints to use
- * @param descriptors the resulting descriptors
- */
-static void computeDescriptors(const Mat& image, std::vector<KeyPoint>& keypoints, Mat& descriptors,
-                               const std::vector<Point>& pattern, int dsize, int WTA_K)
-{
-    //convert to grayscale if more than one color
-    CV_Assert(image.type() == CV_8UC1);
-    //create the descriptor mat, keypoints.size() rows, BYTES cols
-    descriptors = Mat::zeros((int)keypoints.size(), dsize, CV_8UC1);
+        uploadORBKeypoints(allKeypoints, ukeypoints_buf, ukeypoints);
+        useOCL = ocl_ICAngles(uimagePyramid, ulayerInfo, ukeypoints, uresponses, uumax,
+                              nkeypoints, halfPatchSize);
 
-    for (size_t i = 0; i < keypoints.size(); i++)
-        computeOrbDescriptor(keypoints[i], image, &pattern[0], descriptors.ptr((int)i), dsize, WTA_K);
+        if( useOCL )
+        {
+            uresponses.copyTo(responses);
+            for( i = 0; i < nkeypoints; i++ )
+                allKeypoints[i].angle = responses.at<float>(i);
+        }
+    }
+
+    if( !useOCL )
+    {
+        ICAngles(imagePyramid, layerInfo, allKeypoints, umax, halfPatchSize);
+    }
+
+    for( i = 0; i < nkeypoints; i++ )
+    {
+        float scale = layerScale[allKeypoints[i].octave];
+        allKeypoints[i].pt *= scale;
+    }
 }
 
 
@@ -728,8 +889,8 @@ static void computeDescriptors(const Mat& image, std::vector<KeyPoint>& keypoint
  * @param do_keypoints if true, the keypoints are computed, otherwise used as an input
  * @param do_descriptors if true, also computes the descriptors
  */
-void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>& _keypoints,
-                      OutputArray _descriptors, bool useProvidedKeypoints) const
+void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
+                      OutputArray _descriptors, bool useProvidedKeypoints ) const
 {
     CV_Assert(patchSize >= 2);
 
@@ -744,11 +905,14 @@ void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>
     int halfPatchSize = patchSize / 2;
     int border = std::max(edgeThreshold, std::max(halfPatchSize, HARRIS_BLOCK_SIZE/2))+1;
 
+    bool useOCL = ocl::useOpenCL();
+
     Mat image = _image.getMat(), mask = _mask.getMat();
     if( image.type() != CV_8UC1 )
         cvtColor(_image, image, COLOR_BGR2GRAY);
 
-    int levelsNum = this->nlevels;
+    int i, level, nLevels = this->nlevels, nkeypoints = (int)keypoints.size();
+    bool sortedByLevel = true;
 
     if( !do_keypoints )
     {
@@ -761,129 +925,145 @@ void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>
         //
         // In short, ultimately the descriptor should
         // ignore octave parameter and deal only with the keypoint size.
-        levelsNum = 0;
-        for( size_t i = 0; i < _keypoints.size(); i++ )
-            levelsNum = std::max(levelsNum, std::max(_keypoints[i].octave, 0));
-        levelsNum++;
+        nLevels = 0;
+        for( i = 0; i < nkeypoints; i++ )
+        {
+            level = keypoints[i].octave;
+            CV_Assert(level >= 0);
+            if( i > 0 && level < keypoints[i-1].octave )
+                sortedByLevel = false;
+            nLevels = std::max(nLevels, level);
+        }
+        nLevels++;
     }
 
+    std::vector<Rect> layerInfo(nLevels);
+    std::vector<int> layerOfs(nLevels);
+    std::vector<float> layerScale(nLevels);
+    Mat imagePyramid, maskPyramid;
+    UMat uimagePyramid, ulayerInfo;
+
+    int level_dy = image.rows + border*2;
+    Point level_ofs(0,0);
+    Size bufSize((image.cols + border*2 + 15) & -16, 0);
+
+    for( level = 0; level < nLevels; level++ )
+    {
+        float scale = getScale(level, firstLevel, scaleFactor);
+        layerScale[level] = scale;
+        Size sz(cvRound(image.cols/scale), cvRound(image.rows/scale));
+        Size wholeSize(sz.width + border*2, sz.height + border*2);
+        if( level_ofs.x + wholeSize.width > bufSize.width )
+        {
+            level_ofs = Point(0, level_ofs.y + level_dy);
+            level_dy = wholeSize.height;
+        }
+
+        Rect linfo(level_ofs.x + border, level_ofs.y + border, sz.width, sz.height);
+        layerInfo[level] = linfo;
+        layerOfs[level] = linfo.y*bufSize.width + linfo.x;
+        level_ofs.x += wholeSize.width;
+    }
+    bufSize.height = level_ofs.y + level_dy;
+
+    imagePyramid.create(bufSize, CV_8U);
+    if( !mask.empty() )
+        maskPyramid.create(bufSize, CV_8U);
+
+    Mat prevImg = image, prevMask = mask;
+
     // Pre-compute the scale pyramids
-    std::vector<Mat> imagePyramid(levelsNum), maskPyramid(levelsNum);
-    for (int level = 0; level < levelsNum; ++level)
+    for (level = 0; level < nLevels; ++level)
     {
-        float scale = 1/getScale(level, firstLevel, scaleFactor);
-        Size sz(cvRound(image.cols*scale), cvRound(image.rows*scale));
+        Rect linfo = layerInfo[level];
+        Size sz(linfo.width, linfo.height);
         Size wholeSize(sz.width + border*2, sz.height + border*2);
-        Mat temp(wholeSize, image.type()), masktemp;
-        imagePyramid[level] = temp(Rect(border, border, sz.width, sz.height));
+        Rect wholeLinfo = Rect(linfo.x - border, linfo.y - border, wholeSize.width, wholeSize.height);
+        Mat extImg = imagePyramid(wholeLinfo), extMask;
+        Mat currImg = extImg(Rect(border, border, sz.width, sz.height)), currMask;
 
         if( !mask.empty() )
         {
-            masktemp = Mat(wholeSize, mask.type());
-            maskPyramid[level] = masktemp(Rect(border, border, sz.width, sz.height));
+            extMask = maskPyramid(wholeLinfo);
+            currMask = extMask(Rect(border, border, sz.width, sz.height));
         }
 
         // Compute the resized image
         if( level != firstLevel )
         {
-            if( level < firstLevel )
+            resize(prevImg, currImg, sz, 0, 0, INTER_LINEAR);
+            if( !mask.empty() )
             {
-                resize(image, imagePyramid[level], sz, 0, 0, INTER_LINEAR);
-                if (!mask.empty())
-                    resize(mask, maskPyramid[level], sz, 0, 0, INTER_LINEAR);
-            }
-            else
-            {
-                resize(imagePyramid[level-1], imagePyramid[level], sz, 0, 0, INTER_LINEAR);
-                if (!mask.empty())
-                {
-                    resize(maskPyramid[level-1], maskPyramid[level], sz, 0, 0, INTER_LINEAR);
-                    threshold(maskPyramid[level], maskPyramid[level], 254, 0, THRESH_TOZERO);
-                }
+                resize(prevMask, currMask, sz, 0, 0, INTER_LINEAR);
+                if( level > firstLevel )
+                    threshold(currMask, currMask, 254, 0, THRESH_TOZERO);
             }
 
-            copyMakeBorder(imagePyramid[level], temp, border, border, border, border,
+            copyMakeBorder(currImg, extImg, border, border, border, border,
                            BORDER_REFLECT_101+BORDER_ISOLATED);
             if (!mask.empty())
-                copyMakeBorder(maskPyramid[level], masktemp, border, border, border, border,
+                copyMakeBorder(currMask, extMask, border, border, border, border,
                                BORDER_CONSTANT+BORDER_ISOLATED);
         }
         else
         {
-            copyMakeBorder(image, temp, border, border, border, border,
+            copyMakeBorder(image, extImg, border, border, border, border,
                            BORDER_REFLECT_101);
             if( !mask.empty() )
-                copyMakeBorder(mask, masktemp, border, border, border, border,
+                copyMakeBorder(mask, extMask, border, border, border, border,
                                BORDER_CONSTANT+BORDER_ISOLATED);
         }
+        prevImg = currImg;
+        prevMask = currMask;
     }
 
-    // Pre-compute the keypoints (we keep the best over all scales, so this has to be done beforehand
-    std::vector < std::vector<KeyPoint> > allKeypoints;
+    if( useOCL )
+        copyVectorToUMat(layerOfs, ulayerInfo);
+
     if( do_keypoints )
     {
-        // Get keypoints, those will be far enough from the border that no check will be required for the descriptor
-        computeKeyPoints(imagePyramid, maskPyramid, allKeypoints,
-                         nfeatures, firstLevel, scaleFactor,
-                         edgeThreshold, patchSize, scoreType);
-
-        // make sure we have the right number of keypoints keypoints
-        /*std::vector<KeyPoint> temp;
-
-        for (int level = 0; level < n_levels; ++level)
-        {
-            std::vector<KeyPoint>& keypoints = all_keypoints[level];
-            temp.insert(temp.end(), keypoints.begin(), keypoints.end());
-            keypoints.clear();
-        }
+        if( useOCL )
+            imagePyramid.copyTo(uimagePyramid);
 
-        KeyPoint::retainBest(temp, n_features_);
-
-        for (std::vector<KeyPoint>::iterator keypoint = temp.begin(),
-             keypoint_end = temp.end(); keypoint != keypoint_end; ++keypoint)
-            all_keypoints[keypoint->octave].push_back(*keypoint);*/
+        // Get keypoints, those will be far enough from the border that no check will be required for the descriptor
+        computeKeyPoints(imagePyramid, uimagePyramid, maskPyramid,
+                         layerInfo, ulayerInfo, layerScale, keypoints,
+                         nfeatures, scaleFactor, edgeThreshold, patchSize, scoreType, useOCL);
     }
     else
     {
-        // Remove keypoints very close to the border
-        KeyPointsFilter::runByImageBorder(_keypoints, image.size(), edgeThreshold);
-
-        // Cluster the input keypoints depending on the level they were computed at
-        allKeypoints.resize(levelsNum);
-        for (std::vector<KeyPoint>::iterator keypoint = _keypoints.begin(),
-             keypointEnd = _keypoints.end(); keypoint != keypointEnd; ++keypoint)
-            allKeypoints[keypoint->octave].push_back(*keypoint);
+        KeyPointsFilter::runByImageBorder(keypoints, image.size(), edgeThreshold);
 
-        // Make sure we rescale the coordinates
-        for (int level = 0; level < levelsNum; ++level)
+        if( !sortedByLevel )
         {
-            if (level == firstLevel)
-                continue;
-
-            std::vector<KeyPoint> & keypoints = allKeypoints[level];
-            float scale = 1/getScale(level, firstLevel, scaleFactor);
-            for (std::vector<KeyPoint>::iterator keypoint = keypoints.begin(),
-                 keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
-                keypoint->pt *= scale;
+            std::vector<std::vector<KeyPoint> > allKeypoints(nLevels);
+            nkeypoints = (int)keypoints.size();
+            for( i = 0; i < nkeypoints; i++ )
+            {
+                level = keypoints[i].octave;
+                CV_Assert(0 <= level);
+                allKeypoints[level].push_back(keypoints[i]);
+            }
+            keypoints.clear();
+            for( level = 0; level < nLevels; level++ )
+                std::copy(allKeypoints[level].begin(), allKeypoints[level].end(), std::back_inserter(keypoints));
         }
     }
 
-    Mat descriptors;
-    std::vector<Point> pattern;
-
     if( do_descriptors )
     {
-        int nkeypoints = 0;
-        for (int level = 0; level < levelsNum; ++level)
-            nkeypoints += (int)allKeypoints[level].size();
+        int dsize = descriptorSize();
+
+        nkeypoints = (int)keypoints.size();
         if( nkeypoints == 0 )
-            _descriptors.release();
-        else
         {
-            _descriptors.create(nkeypoints, descriptorSize(), CV_8U);
-            descriptors = _descriptors.getMat();
+            _descriptors.release();
+            return;
         }
 
+        _descriptors.create(nkeypoints, dsize, CV_8U);
+        std::vector<Point> pattern;
+
         const int npoints = 512;
         Point patternbuf[npoints];
         const Point* pattern0 = (const Point*)bit_pattern_31_;
@@ -903,43 +1083,36 @@ void ORB::operator()( InputArray _image, InputArray _mask, std::vector<KeyPoint>
             int ntuples = descriptorSize()*4;
             initializeOrbPattern(pattern0, pattern, ntuples, WTA_K, npoints);
         }
-    }
-
-    _keypoints.clear();
-    int offset = 0;
-    for (int level = 0; level < levelsNum; ++level)
-    {
-        // Get the features and compute their orientation
-        std::vector<KeyPoint>& keypoints = allKeypoints[level];
-        int nkeypoints = (int)keypoints.size();
 
-        // Compute the descriptors
-        if (do_descriptors)
+        for( level = 0; level < nLevels; level++ )
         {
-            Mat desc;
-            if (!descriptors.empty())
-            {
-                desc = descriptors.rowRange(offset, offset + nkeypoints);
-            }
-
-            offset += nkeypoints;
             // preprocess the resized image
-            Mat& workingMat = imagePyramid[level];
+            Mat workingMat = imagePyramid(layerInfo[level]);
+
             //boxFilter(working_mat, working_mat, working_mat.depth(), Size(5,5), Point(-1,-1), true, BORDER_REFLECT_101);
             GaussianBlur(workingMat, workingMat, Size(7, 7), 2, 2, BORDER_REFLECT_101);
-            computeDescriptors(workingMat, keypoints, desc, pattern, descriptorSize(), WTA_K);
         }
 
-        // Copy to the output data
-        if (level != firstLevel)
+        if( useOCL )
+        {
+            imagePyramid.copyTo(uimagePyramid);
+            std::vector<Vec4i> kptbuf;
+            UMat ukeypoints, upattern;
+            copyVectorToUMat(pattern, upattern);
+            uploadORBKeypoints(keypoints, layerScale, kptbuf, ukeypoints);
+
+            UMat udescriptors = _descriptors.getUMat();
+            useOCL = ocl_computeOrbDescriptors(uimagePyramid, ulayerInfo,
+                                               ukeypoints, udescriptors, upattern,
+                                               nkeypoints, dsize, WTA_K);
+        }
+
+        if( !useOCL )
         {
-            float scale = getScale(level, firstLevel, scaleFactor);
-            for (std::vector<KeyPoint>::iterator keypoint = keypoints.begin(),
-                 keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
-                keypoint->pt *= scale;
+            Mat descriptors = _descriptors.getMat();
+            computeOrbDescriptors(imagePyramid, layerInfo, layerScale,
+                                  keypoints, descriptors, pattern, dsize, WTA_K);
         }
-        // And add the keypoints to the output
-        _keypoints.insert(_keypoints.end(), keypoints.begin(), keypoints.end());
     }
 }
 
index a54ae46..156df61 100644 (file)
@@ -9,6 +9,10 @@ ocv_add_module(highgui opencv_imgproc OPTIONAL opencv_androidcamera)
 
 ocv_clear_vars(GRFMT_LIBS)
 
+if(HAVE_WINRT_CX)
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /ZW")
+endif()
+
 if(HAVE_PNG OR HAVE_TIFF OR HAVE_OPENEXR)
   ocv_include_directories(${ZLIB_INCLUDE_DIRS})
   list(APPEND GRFMT_LIBS ${ZLIB_LIBRARIES})
index df52f04..80b17ca 100644 (file)
 #include <wrl/client.h>
 using namespace Microsoft::WRL;
 
+#include <mferror.h>
+
+#ifdef HAVE_WINRT
+#ifdef __cplusplus_winrt
+#include <agile.h>
+#include <vccorlib.h>
+#endif
+
+#include <wrl\async.h>
+#include <wrl\implements.h>
+#include <wrl\module.h>
+#include <wrl\wrappers\corewrappers.h>
+#include <windows.media.capture.h>
+#include <windows.devices.enumeration.h>
+#include <concrt.h>
+#include <ppltasks.h>
+
+using namespace Microsoft::WRL::Wrappers;
+#endif
+
 struct IMFMediaType;
+#ifndef HAVE_WINRT
 struct IMFActivate;
 struct IMFMediaSource;
+#endif
 struct IMFAttributes;
 
 namespace
@@ -105,6 +127,8 @@ private:
     DebugPrintOut(void);
 };
 
+#include "cap_msmf.hpp"
+
 // Structure for collecting info about types of video, which are supported by current video device
 struct MediaType
 {
@@ -171,57 +195,103 @@ private:
     RawImage(unsigned int size);
 };
 
-// Class for grabbing image from video stream
-class ImageGrabber : public IMFSampleGrabberSinkCallback
+class ImageGrabberCallback : public IMFSampleGrabberSinkCallback
 {
 public:
-    ~ImageGrabber(void);
-    HRESULT initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat);
-    HRESULT startGrabbing(void);
     void pauseGrabbing();
     void resumeGrabbing();
-    void stopGrabbing();
     RawImage *getRawImage();
-    // Function of creation of the instance of the class
-    static HRESULT CreateInstance(ImageGrabber **ppIG, unsigned int deviceID, bool synchronous = false);
+    // 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;
-
-private:
+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;
+};
+
+#ifdef HAVE_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
+{
+public:
+    ~ImageGrabber(void);
+    HRESULT initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat);
+    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);
+
+private:
     unsigned int ig_DeviceID;
+
     IMFMediaSource *ig_pSource;
     IMFMediaSession *ig_pSession;
     IMFTopology *ig_pTopology;
-    RawImage *ig_RIFirst;
-    RawImage *ig_RISecond;
-    RawImage *ig_RIOut;
     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);
-    // IUnknown methods
-    STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
-    STDMETHODIMP_(ULONG) AddRef();
-    STDMETHODIMP_(ULONG) Release();
-    // 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();
 };
 
 /// Class for controlling of thread of the grabbing raw data from video device
@@ -298,7 +368,19 @@ public:
     CamParametrs getParametrs();
     void setParametrs(CamParametrs parametrs);
     void setEmergencyStopEvent(void *userData, void(*func)(int, void *));
+#ifdef HAVE_WINRT
+    long readInfoOfDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice, unsigned int Num);
+    void waitForDevice()
+    {
+        if (vd_pAction) {
+            HRESULT hr;
+            DO_ACTION_SYNCHRONOUSLY(hr, vd_pAction, GET_CURRENT_CONTEXT);
+            vd_pAction = nullptr;
+        }
+    }
+#else
     long readInfoOfDevice(IMFActivate *pActivate, unsigned int Num);
+#endif
     wchar_t *getName();
     int getCountFormats();
     unsigned int getWidth();
@@ -329,15 +411,29 @@ private:
     std::map<UINT64, FrameRateMap> vd_CaptureFormats;
     std::vector<MediaType> vd_CurrentFormats;
     IMFMediaSource *vd_pSource;
+#ifdef HAVE_WINRT
+    MAKE_WRL_AGILE_REF(_MediaCapture) vd_pMedCap;
+    IMedCapFailHandler* vd_pMedCapFail;
+    ImageGrabberWinRT *vd_pImGr;
+    MAKE_WRL_REF(_AsyncAction) vd_pAction;
+    Concurrency::critical_section vd_lock;
+#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 HAVE_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);
+    long checkDevice(_DeviceClass devClass, DEFINE_TASK<HRESULT>* pTask, MAKE_WRL_REF(_IDeviceInformation)* ppDevice);
+#else
     long resetDevice(IMFActivate *pActivate);
-    long initDevice();
     long checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice);
+#endif
+    long initDevice();
 };
 
 /// Class for managing of list of video devices
@@ -345,13 +441,27 @@ class videoDevices
 {
 public:
     ~videoDevices(void);
+#ifdef HAVE_WINRT
+    long initDevices(_DeviceClass devClass);
+    void waitInit() {
+        if (vds_enumTask) {
+            HRESULT hr;
+            DO_ACTION_SYNCHRONOUSLY(hr, vds_enumTask, GET_CURRENT_CONTEXT);
+            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 HAVE_WINRT
+    MAKE_WRL_REF(_AsyncAction) vds_enumTask;
+#endif
     std::vector<videoDevice *> vds_Devices;
     videoDevices(void);
 };
@@ -414,6 +524,9 @@ 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 HAVE_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);
@@ -884,12 +997,8 @@ FormatReader::~FormatReader(void)
 
 #define CHECK_HR(x) if (FAILED(x)) { goto done; }
 
-ImageGrabber::ImageGrabber(unsigned int deviceID, bool synchronous):
+ImageGrabberCallback::ImageGrabberCallback(bool synchronous):
     m_cRef(1),
-    ig_DeviceID(deviceID),
-    ig_pSource(NULL),
-    ig_pSession(NULL),
-    ig_pTopology(NULL),
     ig_RIE(true),
     ig_Close(false),
     ig_Synchronous(synchronous),
@@ -898,6 +1007,14 @@ ImageGrabber::ImageGrabber(unsigned int deviceID, bool synchronous):
     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)
@@ -917,9 +1034,158 @@ ImageGrabber::~ImageGrabber(void)
     SafeRelease(&ig_pTopology);
     DebugPrintOut *DPO = &DebugPrintOut::getInstance();
 
-    DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Destroing instance of the ImageGrabber class\n", ig_DeviceID);
+    DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Destroying instance of the ImageGrabber class\n", ig_DeviceID);
+}
+
+#ifdef HAVE_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 *DPO = &DebugPrintOut::getInstance();
+
+    DPO->printOut(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_MEDIA_DEVICE_CONTROLLER(pDevCont, pMedDevCont, hr)
+    if (FAILED(hr)) return hr;
+    MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps;
+    WRL_METHOD(pMedDevCont, GetMediaStreamProperties, pMedEncProps, hr, _VideoPreview)
+    if (FAILED(hr)) return hr;
+    GET_WRL_VIDEO_ENCODING_PROPERTIES(pMedEncProps, pVidProps, hr);
+    if (FAILED(hr)) return hr;
+    ComPtr<IMFMediaType> 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_VIDEO_PREVIEW(DEREF_AGILE_WRL_OBJ(ig_pMedCapSource), imedPrevCap, hr);
+        if (FAILED(hr)) return hr;
+        MAKE_WRL_REF(_AsyncAction) pAction;
+        WRL_METHOD_BASE(imedPrevCap, StopPreviewAsync, pAction, hr)
+        if (SUCCEEDED(hr)) {
+            SAVE_CURRENT_CONTEXT(context);
+            *action = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(pAction, context, this)
+                HRESULT hr;
+                DO_ACTION_SYNCHRONOUSLY(hr, pAction, context);
+                SafeRelease(&ig_pMediaSink);
+                SetEvent(ig_hFinish);
+            END_CREATE_ASYNC(hr));
+        }
+    }
+    return hr;
+}
+
+HRESULT ImageGrabberWinRT::startGrabbing(MAKE_WRL_REF(_AsyncAction)* action)
+{
+    HRESULT hr = S_OK;
+    GET_WRL_VIDEO_PREVIEW(DEREF_AGILE_WRL_OBJ(ig_pMedCapSource), imedPrevCap, hr);
+    if (FAILED(hr)) return hr;
+    ACTIVATE_OBJ(RuntimeClass_Windows_Foundation_Collections_PropertySet, MAKE_WRL_OBJ(_PropertySet), pSet, hr)
+    if (FAILED(hr)) return hr;
+    GET_WRL_MAP(pSet, spSetting, 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)_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_MEDIA_DEVICE_CONTROLLER(pDevCont, pMedDevCont, hr)
+    if (FAILED(hr)) return hr;
+    MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps;
+    WRL_METHOD(pMedDevCont, GetMediaStreamProperties, pMedEncProps, hr, _VideoPreview)
+    if (FAILED(hr)) return hr;
+    GET_WRL_VIDEO_ENCODING_PROPERTIES(pMedEncProps, pVidProps, hr);
+    if (FAILED(hr)) return hr;
+    ACTIVATE_OBJ(RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile, MAKE_WRL_OBJ(_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<MediaSink>().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<MAKE_WRL_REF(_MediaExtension)>(ig_pMediaSink))
+        }
+    }
+    return hr;
+}
+
+HRESULT ImageGrabberWinRT::CreateInstance(ImageGrabberWinRT **ppIG, bool synchronous)
+{
+    *ppIG = Microsoft::WRL::Make<ImageGrabberWinRT>(synchronous).Detach();
+    if (ppIG == NULL)
+    {
+        return E_OUTOFMEMORY;
+    }
+    DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+    DPO->printOut(L"IMAGEGRABBER VIDEODEVICE: Creating instance of ImageGrabberWinRT\n");
+    return S_OK;
+}
+#endif
+
 HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat)
 {
     ComPtr<IMFActivate> pSinkActivate = NULL;
@@ -975,6 +1241,7 @@ err:
     {
         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;
@@ -1003,7 +1270,6 @@ done:
         SafeRelease(&ig_pSession);
         SafeRelease(&ig_pTopology);
     }
-
     return hr;
 }
 
@@ -1017,11 +1283,11 @@ void ImageGrabber::stopGrabbing()
 
 HRESULT ImageGrabber::startGrabbing(void)
 {
+    HRESULT hr = S_OK;
     DebugPrintOut *DPO = &DebugPrintOut::getInstance();
     ComPtr<IMFMediaEvent> pEvent = NULL;
     PROPVARIANT var;
     PropVariantInit(&var);
-    HRESULT hr = S_OK;
     hr = ig_pSession->SetTopology(0, ig_pTopology);
     DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Start Grabbing of the images\n", ig_DeviceID);
     hr = ig_pSession->Start(&GUID_NULL, &var);
@@ -1079,11 +1345,11 @@ done:
     return hr;
 }
 
-void ImageGrabber::pauseGrabbing()
+void ImageGrabberCallback::pauseGrabbing()
 {
 }
 
-void ImageGrabber::resumeGrabbing()
+void ImageGrabberCallback::resumeGrabbing()
 {
 }
 
@@ -1218,45 +1484,45 @@ STDMETHODIMP_(ULONG) ImageGrabber::Release()
     return cRef;
 }
 
-STDMETHODIMP ImageGrabber::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset)
+STDMETHODIMP ImageGrabberCallback::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset)
 {
     (void)hnsSystemTime;
     (void)llClockStartOffset;
     return S_OK;
 }
 
-STDMETHODIMP ImageGrabber::OnClockStop(MFTIME hnsSystemTime)
+STDMETHODIMP ImageGrabberCallback::OnClockStop(MFTIME hnsSystemTime)
 {
     (void)hnsSystemTime;
     return S_OK;
 }
 
-STDMETHODIMP ImageGrabber::OnClockPause(MFTIME hnsSystemTime)
+STDMETHODIMP ImageGrabberCallback::OnClockPause(MFTIME hnsSystemTime)
 {
     (void)hnsSystemTime;
     return S_OK;
 }
 
-STDMETHODIMP ImageGrabber::OnClockRestart(MFTIME hnsSystemTime)
+STDMETHODIMP ImageGrabberCallback::OnClockRestart(MFTIME hnsSystemTime)
 {
     (void)hnsSystemTime;
     return S_OK;
 }
 
-STDMETHODIMP ImageGrabber::OnClockSetRate(MFTIME hnsSystemTime, float flRate)
+STDMETHODIMP ImageGrabberCallback::OnClockSetRate(MFTIME hnsSystemTime, float flRate)
 {
     (void)flRate;
     (void)hnsSystemTime;
     return S_OK;
 }
 
-STDMETHODIMP ImageGrabber::OnSetPresentationClock(IMFPresentationClock* pClock)
+STDMETHODIMP ImageGrabberCallback::OnSetPresentationClock(IMFPresentationClock* pClock)
 {
     (void)pClock;
     return S_OK;
 }
 
-STDMETHODIMP ImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags,
+STDMETHODIMP ImageGrabberCallback::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags,
     LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer,
     DWORD dwSampleSize)
 {
@@ -1298,13 +1564,13 @@ STDMETHODIMP ImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwS
     return S_OK;
 }
 
-STDMETHODIMP ImageGrabber::OnShutdown()
+STDMETHODIMP ImageGrabberCallback::OnShutdown()
 {
     SetEvent(ig_hFinish);
     return S_OK;
 }
 
-RawImage *ImageGrabber::getRawImage()
+RawImage *ImageGrabberCallback::getRawImage()
 {
     return ig_RIOut;
 }
@@ -1330,7 +1596,7 @@ HRESULT ImageGrabberThread::CreateInstance(ImageGrabberThread **ppIGT, IMFMediaS
     return S_OK;
 }
 
-ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID, bool synchronious):
+ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID, bool synchronious) :
     igt_func(NULL),
     igt_Handle(NULL),
     igt_stop(false)
@@ -1352,7 +1618,7 @@ ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int dev
     }
     else
     {
-        DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i There is a problem with creation of the instance of the ImageGrabber class\n", deviceID);
+        DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with creation of the instance of the ImageGrabber class\n", deviceID);
     }
 }
 
@@ -1450,6 +1716,10 @@ Media_Foundation::~Media_Foundation(void)
 bool Media_Foundation::buildListOfDevices()
 {
     HRESULT hr = S_OK;
+#ifdef HAVE_WINRT
+    videoDevices *vDs = &videoDevices::getInstance();
+    hr = vDs->initDevices(_VideoCapture);
+#else
     ComPtr<IMFAttributes> pAttributes = NULL;
     CoInitialize(NULL);
     hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1);
@@ -1465,7 +1735,8 @@ bool Media_Foundation::buildListOfDevices()
         videoDevices *vDs = &videoDevices::getInstance();
         hr = vDs->initDevices(pAttributes.Get());
     }
-    else
+#endif
+    if (FAILED(hr))
     {
        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
        DPO->printOut(L"MEDIA FOUNDATION: The access to the video cameras denied\n");
@@ -1532,8 +1803,14 @@ unsigned char * RawImage::getpPixels()
 }
 
 videoDevice::videoDevice(void): vd_IsSetuped(false), vd_LockOut(OpenLock), vd_pFriendlyName(NULL),
-    vd_Width(0), vd_Height(0), vd_pSource(NULL), vd_func(NULL), vd_userData(NULL)
+    vd_Width(0), vd_Height(0), vd_pSource(NULL), vd_pImGrTh(NULL), vd_func(NULL), vd_userData(NULL)
 {
+#ifdef HAVE_WINRT
+    vd_pMedCap = nullptr;
+    vd_pMedCapFail = NULL;
+    vd_pImGr = NULL;
+    vd_pAction = nullptr;
+#endif
 }
 
 void videoDevice::setParametrs(CamParametrs parametrs)
@@ -1616,13 +1893,60 @@ CamParametrs videoDevice::getParametrs()
     return out;
 }
 
+#ifdef HAVE_WINRT
+long videoDevice::resetDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice)
+#else
 long videoDevice::resetDevice(IMFActivate *pActivate)
+#endif
 {
     HRESULT hr = -1;
     vd_CurrentFormats.clear();
     if(vd_pFriendlyName)
         CoTaskMemFree(vd_pFriendlyName);
     vd_pFriendlyName = NULL;
+#ifdef HAVE_WINRT
+    if (pDevice)
+    {
+        ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCapture, MAKE_WRL_OBJ(_MediaCapture), pIMedCap, hr)
+        if (FAILED(hr)) return hr;
+        ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings, MAKE_WRL_OBJ(_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<HSTRING>(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, _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))
+        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<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(pAction, pOldAction, context, &pAgileMedCap, this)
+           HRESULT hr;
+           if (pOldAction) DO_ACTION_SYNCHRONOUSLY(hr, pOldAction, GET_CURRENT_CONTEXT);
+           DO_ACTION_SYNCHRONOUSLY(hr, pAction, context);
+           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(S_OK)
+           }
+           buildLibraryofTypes();
+           RELEASE_AGILE_WRL(pAgileMedCap)
+        END_CREATE_ASYNC(hr));
+    }
+#else
     if(pActivate)
     {
         IMFMediaSource *pSource = NULL;
@@ -1645,9 +1969,19 @@ long videoDevice::resetDevice(IMFActivate *pActivate)
             DPO->printOut(L"VIDEODEVICE %i: IMFMediaSource interface cannot be created \n", vd_CurrentNumber);
         }
     }
+#endif
     return hr;
 }
 
+#ifdef HAVE_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)
 {
     HRESULT hr = -1;
@@ -1655,7 +1989,44 @@ long videoDevice::readInfoOfDevice(IMFActivate *pActivate, unsigned int Num)
     hr = resetDevice(pActivate);
     return hr;
 }
+#endif
 
+#ifdef HAVE_WINRT
+long videoDevice::checkDevice(_DeviceClass devClass, DEFINE_TASK<HRESULT>* 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<MAKE_WRL_REF(_DeviceInformationCollection)>) pAction;
+    WRL_METHOD(pDevStat, _FindAllAsyncDeviceClass, pAction, hr, devClass)
+    if (SUCCEEDED(hr)) {
+        *pTask = CREATE_TASK([pAction, &ppDevice, this]() -> HRESULT {
+            HRESULT hr;
+            MAKE_WRL_OBJ(_VectorView<MAKE_WRL_REF(_DeviceInformation)>) pVector;
+            DO_OPERATION_SYNCHRONOUSLY_VECTOR(hr, pAction, GET_CURRENT_CONTEXT, pVector, _VectorView, _DeviceInformation, _DeviceInformationCollection);
+            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<HSTRING>(DEREF_WRL_OBJ(str)), &length);
+                        if (wcscmp(wstr, vd_pFriendlyName) == 0) {
+                            *ppDevice = PREPARE_TRANSFER_WRL_OBJ(pDevice);
+                        }
+                    }
+                }
+            }
+            return hr;
+        });
+    }
+    return hr;
+}
+#else
 long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice)
 {
     HRESULT hr = S_OK;
@@ -1714,14 +2085,60 @@ long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice)
     }
     return hr;
 }
+#endif
 
 long videoDevice::initDevice()
 {
-    HRESULT hr = -1;
+    HRESULT hr = S_OK;
+    CoInitialize(NULL);
+#ifdef HAVE_WINRT
+    Concurrency::critical_section::scoped_lock _LockHolder(vd_lock);
+    MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction;
+    SAVE_CURRENT_CONTEXT(context);
+    vd_pAction = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(pOldAction, context, this)
+        HRESULT hr;
+        if (pOldAction) DO_ACTION_SYNCHRONOUSLY(hr, pOldAction, GET_CURRENT_CONTEXT);
+        DEFINE_TASK<HRESULT> pTask;
+        MAKE_WRL_OBJ(_IDeviceInformation) pDevInfo;
+        hr = checkDevice(_VideoCapture, &pTask, REF_WRL_OBJ(pDevInfo));
+        if (SUCCEEDED(hr)) hr = pTask.get();
+        if (SUCCEEDED(hr)) {
+            MAKE_WRL_REF(_AsyncAction) pAction;
+            BEGIN_CALL_IN_CONTEXT(hr, context, pDevInfo, &pAction, context, this)
+                HRESULT hr;
+                ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCapture, MAKE_WRL_OBJ(_MediaCapture), pIMedCap, hr)
+                if (SUCCEEDED(hr)) {
+                    RELEASE_WRL(vd_pMedCap);
+                    vd_pMedCap = PREPARE_TRANSFER_WRL_OBJ(pIMedCap);
+                    ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings, MAKE_WRL_OBJ(_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, _Video, hr)
+                    if (SUCCEEDED(hr)) {
+                        vd_pMedCapFail = create_medcapfailedhandler([this, context](){
+                            HRESULT hr;
+                            BEGIN_CALL_IN_CONTEXT(hr, context, this)
+                                closeDevice();
+                            END_CALL_IN_CONTEXT(S_OK)
+                        });
+                    }
+                    if (SUCCEEDED(hr)) hr = vd_pMedCapFail->AddHandler(reinterpret_cast<ABI::Windows::Media::Capture::IMediaCapture*>(DEREF_AGILE_WRL_OBJ(vd_pMedCap)));
+                    if (SUCCEEDED(hr)) WRL_METHOD(vd_pMedCap, _InitializeWithSettingsAsync, pAction, hr, DEREF_WRL_OBJ(pCapInitSet))
+                }
+            END_CALL_IN_CONTEXT(hr)
+            DO_ACTION_SYNCHRONOUSLY(hr, pAction, context);
+        }
+    END_CREATE_ASYNC(hr));
+#else
+    DebugPrintOut *DPO = &DebugPrintOut::getInstance();
     ComPtr<IMFAttributes> pAttributes = NULL;
     IMFActivate *vd_pActivate = NULL;
-    DebugPrintOut *DPO = &DebugPrintOut::getInstance();
-    CoInitialize(NULL);
     hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1);
     if (SUCCEEDED(hr))
     {
@@ -1754,7 +2171,7 @@ long videoDevice::initDevice()
     {
         DPO->printOut(L"VIDEODEVICE %i: The attribute of video cameras cannot be getting \n", vd_CurrentNumber);
     }
-
+#endif
     return hr;
 }
 
@@ -1768,7 +2185,7 @@ MediaType videoDevice::getFormat(unsigned int id)
 }
 int videoDevice::getCountFormats()
 {
-    return vd_CurrentFormats.size();
+    return (int)vd_CurrentFormats.size();
 }
 void videoDevice::setEmergencyStopEvent(void *userData, void(*func)(int, void *))
 {
@@ -1780,6 +2197,30 @@ void videoDevice::closeDevice()
     if(vd_IsSetuped)
     {
         vd_IsSetuped = false;
+
+#ifdef HAVE_WINRT
+        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);
+            vd_pMedCapFail->RemoveHandler(reinterpret_cast<ABI::Windows::Media::Capture::IMediaCapture*>(DEREF_AGILE_WRL_OBJ(vd_pMedCap)));
+            SafeRelease(&vd_pMedCapFail);
+            vd_pAction = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(action, pOldAction, this)
+                HRESULT hr;
+                if (pOldAction) DO_ACTION_SYNCHRONOUSLY(hr, pOldAction, GET_CURRENT_CONTEXT);
+                DO_ACTION_SYNCHRONOUSLY(hr, action, GET_CURRENT_CONTEXT);
+                RELEASE_WRL(vd_pMedCap)
+                if(vd_LockOut == RawDataLock) {
+                    delete vd_pImGr;
+                }
+                vd_pImGr = NULL;
+                vd_LockOut = OpenLock;
+            END_CREATE_ASYNC(hr));
+            return;
+        }
+#endif
+
         vd_pSource->Stop();
         SafeRelease(&vd_pSource);
         if(vd_LockOut == RawDataLock)
@@ -1884,6 +2325,26 @@ void videoDevice::buildLibraryofTypes()
     }
 }
 
+#ifdef HAVE_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_MEDIA_DEVICE_CONTROLLER(pDevCont, pMedDevCont, hr)
+    if (FAILED(hr)) return hr;
+    MAKE_WRL_OBJ(_VectorView<MAKE_WRL_REF(_MediaEncodingProperties)>) pVector;
+    WRL_METHOD(pMedDevCont, GetAvailableMediaStreamProperties, pVector, hr, _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, _VideoPreview, DEREF_WRL_OBJ(pMedEncProps))
+    return hr;
+}
+#endif
+
 long videoDevice::setDeviceFormat(IMFMediaSource *pSource, unsigned long  dwFormatIndex)
 {
     ComPtr<IMFPresentationDescriptor> pPD = NULL;
@@ -1925,6 +2386,9 @@ bool videoDevice::isDeviceSetup()
 RawImage * videoDevice::getRawImageOut()
 {
     if(!vd_IsSetuped) return NULL;
+#ifdef HAVE_WINRT
+    if(vd_pImGr) return vd_pImGr->getRawImage();
+#endif
     if(vd_pImGrTh)
             return vd_pImGrTh->getImageGrabber()->getRawImage();
     else
@@ -1943,6 +2407,27 @@ bool videoDevice::isFrameNew()
         if(vd_LockOut == OpenLock)
         {
             vd_LockOut = RawDataLock;
+
+            //must already be closed
+#ifdef HAVE_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;
+                }
+                Concurrency::critical_section::scoped_lock _LockHolder(vd_lock);
+                MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction;
+                SAVE_CURRENT_CONTEXT(context);
+                vd_pAction = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(action, pOldAction, context, this)
+                    HRESULT hr;
+                    if (pOldAction) DO_ACTION_SYNCHRONOUSLY(hr, pOldAction, GET_CURRENT_CONTEXT);
+                    DO_ACTION_SYNCHRONOUSLY(hr, action, context);
+                END_CREATE_ASYNC(hr));
+                return true;
+            }
+#endif
             HRESULT hr = ImageGrabberThread::CreateInstance(&vd_pImGrTh, vd_pSource, vd_CurrentNumber);
             if(FAILED(hr))
             {
@@ -1954,6 +2439,10 @@ bool videoDevice::isFrameNew()
             vd_pImGrTh->start();
             return true;
         }
+#ifdef HAVE_WINRT
+        if(vd_pImGr)
+            return vd_pImGr->getRawImage()->isNew();
+#endif
         if(vd_pImGrTh)
             return vd_pImGrTh->getImageGrabber()->getRawImage()->isNew();
     }
@@ -1981,14 +2470,35 @@ bool videoDevice::setupDevice(unsigned int id)
         hr = initDevice();
         if(SUCCEEDED(hr))
         {
+#ifdef HAVE_WINRT
+            Concurrency::critical_section::scoped_lock _LockHolder(vd_lock);
+            MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction;
+            SAVE_CURRENT_CONTEXT(context);
+            vd_pAction = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(pOldAction, context, id, DPO, this)
+                HRESULT hr;
+                if (pOldAction) DO_ACTION_SYNCHRONOUSLY(hr, pOldAction, GET_CURRENT_CONTEXT);
+#endif
             vd_Width = vd_CurrentFormats[id].width;
             vd_Height = vd_CurrentFormats[id].height;
+#ifdef HAVE_WINRT
+            if (DEREF_AGILE_WRL_OBJ(vd_pMedCap)) {
+                MAKE_WRL_REF(_AsyncAction) pAction;
+                BEGIN_CALL_IN_CONTEXT(hr, context, id, &pAction, this)
+                END_CALL_IN_CONTEXT(setDeviceFormat(DEREF_AGILE_WRL_OBJ(vd_pMedCap), (DWORD) id, &pAction))
+                if (SUCCEEDED(hr)) DO_ACTION_SYNCHRONOUSLY(hr, pAction, context);
+            } else
+#endif
             hr = setDeviceFormat(vd_pSource, (DWORD) id);
             vd_IsSetuped = (SUCCEEDED(hr));
             if(vd_IsSetuped)
                 DPO->printOut(L"\n\nVIDEODEVICE %i: Device is setuped \n", vd_CurrentNumber);
             vd_PrevParametrs = getParametrs();
+#ifdef HAVE_WINRT
+            END_CREATE_ASYNC(hr));
+            return true;
+#else
             return vd_IsSetuped;
+#endif
         }
         else
         {
@@ -2017,11 +2527,43 @@ wchar_t *videoDevice::getName()
 videoDevice::~videoDevice(void)
 {
     closeDevice();
+#ifdef HAVE_WINRT
+    RELEASE_WRL(vd_pMedCap)
+#endif
     SafeRelease(&vd_pSource);
     if(vd_pFriendlyName)
         CoTaskMemFree(vd_pFriendlyName);
 }
 
+#ifdef HAVE_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_MEDIA_DEVICE_CONTROLLER(pDevCont, pMedDevCont, hr)
+    if (FAILED(hr)) return hr;
+    MAKE_WRL_OBJ(_VectorView<MAKE_WRL_REF(_MediaEncodingProperties)>) pVector;
+    WRL_METHOD(pMedDevCont, GetAvailableMediaStreamProperties, pVector, hr, _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<IMFMediaType> 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)
 {
     ComPtr<IMFPresentationDescriptor> pPD = NULL;
@@ -2066,7 +2608,11 @@ done:
 }
 
 videoDevices::videoDevices(void): count(0)
-{}
+{
+#ifdef HAVE_WINRT
+    vds_enumTask = nullptr;
+#endif
+}
 
 void videoDevices::clearDevices()
 {
@@ -2094,11 +2640,44 @@ videoDevice * videoDevices::getDevice(unsigned int i)
     return vds_Devices[i];
 }
 
+#ifdef HAVE_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<MAKE_WRL_REF(_DeviceInformationCollection)>) pAction;
+    WRL_METHOD(pDevStat, _FindAllAsyncDeviceClass, pAction, hr, devClass)
+    if (SUCCEEDED(hr)) {
+           SAVE_CURRENT_CONTEXT(context);
+           vds_enumTask = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(pAction, context, this)
+            HRESULT hr;
+            MAKE_WRL_OBJ(_VectorView<MAKE_WRL_REF(_DeviceInformation)>) pVector;
+            DO_OPERATION_SYNCHRONOUSLY_VECTOR(hr, pAction, GET_CURRENT_CONTEXT, pVector, _VectorView, _DeviceInformation, _DeviceInformationCollection);
+            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(S_OK)
+                        vds_Devices.push_back(vd);
+                    }
+                }
+            }
+        END_CREATE_ASYNC(hr));
+    }
+    return hr;
+}
+#else
 long videoDevices::initDevices(IMFAttributes *pAttributes)
 {
     HRESULT hr = S_OK;
-    IMFActivate **ppDevices = NULL;
     clearDevices();
+    IMFActivate **ppDevices = NULL;
     hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
     if (SUCCEEDED(hr))
     {
@@ -2123,10 +2702,11 @@ long videoDevices::initDevices(IMFAttributes *pAttributes)
     }
     return hr;
 }
+#endif
 
 unsigned int videoDevices::getCount()
 {
-    return vds_Devices.size();
+    return (unsigned int)vds_Devices.size();
 }
 
 videoDevices& videoDevices::getInstance()
@@ -2192,7 +2772,7 @@ videoInput::videoInput(void): accessToDevices(false)
     DPO->printOut(L"\n***** VIDEOINPUT LIBRARY - 2013 (Author: Evgeny Pereguda) *****\n\n");
     updateListOfDevices();
     if(!accessToDevices)
-        DPO->printOut(L"INITIALIZATION: Ther is not any suitable video device\n");
+        DPO->printOut(L"INITIALIZATION: There is not any suitable video device\n");
 }
 
 void videoInput::updateListOfDevices()
@@ -2201,7 +2781,7 @@ void videoInput::updateListOfDevices()
     Media_Foundation *MF = &Media_Foundation::getInstance();
     accessToDevices = MF->buildListOfDevices();
     if(!accessToDevices)
-        DPO->printOut(L"UPDATING: Ther is not any suitable video device\n");
+        DPO->printOut(L"UPDATING: There is not any suitable video device\n");
 }
 
 videoInput::~videoInput(void)
@@ -2406,6 +2986,37 @@ bool videoInput::isFrameNew(int deviceID)
     return false;
 }
 
+#ifdef HAVE_WINRT
+void videoInput::waitForDevice(int deviceID)
+{
+    DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+    if (deviceID < 0)
+    {
+        DPO->printOut(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
+    {
+        DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
+    }
+    return;
+}
+#endif
+
 unsigned int videoInput::getCountFormats(int deviceID)
 {
     DebugPrintOut *DPO = &DebugPrintOut::getInstance();
@@ -2573,6 +3184,9 @@ unsigned int videoInput::listDevices(bool silent)
     if(accessToDevices)
     {
         videoDevices *VDS = &videoDevices::getInstance();
+#ifdef HAVE_WINRT
+        VDS->waitInit();
+#endif
         out = VDS->getCount();
         DebugPrintOut *DPO = &DebugPrintOut::getInstance();
         if(!silent)DPO->printOut(L"\nVIDEOINPUT SPY MODE!\n\n");
@@ -2762,6 +3376,10 @@ protected:
     int index, width, height, fourcc;
     IplImage* frame;
     videoInput VI;
+#ifdef HAVE_WINRT
+    DEFINE_TASK<bool> openTask;
+    Concurrency::critical_section lock;
+#endif
 };
 
 struct SuppressVideoInputMessages
@@ -2802,6 +3420,10 @@ void CvCaptureCAM_MSMF::close()
 // Initialize camera input
 bool CvCaptureCAM_MSMF::open( int _index )
 {
+#ifdef HAVE_WINRT
+    SAVE_CURRENT_CONTEXT(context);
+    auto func = [_index, context, this]() -> bool {
+#endif
     int try_index = _index;
     int devices = 0;
     close();
@@ -2809,10 +3431,31 @@ 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 HAVE_WINRT
+    HRESULT hr;
+    BEGIN_CALL_IN_CONTEXT(hr, context, this, try_index)
+#endif
     VI.setupDevice(try_index);
+#ifdef HAVE_WINRT
+    END_CALL_IN_CONTEXT(S_OK)
+    VI.waitForDevice(try_index);
+    BEGIN_CALL_IN_CONTEXT(hr, context, this, try_index)
+    HRESULT hr = S_OK;
+#endif
     if( !VI.isFrameNew(try_index) )
+#ifdef HAVE_WINRT
+        hr = E_FAIL;
+#else
         return false;
+#endif
     index = try_index;
+#ifdef HAVE_WINRT
+    END_CALL_IN_CONTEXT(hr);
+    return true;
+    };
+    Concurrency::critical_section::scoped_lock _LockHolder(lock);
+    CREATE_OR_CONTINUE_TASK(openTask, bool, func)
+#endif
     return true;
 }
 
@@ -2928,7 +3571,7 @@ bool CvCaptureFile_MSMF::open(const char* filename)
         return false;
 
     wchar_t* unicodeFileName = new wchar_t[strlen(filename)+1];
-    MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, strlen(filename)+1);
+    MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, (int)strlen(filename)+1);
 
     HRESULT hr = S_OK;
 
@@ -3351,7 +3994,7 @@ HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename)
     spAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true);
 
     wchar_t* unicodeFileName = new wchar_t[strlen(filename)+1];
-    MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, strlen(filename)+1);
+    MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, (int)strlen(filename)+1);
 
     HRESULT hr = MFCreateSinkWriterFromURL(unicodeFileName, NULL, spAttr.Get(), &sinkWriter);
 
diff --git a/modules/highgui/src/cap_msmf.hpp b/modules/highgui/src/cap_msmf.hpp
new file mode 100644 (file)
index 0000000..f755fd7
--- /dev/null
@@ -0,0 +1,3187 @@
+#ifdef HAVE_WINRT
+#define ICustomStreamSink StreamSink
+#include "ppltasks_winrt.h"
+#else
+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;
+};
+#endif
+
+#define MF_PROP_SAMPLEGRABBERCALLBACK L"samplegrabbercallback"
+#define MF_PROP_VIDTYPE L"vidtype"
+#define MF_PROP_VIDENCPROPS L"videncprops"
+
+#include <initguid.h>
+
+// 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 <utility>
+#ifdef _UNICODE
+#define MAKE_MAP(e) std::map<e, std::wstring>
+#define MAKE_ENUM(e) std::pair<e, std::wstring>
+#define MAKE_ENUM_PAIR(e, str) std::pair<e, std::wstring>(str, L#str)
+#else
+#define MAKE_MAP(e) std::map<e, std::string>
+#define MAKE_ENUM(e) std::pair<e, std::string>
+#define MAKE_ENUM_PAIR(e, str) std::pair<e, std::string>(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),
+    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),
+    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),
+    MAKE_ENUM_PAIR(MediaEventType, MEByteStreamCharacteristicsChanged),
+    MAKE_ENUM_PAIR(MediaEventType, MEVideoCaptureDeviceRemoved),
+    MAKE_ENUM_PAIR(MediaEventType, MEVideoCaptureDevicePreempted),
+    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]));
+
+#ifdef HAVE_WINRT
+
+#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 _DeviceInformationCollection Windows::Devices::Enumeration::DeviceInformationCollection
+#define _MediaCapture Windows::Media::Capture::MediaCapture
+#define _MediaCaptureInitializationSettings Windows::Media::Capture::MediaCaptureInitializationSettings
+#define _VideoDeviceController Windows::Media::Devices::VideoDeviceController
+#define _MediaEncodingProperties Windows::Media::MediaProperties::IMediaEncodingProperties
+#define _VideoPreview Windows::Media::Capture::MediaStreamType::VideoPreview
+#define _AsyncAction Windows::Foundation::IAsyncAction
+#define _AsyncOperation Windows::Foundation::IAsyncOperation
+#define _DeviceClass Windows::Devices::Enumeration::DeviceClass
+#define _VideoCapture Windows::Devices::Enumeration::DeviceClass::VideoCapture
+#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 _Video Windows::Media::Capture::StreamingCaptureMode::Video
+#define _PropertySet 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 _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 DO_ACTION_SYNCHRONOUSLY(hr, action, ctxt) hr = S_OK;\
+    CCompletionHandler::PerformActionSynchronously(reinterpret_cast<Windows::Foundation::IAsyncAction^>(action), ctxt)
+#define DO_OPERATION_SYNCHRONOUSLY_VECTOR(hr, action, ctxt, pResult, vectortype, elementtype, _type) hr = S_OK;\
+    pResult = CCompletionHandler::PerformSynchronously<_type^>(reinterpret_cast<Windows::Foundation::IAsyncOperation<_type^>^>(action), ctxt)
+#define BEGIN_CREATE_ASYNC(...) reinterpret_cast<ABI::Windows::Foundation::IAsyncAction*>(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<rettype>()) ? Concurrency::create_task(func) : _task.then([func](rettype) -> rettype { return func(); });
+#define MAKE_WRL_OBJ(x) x^
+#define MAKE_WRL_REF(x) x^
+#define MAKE_WRL_AGILE_REF(x) Platform::Agile<x^>
+#define RELEASE_AGILE_WRL(x) x = nullptr;
+#define RELEASE_WRL(x) x = nullptr;
+#define GET_WRL_VIDEO_PREVIEW(medCap, prevMedCap, hr) Windows::Media::Capture::MediaCapture^ prevMedCap = medCap;\
+    hr = S_OK;
+#define GET_WRL_MEDIA_DEVICE_CONTROLLER(devCont, medDevCont, hr) Windows::Media::Devices::VideoDeviceController^ medDevCont = devCont;\
+    hr = S_OK;
+#define GET_WRL_VIDEO_ENCODING_PROPERTIES(encProp, vidEncProp, hr) Windows::Media::MediaProperties::VideoEncodingProperties^ vidEncProp = safe_cast<Windows::Media::MediaProperties::VideoEncodingProperties^>(encProp);\
+    hr = S_OK;
+#define GET_WRL_MAP(pSet, map, hr) Windows::Foundation::Collections::PropertySet^ map = pSet;\
+    hr = S_OK;
+#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 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<type*>(obj)
+#define PREPARE_TRANSFER_WRL_OBJ(obj) obj
+#define ACTIVATE_OBJ(rtclass, objtype, obj, hr) objtype obj;\
+    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<IInspectable>
+#define _String HSTRING
+#define _StringObj HString
+#define _StringReference HStringReference
+#define _DeviceInformationCollection ABI::Windows::Devices::Enumeration::DeviceInformationCollection
+#define _MediaCapture ABI::Windows::Media::Capture::IMediaCapture
+#define _MediaCaptureInitializationSettings ABI::Windows::Media::Capture::IMediaCaptureInitializationSettings
+#define _VideoDeviceController ABI::Windows::Media::Devices::IVideoDeviceController
+#define _MediaEncodingProperties ABI::Windows::Media::MediaProperties::IMediaEncodingProperties
+#define _VideoPreview ABI::Windows::Media::Capture::MediaStreamType::MediaStreamType_VideoPreview
+#define _AsyncAction ABI::Windows::Foundation::IAsyncAction
+#define _AsyncOperation ABI::Windows::Foundation::IAsyncOperation
+#define _DeviceClass ABI::Windows::Devices::Enumeration::DeviceClass
+#define _VideoCapture ABI::Windows::Devices::Enumeration::DeviceClass::DeviceClass_VideoCapture
+#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 _Video ABI::Windows::Media::Capture::StreamingCaptureMode::StreamingCaptureMode_Video
+#define _PropertySet ABI::Windows::Foundation::Collections::IPropertySet
+#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 _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 DO_ACTION_SYNCHRONOUSLY(hr, action, ctxt) hr = CCompletionHandler<ABI::Windows::Foundation::IAsyncActionCompletedHandler, ABI::Windows::Foundation::IAsyncAction>::PerformActionSynchronously(action, ctxt)
+#define DO_OPERATION_SYNCHRONOUSLY_VECTOR(hr, action, ctxt, pResult, vectortype, elementtype, _type) hr = CCompletionHandler<ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_type*>, ABI::Windows::Foundation::IAsyncOperation<_type*>>::PerformSynchronously<vectortype<elementtype*>*>(action, ctxt, pResult.GetAddressOf())
+#define BEGIN_CREATE_ASYNC(...) 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<rettype>()) ? Concurrency_winrt::create_task(func) : _task.then([func](rettype) -> rettype { return func(); });
+#define MAKE_WRL_OBJ(x) Microsoft::WRL::ComPtr<x>
+#define MAKE_WRL_REF(x) x*
+#define MAKE_WRL_AGILE_REF(x) x*
+#define RELEASE_AGILE_WRL(x) if (x) { (x)->Release(); x = nullptr; }
+#define RELEASE_WRL(x) if (x) { (x)->Release(); x = nullptr; }
+#define GET_WRL_VIDEO_PREVIEW(medCap, prevMedCap, hr) Microsoft::WRL::ComPtr<ABI::Windows::Media::Capture::IMediaCaptureVideoPreview> prevMedCap;\
+    hr = medCap->QueryInterface(__uuidof(ABI::Windows::Media::Capture::IMediaCaptureVideoPreview), &prevMedCap);
+#define GET_WRL_MEDIA_DEVICE_CONTROLLER(devCont, medDevCont, hr) Microsoft::WRL::ComPtr<ABI::Windows::Media::Devices::IMediaDeviceController> medDevCont;\
+    hr = devCont.As(&medDevCont);
+#define GET_WRL_VIDEO_ENCODING_PROPERTIES(encProp, vidEncProp, hr) Microsoft::WRL::ComPtr<ABI::Windows::Media::MediaProperties::IVideoEncodingProperties> vidEncProp;\
+    hr = encProp.As(&vidEncProp);
+#define GET_WRL_MAP(pSet, map, hr) Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable *>> map;\
+    hr = pSet.As(&map);
+#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 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_OBJ(rtclass, objtype, obj, hr) objtype obj;\
+{\
+    Microsoft::WRL::ComPtr<IActivationFactory> objFactory;\
+    hr = Windows::Foundation::GetActivationFactory(HStringReference(rtclass).Get(), objFactory.ReleaseAndGetAddressOf());\
+    if (SUCCEEDED(hr)) {\
+        Microsoft::WRL::ComPtr<IInspectable> 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<IActivationFactory> objFactory;\
+    hr = Windows::Foundation::GetActivationFactory(HStringReference(rtclass).Get(), objFactory.ReleaseAndGetAddressOf());\
+    if (SUCCEEDED(hr)) {\
+        if (SUCCEEDED(hr)) hr = objFactory.As(&obj);\
+    }\
+}
+#endif
+
+#define GET_CURRENT_CONTEXT _ContextCallback::_CaptureCurrent()
+#define SAVE_CURRENT_CONTEXT(var) _ContextCallback var = GET_CURRENT_CONTEXT
+
+#ifdef __cplusplus_winrt
+ref class CCompletionHandler sealed
+#else
+template <typename TCompletionHandler, typename TAction>
+class CCompletionHandler
+    : public Microsoft::WRL::RuntimeClass<
+    Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::ClassicCom>,
+    TCompletionHandler, IAgileObject, FtmBase>
+#endif
+{
+#ifndef __cplusplus_winrt
+public:
+    CCompletionHandler() {}
+
+    STDMETHODIMP Invoke(TAction* /*asyncInfo*/, AsyncStatus /*asyncStatus*/)
+    {
+        m_Event.set();
+        return S_OK;
+    }
+    void wait() { m_Event.wait(); }
+#endif
+#ifdef __cplusplus_winrt
+internal:
+    template <typename TResult>
+    static TResult PerformSynchronously(Windows::Foundation::IAsyncOperation<TResult>^ asyncOp, _ContextCallback context)
+    {
+        TResult pResult;
+        context._CallInContext([asyncOp, &pResult]() { Concurrency::task<TResult> asyncTask = Concurrency::task<TResult>(asyncOp); pResult = asyncTask.get(); });
+        return pResult;
+#else
+    template <typename TResult>
+    static HRESULT PerformSynchronously(TAction* asyncOp, _ContextCallback context, TResult* pResult)
+    {
+        HRESULT hr;
+        ComPtr<CCompletionHandler<TCompletionHandler, TAction>> completeHandler = Microsoft::WRL::Make<CCompletionHandler<TCompletionHandler, TAction>>();
+        hr = context._CallInContext([&asyncOp, &completeHandler]() -> HRESULT {
+            HRESULT hr = asyncOp->put_Completed(completeHandler.Get());
+            if (FAILED(hr)) asyncOp->Release();
+            return hr;
+        });
+        if (SUCCEEDED(hr))
+            completeHandler->wait();
+        else
+            return hr;
+        hr = context._CallInContext([&asyncOp, &pResult]() -> HRESULT {
+            HRESULT hr = asyncOp->GetResults(pResult);
+            asyncOp->Release();
+            return hr;
+        });
+        return hr;
+#endif
+    }
+
+#ifdef __cplusplus_winrt
+    static void PerformActionSynchronously(Windows::Foundation::IAsyncAction^ asyncOp, _ContextCallback context)
+    {
+        context._CallInContext([asyncOp](){ Concurrency::task<void>(asyncOp).get(); });
+#else
+    static HRESULT PerformActionSynchronously(TAction* asyncOp, _ContextCallback context)
+    {
+        HRESULT hr;
+        ComPtr<CCompletionHandler<TCompletionHandler, TAction>> completeHandler = Microsoft::WRL::Make<CCompletionHandler<TCompletionHandler, TAction>>();
+        hr = context._CallInContext([&asyncOp, &completeHandler]() -> HRESULT {
+            HRESULT hr = asyncOp->put_Completed(completeHandler.Get());
+            if (FAILED(hr)) asyncOp->Release();
+            return hr;
+        });
+        if (SUCCEEDED(hr))
+            completeHandler->wait();
+        else
+            return hr;
+        hr = context._CallInContext([&asyncOp]() -> HRESULT {
+            HRESULT hr = asyncOp->GetResults();
+            asyncOp->Release();
+            return hr;
+        });
+        return hr;
+#endif
+    }
+#ifndef __cplusplus_winrt
+private:
+    Concurrency::event m_Event;
+#endif
+};
+
+#ifndef __cplusplus_winrt
+
+// Helpers for create_async validation
+//
+// A parameter lambda taking no arguments is valid
+template<typename _Ty>
+static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int) -> typename decltype(_Param(), std::true_type());
+
+// A parameter lambda taking an cancellation_token argument is valid
+template<typename _Ty>
+static auto _IsValidCreateAsync(_Ty _Param, int, int, int, ...) -> typename decltype(_Param(cancellation_token::none()), std::true_type());
+
+// A parameter lambda taking a progress report argument is valid
+template<typename _Ty>
+static auto _IsValidCreateAsync(_Ty _Param, int, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType()), std::true_type());
+
+// A parameter lambda taking a progress report and a cancellation_token argument is valid
+template<typename _Ty>
+static auto _IsValidCreateAsync(_Ty _Param, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType(), cancellation_token::none()), std::true_type());
+
+// All else is invalid
+template<typename _Ty>
+static std::false_type _IsValidCreateAsync(_Ty _Param, ...);
+
+//for task specific architecture
+//could add a CancelPending which is set when Cancel is called, return as Cancel when get_Status is called and set when a task_canceled exception is thrown
+
+extern const __declspec(selectany) WCHAR RuntimeClass_CV_CAsyncAction[] = L"cv.CAsyncAction";
+
+template<typename _Function>
+class CAsyncAction
+    : public Microsoft::WRL::RuntimeClass<
+    Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRt>,
+    Microsoft::WRL::Implements<ABI::Windows::Foundation::IAsyncAction>, Microsoft::WRL::AsyncBase<ABI::Windows::Foundation::IAsyncActionCompletedHandler >>
+{
+    InspectableClass(RuntimeClass_CV_CAsyncAction, BaseTrust)
+public:
+    STDMETHOD(RuntimeClassInitialize)() { return S_OK; }
+    virtual ~CAsyncAction() {}
+    CAsyncAction(const _Function &_Func) : _M_func(_Func) {
+        Start();
+    }
+    void _SetTaskCreationAddressHint(void* _SourceAddressHint)
+    {
+        if (!(std::is_same<Concurrency_winrt::details::_TaskTypeTraits<Concurrency_winrt::task<HRESULT>>::_AsyncKind, Concurrency_winrt::details::_TypeSelectorAsyncTask>::value))
+        {
+            // Overwrite the creation address with the return address of create_async unless the
+            // lambda returned a task. If the create async lambda returns a task, that task is reused and
+            // we want to preserve its creation address hint.
+            _M_task._SetTaskCreationAddressHint(_SourceAddressHint);
+        }
+    }
+    HRESULT STDMETHODCALLTYPE put_Completed(
+        /* [in] */ __RPC__in_opt ABI::Windows::Foundation::IAsyncActionCompletedHandler *handler)
+    {
+        HRESULT hr;
+        if (SUCCEEDED(hr = PutOnComplete(handler)) && cCallbackMade_ == 0) {
+            //okay to use default implementation even for the callback as already running in context
+            //otherwise check for the alternate case and save the context
+            _M_completeDelegateContext = _ContextCallback::_CaptureCurrent();
+        }
+        return hr;
+    }
+    HRESULT STDMETHODCALLTYPE get_Completed(
+        /* [out][retval] */ __RPC__deref_out_opt ABI::Windows::Foundation::IAsyncActionCompletedHandler **handler) {
+        if (!handler) return E_POINTER;
+        return GetOnComplete(handler);
+    }
+    HRESULT STDMETHODCALLTYPE GetResults(void) {
+        HRESULT hr = CheckValidStateForResultsCall();
+        if (SUCCEEDED(hr)) {
+            _M_task.get();
+        }
+        return hr;
+    }
+    HRESULT OnStart() {
+        _M_task = Concurrency_winrt::task<HRESULT>(_M_func, _M_cts.get_token());
+        AddRef();
+        _M_task.then([this](Concurrency_winrt::task<HRESULT> _Antecedent) {
+            try {
+                HRESULT hr = _Antecedent.get();
+                if (FAILED(hr)) TryTransitionToError(hr);
+            }
+            catch (Concurrency::task_canceled&){
+            }
+            catch (...) {
+                TryTransitionToError(E_FAIL);
+            }
+            _FireCompletion();
+            Release();
+        });
+        return S_OK;
+    }
+    void OnClose() {}
+    void OnCancel() { _M_cts.cancel(); }
+
+protected:
+    //modified for _CallInContext to support UI STA thread
+    //can wrap the base clase implementation or duplicate it but must use get_Completed to fetch the private member variable
+    virtual void _FireCompletion()
+    {
+        AddRef();
+        _M_completeDelegateContext._CallInContext([this]() -> HRESULT {
+            FireCompletion();
+            Release();
+            return S_OK;
+        });
+    }
+private:
+
+    _Function _M_func;
+    Concurrency_winrt::task<HRESULT> _M_task;
+    Concurrency::cancellation_token_source _M_cts;
+    _ContextCallback        _M_completeDelegateContext;
+};
+
+template<typename _Function>
+__declspec(noinline)
+CAsyncAction<_Function>* create_async(const _Function& _Func)
+{
+    static_assert(std::is_same<decltype(_IsValidCreateAsync(_Func, 0, 0, 0, 0)), std::true_type>::value,
+        "argument to create_async must be a callable object taking zero, one or two arguments");
+    CAsyncAction<_Function>* action = Microsoft::WRL::Make<CAsyncAction<_Function>>(_Func).Detach();
+    action->_SetTaskCreationAddressHint(_ReturnAddress());
+    return action;
+}
+#endif
+
+EXTERN_C const IID IID_IMedCapFailHandler;
+
+class DECLSPEC_UUID("CE22BEDB-0B3C-4BE0-BE8F-E53AB457EA2C") DECLSPEC_NOVTABLE IMedCapFailHandler : public IUnknown
+{
+public:
+    virtual HRESULT AddHandler(ABI::Windows::Media::Capture::IMediaCapture* pMedCap) = 0;
+    virtual HRESULT RemoveHandler(ABI::Windows::Media::Capture::IMediaCapture* pMedCap) = 0;
+};
+
+template<typename _Function>
+class MediaCaptureFailedHandler :
+    public Microsoft::WRL::RuntimeClass<
+    Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::ClassicCom>,
+    IMedCapFailHandler, ABI::Windows::Media::Capture::IMediaCaptureFailedEventHandler, IAgileObject, FtmBase>
+{
+public:
+    MediaCaptureFailedHandler(const _Function &_Func) : _M_func(_Func) { m_cookie.value = 0; }
+    HRESULT AddHandler(ABI::Windows::Media::Capture::IMediaCapture* pMedCap)
+    {
+        return pMedCap->add_Failed(this, &m_cookie);
+    }
+    HRESULT RemoveHandler(ABI::Windows::Media::Capture::IMediaCapture* pMedCap)
+    {
+        return pMedCap->remove_Failed(m_cookie);
+    }
+    HRESULT STDMETHODCALLTYPE Invoke(
+        ABI::Windows::Media::Capture::IMediaCapture *sender,
+        ABI::Windows::Media::Capture::IMediaCaptureFailedEventArgs *errorEventArgs)
+    {
+        (void)sender;
+        (void)errorEventArgs;
+        AddRef();
+        _M_func();
+        Release();
+        return S_OK;
+    }
+
+private:
+    _Function _M_func;
+    EventRegistrationToken m_cookie;
+};
+
+template<typename _Function>
+__declspec(noinline)
+MediaCaptureFailedHandler<_Function>* create_medcapfailedhandler(const _Function& _Func)
+{
+    return Microsoft::WRL::Make<MediaCaptureFailedHandler<_Function>>(_Func).Detach();
+}
+
+#endif
+
+template <class TBase=IMFAttributes>
+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<IMFAttributes> _spAttributes;
+};
+
+class StreamSink :
+#ifdef HAVE_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
+    STDMETHOD(QueryInterface)(REFIID riid, _Outptr_result_nullonfailure_ void **ppv)
+    {
+        if (ppv == nullptr) {
+            return E_POINTER;
+        }
+        (*ppv) = nullptr;
+        HRESULT hr = S_OK;
+        if (riid == IID_IMarshal) {
+            return MarshalQI(riid, ppv);
+        } else {
+#ifdef HAVE_WINRT
+            hr = RuntimeClassT::QueryInterface(riid, ppv);
+#else
+            if (riid == IID_IUnknown || riid == IID_IMFStreamSink) {
+                *ppv = static_cast<IMFStreamSink*>(this);
+                AddRef();
+            } else if (riid == IID_IMFMediaEventGenerator) {
+                *ppv = static_cast<IMFMediaEventGenerator*>(this);
+                AddRef();
+            } else if (riid == IID_IMFMediaTypeHandler) {
+                *ppv = static_cast<IMFMediaTypeHandler*>(this);
+                AddRef();
+            } else if (riid == IID_IMFAttributes) {
+                *ppv = static_cast<IMFAttributes*>(this);
+                AddRef();
+            } else if (riid == IID_ICustomStreamSink) {
+                *ppv = static_cast<ICustomStreamSink*>(this);
+                AddRef();
+            } else
+                hr = E_NOINTERFACE;
+#endif
+        }
+
+        return hr;
+    }
+
+#ifdef HAVE_WINRT
+    STDMETHOD(RuntimeClassInitialize)() { return S_OK; }
+#else
+    ULONG AddRef()
+    {
+        return InterlockedIncrement(&m_cRef);
+    }
+    ULONG Release()
+    {
+        ULONG cRef = InterlockedDecrement(&m_cRef);
+        if (cRef == 0)
+        {
+            delete this;
+        }
+        return cRef;
+    }
+#endif
+    HRESULT MarshalQI(REFIID riid, LPVOID* ppv)
+    {
+        HRESULT hr = S_OK;
+        if (m_spFTM == nullptr) {
+            EnterCriticalSection(&m_critSec);
+            if (m_spFTM == nullptr) {
+                hr = CoCreateFreeThreadedMarshaler(static_cast<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) {
+#ifdef HAVE_WINRT
+        m_token.value = 0;
+#else
+        m_bConnected = false;
+#endif
+        InitializeCriticalSectionEx(&m_critSec, 3000, 0);
+        ZeroMemory(&m_guiCurrentSubtype, sizeof(m_guiCurrentSubtype));
+        CBaseAttributes::Initialize(0U);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"StreamSink::StreamSink\n");
+    }
+    virtual ~StreamSink() {
+        DeleteCriticalSection(&m_critSec);
+        assert(m_IsShutdown);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"StreamSink::~StreamSink\n");
+    }
+
+    HRESULT Initialize()
+    {
+        HRESULT hr;
+        // Create the event queue helper.
+        hr = MFCreateEventQueue(&m_spEventQueue);
+        if (SUCCEEDED(hr))
+        {
+            ComPtr<IMFMediaSink> 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)
+    {
+        EnterCriticalSection(&m_critSec);
+
+        HRESULT hr = S_OK;
+
+        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<IMFSampleGrabberSinkCallback> 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<IMFMediaSink> pMedSink;
+            hr = CBaseAttributes<>::GetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, __uuidof(IMFMediaSink), (LPVOID*)pMedSink.GetAddressOf());
+            if (SUCCEEDED(hr)) {
+                *ppMediaSink = pMedSink.Detach();
+            }
+        }
+
+        LeaveCriticalSection(&m_critSec);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"StreamSink::GetMediaTypeHandler: HRESULT=%i\n", hr);
+        return hr;
+    }
+
+    HRESULT STDMETHODCALLTYPE ProcessSample(IMFSample *pSample) {
+        ComPtr<IMFMediaBuffer> pInput;
+        ComPtr<IMFSampleGrabberSinkCallback> 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*/) {
+        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))
+        {
+            hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL);
+        }
+
+        LeaveCriticalSection(&m_critSec);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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<IMFMediaEventQueue> 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;
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        if (SUCCEEDED(hr))
+            hr = (*ppEvent)->GetStatus(&hrStatus);
+        if (SUCCEEDED(hr))
+            DPO->printOut(L"StreamSink::GetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str());
+        else
+            DPO->printOut(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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        HRESULT hrStatus = S_OK;
+        if (SUCCEEDED(hr))
+            hr = (*ppEvent)->GetStatus(&hrStatus);
+        if (SUCCEEDED(hr))
+            DPO->printOut(L"StreamSink::EndGetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str());
+        else
+            DPO->printOut(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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"StreamSink::QueueEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(met).c_str());
+        DPO->printOut(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;
+            }
+        }
+        if (ppMediaType)
+        {
+            *ppMediaType = nullptr;
+        }
+
+        if (ppMediaType && SUCCEEDED(hr)) {
+            ComPtr<IMFMediaType> 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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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<IMFMediaType> 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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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))
+        {
+            GUID guiMajorType;
+            pMediaType->GetMajorType(&guiMajorType);
+
+            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);
+            }
+            if (SUCCEEDED(hr)) {
+                hr = MFGetAttributeSize(m_spCurrentType.Get(), MF_MT_FRAME_SIZE, &m_imageWidthInPixels, &m_imageHeightInPixels);
+            }
+            if (SUCCEEDED(hr))
+            {
+                m_state = State_Ready;
+            }
+        }
+
+        LeaveCriticalSection(&m_critSec);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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<IMFMediaType> pType;
+        hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType);
+        if (SUCCEEDED(hr)) {
+            hr = pType->GetMajorType(pguidMajorType);
+        }
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"StreamSink::GetMajorType: HRESULT=%i\n", hr);
+        return hr;
+    }
+private:
+#ifdef HAVE_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 HAVE_WINRT
+    long m_cRef;
+#endif
+    IMFAttributes*        m_pParent;
+    ComPtr<IMFMediaType>        m_spCurrentType;
+    ComPtr<IMFMediaEventQueue>  m_spEventQueue;              // Event queue
+
+    ComPtr<IUnknown>            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<T>::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 <class T>
+struct NoOp
+{
+    void operator()(T& /*t*/)
+    {
+    }
+};
+
+template <class T>
+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<T>;
+
+    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 <class FN>
+    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<T> 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<Node*>(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<IUnknown>
+//
+// 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 T, bool NULLABLE = FALSE>
+class ComPtrList : public List<T*>
+{
+public:
+
+    typedef T* Ptr;
+
+    void Clear()
+    {
+        ComAutoRelease car;
+        List<Ptr>::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<Ptr>::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<Ptr>::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<Ptr>::RemoveItem(pNode, &pItem);
+
+        if (SUCCEEDED(hr))
+        {
+            assert(pItem || NULLABLE);
+            if (ppItem && pItem)
+            {
+                *ppItem = pItem;
+                (*ppItem)->AddRef();
+            }
+
+            if (pItem)
+            {
+                pItem->Release();
+                pItem = nullptr;
+            }
+        }
+
+        return hr;
+    }
+};
+
+/* 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
+    (highgui needs DLL activation class factoryentry points):
+  <Extensions>
+    <Extension Category="windows.activatableClass.inProcessServer">
+      <InProcessServer>
+        <Path>modulename</Path>
+        <ActivatableClass ActivatableClassId="cv.MediaSink" ThreadingModel="both" />
+      </InProcessServer>
+    </Extension>
+  </Extensions>*/
+
+extern const __declspec(selectany) WCHAR RuntimeClass_CV_MediaSink[] = L"cv.MediaSink";
+
+class MediaSink :
+#ifdef HAVE_WINRT
+    public Microsoft::WRL::RuntimeClass<
+    Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >,
+    Microsoft::WRL::Implements<ABI::Windows::Media::IMediaExtension>,
+    IMFMediaSink,
+    IMFClockStateSink,
+    FtmBase,
+    CBaseAttributes<>>
+#else
+    public IMFMediaSink, public IMFClockStateSink, public CBaseAttributes<>
+#endif
+{
+#ifdef HAVE_WINRT
+    InspectableClass(RuntimeClass_CV_MediaSink, BaseTrust)
+public:
+#else
+public:
+    ULONG AddRef()
+    {
+        return InterlockedIncrement(&m_cRef);
+    }
+    ULONG Release()
+    {
+        ULONG cRef = InterlockedDecrement(&m_cRef);
+        if (cRef == 0)
+        {
+            delete this;
+        }
+        return cRef;
+    }
+    STDMETHOD(QueryInterface)(REFIID riid, _Outptr_result_nullonfailure_ void **ppv)
+    {
+        if (ppv == nullptr) {
+            return E_POINTER;
+        }
+        (*ppv) = nullptr;
+        HRESULT hr = S_OK;
+        if (riid == IID_IUnknown ||
+            riid == IID_IMFMediaSink) {
+            (*ppv) = static_cast<IMFMediaSink*>(this);
+            AddRef();
+        } else if (riid == IID_IMFClockStateSink) {
+            (*ppv) = static_cast<IMFClockStateSink*>(this);
+            AddRef();
+        } else if (riid == IID_IMFAttributes) {
+            (*ppv) = static_cast<IMFAttributes*>(this);
+            AddRef();
+        } else {
+            hr = E_NOINTERFACE;
+        }
+
+        return hr;
+    }
+#endif
+    MediaSink() : m_IsShutdown(false), m_llStartTime(0) {
+        CBaseAttributes<>::Initialize(0U);
+        InitializeCriticalSectionEx(&m_critSec, 3000, 0);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"MediaSink::MediaSink\n");
+    }
+
+    virtual ~MediaSink() {
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"MediaSink::~MediaSink\n");
+        DeleteCriticalSection(&m_critSec);
+        assert(m_IsShutdown);
+    }
+    HRESULT CheckShutdown() const
+    {
+        if (m_IsShutdown)
+        {
+            return MF_E_SHUTDOWN;
+        }
+        else
+        {
+            return S_OK;
+        }
+    }
+#ifdef HAVE_WINRT
+    STDMETHODIMP SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration)
+    {
+        HRESULT hr = S_OK;
+        if (pConfiguration) {
+            Microsoft::WRL::ComPtr<IInspectable> spInsp;
+            Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable *>> spSetting;
+            Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValue> spPropVal;
+            ComPtr<ABI::Windows::Media::MediaProperties::IMediaEncodingProperties> 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(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(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(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:
+            {
+                                                                  HSTRING value;
+                                                                  hr = pValue->GetString(&value);
+                                                                  if (SUCCEEDED(hr))
+                                                                  {
+                                                                      UINT32 len = 0;
+                                                                      LPCWSTR szValue = WindowsGetStringRawBuffer(value, &len);
+                                                                      hr = pAttr->SetString(guidKey, szValue);
+                                                                      WindowsDeleteString(value);
+                                                                  }
+            }
+                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:
+            {
+                                                                       ComPtr<IInspectable> 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<IMFMediaType> spMT;
+        ComPtr<ABI::Windows::Foundation::Collections::IMap<GUID, IInspectable*>> spMap;
+        ComPtr<ABI::Windows::Foundation::Collections::IIterable<ABI::Windows::Foundation::Collections::IKeyValuePair<GUID, IInspectable*>*>> spIterable;
+        ComPtr<ABI::Windows::Foundation::Collections::IIterator<ABI::Windows::Foundation::Collections::IKeyValuePair<GUID, IInspectable*>*>> spIterator;
+
+        if (pMEP == nullptr || ppMT == nullptr)
+        {
+            return E_INVALIDARG;
+        }
+        *ppMT = nullptr;
+
+        hr = pMEP->get_Properties(&spMap);
+
+        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)
+        {
+            ComPtr<ABI::Windows::Foundation::Collections::IKeyValuePair<GUID, IInspectable*> > spKeyValuePair;
+            ComPtr<IInspectable> spValue;
+            ComPtr<ABI::Windows::Foundation::IPropertyValue> 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))
+        {
+            ComPtr<IInspectable> spValue;
+            ComPtr<ABI::Windows::Foundation::IPropertyValue> 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;
+    }
+    HRESULT SetMediaStreamProperties(
+        ABI::Windows::Media::Capture::MediaStreamType MediaStreamType,
+        _In_opt_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties *mediaEncodingProperties)
+    {
+        HRESULT hr = S_OK;
+        ComPtr<IMFMediaType> 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<IMFStreamSink> 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) {
+        HRESULT hr;
+        if (pdwCharacteristics == NULL) return E_INVALIDARG;
+        EnterCriticalSection(&m_critSec);
+        if (SUCCEEDED(hr = CheckShutdown())) {
+            *pdwCharacteristics = MEDIASINK_FIXED_STREAMS;
+        }
+        LeaveCriticalSection(&m_critSec);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"MediaSink::GetCharacteristics: HRESULT=%i\n", hr);
+        return S_OK;
+    }
+
+    HRESULT STDMETHODCALLTYPE AddStreamSink(
+        DWORD dwStreamSinkIdentifier, IMFMediaType * /*pMediaType*/, IMFStreamSink **ppStreamSink) {
+        ComPtr<IMFStreamSink> spMFStream;
+        ComPtr<ICustomStreamSink> 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))
+        {
+#ifdef HAVE_WINRT
+            pStream = Microsoft::WRL::Make<StreamSink>();
+            if (pStream == nullptr) {
+                hr = E_OUTOFMEMORY;
+            }
+            if (SUCCEEDED(hr))
+                hr = pStream.As<IMFStreamSink>(&spMFStream);
+#else
+            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;
+            }
+#endif
+        }
+
+        // Initialize the stream.
+        ComPtr<IMFAttributes> 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<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
+            ComPtrList<IMFStreamSink>::POSITION posEnd = m_streams.EndPosition();
+
+            // Insert in proper position
+            for (; pos != posEnd; pos = m_streams.Next(pos))
+            {
+                DWORD dwCurrId;
+                ComPtr<IMFStreamSink> 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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"MediaSink::AddStreamSink: HRESULT=%i\n", hr);
+        return hr;
+    }
+
+    HRESULT STDMETHODCALLTYPE RemoveStreamSink(DWORD dwStreamSinkIdentifier) {
+        EnterCriticalSection(&m_critSec);
+        HRESULT hr = CheckShutdown();
+        ComPtrList<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
+        ComPtrList<IMFStreamSink>::POSITION endPos = m_streams.EndPosition();
+        ComPtr<IMFStreamSink> 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);
+            static_cast<StreamSink *>(spStream.Get())->Shutdown();
+        }
+        LeaveCriticalSection(&m_critSec);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"MediaSink::GetStreamSinkCount: HRESULT=%i\n", hr);
+        return hr;
+    }
+
+    HRESULT STDMETHODCALLTYPE GetStreamSinkByIndex(
+        DWORD dwIndex, IMFStreamSink **ppStreamSink) {
+        if (ppStreamSink == NULL)
+        {
+            return E_INVALIDARG;
+        }
+
+        ComPtr<IMFStreamSink> spStream;
+        EnterCriticalSection(&m_critSec);
+        DWORD cStreams = m_streams.GetCount();
+
+        if (dwIndex >= cStreams)
+        {
+            return MF_E_INVALIDINDEX;
+        }
+
+        HRESULT hr = CheckShutdown();
+
+        if (SUCCEEDED(hr))
+        {
+            ComPtrList<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
+            ComPtrList<IMFStreamSink>::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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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<IMFStreamSink> spResult;
+
+        if (SUCCEEDED(hr))
+        {
+            ComPtrList<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
+            ComPtrList<IMFStreamSink>::POSITION endPos = m_streams.EndPosition();
+
+            for (; pos != endPos; pos = m_streams.Next(pos))
+            {
+                ComPtr<IMFStreamSink> 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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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<IMFSampleGrabberSinkCallback> 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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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 == NULL) {
+                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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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();
+
+            hr = DeleteItem(MF_MEDIASINK_PREFERREDTYPE);
+            m_IsShutdown = true;
+        }
+
+        LeaveCriticalSection(&m_critSec);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"MediaSink::Shutdown: HRESULT=%i\n", hr);
+        return hr;
+    }
+    class ShutdownFunc
+    {
+    public:
+        HRESULT operator()(IMFStreamSink *pStream) const
+        {
+            static_cast<StreamSink *>(pStream)->Shutdown();
+            return S_OK;
+        }
+    };
+
+    class StartFunc
+    {
+    public:
+        StartFunc(LONGLONG llStartTime)
+            : _llStartTime(llStartTime)
+        {
+        }
+
+        HRESULT operator()(IMFStreamSink *pStream) const
+        {
+            return static_cast<StreamSink *>(pStream)->Start(_llStartTime);
+        }
+
+        LONGLONG _llStartTime;
+    };
+
+    class StopFunc
+    {
+    public:
+        HRESULT operator()(IMFStreamSink *pStream) const
+        {
+            return static_cast<StreamSink *>(pStream)->Stop();
+        }
+    };
+
+    template <class T, class TFunc>
+    HRESULT ForEach(ComPtrList<T> &col, TFunc fn)
+    {
+        ComPtrList<T>::POSITION pos = col.FrontPosition();
+        ComPtrList<T>::POSITION endPos = col.EndPosition();
+        HRESULT hr = S_OK;
+
+        for (; pos != endPos; pos = col.Next(pos))
+        {
+            ComPtr<T> 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<IMFSampleGrabberSinkCallback> 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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(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<IMFSampleGrabberSinkCallback> 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 *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"MediaSink::OnClockStop: HRESULT=%i\n", hr);
+        return hr;
+    }
+
+    HRESULT STDMETHODCALLTYPE OnClockPause(
+        MFTIME hnsSystemTime) {
+        HRESULT hr;
+        ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
+        hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
+        if (SUCCEEDED(hr))
+            hr = pSampleCallback->OnClockPause(hnsSystemTime);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"MediaSink::OnClockPause: HRESULT=%i\n", hr);
+        return hr;
+    }
+
+    HRESULT STDMETHODCALLTYPE OnClockRestart(
+        MFTIME hnsSystemTime) {
+           HRESULT hr;
+        ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
+        hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
+        if (SUCCEEDED(hr))
+            hr = pSampleCallback->OnClockRestart(hnsSystemTime);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"MediaSink::OnClockRestart: HRESULT=%i\n", hr);
+        return hr;
+    }
+
+    HRESULT STDMETHODCALLTYPE OnClockSetRate(
+        MFTIME hnsSystemTime,
+        float flRate) {
+           HRESULT hr;
+        ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
+        hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
+        if (SUCCEEDED(hr))
+            hr = pSampleCallback->OnClockSetRate(hnsSystemTime, flRate);
+        DebugPrintOut *DPO = &DebugPrintOut::getInstance();
+        DPO->printOut(L"MediaSink::OnClockSetRate: HRESULT=%i\n", hr);
+        return hr;
+    }
+private:
+#ifndef HAVE_WINRT
+    long m_cRef;
+#endif
+    CRITICAL_SECTION            m_critSec;
+    bool                        m_IsShutdown;
+    ComPtrList<IMFStreamSink>    m_streams;
+    ComPtr<IMFPresentationClock>    m_spClock;
+    LONGLONG                        m_llStartTime;
+};
+
+#ifdef HAVE_WINRT
+ActivatableClass(MediaSink);
+#endif
diff --git a/modules/highgui/src/ppltasks_winrt.h b/modules/highgui/src/ppltasks_winrt.h
new file mode 100644 (file)
index 0000000..8cf91a3
--- /dev/null
@@ -0,0 +1,6326 @@
+/***
+* ==++==
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+*
+* Modified for native C++ WRL support by Gregory Morse
+*
+* ==--==
+* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*
+* ppltasks_winrt.h
+*
+* Parallel Patterns Library - PPL Tasks
+*
+* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+****/
+
+#pragma once
+
+#include <concrt.h>
+#include <ppltasks.h>
+#include <ppl.h>
+#include <functional>
+#include <vector>
+#include <utility>
+#include <exception>
+
+#ifndef __cplusplus_winrt
+
+#include <wrl\implements.h>
+#include <wrl\async.h>
+#include <windows.foundation.h>
+#include <ctxtcall.h>
+#include <comdef.h>
+
+#ifndef _UITHREADCTXT_SUPPORT
+
+#ifdef WINAPI_FAMILY
+
+// It is safe to include winapifamily as WINAPI_FAMILY was defined by the user
+#include <winapifamily.h>
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_APP /*IFSTRIP=IGN*/
+    // UI thread context support is not required for desktop and Windows Store apps
+    #define _UITHREADCTXT_SUPPORT 0
+#elif WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP /*IFSTRIP=IGN*/
+    // UI thread context support is not required for desktop and Windows Store apps
+    #define _UITHREADCTXT_SUPPORT 0
+#else
+    #define _UITHREADCTXT_SUPPORT 1
+#endif
+
+#else
+    // Not supported without a WINAPI_FAMILY setting.
+    #define _UITHREADCTXT_SUPPORT 0
+#endif // #ifdef WINAPI_FAMILY
+
+#endif // #ifndef _UITHREADCTXT_SUPPORT
+
+#if _UITHREADCTXT_SUPPORT
+#include <uithreadctxt.h>
+#endif // _UITHREADCTXT_SUPPORT
+
+#pragma detect_mismatch("_PPLTASKS_WITH_WINRT", "0")
+#pragma pack(push,_CRT_PACKING)
+
+#pragma warning(push)
+#pragma warning(disable: 28197)
+#pragma warning(disable: 4100) // Unreferenced formal parameter - needed for document generation
+#pragma warning(disable: 4702) // Unreachable code - it is caused by user lambda throw exceptions
+
+// All CRT public header files are required to be protected from the macro new
+#pragma push_macro("new")
+#undef new
+
+#define __is_valid_winrt_type(_Type) (std::is_void<_Type>::value || \
+    std::is_same<_Type, BYTE>::value || \
+    std::is_same<_Type, INT16>::value || \
+    std::is_same<_Type, UINT16>::value || \
+    std::is_same<_Type, INT32>::value || \
+    std::is_same<_Type, UINT32>::value || \
+    std::is_same<_Type, INT64>::value || \
+    std::is_same<_Type, UINT64>::value || \
+    std::is_same<_Type, FLOAT>::value || \
+    std::is_same<_Type, DOUBLE>::value || \
+    std::is_same<_Type, WCHAR>::value || \
+    std::is_same<_Type, boolean>::value || \
+    std::is_same<_Type, HSTRING>::value || \
+    std::is_same<_Type, IInspectable *>::value || \
+    std::is_same<_Type, GUID>::value || \
+    std::is_same<_Type, ABI::Windows::Foundation::DateTime>::value || \
+    std::is_same<_Type, ABI::Windows::Foundation::TimeSpan>::value || \
+    std::is_same<_Type, ABI::Windows::Foundation::Point>::value || \
+    std::is_same<_Type, ABI::Windows::Foundation::Size>::value || \
+    std::is_same<_Type, ABI::Windows::Foundation::Rect>::value || \
+    std::is_same<_Type, BYTE*>::value || \
+    std::is_same<_Type, INT16*>::value || \
+    std::is_same<_Type, UINT16*>::value || \
+    std::is_same<_Type, INT32*>::value || \
+    std::is_same<_Type, UINT32*>::value || \
+    std::is_same<_Type, INT64*>::value || \
+    std::is_same<_Type, UINT64*>::value || \
+    std::is_same<_Type, FLOAT*>::value || \
+    std::is_same<_Type, DOUBLE*>::value || \
+    std::is_same<_Type, WCHAR*>::value || \
+    std::is_same<_Type, boolean*>::value || \
+    std::is_same<_Type, HSTRING*>::value || \
+    std::is_same<_Type, IInspectable **>::value || \
+    std::is_same<_Type, GUID*>::value || \
+    std::is_same<_Type, ABI::Windows::Foundation::DateTime*>::value || \
+    std::is_same<_Type, ABI::Windows::Foundation::TimeSpan*>::value || \
+    std::is_same<_Type, ABI::Windows::Foundation::Point*>::value || \
+    std::is_same<_Type, ABI::Windows::Foundation::Size*>::value || \
+    std::is_same<_Type, ABI::Windows::Foundation::Rect*>::value)
+
+/// <summary>
+///     The <c>Concurrency_winrt</c> namespace provides classes and functions that give you access to the Concurrency Runtime,
+///     a concurrent programming framework for C++. For more information, see <see cref="Concurrency Runtime"/>.
+/// </summary>
+/**/
+namespace Concurrency_winrt
+{
+/// <summary>
+///     A type that represents the terminal state of a task. Valid values are <c>completed</c> and <c>canceled</c>.
+/// </summary>
+/// <seealso cref="task Class"/>
+/**/
+typedef Concurrency::task_group_status task_status;
+
+template <typename _Type> class task;
+template <> class task<void>;
+
+/// <summary>
+///     Returns an indication of whether the task that is currently executing has received a request to cancel its
+///     execution. Cancellation is requested on a task if the task was created with a cancellation token, and
+///     the token source associated with that token is canceled.
+/// </summary>
+/// <returns>
+///     <c>true</c> if the currently executing task has received a request for cancellation, <c>false</c> otherwise.
+/// </returns>
+/// <remarks>
+///     If you call this method in the body of a task and it returns <c>true</c>, you must respond with a call to
+///     <see cref="cancel_current_task Function">cancel_current_task</see> to acknowledge the cancellation request,
+///     after performing any cleanup you need. This will abort the execution of the task and cause it to enter into
+///     the <c>canceled</c> state. If you do not respond and continue execution, or return instead of calling
+///     <c>cancel_current_task</c>, the task will enter the <c>completed</c> state when it is done.
+///     state.
+///     <para>A task is not cancellable if it was created without a cancellation token.</para>
+/// </remarks>
+/// <seealso cref="task Class"/>
+/// <seealso cref="cancellation_token_source Class"/>
+/// <seealso cref="cancellation_token Class"/>
+/// <seealso cref="cancel_current_task Function"/>
+/**/
+_CRTIMP2 bool __cdecl is_task_cancellation_requested();
+
+/// <summary>
+///     Cancels the currently executing task. This function can be called from within the body of a task to abort the
+///     task's execution and cause it to enter the <c>canceled</c> state. While it may be used in response to
+///     the <see cref="is_task_cancellation_requested Function">is_task_cancellation_requested</see> function, you may
+///     also use it by itself, to initiate cancellation of the task that is currently executing.
+///     <para>It is not a supported scenario to call this function if you are not within the body of a <c>task</c>.
+///     Doing so will result in undefined behavior such as a crash or a hang in your application.</para>
+/// </summary>
+/// <seealso cref="task Class"/>
+/// <seealso cref="is_task_cancellation_requested"/>
+/**/
+_CRTIMP2 __declspec(noreturn) void __cdecl cancel_current_task();
+
+namespace details
+{
+    typedef UINT32 _Unit_type;
+
+    struct _TypeSelectorNoAsync {};
+    struct _TypeSelectorAsyncOperationOrTask {};
+    struct _TypeSelectorAsyncOperation : public _TypeSelectorAsyncOperationOrTask { };
+    struct _TypeSelectorAsyncTask : public _TypeSelectorAsyncOperationOrTask { };
+    struct _TypeSelectorAsyncAction {};
+    struct _TypeSelectorAsyncActionWithProgress {};
+    struct _TypeSelectorAsyncOperationWithProgress {};
+
+    template<typename _Ty>
+    struct _NormalizeVoidToUnitType
+    {
+        typedef _Ty _Type;
+    };
+
+    template<>
+    struct _NormalizeVoidToUnitType<void>
+    {
+        typedef _Unit_type _Type;
+    };
+
+    template<typename _T>
+    struct _IsUnwrappedAsyncSelector
+    {
+        static const bool _Value = true;
+    };
+
+    template<>
+    struct _IsUnwrappedAsyncSelector<_TypeSelectorNoAsync>
+    {
+        static const bool _Value = false;
+    };
+
+    template <typename _Ty>
+    struct _UnwrapTaskType
+    {
+        typedef _Ty _Type;
+    };
+
+    template <typename _Ty>
+    struct _UnwrapTaskType<task<_Ty>>
+    {
+        typedef _Ty _Type;
+    };
+
+    template <typename _T>
+    _TypeSelectorAsyncTask _AsyncOperationKindSelector(task<_T>);
+
+    _TypeSelectorNoAsync _AsyncOperationKindSelector(...);
+
+    template <typename _Type>
+    struct _Unhat
+    {
+        typedef _Type _Value;
+    };
+
+    template <typename _Type>
+    struct _Unhat<_Type*>
+    {
+        typedef _Type _Value;
+    };
+
+    struct _NonUserType { public: int _Dummy; };
+
+    template <typename _Type, bool _IsValueTypeOrRefType = __is_valid_winrt_type(_Type)>
+    struct _ValueTypeOrRefType
+    {
+        typedef _NonUserType _Value;
+    };
+
+    template <typename _Type>
+    struct _ValueTypeOrRefType<_Type, true>
+    {
+        typedef _Type _Value;
+    };
+
+    template <typename _T1, typename _T2>
+    _T2 _ProgressTypeSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*);
+
+    template <typename _T1>
+    _T1 _ProgressTypeSelector(ABI::Windows::Foundation::IAsyncActionWithProgress<_T1>*);
+
+    template <typename _Type>
+    struct _GetProgressType
+    {
+        typedef decltype(_ProgressTypeSelector(std::declval<_Type>())) _Value;
+    };
+
+    template <template <typename> class F>
+    struct conversion_tester
+    {
+        template <typename T>
+        conversion_tester(const F<T> &);
+    };
+
+    template <template <typename, typename> class F>
+    struct conversion_tester2
+    {
+        template <typename T0, typename T1>
+        conversion_tester2(const F<T0, T1> &);
+    };
+
+    template <class From, template <typename> class To>
+    struct is_instance_of
+    {
+        static const bool value = std::is_convertible<From, conversion_tester<To>>::value;
+    };
+
+    template <class From, template <typename, typename> class To>
+    struct is_instance_of2
+    {
+        static const bool value = std::is_convertible<From, conversion_tester2<To>>::value;
+    };
+
+    template <typename _Type>
+    struct _IsIAsyncInfo
+    {
+        static const bool _Value = std::is_same<ABI::Windows::Foundation::IAsyncAction*, typename _Unhat<_Type>::_Value>::value ||
+            is_instance_of<_Type, ABI::Windows::Foundation::IAsyncOperation>::value ||
+            is_instance_of2<_Type, ABI::Windows::Foundation::IAsyncOperationWithProgress>::value ||
+            is_instance_of<_Type, ABI::Windows::Foundation::IAsyncActionWithProgress>::value;
+    };
+
+    template <typename _T>
+    _TypeSelectorAsyncOperation _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperation<_T>*);
+
+    _TypeSelectorAsyncAction _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncAction*);
+
+    template <typename _T1, typename _T2>
+    _TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*);
+
+    template <typename _T>
+    _TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncActionWithProgress<_T>*);
+
+    template <typename _T>
+    _T _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperation<_T>*);
+
+    void _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncAction*);
+
+    template <typename _T1, typename _T2>
+    _T1 _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*);
+
+    template <typename _T>
+    void _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncActionWithProgress<_T>*);
+
+    class _ProgressReporterCtorArgType{};
+
+    template <typename _Type, bool _IsAsync = _IsIAsyncInfo<_Type>::_Value>
+    struct _TaskTypeTraits
+    {
+        typedef typename details::_UnwrapTaskType<_Type>::_Type _TaskRetType;
+        typedef decltype(_AsyncOperationKindSelector(std::declval<_Type>())) _AsyncKind;
+        typedef typename details::_NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType;
+
+        static const bool _IsAsyncTask = _IsAsync;
+        static const bool _IsUnwrappedTaskOrAsync = details::_IsUnwrappedAsyncSelector<_AsyncKind>::_Value;
+    };
+
+    template<typename _Type>
+    struct _TaskTypeTraits<_Type, true>
+    {
+        typedef decltype(_ReturnAsyncOperationKindSelector(std::declval<_Type>())) _TaskRetType;
+        typedef _TaskRetType _NormalizedTaskRetType;
+        typedef decltype(std::is_same<_Type, ABI::Windows::Foundation::IAsyncAction*>::value ? _TypeSelectorAsyncAction : _AsyncOperationKindSelector((_Type)nullptr)) _AsyncKind;
+
+        static const bool _IsAsyncTask = true;
+        static const bool _IsUnwrappedTaskOrAsync = details::_IsUnwrappedAsyncSelector<_AsyncKind>::_Value;
+    };
+
+    template <typename _Function> auto _IsCallable(_Function _Func, int) -> decltype(_Func(), std::true_type()) { (void)_Func; return std::true_type(); }
+    template <typename _Function> std::false_type _IsCallable(_Function, ...) { return std::false_type(); }
+
+    template <>
+    struct _TaskTypeTraits<void>
+    {
+        typedef void _TaskRetType;
+        typedef _TypeSelectorNoAsync _AsyncKind;
+        typedef _Unit_type _NormalizedTaskRetType;
+
+        static const bool _IsAsyncTask = false;
+        static const bool _IsUnwrappedTaskOrAsync = false;
+    };
+
+    template<typename _Type>
+    task<_Type> _To_task(_Type t);
+
+    task<void> _To_task();
+
+    struct _BadContinuationParamType{};
+
+    template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)));
+    template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, ...) -> decltype(_Func(t));
+    template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, ...)->_BadContinuationParamType;
+
+    template <typename _Function, typename _Type> auto _IsTaskHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)), std::true_type());
+    template <typename _Function, typename _Type> std::false_type _IsTaskHelper(_Type t, _Function _Func, int, ...);
+
+    template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, int) -> decltype(_Func(_To_task()));
+    template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, ...) -> decltype(_Func());
+
+    template <typename _Function> auto _VoidIsTaskHelper(_Function _Func, int, int) -> decltype(_Func(_To_task()), std::true_type());
+    template <typename _Function> std::false_type _VoidIsTaskHelper(_Function _Func, int, ...);
+
+    template<typename _Function, typename _ExpectedParameterType>
+    struct _FunctionTypeTraits
+    {
+        typedef decltype(_ReturnTypeHelper(std::declval<_ExpectedParameterType>(), std::declval<_Function>(), 0, 0)) _FuncRetType;
+        static_assert(!std::is_same<_FuncRetType, _BadContinuationParamType>::value, "incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below)");
+
+        typedef decltype(_IsTaskHelper(std::declval<_ExpectedParameterType>(), std::declval<_Function>(), 0, 0)) _Takes_task;
+    };
+
+    template<typename _Function>
+    struct _FunctionTypeTraits<_Function, void>
+    {
+        typedef decltype(_VoidReturnTypeHelper(std::declval<_Function>(), 0, 0)) _FuncRetType;
+        typedef decltype(_VoidIsTaskHelper(std::declval<_Function>(), 0, 0)) _Takes_task;
+    };
+
+    template<typename _Function, typename _ReturnType>
+    struct _ContinuationTypeTraits
+    {
+        typedef typename task<typename _TaskTypeTraits<typename _FunctionTypeTraits<_Function, _ReturnType>::_FuncRetType>::_TaskRetType> _TaskOfType;
+    };
+
+    // _InitFunctorTypeTraits is used to decide whether a task constructed with a lambda should be unwrapped. Depending on how the variable is
+    // declared, the constructor may or may not perform unwrapping. For eg.
+    //
+    //  This declaration SHOULD NOT cause unwrapping
+    //    task<task<void>> t1([]() -> task<void> {
+    //        task<void> t2([]() {});
+    //        return t2;
+    //    });
+    //
+    // This declaration SHOULD cause unwrapping
+    //    task<void>> t1([]() -> task<void> {
+    //        task<void> t2([]() {});
+    //        return t2;
+    //    });
+    // If the type of the task is the same as the return type of the function, no unwrapping should take place. Else normal rules apply.
+    template <typename _TaskType, typename _FuncRetType>
+    struct _InitFunctorTypeTraits
+    {
+        typedef typename _TaskTypeTraits<_FuncRetType>::_AsyncKind _AsyncKind;
+        static const bool _IsAsyncTask = _TaskTypeTraits<_FuncRetType>::_IsAsyncTask;
+        static const bool _IsUnwrappedTaskOrAsync = _TaskTypeTraits<_FuncRetType>::_IsUnwrappedTaskOrAsync;
+    };
+
+    template<typename T>
+    struct _InitFunctorTypeTraits<T, T>
+    {
+        typedef _TypeSelectorNoAsync _AsyncKind;
+        static const bool _IsAsyncTask = false;
+        static const bool _IsUnwrappedTaskOrAsync = false;
+    };
+    /// <summary>
+    ///     Helper object used for LWT invocation.
+    /// </summary>
+    struct _TaskProcThunk
+    {
+        _TaskProcThunk(const std::function<void()> & _Callback) :
+        _M_func(_Callback)
+        {
+        }
+
+        static void _Bridge(void *_PData)
+        {
+            _TaskProcThunk *_PThunk = reinterpret_cast<_TaskProcThunk *>(_PData);
+            _PThunk->_M_func();
+            delete _PThunk;
+        }
+    private:
+        std::function<void()> _M_func;
+        _TaskProcThunk& operator=(const _TaskProcThunk&);
+    };
+
+    /// <summary>
+    ///     Schedule a functor with automatic inlining. Note that this is "fire and forget" scheduling, which cannot be
+    ///     waited on or canceled after scheduling.
+    ///     This schedule method will perform automatic inlining base on <paramref value="_InliningMode"/>.
+    /// </summary>
+    /// <param name="_Func">
+    ///     The user functor need to be scheduled.
+    /// </param>
+    /// <param name="_InliningMode">
+    ///     The inlining scheduling policy for current functor.
+    /// </param>
+    static void _ScheduleFuncWithAutoInline(const std::function<void()> & _Func, Concurrency::details::_TaskInliningMode _InliningMode)
+    {
+        Concurrency::details::_StackGuard _Guard;
+        if (_Guard._ShouldInline(_InliningMode))
+        {
+            _Func();
+        }
+        else
+        {
+            Concurrency::details::_CurrentScheduler::_ScheduleTask(reinterpret_cast<Concurrency::TaskProc>(&_TaskProcThunk::_Bridge), new _TaskProcThunk(_Func));
+        }
+    }
+    class _ContextCallback
+    {
+        typedef std::function<HRESULT(void)> _CallbackFunction;
+
+    public:
+
+        static _ContextCallback _CaptureCurrent()
+        {
+            _ContextCallback _Context;
+            _Context._Capture();
+            return _Context;
+        }
+
+        ~_ContextCallback()
+        {
+            _Reset();
+        }
+
+        _ContextCallback(bool _DeferCapture = false)
+        {
+            if (_DeferCapture)
+            {
+                _M_context._M_captureMethod = _S_captureDeferred;
+            }
+            else
+            {
+                _M_context._M_pContextCallback = nullptr;
+            }
+        }
+
+        // Resolves a context that was created as _S_captureDeferred based on the environment (ancestor, current context).
+        void _Resolve(bool _CaptureCurrent)
+        {
+            if (_M_context._M_captureMethod == _S_captureDeferred)
+            {
+                _M_context._M_pContextCallback = nullptr;
+
+                if (_CaptureCurrent)
+                {
+                    if (_IsCurrentOriginSTA())
+                    {
+                        _Capture();
+                    }
+#if _UITHREADCTXT_SUPPORT
+                    else
+                    {
+                        // This method will fail if not called from the UI thread.
+                        HRESULT _Hr = CaptureUiThreadContext(&_M_context._M_pContextCallback);
+                        if (FAILED(_Hr))
+                        {
+                            _M_context._M_pContextCallback = nullptr;
+                        }
+                    }
+#endif // _UITHREADCTXT_SUPPORT
+                }
+            }
+        }
+
+        void _Capture()
+        {
+            HRESULT _Hr = CoGetObjectContext(IID_IContextCallback, reinterpret_cast<void **>(&_M_context._M_pContextCallback));
+            if (FAILED(_Hr))
+            {
+                _M_context._M_pContextCallback = nullptr;
+            }
+        }
+
+        _ContextCallback(const _ContextCallback& _Src)
+        {
+            _Assign(_Src._M_context._M_pContextCallback);
+        }
+
+        _ContextCallback(_ContextCallback&& _Src)
+        {
+            _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;
+            _Src._M_context._M_pContextCallback = nullptr;
+        }
+
+        _ContextCallback& operator=(const _ContextCallback& _Src)
+        {
+            if (this != &_Src)
+            {
+                _Reset();
+                _Assign(_Src._M_context._M_pContextCallback);
+            }
+            return *this;
+        }
+
+        _ContextCallback& operator=(_ContextCallback&& _Src)
+        {
+            if (this != &_Src)
+            {
+                _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;
+                _Src._M_context._M_pContextCallback = nullptr;
+            }
+            return *this;
+        }
+
+        bool _HasCapturedContext() const
+        {
+            _CONCRT_ASSERT(_M_context._M_captureMethod != _S_captureDeferred);
+            return (_M_context._M_pContextCallback != nullptr);
+        }
+
+        HRESULT _CallInContext(_CallbackFunction _Func) const
+        {
+            if (!_HasCapturedContext())
+            {
+                _Func();
+            }
+            else
+            {
+                ComCallData callData;
+                ZeroMemory(&callData, sizeof(callData));
+                callData.pUserDefined = reinterpret_cast<void *>(&_Func);
+
+                HRESULT _Hr = _M_context._M_pContextCallback->ContextCallback(&_Bridge, &callData, IID_ICallbackWithNoReentrancyToApplicationSTA, 5, nullptr);
+                if (FAILED(_Hr))
+                {
+                    return _Hr;
+                }
+            }
+            return S_OK;
+        }
+
+        bool operator==(const _ContextCallback& _Rhs) const
+        {
+            return (_M_context._M_pContextCallback == _Rhs._M_context._M_pContextCallback);
+        }
+
+        bool operator!=(const _ContextCallback& _Rhs) const
+        {
+            return !(operator==(_Rhs));
+        }
+
+    private:
+
+        void _Reset()
+        {
+            if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)
+            {
+                _M_context._M_pContextCallback->Release();
+            }
+        }
+
+        void _Assign(IContextCallback *_PContextCallback)
+        {
+            _M_context._M_pContextCallback = _PContextCallback;
+            if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)
+            {
+                _M_context._M_pContextCallback->AddRef();
+            }
+        }
+
+        static HRESULT __stdcall _Bridge(ComCallData *_PParam)
+        {
+            _CallbackFunction *pFunc = reinterpret_cast<_CallbackFunction *>(_PParam->pUserDefined);
+            return (*pFunc)();
+        }
+
+        // Returns the origin information for the caller (runtime / Windows Runtime apartment as far as task continuations need know)
+        bool _IsCurrentOriginSTA()
+        {
+            APTTYPE _AptType;
+            APTTYPEQUALIFIER _AptTypeQualifier;
+
+            HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);
+            if (SUCCEEDED(hr))
+            {
+                // We determine the origin of a task continuation by looking at where .then is called, so we can tell whether
+                // to need to marshal the continuation back to the originating apartment. If an STA thread is in executing in
+                // a neutral aparment when it schedules a continuation, we will not marshal continuations back to the STA,
+                // since variables used within a neutral apartment are expected to be apartment neutral.
+                switch (_AptType)
+                {
+                case APTTYPE_MAINSTA:
+                case APTTYPE_STA:
+                    return true;
+                default:
+                    break;
+                }
+            }
+            return false;
+        }
+
+        union
+        {
+            IContextCallback *_M_pContextCallback;
+            size_t _M_captureMethod;
+        } _M_context;
+
+        static const size_t _S_captureDeferred = 1;
+    };
+
+    template<typename _Type>
+    struct _ResultContext
+    {
+        static _ContextCallback _GetContext(bool /* _RuntimeAggregate */)
+        {
+            return _ContextCallback();
+        }
+
+        static _Type _GetValue(_Type _ObjInCtx, const _ContextCallback & /* _Ctx */, bool /* _RuntimeAggregate */)
+        {
+            return _ObjInCtx;
+        }
+    };
+
+    template<typename _Type, bool bUnknown = __is_base_of(IUnknown, _Type)>
+    struct winrt_type
+    {
+    };
+    template<typename _Type>
+    struct winrt_type<_Type, true>
+    {
+        static IUnknown* create(_Type* _ObjInCtx) {
+            return reinterpret_cast<IUnknown*>(_ObjInCtx);
+        }
+        static IID getuuid() { return __uuidof(_Type); }
+    };
+    template <typename _Type>
+    struct winrt_type<_Type, false>
+    {
+        static IUnknown* create(_Type* _ObjInCtx) {
+            Microsoft::WRL::ComPtr<IInspectable> _PObj;
+            Microsoft::WRL::ComPtr<IActivationFactory> objFactory;
+            HRESULT hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), objFactory.ReleaseAndGetAddressOf());
+            if (FAILED(hr)) return nullptr;
+            Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValueStatics> spPropVal;
+            if (SUCCEEDED(hr))
+                hr = objFactory.As(&spPropVal);
+            if (SUCCEEDED(hr)) {
+                hr = winrt_type<_Type>::create(spPropVal.Get(), _ObjInCtx, _PObj.GetAddressOf());
+                if (SUCCEEDED(hr))
+                    return reinterpret_cast<IUnknown*>(_PObj.Detach());
+            }
+            return nullptr;
+        }
+        static IID getuuid() { return __uuidof(ABI::Windows::Foundation::IPropertyValue); }
+    };
+
+    template<>
+    struct winrt_type<void>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, void* _ObjInCtx, IInspectable** ppInsp) {
+            (void)_ObjInCtx;
+            return spPropVal->CreateEmpty(ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<BYTE>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, BYTE* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateUInt8(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<INT16>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, INT16* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateInt16(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<UINT16>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT16* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateUInt16(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<INT32>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, INT32* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateInt32(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<UINT32>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateUInt32(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<INT64>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, INT64* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateInt64(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<UINT64>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT64* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateUInt64(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<FLOAT>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, FLOAT* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateSingle(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<DOUBLE>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, DOUBLE* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateDouble(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<WCHAR>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, WCHAR* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateChar16(*_ObjInCtx, ppInsp);
+        }
+    };
+    //template<>
+    //struct winrt_type<boolean>
+    //{
+    //    static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, boolean* _ObjInCtx, IInspectable** ppInsp) {
+    //        return spPropVal->CreateBoolean(*_ObjInCtx, ppInsp);
+    //    }
+    //};
+    template<>
+    struct winrt_type<HSTRING>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, HSTRING* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateString(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<IInspectable*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, IInspectable** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateInspectable(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<GUID>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, GUID* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateGuid(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<ABI::Windows::Foundation::DateTime>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, ABI::Windows::Foundation::DateTime* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateDateTime(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<ABI::Windows::Foundation::TimeSpan>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, ABI::Windows::Foundation::TimeSpan* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateTimeSpan(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<ABI::Windows::Foundation::Point>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, ABI::Windows::Foundation::Point* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreatePoint(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<ABI::Windows::Foundation::Size>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, ABI::Windows::Foundation::Size* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateSize(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_type<ABI::Windows::Foundation::Rect>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, ABI::Windows::Foundation::Rect* _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateRect(*_ObjInCtx, ppInsp);
+        }
+    };
+    template<typename _Type>
+    struct winrt_array_type
+    {
+        static IUnknown* create(_Type* _ObjInCtx, size_t N) {
+            Microsoft::WRL::ComPtr<IInspectable> _PObj;
+            Microsoft::WRL::ComPtr<IActivationFactory> objFactory;
+            HRESULT hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), objFactory.ReleaseAndGetAddressOf());
+            if (FAILED(hr)) return nullptr;
+            Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValueStatics> spPropVal;
+            if (SUCCEEDED(hr))
+                hr = objFactory.As(&spPropVal);
+            if (SUCCEEDED(hr)) {
+                hr = winrt_array_type<_Type>::create(spPropVal.Get(), N, _ObjInCtx, _PObj.GetAddressOf());
+                if (SUCCEEDED(hr))
+                    return reinterpret_cast<IUnknown*>(_PObj.Detach());
+            }
+            return nullptr;
+        }
+    };
+    template<>
+    struct winrt_array_type<BYTE*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, BYTE** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateUInt8Array(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<INT16*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, INT16** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateInt16Array(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<UINT16*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, UINT16** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateUInt16Array(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<INT32*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, INT32** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateInt32Array(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<UINT32*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, UINT32** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateUInt32Array(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<INT64*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, INT64** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateInt64Array(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<UINT64*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, UINT64** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateUInt64Array(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<FLOAT*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, FLOAT** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateSingleArray(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<DOUBLE*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, DOUBLE** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateDoubleArray(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<WCHAR*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, WCHAR** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateChar16Array(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    //template<>
+    //struct winrt_array_type<boolean*>
+    //{
+    //    static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, boolean** _ObjInCtx, IInspectable** ppInsp) {
+    //        return spPropVal->CreateBooleanArray(__valueSize, *_ObjInCtx, ppInsp);
+    //    }
+    //};
+    template<>
+    struct winrt_array_type<HSTRING*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, HSTRING** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateStringArray(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<IInspectable*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, IInspectable*** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateInspectableArray(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<GUID>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, GUID** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateGuidArray(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<ABI::Windows::Foundation::DateTime*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, ABI::Windows::Foundation::DateTime** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateDateTimeArray(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<ABI::Windows::Foundation::TimeSpan*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, ABI::Windows::Foundation::TimeSpan** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateTimeSpanArray(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<ABI::Windows::Foundation::Point*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, ABI::Windows::Foundation::Point** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreatePointArray(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<ABI::Windows::Foundation::Size*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, ABI::Windows::Foundation::Size** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateSizeArray(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+    template<>
+    struct winrt_array_type<ABI::Windows::Foundation::Rect*>
+    {
+        static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, ABI::Windows::Foundation::Rect** _ObjInCtx, IInspectable** ppInsp) {
+            return spPropVal->CreateRectArray(__valueSize, *_ObjInCtx, ppInsp);
+        }
+    };
+
+    template<typename _Type, size_t N = 0, bool bIsArray = std::is_array<_Type>::value>
+    struct _MarshalHelper
+    {
+    };
+    template<typename _Type, size_t N>
+    struct _MarshalHelper<_Type, N, true>
+    {
+        static _Type* _Perform(_Type(&_ObjInCtx)[N], const _ContextCallback& _Ctx)
+        {
+            static_assert(__is_valid_winrt_type(_Type*), "must be a WinRT array compatible type");
+            if (_ObjInCtx == nullptr)
+            {
+                return nullptr;
+            }
+
+            HRESULT _Hr;
+            IStream * _PStream;
+            _Ctx._CallInContext([&]() -> HRESULT {
+                // It isn't safe to simply reinterpret_cast a hat type to IUnknown* because some types do not have a real vtable ptr.
+                // Instead, we could to create a property value to make it "grow" the vtable ptr but instead primitives are not marshalled.
+
+                IUnknown * _PUnk = winrt_array_type::create(_ObjInCtx, N);
+                _Hr = CoMarshalInterThreadInterfaceInStream(winrt_type<_Type>::getuuid(), _PUnk, &_PStream);
+                return S_OK;
+            });
+
+            // With an APPX manifest, this call should never fail.
+            _CONCRT_ASSERT(SUCCEEDED(_Hr));
+
+            _Type* _Proxy;
+            //
+            // Cannot use IID_PPV_ARGS with ^ types.
+            //
+            _Hr = CoGetInterfaceAndReleaseStream(_PStream, winrt_type<_Type>::getuuid(), reinterpret_cast<void**>(&_Proxy));
+            if (FAILED(_Hr))
+            {
+                throw std::make_exception_ptr(_Hr);
+            }
+            return _Proxy;
+        }
+    };
+    template<typename _Type>
+    struct _MarshalHelper<_Type, 0, false>
+    {
+        static _Type* _Perform(_Type* _ObjInCtx, const _ContextCallback& _Ctx)
+        {
+            static_assert(__is_base_of(IUnknown, _Type) || __is_valid_winrt_type(_Type), "must be a COM or WinRT type");
+            if (_ObjInCtx == nullptr)
+            {
+                return nullptr;
+            }
+
+            HRESULT _Hr;
+            IStream * _PStream;
+            _Ctx._CallInContext([&]() -> HRESULT {
+                // It isn't safe to simply reinterpret_cast a hat type to IUnknown* because some types do not have a real vtable ptr.
+                // Instead, we could to create a property value to make it "grow" the vtable ptr but instead primitives are not marshalled.
+
+                IUnknown * _PUnk = winrt_type<_Type>::create(_ObjInCtx);
+                _Hr = CoMarshalInterThreadInterfaceInStream(winrt_type<_Type>::getuuid(), _PUnk, &_PStream);
+                return S_OK;
+            });
+
+            // With an APPX manifest, this call should never fail.
+            _CONCRT_ASSERT(SUCCEEDED(_Hr));
+
+            _Type* _Proxy;
+            //
+            // Cannot use IID_PPV_ARGS with ^ types.
+            //
+            _Hr = CoGetInterfaceAndReleaseStream(_PStream, winrt_type<_Type>::getuuid(), reinterpret_cast<void**>(&_Proxy));
+            if (FAILED(_Hr))
+            {
+                throw std::make_exception_ptr(_Hr);
+            }
+            return _Proxy;
+        }
+    };
+
+    // Strings and arrays must be converted to IPropertyValue objects.
+
+    template<typename _Type>
+    _Type* _Marshal(_Type* _ObjInCtx, const _ContextCallback& _Ctx)
+    {
+        return _MarshalHelper<_Type>::_Perform(_ObjInCtx, _Ctx);
+    }
+
+    template<typename _Type>
+    struct _InContext
+    {
+        static _Type _Get(_Type _ObjInCtx, const _ContextCallback& _Ctx)
+        {
+            return _ObjInCtx;
+        }
+    };
+
+    template<typename _Type>
+    struct _InContext<_Type*>
+    {
+        static _Type* _Get(_Type* _ObjInCtx, const _ContextCallback& _Ctx)
+        {
+            _ContextCallback _CurrentContext = _ContextCallback::_CaptureCurrent();
+            if (!_Ctx._HasCapturedContext() || _Ctx == _CurrentContext)
+            {
+                return _ObjInCtx;
+            }
+
+            //
+            // The object is from another apartment. If it's marshalable, do so.
+            //
+            return _Marshal<_Type>(_ObjInCtx, _Ctx);
+        }
+    };
+
+    template<typename _Type>
+    struct _ResultContext<_Type*>
+    {
+        static _Type* _GetValue(_Type* _ObjInCtx, const _ContextCallback& _Ctx, bool /* _RuntimeAggregate */)
+        {
+            return _InContext<_Type*>::_Get(_ObjInCtx, _Ctx);
+        }
+
+        static _ContextCallback _GetContext(bool /* _RuntimeAggregate */)
+        {
+            return _ContextCallback::_CaptureCurrent();
+        }
+    };
+
+    //
+    // The below are for composability with tasks auto-created from when_any / when_all / && / || constructs.
+    //
+    template<typename _Type>
+    struct _ResultContext<std::vector<_Type*>>
+    {
+        static std::vector<_Type*> _GetValue(std::vector<_Type*> _ObjInCtx, const _ContextCallback& _Ctx, bool _RuntimeAggregate)
+        {
+            if (!_RuntimeAggregate)
+            {
+                return _ObjInCtx;
+            }
+
+            _ContextCallback _CurrentContext = _ContextCallback::_CaptureCurrent();
+            if (!_Ctx._HasCapturedContext() || _Ctx == _CurrentContext)
+            {
+                return _ObjInCtx;
+            }
+
+            for (auto _It = _ObjInCtx.begin(); _It != _ObjInCtx.end(); ++_It)
+            {
+                *_It = _Marshal<_Type>(*_It, _Ctx);
+            }
+
+            return _ObjInCtx;
+        }
+
+        static _ContextCallback _GetContext(bool _RuntimeAggregate)
+        {
+            if (!_RuntimeAggregate)
+            {
+                return _ContextCallback();
+            }
+            else
+            {
+                return _ContextCallback::_CaptureCurrent();
+            }
+        }
+    };
+
+    template<typename _Type>
+    struct _ResultContext<std::pair<_Type*, size_t>>
+    {
+        static std::pair<_Type*, size_t> _GetValue(std::pair<_Type*, size_t> _ObjInCtx, const _ContextCallback& _Ctx, bool _RuntimeAggregate)
+        {
+            if (!_RuntimeAggregate)
+            {
+                return _ObjInCtx;
+            }
+
+            _ContextCallback _CurrentContext = _ContextCallback::_CaptureCurrent();
+            if (!_Ctx._HasCapturedContext() || _Ctx == _CurrentContext)
+            {
+                return _ObjInCtx;
+            }
+
+            return std::pair<_Type*, size_t>(_Marshal<_Type>(_ObjInCtx.first, _Ctx), _ObjInCtx.second);
+        }
+
+        static _ContextCallback _GetContext(bool _RuntimeAggregate)
+        {
+            if (!_RuntimeAggregate)
+            {
+                return _ContextCallback();
+            }
+            else
+            {
+                return _ContextCallback::_CaptureCurrent();
+            }
+        }
+    };
+    // An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task.
+    // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception
+    // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.
+    struct _ExceptionHolder
+    {
+        explicit _ExceptionHolder(const std::exception_ptr& _E, void* _SourceAddressHint) :
+        _M_exceptionObserved(0), _M_stdException(_E), _M_disassembleMe(_SourceAddressHint)
+        {
+        }
+
+        explicit _ExceptionHolder(const _com_error& _E, void* _SourceAddressHint) :
+            _M_exceptionObserved(0), _M_disassembleMe(_SourceAddressHint)
+        {
+            _M_winRTException = std::unique_ptr<_com_error>(new _com_error(_E));
+        }
+        __declspec(noinline)
+            ~_ExceptionHolder()
+        {
+                if (_M_exceptionObserved == 0)
+                {
+                    // Disassemble at this->_M_disassembleMe to get to the source location right after either the creation of the task (constructor
+                    // or then method) that encountered this exception, or the set_exception call for a task_completion_event.
+                    Concurrency::details::_ReportUnobservedException();
+                }
+            }
+
+        void _RethrowUserException()
+        {
+            if (_M_exceptionObserved == 0)
+            {
+                _InterlockedExchange(&_M_exceptionObserved, 1);
+            }
+
+            if (_M_winRTException != nullptr)
+            {
+                throw _M_winRTException.get();
+            }
+            std::rethrow_exception(_M_stdException);
+        }
+
+        // A variable that remembers if this exception was every rethrown into user code (and hence handled by the user). Exceptions that
+        // are unobserved when the exception holder is destructed will terminate the process.
+        long volatile _M_exceptionObserved;
+
+        // Either _M_stdException or _M_winRTException is populated based on the type of exception encountered.
+        std::exception_ptr _M_stdException;
+        std::unique_ptr<_com_error> _M_winRTException;
+
+        // Disassembling this value will point to a source instruction right after a call instruction. If the call is to create_task,
+        // a task constructor or the then method, the task created by that method is the one that encountered this exception. If the call
+        // is to task_completion_event::set_exception, the set_exception method was the source of the exception.
+        // DO NOT REMOVE THIS VARIABLE. It is extremely helpful for debugging.
+        void* _M_disassembleMe;
+    };
+
+    template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Function>
+    struct _AsyncInfoCompletionHandler : public Microsoft::WRL::RuntimeClass<
+        Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::ClassicCom>, _CompletionHandlerType>
+    {
+    public:
+        _AsyncInfoCompletionHandler(_Function func) : _M_function(func) {}
+        STDMETHODIMP Invoke(_AsyncOperationType *asyncInfo, ABI::Windows::Foundation::AsyncStatus status)
+        {
+            return _M_function(asyncInfo, status);
+        }
+    protected:
+        _Function _M_function;
+    };
+
+    template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Function>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        _AsyncInfoCompletionHandler<_AsyncOperationType, _CompletionHandlerType, _Function>* create_completionhandler(const _Function& _Func)
+    {
+        return Microsoft::WRL::Make<_AsyncInfoCompletionHandler<_AsyncOperationType, _CompletionHandlerType, _Function>>(_Func).Detach();
+    }
+    /// <summary>
+    ///     Base converter class for converting asynchronous interfaces to IAsyncOperation
+    /// </summary>
+    template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Result>
+    struct _AsyncInfoImpl abstract : public Microsoft::WRL::RuntimeClass<
+        Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRt>,
+        Microsoft::WRL::Implements<ABI::Windows::Foundation::IAsyncOperation<_Result>, Microsoft::WRL::AsyncBase<_CompletionHandlerType>>>
+    {
+    public:
+        // The async action, action with progress or operation with progress that this stub forwards to.
+        Microsoft::WRL::ComPtr<_AsyncOperationType> _M_asyncInfo;
+        // The context in which this async info is valid - may be different from the context where the completion handler runs,
+        // and may require marshalling before it is used.
+        _ContextCallback _M_asyncInfoContext;
+
+        Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>> _M_CompletedHandler;
+
+        _AsyncInfoImpl(_AsyncOperationType* _AsyncInfo) : _M_asyncInfo(_AsyncInfo), _M_asyncInfoContext(_ContextCallback::_CaptureCurrent()) {}
+
+    public:
+        virtual HRESULT OnStart() { return S_OK; }
+        virtual void OnCancel() {
+            Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
+            if (SUCCEEDED(_M_asyncInfo.As(&pAsyncInfo)))
+                pAsyncInfo->Cancel();
+        }
+        virtual void OnClose() {
+            Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
+            if (SUCCEEDED(_M_asyncInfo.As(&pAsyncInfo)))
+                pAsyncInfo->Close();
+        }
+
+        virtual STDMETHODIMP get_ErrorCode(HRESULT* errorCode)
+        {
+            Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
+            HRESULT hr;
+            if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo)))
+                return pAsyncInfo->get_ErrorCode(errorCode);
+            return hr;
+        }
+
+        virtual STDMETHODIMP get_Id(UINT* id)
+        {
+            Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
+            HRESULT hr;
+            if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo)))
+                return pAsyncInfo->get_Id(id);
+            return hr;
+        }
+
+        virtual STDMETHODIMP get_Status(ABI::Windows::Foundation::AsyncStatus *status)
+        {
+            Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
+            HRESULT hr;
+            if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo)))
+                return pAsyncInfo->get_Status(status);
+            return hr;
+        }
+
+        virtual STDMETHODIMP GetResults(_Result*) { throw std::runtime_error("derived class must implement"); }
+
+        virtual STDMETHODIMP get_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>** handler)
+        {
+            if (!handler) return E_POINTER;
+            _M_CompletedHandler.CopyTo(handler);
+            return S_OK;
+        }
+
+        virtual    STDMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>* value)
+        {
+            _M_CompletedHandler = value;
+            return _M_asyncInfo->put_Completed(create_completionhandler<_AsyncOperationType, _CompletionHandlerType>([&](_AsyncOperationType*, ABI::Windows::Foundation::AsyncStatus status) -> HRESULT {
+                // Update the saved _M_asyncInfo with a proxy valid in the current context if required. Some Windows APIs return an IAsyncInfo
+                // that is only valid for the thread that called the API to retrieve. Since this completion handler can run on any thread, we
+                // need to ensure that the async info is valid in the current apartment. _M_asyncInfo will be accessed via calls to 'this' inside
+                // _AsyncInit.
+                _M_asyncInfo = _ResultContext<_AsyncOperationType*>::_GetValue(_M_asyncInfo.Get(), _M_asyncInfoContext, false);
+                return _M_CompletedHandler->Invoke(this, status);
+            }));
+        }
+    };
+
+    extern const __declspec(selectany) WCHAR RuntimeClass_IAsyncOperationWithProgressToAsyncOperationConverter[] = L"_IAsyncOperationWithProgressToAsyncOperationConverter";
+
+    /// <summary>
+    ///     Class _IAsyncOperationWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncOperationWithProgress<T> into IAsyncOperation<T>
+    /// </summary>
+    template<typename _Result, typename _Progress>
+    struct _IAsyncOperationWithProgressToAsyncOperationConverter sealed :
+    _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>,
+        ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<_Result, _Progress>,
+        _Result>
+    {
+        InspectableClass(RuntimeClass_IAsyncOperationWithProgressToAsyncOperationConverter, BaseTrust)
+    public:
+        _IAsyncOperationWithProgressToAsyncOperationConverter(ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>* _Operation) :
+            _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>,
+            ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<_Result, _Progress>,
+            _Result>(_Operation) {}
+    public:
+        virtual STDMETHODIMP GetResults(_Result* results) override {
+            if (!results) return E_POINTER;
+            return _M_asyncInfo->GetResults(results);
+        }
+    };
+
+    extern const __declspec(selectany) WCHAR RuntimeClass_IAsyncActionToAsyncOperationConverter[] = L"_IAsyncActionToAsyncOperationConverter";
+
+    /// <summary>
+    ///     Class _IAsyncActionToAsyncOperationConverter is used to convert an instance of IAsyncAction into IAsyncOperation<_Unit_type>
+    /// </summary>
+    struct _IAsyncActionToAsyncOperationConverter sealed :
+    _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncAction,
+        ABI::Windows::Foundation::IAsyncActionCompletedHandler,
+        _Unit_type>
+    {
+        InspectableClass(RuntimeClass_IAsyncActionToAsyncOperationConverter, BaseTrust)
+    public:
+        _IAsyncActionToAsyncOperationConverter(ABI::Windows::Foundation::IAsyncAction* _Operation) :
+            _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncAction,
+            ABI::Windows::Foundation::IAsyncActionCompletedHandler,
+            _Unit_type>(_Operation) {}
+
+    public:
+        virtual STDMETHODIMP GetResults(details::_Unit_type* results)
+        {
+            if (!results) return E_POINTER;
+            // Invoke GetResults on the IAsyncAction to allow exceptions to be thrown to higher layers before returning a dummy value.
+            HRESULT hr = _M_asyncInfo->GetResults();
+            if (SUCCEEDED(hr)) *results = _Unit_type();
+            return hr;
+        }
+    };
+
+    extern const __declspec(selectany) WCHAR RuntimeClass_IAsyncActionWithProgressToAsyncOperationConverter[] = L"_IAsyncActionWithProgressToAsyncOperationConverter";
+
+    /// <summary>
+    ///     Class _IAsyncActionWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncActionWithProgress into IAsyncOperation<_Unit_type>
+    /// </summary>
+    template<typename _Progress>
+    struct _IAsyncActionWithProgressToAsyncOperationConverter sealed :
+    _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>,
+        ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler<_Progress>,
+        _Unit_type>
+    {
+        InspectableClass(RuntimeClass_IAsyncActionWithProgressToAsyncOperationConverter, BaseTrust)
+    public:
+        _IAsyncActionWithProgressToAsyncOperationConverter(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>* _Action) :
+            _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>,
+            ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler<_Progress>,
+            _Unit_type>(_Action) {}
+    public:
+        virtual STDMETHODIMP GetResults(_Unit_type* results) override
+        {
+            if (!result) return E_POINTER;
+            // Invoke GetResults on the IAsyncActionWithProgress to allow exceptions to be thrown before returning a dummy value.
+            HRESULT hr = _M_asyncInfo->GetResults();
+            if (SUCCEEDED(hr)) *results = _Unit_type();
+            return hr;
+        }
+    };
+}
+
+/// <summary>
+///     The <c>task_continuation_context</c> class allows you to specify where you would like a continuation to be executed.
+///     It is only useful to use this class from a Windows Store app. For non-Windows Store apps, the task continuation's
+///     execution context is determined by the runtime, and not configurable.
+/// </summary>
+/// <seealso cref="task Class"/>
+/**/
+class task_continuation_context : public details::_ContextCallback
+{
+public:
+
+    /// <summary>
+    ///     Creates the default task continuation context.
+    /// </summary>
+    /// <returns>
+    ///     The default continuation context.
+    /// </returns>
+    /// <remarks>
+    ///     The default context is used if you don't specifiy a continuation context when you call the <c>then</c> method. In Windows
+    ///     applications for Windows 7 and below, as well as desktop applications on Windows 8 and higher, the runtime determines where
+    ///     task continuations will execute. However, in a Windows Store app, the default continuation context for a continuation on an
+    ///     apartment aware task is the apartment where <c>then</c> is invoked.
+    ///     <para>An apartment aware task is a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such
+    ///     a task. Therefore, if you schedule a continuation on an apartment aware task in a Windows Runtime STA, the continuation will execute in
+    ///     that STA.</para>
+    ///     <para>A continuation on a non-apartment aware task will execute in a context the Runtime chooses.</para>
+    /// </remarks>
+    /**/
+    static task_continuation_context use_default()
+    {
+        // The callback context is created with the context set to CaptureDeferred and resolved when it is used in .then()
+        return task_continuation_context(true); // sets it to deferred, is resolved in the constructor of _ContinuationTaskHandle
+    }
+
+    /// <summary>
+    ///     Creates a task continuation context which allows the Runtime to choose the execution context for a continuation.
+    /// </summary>
+    /// <returns>
+    ///     A task continuation context that represents an arbitrary location.
+    /// </returns>
+    /// <remarks>
+    ///     When this continuation context is used the continuation will execute in a context the runtime chooses even if the antecedent task
+    ///     is apartment aware.
+    ///     <para><c>use_arbitrary</c> can be used to turn off the default behavior for a continuation on an apartment
+    ///     aware task created in an STA. </para>
+    ///     <para>This method is only available to Windows Store apps.</para>
+    /// </remarks>
+    /**/
+    static task_continuation_context use_arbitrary()
+    {
+        task_continuation_context _Arbitrary(true);
+        _Arbitrary._Resolve(false);
+        return _Arbitrary;
+    }
+
+    /// <summary>
+    ///     Returns a task continuation context object that represents the current execution context.
+    /// </summary>
+    /// <returns>
+    ///     The current execution context.
+    /// </returns>
+    /// <remarks>
+    ///     This method captures the caller's Windows Runtime context so that continuations can be executed in the right apartment.
+    ///     <para>The value returned by <c>use_current</c> can be used to indicate to the Runtime that the continuation should execute in
+    ///     the captured context (STA vs MTA) regardless of whether or not the antecedent task is apartment aware. An apartment aware task is
+    ///     a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such a task. </para>
+    ///     <para>This method is only available to Windows Store apps.</para>
+    /// </remarks>
+    /**/
+    static task_continuation_context use_current()
+    {
+        task_continuation_context _Current(true);
+        _Current._Resolve(true);
+        return _Current;
+    }
+
+private:
+
+    task_continuation_context(bool _DeferCapture = false) : details::_ContextCallback(_DeferCapture)
+    {
+    }
+};
+
+namespace details
+{
+    struct _Task_impl_base;
+    template<typename _ReturnType, typename _Result> struct _Task_impl;
+
+    template<typename _ReturnType, typename _Result = details::_Unit_type>
+    struct _Task_ptr
+    {
+        typedef std::shared_ptr<_Task_impl<_ReturnType, _Result>> _Type;
+        static _Type _Make(Concurrency::details::_CancellationTokenState * _Ct) { return std::make_shared<_Task_impl<_ReturnType, _Result>>(_Ct); }
+    };
+
+    typedef std::shared_ptr<_Task_impl_base> _Task_ptr_base;
+    // The weak-typed base task handler for continuation tasks.
+    struct _ContinuationTaskHandleBase : Concurrency::details::_UnrealizedChore
+    {
+        _ContinuationTaskHandleBase * _M_next;
+        task_continuation_context _M_continuationContext;
+        bool _M_isTaskBasedContinuation;
+
+        // This field gives inlining scheduling policy for current chore.
+        Concurrency::details::_TaskInliningMode _M_inliningMode;
+
+        virtual _Task_ptr_base _GetTaskImplBase() const = 0;
+
+        _ContinuationTaskHandleBase() :
+            _M_next(nullptr), _M_isTaskBasedContinuation(false), _M_continuationContext(task_continuation_context::use_default()), _M_inliningMode(Concurrency::details::_NoInline)
+        {
+        }
+        virtual ~_ContinuationTaskHandleBase() {}
+    };
+
+    /// <summary>
+    ///     The _PPLTaskHandle is the strong-typed task handle base. All user task functions need to be wrapped in this task handler
+    ///     to be executable by PPL. By deriving from a different _BaseTaskHandle, it can be used for both initial tasks and continuation tasks.
+    ///     For initial tasks, _PPLTaskHandle will be derived from _UnrealizedChore, and for continuation tasks, it will be derived from
+    ///     _ContinuationTaskHandleBase. The life time of the _PPLTaskHandle object is be managed by runtime if task handle is scheduled.
+    /// </summary>
+    /// <typeparam name="_ReturnType">
+    ///     The result type of the _Task_impl.
+    /// </typeparam>
+    /// <typeparam name="_DerivedTaskHandle">
+    ///     The derived task handle class. The <c>operator ()</c> needs to be implemented.
+    /// </typeparam>
+    /// <typeparam name="_BaseTaskHandle">
+    ///     The base class from which _PPLTaskHandle should be derived. This is either _UnrealizedChore or _ContinuationTaskHandleBase.
+    /// </typeparam>
+    template<typename _ReturnType, typename _DerivedTaskHandle, typename _BaseTaskHandle>
+    struct _PPLTaskHandle : _BaseTaskHandle
+    {
+        _PPLTaskHandle(const typename _Task_ptr<_ReturnType>::_Type & _PTask) : _M_pTask(_PTask)
+        {
+            m_pFunction = reinterpret_cast <Concurrency::TaskProc> (&_UnrealizedChore::_InvokeBridge<_PPLTaskHandle>);
+            _SetRuntimeOwnsLifetime(true);
+        }
+        virtual ~_PPLTaskHandle() {}
+        void operator()() const
+        {
+            // All exceptions should be rethrown to finish cleanup of the task collection. They will be caught and handled
+            // by the runtime.
+            _CONCRT_ASSERT(_M_pTask != nullptr);
+            if (!_M_pTask->_TransitionedToStarted())
+                return;
+
+            try
+            {
+                // All derived task handle must implement this contract function.
+                static_cast<const _DerivedTaskHandle *>(this)->_Perform();
+            }
+            catch (const Concurrency::task_canceled &)
+            {
+                _M_pTask->_Cancel(true);
+                throw;
+            }
+            catch (const Concurrency::details::_Interruption_exception &)
+            {
+                _M_pTask->_Cancel(true);
+                throw;
+            }
+            catch(const _com_error& _E)
+            {
+                _M_pTask->_CancelWithException(_E);
+                throw;
+            }
+            catch (...)
+            {
+                _M_pTask->_CancelWithException(std::current_exception());
+                throw;
+            }
+        }
+
+        // Cast _M_pTask pointer to "type-less" _Task_impl_base pointer, which can be used in _ContinuationTaskHandleBase.
+        // The return value should be automatically optimized by R-value ref.
+        _Task_ptr_base _GetTaskImplBase() const
+        {
+            return _M_pTask;
+        }
+
+        typename _Task_ptr<_ReturnType>::_Type _M_pTask;
+
+    private:
+        _PPLTaskHandle const & operator=(_PPLTaskHandle const&);    // no assignment operator
+    };
+
+    /// <summary>
+    ///     The base implementation of a first-class task. This class contains all the non-type specific
+    ///     implementation details of the task.
+    /// </summary>
+    /**/
+    struct _Task_impl_base
+    {
+        enum _TaskInternalState
+        {
+            // Tracks the state of the task, rather than the task collection on which the task is scheduled
+            _Created,
+            _Started,
+            _PendingCancel,
+            _Completed,
+            _Canceled
+        };
+        _Task_impl_base(Concurrency::details::_CancellationTokenState * _PTokenState) : _M_TaskState(_Created),
+            _M_fFromAsync(false), _M_fRuntimeAggregate(false), _M_fUnwrappedTask(false),
+            _M_pRegistration(nullptr), _M_Continuations(nullptr), _M_pTaskCollection(nullptr),
+            _M_pTaskCreationAddressHint(nullptr)
+        {
+            // Set cancelation token
+            _M_pTokenState = _PTokenState;
+            _CONCRT_ASSERT(_M_pTokenState != nullptr);
+            if (_M_pTokenState != Concurrency::details::_CancellationTokenState::_None())
+                _M_pTokenState->_Reference();
+
+        }
+
+        virtual ~_Task_impl_base()
+        {
+            _CONCRT_ASSERT(_M_pTokenState != nullptr);
+            if (_M_pTokenState != Concurrency::details::_CancellationTokenState::_None())
+            {
+                _M_pTokenState->_Release();
+            }
+
+            if (_M_pTaskCollection != nullptr)
+            {
+                _M_pTaskCollection->_Release();
+                _M_pTaskCollection = nullptr;
+            }
+        }
+
+        task_status _Wait()
+        {
+            bool _DoWait = true;
+
+            if (_IsNonBlockingThread())
+            {
+                // In order to prevent Windows Runtime STA threads from blocking the UI, calling task.wait() task.get() is illegal
+                // if task has not been completed.
+                if (!_IsCompleted() && !_IsCanceled())
+                {
+                    throw Concurrency::invalid_operation("Illegal to wait on a task in a Windows Runtime STA");
+                }
+                else
+                {
+                    // Task Continuations are 'scheduled' *inside* the chore that is executing on the ancestors's task group. If a continuation
+                    // needs to be marshalled to a different apartment, instead of scheduling, we make a synchronous cross apartment COM
+                    // call to execute the continuation. If it then happens to do something which waits on the ancestor (say it calls .get(), which
+                    // task based continuations are wont to do), waiting on the task group results in on the chore that is making this
+                    // synchronous callback, which causes a deadlock. To avoid this, we test the state ancestor's event , and we will NOT wait on
+                    // if it has finished execution (which means now we are on the inline synchronous callback).
+                    _DoWait = false;
+                }
+            }
+            if (_DoWait)
+            {
+                // Wait for the task to be actually scheduled, otherwise the underlying task collection
+                // might not be created yet. If we don't wait, we will miss the chance to inline this task.
+                _M_Scheduled.wait();
+
+
+                // A PPL task created by a task_completion_event does not have an underlying TaskCollection. For
+                // These tasks, a call to wait should wait for the event to be set. The TaskCollection must either
+                // be nullptr or allocated (the setting of _M_Scheduled) ensures that.
+                // If this task was created from a Windows Runtime async operation, do not attempt to inline it. The
+                // async operation will take place on a thread in the appropriate apartment Simply wait for the completed
+                // event to be set.
+                if ((_M_pTaskCollection == nullptr) || _M_fFromAsync)
+                {
+                    _M_Completed.wait();
+                }
+                else
+                {
+                    // Wait on the task collection to complete. The task collection is guaranteed to still be
+                    // valid since the task must be still within scope so that the _Task_impl_base destructor
+                    // has not yet been called. This call to _Wait potentially inlines execution of work.
+                    try
+                    {
+                        // Invoking wait on a task collection resets the state of the task collection. This means that
+                        // if the task collection itself were canceled, or had encountered an exception, only the first
+                        // call to wait will receive this status. However, both cancellation and exceptions flowing through
+                        // tasks set state in the task impl itself.
+
+                        // When it returns cancelled, either work chore or the cancel thread should already have set task's state
+                        // properly -- cancelled state or completed state (because there was no interruption point).
+                        // For tasks with unwrapped tasks, we should not change the state of current task, since the unwrapped task are still running.
+                        _M_pTaskCollection->_RunAndWait();
+                    }
+                    catch (Concurrency::details::_Interruption_exception&)
+                    {
+                        // The _TaskCollection will never be an interruption point since it has a none token.
+                        _CONCRT_ASSERT(false);
+                    }
+                    catch (Concurrency::task_canceled&)
+                    {
+                        // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task
+                        // must be called from code that is executed within the task (throwing it from parallel work created by and waited
+                        // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen
+                        // the exception and canceled the task. Swallow the exception here.
+                        _CONCRT_ASSERT(_IsCanceled());
+                    }
+                    catch(const _com_error& _E)
+                    {
+                        // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.
+                        if(!_HasUserException())
+                        {
+                            _CancelWithException(_E);
+                        }
+                        // Rethrow will mark the exception as observed.
+                        _M_exceptionHolder->_RethrowUserException();
+                    }
+                    catch (...)
+                    {
+                        // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.
+                        if (!_HasUserException())
+                        {
+                            _CancelWithException(std::current_exception());
+                        }
+                        // Rethrow will mark the exception as observed.
+                        _M_exceptionHolder->_RethrowUserException();
+                    }
+
+                    // If the lambda body for this task (executed or waited upon in _RunAndWait above) happened to return a task
+                    // which is to be unwrapped and plumbed to the output of this task, we must not only wait on the lambda body, we must
+                    // wait on the **INNER** body. It is in theory possible that we could inline such if we plumb a series of things through;
+                    // however, this takes the tact of simply waiting upon the completion signal.
+                    if (_M_fUnwrappedTask)
+                    {
+                        _M_Completed.wait();
+                    }
+                }
+            }
+
+            if (_HasUserException())
+            {
+                _M_exceptionHolder->_RethrowUserException();
+            }
+            else if (_IsCanceled())
+            {
+                return Concurrency::canceled;
+            }
+            _CONCRT_ASSERT(_IsCompleted());
+            return Concurrency::completed;
+        }
+        /// <summary>
+        ///     Requests cancellation on the task and schedules continuations if the task can be transitioned to a terminal state.
+        /// </summary>
+        /// <param name="_SynchronousCancel">
+        ///     Set to true if the cancel takes place as a result of the task body encountering an exception, or because an ancestor or task_completion_event the task
+        ///     was registered with were canceled with an exception. A synchronous cancel is one that assures the task could not be running on a different thread at
+        ///     the time the cancellation is in progress. An asynchronous cancel is one where the thread performing the cancel has no control over the thread that could
+        ///     be executing the task, that is the task could execute concurrently while the cancellation is in progress.
+        /// </param>
+        /// <param name="_UserException">
+        ///     Whether an exception other than the internal runtime cancellation exceptions caused this cancellation.
+        /// </param>
+        /// <param name="_PropagatedFromAncestor">
+        ///     Whether this exception came from an ancestor task or a task_completion_event as opposed to an exception that was encountered by the task itself. Only valid when
+        ///     _UserException is set to true.
+        /// </param>
+        /// <param name="_ExHolder">
+        ///     The exception holder that represents the exception. Only valid when _UserException is set to true.
+        /// </param>
+        virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder>& _ExHolder) = 0;
+
+        bool _Cancel(bool _SynchronousCancel)
+        {
+            // Send in a dummy value for exception. It is not used when the first parameter is false.
+            return _CancelAndRunContinuations(_SynchronousCancel, false, false, _M_exceptionHolder);
+        }
+
+        bool _CancelWithExceptionHolder(const std::shared_ptr<_ExceptionHolder>& _ExHolder, bool _PropagatedFromAncestor)
+        {
+            // This task was canceled because an ancestor task encountered an exception.
+            return _CancelAndRunContinuations(true, true, _PropagatedFromAncestor, _ExHolder);
+        }
+
+        bool _CancelWithException(const _com_error& _Exception)
+        {
+            // This task was canceled because the task body encountered an exception.
+            _CONCRT_ASSERT(!_HasUserException());
+            return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationAddressHint()));
+        }
+        bool _CancelWithException(const std::exception_ptr& _Exception)
+        {
+            // This task was canceled because the task body encountered an exception.
+            _CONCRT_ASSERT(!_HasUserException());
+            return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationAddressHint()));
+        }
+
+        void _RegisterCancellation()
+        {
+            _CONCRT_ASSERT(Concurrency::details::_CancellationTokenState::_IsValid(_M_pTokenState));
+            _M_pRegistration = _M_pTokenState->_RegisterCallback(reinterpret_cast<Concurrency::TaskProc>(&_CancelViaToken), (_Task_impl_base *)this);
+        }
+
+        void _DeregisterCancellation()
+        {
+            if (_M_pRegistration != nullptr)
+            {
+                _M_pTokenState->_DeregisterCallback(_M_pRegistration);
+                _M_pRegistration->_Release();
+                _M_pRegistration = nullptr;
+            }
+        }
+
+        static void _CancelViaToken(_Task_impl_base *_PImpl)
+        {
+            _PImpl->_Cancel(false);
+        }
+
+        bool _IsCreated()
+        {
+            return (_M_TaskState == _Created);
+        }
+
+        bool _IsStarted()
+        {
+            return (_M_TaskState == _Started);
+        }
+
+        bool _IsPendingCancel()
+        {
+            return (_M_TaskState == _PendingCancel);
+        }
+
+        bool _IsCompleted()
+        {
+            return (_M_TaskState == _Completed);
+        }
+
+        bool _IsCanceled()
+        {
+            return (_M_TaskState == _Canceled);
+        }
+
+        bool _HasUserException()
+        {
+            return _M_exceptionHolder;
+        }
+
+        void _SetScheduledEvent()
+        {
+            _M_Scheduled.set();
+        }
+
+        const std::shared_ptr<_ExceptionHolder>& _GetExceptionHolder()
+        {
+            _CONCRT_ASSERT(_HasUserException());
+            return _M_exceptionHolder;
+        }
+
+        bool _IsApartmentAware()
+        {
+            return _M_fFromAsync;
+        }
+
+        void _SetAsync(bool _Async = true)
+        {
+            _M_fFromAsync = _Async;
+        }
+
+        void* _GetTaskCreationAddressHint()
+        {
+            return _M_pTaskCreationAddressHint;
+        }
+
+        void _SetTaskCreationAddressHint(void* _AddressHint)
+        {
+            _M_pTaskCreationAddressHint = _AddressHint;
+        }
+
+        /// <summary>
+        ///     Helper function to schedule the task on the Task Collection.
+        /// </summary>
+        /// <param name="_PTaskHandle">
+        ///     The task chore handle that need to be executed.
+        /// </param>
+        /// <param name="_InliningMode">
+        ///     The inlining scheduling policy for current _PTaskHandle.
+        /// </param>
+        void _ScheduleTask(Concurrency::details::_UnrealizedChore * _PTaskHandle, Concurrency::details::_TaskInliningMode _InliningMode)
+        {
+            // Construct the task collection; We use none token to provent it becoming interruption point.
+            _M_pTaskCollection = Concurrency::details::_AsyncTaskCollection::_NewCollection(Concurrency::details::_CancellationTokenState::_None());
+
+            // _M_pTaskCollection->_ScheduleWithAutoInline will schedule the chore onto AsyncTaskCollection with automatic inlining, in a way that honors cancellation etc.
+            try
+            {
+                // Do not need to check its returning state, more details please refer to _Wait method.
+                _M_pTaskCollection->_ScheduleWithAutoInline(_PTaskHandle, _InliningMode);
+            }
+            catch (const Concurrency::task_canceled &)
+            {
+                // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task
+                // must be called from code that is executed within the task (throwing it from parallel work created by and waited
+                // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen
+                // the exception and canceled the task. Swallow the exception here.
+                _CONCRT_ASSERT(_IsCanceled());
+            }
+            catch (const Concurrency::details::_Interruption_exception &)
+            {
+                // The _TaskCollection will never be an interruption point since it has a none token.
+                _CONCRT_ASSERT(false);
+            }
+            catch (...)
+            {
+                // This exception could only have come from within the chore body. It should've been caught
+                // and the task should be canceled with exception. Swallow the exception here.
+                _CONCRT_ASSERT(_HasUserException());
+            }
+
+            // Set the event in case anyone is waiting to notify that this task has been scheduled. In the case where we
+            // execute the chore inline, the event should be set after the chore has executed, to prevent a different thread
+            // performing a wait on the task from waiting on the task collection before the chore is actually added to it,
+            // and thereby returning from the wait() before the chore has executed.
+            _SetScheduledEvent();
+        }
+
+        /// <summary>
+        ///     Function executes a continuation. This function is recorded by a parent task implementation
+        ///     when a continuation is created in order to execute later.
+        /// </summary>
+        /// <param name="_PTaskHandle">
+        ///     The continuation task chore handle that need to be executed.
+        /// </param>
+        /**/
+        void _RunContinuation(_ContinuationTaskHandleBase * _PTaskHandle)
+        {
+            _Task_ptr_base _ImplBase = _PTaskHandle->_GetTaskImplBase();
+            if (_IsCanceled() && !_PTaskHandle->_M_isTaskBasedContinuation)
+            {
+                if (_HasUserException())
+                {
+                    // If the ancestor encountered an exception, transfer the exception to the continuation
+                    // This traverses down the tree to propagate the exception.
+                    _ImplBase->_CancelWithExceptionHolder(_GetExceptionHolder(), true);
+                }
+                else
+                {
+                    // If the ancestor was canceled, then your own execution should be canceled.
+                    // This traverses down the tree to cancel it.
+                    _ImplBase->_Cancel(true);
+                }
+            }
+            else
+            {
+                // This can only run when the ancestor has completed or it's a task based continuation that fires when a task is canceled
+                // (with or without a user exception).
+                _CONCRT_ASSERT(_IsCompleted() || _PTaskHandle->_M_isTaskBasedContinuation);
+
+                // If it has been canceled here (before starting), do nothing. The guy firing cancel will do the clean up.
+                if (!_ImplBase->_IsCanceled())
+                {
+                    return _ImplBase->_ScheduleContinuationTask(_PTaskHandle);
+                }
+            }
+
+            // If the handle is not scheduled, we need to manually delete it.
+            delete _PTaskHandle;
+        }
+
+        // Schedule a continuation to run
+        void _ScheduleContinuationTask(_ContinuationTaskHandleBase * _PTaskHandle)
+        {
+            // Ensure that the continuation runs in proper context (this might be on a Concurrency Runtime thread or in a different Windows Runtime apartment)
+            if (_PTaskHandle->_M_continuationContext._HasCapturedContext())
+            {
+                // For those continuations need to be scheduled inside captured context, we will try to apply automatic inlining to their inline modes,
+                // if they haven't been specified as _ForceInline yet. This change will encourage those continuations to be executed inline so that reduce
+                // the cost of marshaling.
+                // For normal continuations we won't do any change here, and their inline policies are completely decided by ._ThenImpl method.
+                if (_PTaskHandle->_M_inliningMode != Concurrency::details::_ForceInline)
+                {
+                    _PTaskHandle->_M_inliningMode = Concurrency::details::_DefaultAutoInline;
+                }
+                details::_ScheduleFuncWithAutoInline([_PTaskHandle]() {
+                    // Note that we cannot directly capture "this" pointer, instead, we should use _TaskImplPtr, a shared_ptr to the _Task_impl_base.
+                    // Because "this" pointer will be invalid as soon as _PTaskHandle get deleted. _PTaskHandle will be deleted after being scheduled.
+                    auto _TaskImplPtr = _PTaskHandle->_GetTaskImplBase();
+                    if (details::_ContextCallback::_CaptureCurrent() == _PTaskHandle->_M_continuationContext)
+                    {
+                        _TaskImplPtr->_ScheduleTask(_PTaskHandle, Concurrency::details::_ForceInline);
+                    }
+                    else
+                    {
+                        //
+                        // It's entirely possible that the attempt to marshal the call into a differing context will fail. In this case, we need to handle
+                        // the exception and mark the continuation as canceled with the appropriate exception. There is one slight hitch to this:
+                        //
+                        // NOTE: COM's legacy behavior is to swallow SEH exceptions and marshal them back as HRESULTS. This will in effect turn an SEH into
+                        // a C++ exception that gets tagged on the task. One unfortunate result of this is that various pieces of the task infrastructure will
+                        // not be in a valid state after this in /EHsc (due to the lack of destructors running, etc...).
+                        //
+                        try
+                        {
+                            _PTaskHandle->_M_continuationContext._CallInContext([_PTaskHandle, _TaskImplPtr]() -> HRESULT {
+                                _TaskImplPtr->_ScheduleTask(_PTaskHandle, Concurrency::details::_ForceInline);
+                                return S_OK;
+                            });
+                        }
+                        catch(const _com_error& _E)
+                        {
+                            _TaskImplPtr->_CancelWithException(_E);
+                        }
+                        catch (...)
+                        {
+                            _TaskImplPtr->_CancelWithException(std::current_exception());
+                        }
+                    }
+                }, _PTaskHandle->_M_inliningMode);
+            }
+            else
+            {
+                _ScheduleTask(_PTaskHandle, _PTaskHandle->_M_inliningMode);
+            }
+        }
+
+        /// <summary>
+        ///     Schedule the actual continuation. This will either schedule the function on the continuation task's implementation
+        ///     if the task has completed or append it to a list of functions to execute when the task actually does complete.
+        /// </summary>
+        /// <typeparam name="_FuncInputType">
+        ///     The input type of the task.
+        /// </typeparam>
+        /// <typeparam name="_FuncOutputType">
+        ///     The output type of the task.
+        /// </typeparam>
+        /**/
+        void _ScheduleContinuation(_ContinuationTaskHandleBase * _PTaskHandle)
+        {
+            enum { _Nothing, _Schedule, _Cancel, _CancelWithException } _Do = _Nothing;
+
+            // If the task has canceled, cancel the continuation. If the task has completed, execute the continuation right away.
+            // Otherwise, add it to the list of pending continuations
+            {
+                Concurrency::critical_section::scoped_lock _LockHolder(_M_ContinuationsCritSec);
+                if (_IsCompleted() || (_IsCanceled() && _PTaskHandle->_M_isTaskBasedContinuation))
+                {
+                    _Do = _Schedule;
+                }
+                else if (_IsCanceled())
+                {
+                    if (_HasUserException())
+                    {
+                        _Do = _CancelWithException;
+                    }
+                    else
+                    {
+                        _Do = _Cancel;
+                    }
+                }
+                else
+                {
+                    // chain itself on the continuation chain.
+                    _PTaskHandle->_M_next = _M_Continuations;
+                    _M_Continuations = _PTaskHandle;
+                }
+            }
+
+            // Cancellation and execution of continuations should be performed after releasing the lock. Continuations off of
+            // async tasks may execute inline.
+            switch (_Do)
+            {
+            case _Schedule:
+            {
+                              _PTaskHandle->_GetTaskImplBase()->_ScheduleContinuationTask(_PTaskHandle);
+                              break;
+            }
+            case _Cancel:
+            {
+                            // If the ancestor was canceled, then your own execution should be canceled.
+                            // This traverses down the tree to cancel it.
+                            _PTaskHandle->_GetTaskImplBase()->_Cancel(true);
+
+                            delete _PTaskHandle;
+                            break;
+            }
+            case _CancelWithException:
+            {
+                                         // If the ancestor encountered an exception, transfer the exception to the continuation
+                                         // This traverses down the tree to propagate the exception.
+                                         _PTaskHandle->_GetTaskImplBase()->_CancelWithExceptionHolder(_GetExceptionHolder(), true);
+
+                                         delete _PTaskHandle;
+                                         break;
+            }
+            case _Nothing:
+            default:
+                // In this case, we have inserted continuation to continuation chain,
+                // nothing more need to be done, just leave.
+                break;
+            }
+        }
+
+        void _RunTaskContinuations()
+        {
+            // The link list can no longer be modified at this point,
+            // since all following up continuations will be scheduled by themselves.
+            _ContinuationList _Cur = _M_Continuations, _Next;
+            _M_Continuations = nullptr;
+            while (_Cur)
+            {
+                // Current node might be deleted after running,
+                // so we must fetch the next first.
+                _Next = _Cur->_M_next;
+                _RunContinuation(_Cur);
+                _Cur = _Next;
+            }
+        }
+        static bool  _IsNonBlockingThread()
+        {
+            APTTYPE _AptType;
+            APTTYPEQUALIFIER _AptTypeQualifier;
+
+            HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);
+            //
+            // If it failed, it's not a Windows Runtime/COM initialized thread. This is not a failure.
+            //
+            if (SUCCEEDED(hr))
+            {
+                switch (_AptType)
+                {
+                case APTTYPE_STA:
+                case APTTYPE_MAINSTA:
+                    return true;
+                    break;
+                case APTTYPE_NA:
+                    switch (_AptTypeQualifier)
+                    {
+                        // A thread executing in a neutral apartment is either STA or MTA. To find out if this thread is allowed
+                        // to wait, we check the app qualifier. If it is an STA thread executing in a neutral apartment, waiting
+                        // is illegal, because the thread is responsible for pumping messages and waiting on a task could take the
+                        // thread out of circulation for a while.
+                    case APTTYPEQUALIFIER_NA_ON_STA:
+                    case APTTYPEQUALIFIER_NA_ON_MAINSTA:
+                        return true;
+                        break;
+                    }
+                    break;
+                }
+            }
+#if _UITHREADCTXT_SUPPORT
+            // This method is used to throw an exepection in _Wait() if called within STA.  We
+            // want the same behavior if _Wait is called on the UI thread.
+            if (SUCCEEDED(CaptureUiThreadContext(nullptr)))
+            {
+                return true;
+            }
+#endif // _UITHREADCTXT_SUPPORT
+
+            return false;
+        }
+
+        template<typename _ReturnType, typename _Result>
+        static void _AsyncInit(const typename _Task_ptr<_ReturnType, _Result>::_Type & _OuterTask,
+            ABI::Windows::Foundation::IAsyncOperation<_Result>* _AsyncOp)
+        {
+            // This method is invoked either when a task is created from an existing async operation or
+            // when a lambda that creates an async operation executes.
+
+            // If the outer task is pending cancel, cancel the async operation before setting the completed handler. The COM reference on
+            // the IAsyncInfo object will be released when all *references to the operation go out of scope.
+            _CONCRT_ASSERT(((_OuterTask->_M_pTaskCollection == nullptr) || _OuterTask->_M_fUnwrappedTask) && !_OuterTask->_IsCanceled());
+
+            // Pass the shared_ptr by value into the lambda instead of using 'this'.
+            _AsyncOp->put_Completed(create_completionhandler<ABI::Windows::Foundation::IAsyncOperation<_Result>, ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>>(
+                [_OuterTask](ABI::Windows::Foundation::IAsyncOperation<_Result>* _Operation, ABI::Windows::Foundation::AsyncStatus _Status) mutable -> HRESULT
+            {
+                if (_Status == ABI::Windows::Foundation::AsyncStatus::Canceled)
+                {
+                    _OuterTask->_Cancel(true);
+                }
+                else if (_Status == ABI::Windows::Foundation::AsyncStatus::Error)
+                {
+                    HRESULT hr;
+                    Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
+                    if (SUCCEEDED(_Operation->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf())) && SUCCEEDED(pAsyncInfo->get_ErrorCode(&hr)))
+                        _OuterTask->_CancelWithException(std::make_exception_ptr(hr));
+                }
+                else
+                {
+                    _CONCRT_ASSERT(_Status == ABI::Windows::Foundation::AsyncStatus::Completed);
+                    _Result results;
+                    if (SUCCEEDED(_Operation->GetResults(&results)))
+                        _OuterTask->_FinalizeAndRunContinuations(results);
+                }
+                // Take away this shared pointers reference on the task instead of waiting for the delegate to be released. It could
+                // be released on a different thread after a delay, and not releasing the reference here could cause the tasks to hold
+                // on to resources longer than they should. As an example, without this reset, writing to a file followed by reading from
+                // it using the Windows Runtime Async APIs causes a sharing violation.
+                // Using const_cast is the workaround for failed mutable keywords
+                const_cast<_Task_ptr<_ReturnType, _Result>::_Type &>(_OuterTask).reset();
+                return S_OK;
+            }));
+            _OuterTask->_SetUnwrappedAsyncOp(_AsyncOp);
+        }
+        template<typename _ReturnType, typename _InternalReturnType>
+        static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type& _OuterTask, const task<_InternalReturnType> & _UnwrappedTask)
+        {
+            _CONCRT_ASSERT(_OuterTask->_M_fUnwrappedTask && !_OuterTask->_IsCanceled());
+            //
+            // We must ensure that continuations off _OuterTask (especially exception handling ones) continue to function in the
+            // presence of an exception flowing out of the inner task _UnwrappedTask. This requires an exception handling continuation
+            // off the inner task which does the appropriate funnelling to the outer one. We use _Then instead of then to prevent
+            // the exception from being marked as observed by our internal continuation. This continuation must be scheduled regardless
+            // of whether or not the _OuterTask task is canceled.
+            //
+            _UnwrappedTask._Then([_OuterTask](task<_InternalReturnType> _AncestorTask) {
+
+                if (_AncestorTask._GetImpl()->_IsCompleted())
+                {
+                    _OuterTask->_FinalizeAndRunContinuations(_AncestorTask._GetImpl()->_GetResult());
+                }
+                else
+                {
+                    _CONCRT_ASSERT(_AncestorTask._GetImpl()->_IsCanceled());
+                    if (_AncestorTask._GetImpl()->_HasUserException())
+                    {
+                        // Set _PropagatedFromAncestor to false, since _AncestorTask is not an ancestor of _UnwrappedTask.
+                        // Instead, it is the enclosing task.
+                        _OuterTask->_CancelWithExceptionHolder(_AncestorTask._GetImpl()->_GetExceptionHolder(), false);
+                    }
+                    else
+                    {
+                        _OuterTask->_Cancel(true);
+                    }
+                }
+            }, nullptr, false, details::_DefaultAutoInline);
+        }
+
+        Concurrency::event _M_Completed;
+        Concurrency::event _M_Scheduled;
+
+        // Tracks the internal state of the task
+        _TaskInternalState _M_TaskState;
+        // Set to true either if the ancestor task had the flag set to true, or if the lambda that does the work of this task returns an
+        // async operation or async action that is unwrapped by the runtime.
+        bool _M_fFromAsync;
+        // Set to true if we need to marshal the inner parts of an aggregate type like std::vector<T^> or std::pair<T^, size_t>. We only marshal
+        // the contained T^s if we create the vector or pair, such as on a when_any or a when_all operation.
+        bool _M_fRuntimeAggregate;
+        // Set to true when a continuation unwraps a task or async operation.
+        bool _M_fUnwrappedTask;
+
+        // An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task.
+        // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception
+        // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.
+        std::shared_ptr<_ExceptionHolder> _M_exceptionHolder;
+
+        typedef _ContinuationTaskHandleBase * _ContinuationList;
+
+        Concurrency::critical_section _M_ContinuationsCritSec;
+        _ContinuationList _M_Continuations;
+
+        // The cancellation token state.
+        Concurrency::details::_CancellationTokenState * _M_pTokenState;
+
+        // The registration on the token.
+        Concurrency::details::_CancellationTokenRegistration * _M_pRegistration;
+
+        // The async task collection wrapper
+        Concurrency::details::_AsyncTaskCollection * _M_pTaskCollection;
+
+        // Points to the source code instruction right after the function call (constructor or .then) that created this task impl.
+        void* _M_pTaskCreationAddressHint;
+
+    private:
+        // Must not be copied by value:
+        _Task_impl_base(const _Task_impl_base&);
+        _Task_impl_base const & operator=(_Task_impl_base const&);
+    };
+    template<typename _ReturnType, typename _Result = details::_Unit_type>
+    struct _Task_impl : public _Task_impl_base
+    {
+        typedef ABI::Windows::Foundation::IAsyncOperation<_Result> _AsyncOperationType;
+        _Task_impl(Concurrency::details::_CancellationTokenState * _Ct) : _Task_impl_base(_Ct)
+        {
+            _M_unwrapped_async_op = nullptr;
+        }
+        virtual ~_Task_impl()
+        {
+            // We must invoke _DeregisterCancellation in the derived class destructor. Calling it in the base class destructor could cause
+            // a partially initialized _Task_impl to be in the list of registrations for a cancellation token.
+            _DeregisterCancellation();
+        }
+        virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder> & _ExceptionHolder)
+        {
+            bool _RunContinuations = false;
+            {
+                Concurrency::critical_section::scoped_lock _LockHolder(_M_ContinuationsCritSec);
+                if (_UserException)
+                {
+                    _CONCRT_ASSERT(_SynchronousCancel && !_IsCompleted());
+                    // If the state is _Canceled, the exception has to be coming from an ancestor.
+                    _CONCRT_ASSERT(!_IsCanceled() || _PropagatedFromAncestor);
+                    // If the state is _Started or _PendingCancel, the exception cannot be coming from an ancestor.
+                    _CONCRT_ASSERT((!_IsStarted() && !_IsPendingCancel()) || !_PropagatedFromAncestor);
+
+                    // We should not be canceled with an exception more than once.
+                    _CONCRT_ASSERT(!_HasUserException());
+
+                    if (_M_TaskState == _Canceled)
+                    {
+                        // If the task has finished cancelling there should not be any continuation records in the array.
+                        return false;
+                    }
+                    else
+                    {
+                        _CONCRT_ASSERT(_M_TaskState != _Completed);
+                        _M_exceptionHolder = _ExceptionHolder;
+                    }
+                }
+                else
+                {
+                    // Completed is a non-cancellable state, and if this is an asynchronous cancel, we're unable to do better than the last async cancel
+                    // which is to say, cancellation is already initiated, so return early.
+                    if (_IsCompleted() || _IsCanceled() || (_IsPendingCancel() && !_SynchronousCancel))
+                    {
+                        _CONCRT_ASSERT(!_IsCompleted() || !_HasUserException());
+                        return false;
+                    }
+                    _CONCRT_ASSERT(!_SynchronousCancel || !_HasUserException());
+                }
+
+                if (_SynchronousCancel || _IsCreated())
+                {
+                    // Be aware that this set must be done BEFORE _M_Scheduled being set, or race will happen between this and wait()
+                    _M_TaskState = _Canceled;
+                    _M_Scheduled.set();
+
+                    // Cancellation completes the task, so all dependent tasks must be run to cancel them
+                    // They are canceled when they begin running (see _RunContinuation) and see that their
+                    // ancestor has been canceled.
+                    _RunContinuations = true;
+                }
+                else
+                {
+                    _CONCRT_ASSERT(_IsStarted() && !_UserException);
+                    // The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore).
+                    // In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from
+                    // _Started to _PendingCancel before it can move to _Canceled when it is finished executing.
+                    _M_TaskState = _PendingCancel;
+                    if (_M_unwrapped_async_op != nullptr)
+                    {
+                        // We will only try to cancel async operation but not unwrapped tasks, since unwrapped tasks cannot be canceled without its token.
+                        Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
+                        if (SUCCEEDED(_M_unwrapped_async_op.As(&pAsyncInfo)))
+                            pAsyncInfo->Cancel();
+                    }
+                }
+
+                // Optimistic trying for cancelation
+                if (_M_pTaskCollection != nullptr)
+                {
+                    _M_pTaskCollection->_Cancel();
+                }
+            }
+
+            // Only execute continuations and mark the task as completed if we were able to move the task to the _Canceled state.
+            if (_RunContinuations)
+            {
+                _M_Completed.set();
+
+                if (_M_Continuations)
+                {
+                    // Scheduling cancellation with automatic inlining.
+                    details::_ScheduleFuncWithAutoInline([=](){ _RunTaskContinuations(); }, Concurrency::details::_DefaultAutoInline);
+                }
+            }
+            return true;
+        }
+        void _FinalizeAndRunContinuations(_ReturnType _Result)
+        {
+            _M_Result = _Result;
+
+            _M_ResultContext = _ResultContext<_ReturnType>::_GetContext(_M_fRuntimeAggregate);
+            {
+                //
+                // Hold this lock to ensure continuations being concurrently either get added
+                // to the _M_Continuations vector or wait for the result
+                //
+                Concurrency::critical_section::scoped_lock _LockHolder(_M_ContinuationsCritSec);
+
+                // A task could still be in the _Created state if it was created with a task_completion_event.
+                // It could also be in the _Canceled state for the same reason.
+                _CONCRT_ASSERT(!_HasUserException() && !_IsCompleted());
+                if (_IsCanceled())
+                {
+                    return;
+                }
+
+                // Always transition to "completed" state, even in the face of unacknowledged pending cancellation
+                _M_TaskState = _Completed;
+            }
+            _M_Completed.set();
+            _RunTaskContinuations();
+        }
+        //
+        // This method is invoked when the starts executing. The task returns early if this method returns true.
+        //
+        bool _TransitionedToStarted()
+        {
+            Concurrency::critical_section::scoped_lock _LockHolder(_M_ContinuationsCritSec);
+            if (_IsCanceled())
+            {
+                return false;
+            }
+            _CONCRT_ASSERT(_IsCreated());
+            _M_TaskState = _Started;
+            return true;
+        }
+        void _SetUnwrappedAsyncOp(_AsyncOperationType* _AsyncOp)
+        {
+            Concurrency::critical_section::scoped_lock _LockHolder(_M_ContinuationsCritSec);
+            // Cancel the async operation if the task itself is canceled, since the thread that canceled the task missed it.
+            if (_IsPendingCancel())
+            {
+                _CONCRT_ASSERT(!_IsCanceled());
+                Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
+                if (SUCCEEDED(_AsyncOp->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(&pAsyncInfo)))
+                    pAsyncInfo->Cancel();
+            }
+            else
+            {
+                _M_unwrapped_async_op = _AsyncOp;
+            }
+        }
+        _ReturnType _GetResult()
+        {
+            return _ResultContext<_ReturnType>::_GetValue(_M_Result, _M_ResultContext, _M_fRuntimeAggregate);
+        }
+        _ReturnType                                 _M_Result;        // this means that the result type must have a public default ctor.
+        Microsoft::WRL::ComPtr<_AsyncOperationType> _M_unwrapped_async_op;
+        _ContextCallback                            _M_ResultContext;
+    };
+
+    template<typename _ResultType>
+    struct _Task_completion_event_impl
+    {
+        typedef std::vector<typename _Task_ptr<_ResultType>::_Type> _TaskList;
+
+        _Task_completion_event_impl() : _M_fHasValue(false), _M_fIsCanceled(false)
+        {
+        }
+
+        bool _HasUserException()
+        {
+            return _M_exceptionHolder;
+        }
+
+        ~_Task_completion_event_impl()
+        {
+            for (auto _TaskIt = _M_tasks.begin(); _TaskIt != _M_tasks.end(); ++_TaskIt)
+            {
+                _CONCRT_ASSERT(!_M_fHasValue && !_M_fIsCanceled);
+                // Cancel the tasks since the event was never signaled or canceled.
+                (*_TaskIt)->_Cancel(true);
+            }
+        }
+
+        // We need to protect the loop over the array, so concurrent_vector would not have helped
+        _TaskList                           _M_tasks;
+        Concurrency::critical_section                    _M_taskListCritSec;
+        _ResultType                         _M_value;
+        std::shared_ptr<_ExceptionHolder>   _M_exceptionHolder;
+        bool                                _M_fHasValue;
+        bool                                _M_fIsCanceled;
+    };
+
+    // Utility method for dealing with void functions
+    inline std::function<_Unit_type(void)> _MakeVoidToUnitFunc(const std::function<void(void)>& _Func)
+    {
+        return [=]() -> _Unit_type { _Func(); return _Unit_type(); };
+    }
+
+    template <typename _Type>
+    std::function<_Type(_Unit_type)> _MakeUnitToTFunc(const std::function<_Type(void)>& _Func)
+    {
+        return [=](_Unit_type) -> _Type { return _Func(); };
+    }
+
+    template <typename _Type>
+    std::function<_Unit_type(_Type)> _MakeTToUnitFunc(const std::function<void(_Type)>& _Func)
+    {
+        return [=](_Type t) -> _Unit_type { _Func(t); return _Unit_type(); };
+    }
+
+    inline std::function<_Unit_type(_Unit_type)> _MakeUnitToUnitFunc(const std::function<void(void)>& _Func)
+    {
+        return [=](_Unit_type) -> _Unit_type { _Func(); return _Unit_type(); };
+    }
+}
+
+
+/// <summary>
+///     The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied,
+///     or start a task in response to an external event.
+/// </summary>
+/// <typeparam name="_ResultType">
+///     The result type of this <c>task_completion_event</c> class.
+/// </typeparam>
+/// <remarks>
+///     Use a task created from a task completion event when your scenario requires you to create a task that will complete, and
+///     thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must
+///     have the same type as the task you create, and calling the set method on the task completion event with a value of that type
+///     will cause the associated task to complete, and provide that value as a result to its continuations.
+///     <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para>
+///     <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para>
+/// </remarks>
+/// <seealso cref="task Class"/>
+/**/
+template<typename _ResultType>
+class task_completion_event
+{
+public:
+    /// <summary>
+    ///     Constructs a <c>task_completion_event</c> object.
+    /// </summary>
+    /**/
+    task_completion_event() : _M_Impl(std::make_shared<details::_Task_completion_event_impl<_ResultType>>())
+    {
+    }
+
+    /// <summary>
+    ///     Sets the task completion event.
+    /// </summary>
+    /// <param name="_Result">
+    ///     The result to set this event with.
+    /// </param>
+    /// <returns>
+    ///     The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set.
+    /// </returns>
+    /// <remarks>
+    ///     In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the
+    ///     task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the
+    ///     tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have
+    ///     a <typeparamref name="_ResultType"/> other than <c>void</c> will pass the value <paramref value="_Result"/> to their continuations.
+    /// </remarks>
+    /**/
+    bool set(_ResultType _Result) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
+    {
+        // Subsequent sets are ignored. This makes races to set benign: the first setter wins and all others are ignored.
+        if (_IsTriggered())
+        {
+            return false;
+        }
+
+        _TaskList _Tasks;
+        bool _RunContinuations = false;
+        {
+            Concurrency::critical_section::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
+
+            if (!_IsTriggered())
+            {
+                _M_Impl->_M_value = _Result;
+                _M_Impl->_M_fHasValue = true;
+
+                _Tasks.swap(_M_Impl->_M_tasks);
+                _RunContinuations = true;
+            }
+        }
+
+        if (_RunContinuations)
+        {
+            for (auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt)
+            {
+                // Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all
+                // if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we
+                // need to run continuations after the lock is released.
+                (*_TaskIt)->_FinalizeAndRunContinuations(_M_Impl->_M_value);
+            }
+            if (_M_Impl->_HasUserException())
+            {
+                _M_Impl->_M_exceptionHolder.reset();
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    /// <summary>
+    ///     Propagates an exception to all tasks associated with this event.
+    /// </summary>
+    /// <param>
+    ///     The exception_ptr that indicates the exception to set this event with.
+    /// </param>
+    /**/
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
+    {
+            // It is important that _ReturnAddress() evaluate to the instruction after the call instruction for set_exception.
+            return _Cancel(_ExceptionPtr, _ReturnAddress());
+        }
+
+    /// <summary>
+    ///     Internal method to cancel the task_completion_event. Any task created using this event will be marked as canceled if it has
+    ///     not already been set.
+    /// </summary>
+    bool _Cancel() const
+    {
+        // Cancel with the stored exception if one exists.
+        return _CancelInternal();
+    }
+
+    /// <summary>
+    ///     Internal method to cancel the task_completion_event with the exception provided. Any task created using this event will be canceled
+    ///     with the same exception.
+    /// </summary>
+    template<typename _ExHolderType>
+    bool _Cancel(_ExHolderType _ExHolder, void* _SetExceptionAddressHint = nullptr) const
+    {
+        (void)_SetExceptionAddressHint;
+        bool _Canceled;
+        if (_StoreException(_ExHolder))
+        {
+            _Canceled = _CancelInternal();
+            _CONCRT_ASSERT(_Canceled);
+        }
+        else
+        {
+            _Canceled = false;
+        }
+        return _Canceled;
+    }
+
+    /// <summary>
+    ///     Internal method that stores an exception in the task completion event. This is used internally by when_any.
+    ///     Note, this does not cancel the task completion event. A task completion event with a stored exception
+    ///     can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present.
+    /// </summary>
+    template<typename _ExHolderType>
+    bool _StoreException(_ExHolderType _ExHolder, void* _SetExceptionAddressHint = nullptr) const
+    {
+        Concurrency::critical_section::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
+        if (!_IsTriggered() && !_M_Impl->_HasUserException())
+        {
+            // Create the exception holder only if we have ensured there we will be successful in setting it onto the
+            // task completion event. Failing to do so will result in an unobserved task exception.
+            _M_Impl->_M_exceptionHolder = _ToExceptionHolder(_ExHolder, _SetExceptionAddressHint);
+            return true;
+        }
+        return false;
+    }
+
+    /// <summary>
+    ///     Tests whether current event has been either Set, or Canceled.
+    /// </summary>
+    bool _IsTriggered() const
+    {
+        return _M_Impl->_M_fHasValue || _M_Impl->_M_fIsCanceled;
+    }
+
+private:
+
+    static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder, void*)
+    {
+        return _ExHolder;
+    }
+
+    static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(std::exception_ptr _ExceptionPtr, void* _SetExceptionAddressHint)
+    {
+        return std::make_shared<details::_ExceptionHolder>(_ExceptionPtr, _SetExceptionAddressHint);
+    }
+
+    template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask
+    template <typename T> friend class task_completion_event;
+
+    typedef typename details::_Task_completion_event_impl<_ResultType>::_TaskList _TaskList;
+
+    /// <summary>
+    ///    Cancels the task_completion_event.
+    /// </summary>
+    bool _CancelInternal() const
+    {
+        // Cancellation of task completion events is an internal only utility. Our usage is such that _CancelInternal
+        // will never be invoked if the task completion event has been set.
+        _CONCRT_ASSERT(!_M_Impl->_M_fHasValue);
+        if (_M_Impl->_M_fIsCanceled)
+        {
+            return false;
+        }
+
+        _TaskList _Tasks;
+        bool _Cancel = false;
+        {
+            Concurrency::critical_section::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
+            _CONCRT_ASSERT(!_M_Impl->_M_fHasValue);
+            if (!_M_Impl->_M_fIsCanceled)
+            {
+                _M_Impl->_M_fIsCanceled = true;
+                _Tasks.swap(_M_Impl->_M_tasks);
+                _Cancel = true;
+            }
+        }
+
+        bool _UserException = _M_Impl->_HasUserException();
+
+        if (_Cancel)
+        {
+            for (auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt)
+            {
+                // Need to call this after the lock is released. See comments in set().
+                if (_UserException)
+                {
+                    (*_TaskIt)->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);
+                }
+                else
+                {
+                    (*_TaskIt)->_Cancel(true);
+                }
+            }
+        }
+        return _Cancel;
+    }
+
+    /// <summary>
+    ///     Register a task with this event. This function is called when a task is constructed using
+    ///     a task_completion_event.
+    /// </summary>
+    void _RegisterTask(const typename details::_Task_ptr<_ResultType>::_Type & _TaskParam)
+    {
+        _TaskParam->_SetScheduledEvent();
+        Concurrency::critical_section::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
+
+        //If an exception was already set on this event, then cancel the task with the stored exception.
+        if (_M_Impl->_HasUserException())
+        {
+            _TaskParam->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);
+        }
+        else if (_M_Impl->_M_fHasValue)
+        {
+            _TaskParam->_FinalizeAndRunContinuations(_M_Impl->_M_value);
+        }
+        else
+        {
+            _M_Impl->_M_tasks.push_back(_TaskParam);
+        }
+    }
+
+    std::shared_ptr<details::_Task_completion_event_impl<_ResultType>> _M_Impl;
+};
+
+/// <summary>
+///     The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied,
+///     or start a task in response to an external event.
+/// </summary>
+/// <remarks>
+///     Use a task created from a task completion event when your scenario requires you to create a task that will complete, and
+///     thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must
+///     have the same type as the task you create, and calling the set method on the task completion event with a value of that type
+///     will cause the associated task to complete, and provide that value as a result to its continuations.
+///     <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para>
+///     <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para>
+/// </remarks>
+/// <seealso cref="task Class"/>
+/**/
+template<>
+class task_completion_event<void>
+{
+public:
+    /// <summary>
+    ///     Sets the task completion event.
+    /// </summary>
+    /// <returns>
+    ///     The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set.
+    /// </returns>
+    /// <remarks>
+    ///     In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the
+    ///     task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the
+    ///     tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have
+    ///     a <typeparamref name="_ResultType"/> other than <c>void</c> will pass the value <paramref value="_Result"/> to their continuations.
+    /// </remarks>
+    /**/
+    bool set() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
+    {
+        return _M_unitEvent.set(details::_Unit_type());
+    }
+
+    /// <summary>
+    ///     Propagates an exception to all tasks associated with this event.
+    /// </summary>
+    /// <param>
+    ///     The exception_ptr that indicates the exception to set this event with.
+    /// </param>
+    /**/
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
+    {
+            // It is important that _ReturnAddress() evaluate to the instruction after the call instruction for set_exception.
+            return _M_unitEvent._Cancel(_ExceptionPtr, _ReturnAddress());
+        }
+
+    /// <summary>
+    ///     Cancel the task_completion_event. Any task created using this event will be marked as canceled if it has
+    ///     not already been set.
+    /// </summary>
+    void _Cancel() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
+    {
+        _M_unitEvent._Cancel();
+    }
+
+    /// <summary>
+    ///     Cancel the task_completion_event with the exception holder provided. Any task created using this event will be canceled
+    ///     with the same exception.
+    /// </summary>
+    void _Cancel(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const
+    {
+        _M_unitEvent._Cancel(_ExHolder);
+    }
+
+    /// <summary>
+    ///     Method that stores an exception in the task completion event. This is used internally by when_any.
+    ///     Note, this does not cancel the task completion event. A task completion event with a stored exception
+    ///     can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present.
+    /// </summary>
+    bool _StoreException(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const
+    {
+        return _M_unitEvent._StoreException(_ExHolder);
+    }
+
+    /// <summary>
+    ///     Test whether current event has been either Set, or Canceled.
+    /// </summary>
+    bool _IsTriggered() const
+    {
+        return _M_unitEvent._IsTriggered();
+    }
+
+private:
+    template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask
+
+    /// <summary>
+    ///     Register a task with this event. This function is called when a task is constructed using
+    ///     a task_completion_event.
+    /// </summary>
+    void _RegisterTask(details::_Task_ptr<details::_Unit_type>::_Type _TaskParam)
+    {
+        _M_unitEvent._RegisterTask(_TaskParam);
+    }
+
+    // The void event contains an event a dummy type so common code can be used for events with void and non-void results.
+    task_completion_event<details::_Unit_type> _M_unitEvent;
+};
+namespace details
+{
+    //
+    // Compile-time validation helpers
+    //
+
+    // Task constructor validation: issue helpful diagnostics for common user errors. Do not attempt full validation here.
+    //
+    // Anything callable is fine
+    template<typename _ReturnType, typename _Ty>
+    auto _IsValidTaskCtor(_Ty _Param, int, int, int, int) -> typename decltype(_Param(), std::true_type());
+
+    // Anything that has GetResults is fine: this covers all async operations
+    template<typename _ReturnType, typename _Ty>
+    auto _IsValidTaskCtor(_Ty _Param, int, int, int, ...) -> typename decltype(_Param->GetResults(), std::true_type());
+
+    // Allow parameters with set: this covers task_completion_event
+    template<typename _ReturnType, typename _Ty>
+    auto _IsValidTaskCtor(_Ty _Param, int, int, ...) -> typename decltype(_Param.set(std::declval<_ReturnType>()), std::true_type());
+
+    template<typename _ReturnType, typename _Ty>
+    auto _IsValidTaskCtor(_Ty _Param, int, ...) -> typename decltype(_Param.set(), std::true_type());
+
+    // All else is invalid
+    template<typename _ReturnType, typename _Ty>
+    std::false_type _IsValidTaskCtor(_Ty _Param, ...);
+
+    template<typename _ReturnType, typename _Ty>
+    void _ValidateTaskConstructorArgs(_Ty _Param)
+    {
+        (void)_Param;
+        static_assert(std::is_same<decltype(_IsValidTaskCtor<_ReturnType>(_Param, 0, 0, 0, 0)), std::true_type>::value,
+            "incorrect argument for task constructor; can be a callable object, an asynchronous operation, or a task_completion_event"
+            );
+        static_assert(!(std::is_same<_Ty, _ReturnType>::value && details::_IsIAsyncInfo<_Ty>::_Value),
+            "incorrect template argument for task; consider using the return type of the async operation");
+    }
+    // Helpers for create_async validation
+    //
+    // A parameter lambda taking no arguments is valid
+    template<typename _Ty>
+    static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int) -> typename decltype(_Param(), std::true_type());
+
+    // A parameter lambda taking an cancellation_token argument is valid
+    template<typename _Ty>
+    static auto _IsValidCreateAsync(_Ty _Param, int, int, int, ...) -> typename decltype(_Param(cancellation_token::none()), std::true_type());
+
+    // A parameter lambda taking a progress report argument is valid
+    template<typename _Ty>
+    static auto _IsValidCreateAsync(_Ty _Param, int, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType()), std::true_type());
+
+    // A parameter lambda taking a progress report and a cancellation_token argument is valid
+    template<typename _Ty>
+    static auto _IsValidCreateAsync(_Ty _Param, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType(), cancellation_token::none()), std::true_type());
+
+    // All else is invalid
+    template<typename _Ty>
+    static std::false_type _IsValidCreateAsync(_Ty _Param, ...);
+}
+
+/// <summary>
+///     The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously,
+///     and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces
+///     a result of type <typeparamref name="_ResultType"/> on successful completion. Tasks of type <c>task&lt;void&gt;</c> produce no result.
+///     A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using
+///     continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns.
+/// </summary>
+/// <typeparam name="_ReturnType">
+///     The result type of this task.
+/// </typeparam>
+/// <remarks>
+///     For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.
+/// </remarks>
+/**/
+template<typename _ReturnType>
+class task
+{
+public:
+    /// <summary>
+    ///     The type of the result an object of this class produces.
+    /// </summary>
+    /**/
+    typedef _ReturnType result_type;
+
+    /// <summary>
+    ///     Constructs a <c>task</c> object.
+    /// </summary>
+    /// <remarks>
+    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
+    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
+    ///     will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
+    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
+    ///     completion event is set.</para>
+    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
+    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
+    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
+    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
+    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,
+    ///     and not when the lamda returns.</para>
+    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
+    ///     without the need for locks.</para>
+    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
+    ///     to Windows Store apps.</para>
+    ///     <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    task() : _M_Impl(nullptr)
+    {
+        // The default constructor should create a task with a nullptr impl. This is a signal that the
+        // task is not usable and should throw if any wait(), get() or then() APIs are used.
+    }
+
+    /// <summary>
+    ///     Constructs a <c>task</c> object.
+    /// </summary>
+    /// <typeparam name="_Ty">
+    ///     The type of the parameter from which the task is to be constructed.
+    /// </typeparam>
+    /// <param name="_Param">
+    ///     The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event&lt;result_type&gt;</c>
+    ///     object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
+    ///     object should be a type equivalent to <c>std::function&lt;X(void)&gt;</c>, where X can be a variable of type <c>result_type</c>,
+    ///     <c>task&lt;result_type&gt;</c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
+    /// </param>
+    /// <remarks>
+    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
+    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
+    ///     will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
+    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
+    ///     completion event is set.</para>
+    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
+    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
+    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
+    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
+    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,
+    ///     and not when the lamda returns.</para>
+    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
+    ///     without the need for locks.</para>
+    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
+    ///     to Windows Store apps.</para>
+    ///     <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Ty>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        explicit task(_Ty _Param)
+    {
+            details::_ValidateTaskConstructorArgs<_ReturnType, _Ty>(_Param);
+
+            _CreateImpl(Concurrency::cancellation_token::none()._GetImplValue());
+            // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor.
+            _SetTaskCreationAddressHint(_ReturnAddress());
+
+            _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param, 0));
+        }
+
+    /// <summary>
+    ///     Constructs a <c>task</c> object.
+    /// </summary>
+    /// <typeparam name="_Ty">
+    ///     The type of the parameter from which the task is to be constructed.
+    /// </typeparam>
+    /// <param name="_Param">
+    ///     The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event&lt;result_type&gt;</c>
+    ///     object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
+    ///     object should be a type equivalent to <c>std::function&lt;X(void)&gt;</c>, where X can be a variable of type <c>result_type</c>,
+    ///     <c>task&lt;result_type&gt;</c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
+    /// </param>
+    /// <param name="_Token">
+    ///     The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives
+    ///     the token <c>cancellation_token::none()</c>.
+    /// </param>
+    /// <remarks>
+    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
+    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
+    ///     will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
+    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
+    ///     completion event is set.</para>
+    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
+    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
+    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
+    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
+    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,
+    ///     and not when the lamda returns.</para>
+    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
+    ///     without the need for locks.</para>
+    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
+    ///     to Windows Store apps.</para>
+    ///     <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Ty>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        explicit task(_Ty _Param, Concurrency::cancellation_token _Token)
+    {
+            details::_ValidateTaskConstructorArgs<_ReturnType, _Ty>(_Param);
+
+            _CreateImpl(_Token._GetImplValue());
+            // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor.
+            _SetTaskCreationAddressHint(_ReturnAddress());
+
+            _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param, 0));
+        }
+
+    /// <summary>
+    ///     Constructs a <c>task</c> object.
+    /// </summary>
+    /// <param name="_Other">
+    ///     The source <c>task</c> object.
+    /// </param>
+    /// <remarks>
+    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
+    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
+    ///     will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
+    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
+    ///     completion event is set.</para>
+    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
+    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
+    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
+    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
+    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,
+    ///     and not when the lamda returns.</para>
+    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
+    ///     without the need for locks.</para>
+    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
+    ///     to Windows Store apps.</para>
+    ///     <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    task(const task& _Other) : _M_Impl(_Other._M_Impl) {}
+
+    /// <summary>
+    ///     Constructs a <c>task</c> object.
+    /// </summary>
+    /// <param name="_Other">
+    ///     The source <c>task</c> object.
+    /// </param>
+    /// <remarks>
+    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
+    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
+    ///     will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
+    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
+    ///     completion event is set.</para>
+    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
+    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
+    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
+    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
+    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,
+    ///     and not when the lamda returns.</para>
+    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
+    ///     without the need for locks.</para>
+    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
+    ///     to Windows Store apps.</para>
+    ///     <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    task(task&& _Other) : _M_Impl(std::move(_Other._M_Impl)) {}
+
+    /// <summary>
+    ///     Replaces the contents of one <c>task</c> object with another.
+    /// </summary>
+    /// <param name="_Other">
+    ///     The source <c>task</c> object.
+    /// </param>
+    /// <remarks>
+    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
+    ///     actual task as <paramref name="_Other"/> does.
+    /// </remarks>
+    /**/
+    task& operator=(const task& _Other)
+    {
+        if (this != &_Other)
+        {
+            _M_Impl = _Other._M_Impl;
+        }
+        return *this;
+    }
+
+    /// <summary>
+    ///     Replaces the contents of one <c>task</c> object with another.
+    /// </summary>
+    /// <param name="_Other">
+    ///     The source <c>task</c> object.
+    /// </param>
+    /// <remarks>
+    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
+    ///     actual task as <paramref name="_Other"/> does.
+    /// </remarks>
+    /**/
+    task& operator=(task&& _Other)
+    {
+        if (this != &_Other)
+        {
+            _M_Impl = std::move(_Other._M_Impl);
+        }
+        return *this;
+    }
+
+    /// <summary>
+    ///     Adds a continuation task to this task.
+    /// </summary>
+    /// <typeparam name="_Function">
+    ///     The type of the function object that will be invoked by this task.
+    /// </typeparam>
+    /// <param name="_Func">
+    ///     The continuation function to execute when this task completes. This continuation function must take as input
+    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type
+    ///     of the result this task produces.
+    /// </param>
+    /// <returns>
+    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
+    /// </returns>
+    /// <remarks>
+    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
+    ///     to Windows Store apps.
+    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Function>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        auto then(const _Function& _Func) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
+    {
+            auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, nullptr, task_continuation_context::use_default());
+            // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
+            _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
+            return _ContinuationTask;
+        }
+
+    /// <summary>
+    ///     Adds a continuation task to this task.
+    /// </summary>
+    /// <typeparam name="_Function">
+    ///     The type of the function object that will be invoked by this task.
+    /// </typeparam>
+    /// <param name="_Func">
+    ///     The continuation function to execute when this task completes. This continuation function must take as input
+    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type
+    ///     of the result this task produces.
+    /// </param>
+    /// <param name="_CancellationToken">
+    ///     The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
+    ///     the token of its antecedent task.
+    /// </param>
+    /// <returns>
+    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
+    /// </returns>
+    /// <remarks>
+    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
+    ///     to Windows Store apps.
+    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Function>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
+    {
+        auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, _CancellationToken._GetImplValue(), task_continuation_context::use_default());
+        // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
+        _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
+        return _ContinuationTask;
+    }
+    /// <summary>
+    ///     Adds a continuation task to this task.
+    /// </summary>
+    /// <typeparam name="_Function">
+    ///     The type of the function object that will be invoked by this task.
+    /// </typeparam>
+    /// <param name="_Func">
+    ///     The continuation function to execute when this task completes. This continuation function must take as input
+    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type
+    ///     of the result this task produces.
+    /// </param>
+    /// <param name="_ContinuationContext">
+    ///     A variable that specifies where the continuation should execute. This variable is only useful when used in a
+    ///     Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
+    /// </param>
+    /// <returns>
+    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
+    /// </returns>
+    /// <remarks>
+    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
+    ///     to Windows Store apps.
+    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Function>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        auto then(const _Function& _Func, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
+    {
+        auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, nullptr, _ContinuationContext);
+        // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
+        _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
+        return _ContinuationTask;
+    }
+
+    /// <summary>
+    ///     Adds a continuation task to this task.
+    /// </summary>
+    /// <typeparam name="_Function">
+    ///     The type of the function object that will be invoked by this task.
+    /// </typeparam>
+    /// <param name="_Func">
+    ///     The continuation function to execute when this task completes. This continuation function must take as input
+    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type
+    ///     of the result this task produces.
+    /// </param>
+    /// <param name="_CancellationToken">
+    ///     The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
+    ///     the token of its antecedent task.
+    /// </param>
+    /// <param name="_ContinuationContext">
+    ///     A variable that specifies where the continuation should execute. This variable is only useful when used in a
+    ///     Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
+    /// </param>
+    /// <returns>
+    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
+    /// </returns>
+    /// <remarks>
+    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
+    ///     to Windows Store apps.
+    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Function>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
+    {
+            auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, _CancellationToken._GetImplValue(), _ContinuationContext);
+            // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
+            _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
+            return _ContinuationTask;
+        }
+
+    /// <summary>
+    ///     Waits for this task to reach a terminal state. It is possible for <c>wait</c> to execute the task inline, if all of the tasks
+    ///     dependencies are satisfied, and it has not already been picked up for execution by a background worker.
+    /// </summary>
+    /// <returns>
+    ///     A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception
+    ///     during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception.
+    /// </returns>
+    /**/
+    task_status wait() const
+    {
+        if (_M_Impl == nullptr)
+        {
+            throw Concurrency::invalid_operation("wait() cannot be called on a default constructed task.");
+        }
+
+        return _M_Impl->_Wait();
+    }
+
+    /// <summary>
+    ///     Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to
+    ///     finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>.
+    /// </summary>
+    /// <returns>
+    ///     The result of the task.
+    /// </returns>
+    /// <remarks>
+    ///     If the task is canceled, a call to <c>get</c> will throw a <see cref="task_canceled Class">task_canceled</see> exception. If the task
+    ///     encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception.
+    /// </remarks>
+    /**/
+    _ReturnType get() const
+    {
+        if (_M_Impl == nullptr)
+        {
+            throw Concurrency::invalid_operation("get() cannot be called on a default constructed task.");
+        }
+
+        if (_M_Impl->_Wait() == Concurrency::canceled)
+        {
+            throw Concurrency::task_canceled();
+        }
+
+        return _M_Impl->_GetResult();
+    }
+
+    /// <summary>
+    ///     Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task.
+    /// </summary>
+    /// <returns>
+    ///     <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise.
+    /// </returns>
+    /**/
+    bool is_apartment_aware() const
+    {
+        if (_M_Impl == nullptr)
+        {
+            throw Concurrency::invalid_operation("is_apartment_aware() cannot be called on a default constructed task.");
+        }
+        return _M_Impl->_IsApartmentAware();
+    }
+
+    /// <summary>
+    ///     Determines whether two <c>task</c> objects represent the same internal task.
+    /// </summary>
+    /// <returns>
+    ///     <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise.
+    /// </returns>
+    /**/
+    bool operator==(const task<_ReturnType>& _Rhs) const
+    {
+        return (_M_Impl == _Rhs._M_Impl);
+    }
+
+    /// <summary>
+    ///     Determines whether two <c>task</c> objects represent different internal tasks.
+    /// </summary>
+    /// <returns>
+    ///     <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise.
+    /// </returns>
+    /**/
+    bool operator!=(const task<_ReturnType>& _Rhs) const
+    {
+        return !operator==(_Rhs);
+    }
+
+    /// <summary>
+    ///     Create an underlying task implementation.
+    /// </summary>
+    void _CreateImpl(Concurrency::details::_CancellationTokenState * _Ct)
+    {
+        _CONCRT_ASSERT(_Ct != nullptr);
+        _M_Impl = details::_Task_ptr<_ReturnType>::_Make(_Ct);
+        if (_Ct != Concurrency::details::_CancellationTokenState::_None())
+        {
+            _M_Impl->_RegisterCancellation();
+        }
+    }
+
+    /// <summary>
+    ///     Return the underlying implementation for this task.
+    /// </summary>
+    const typename details::_Task_ptr<_ReturnType>::_Type & _GetImpl() const
+    {
+        return _M_Impl;
+    }
+
+    /// <summary>
+    ///     Set the implementation of the task to be the supplied implementaion.
+    /// </summary>
+    void _SetImpl(const typename details::_Task_ptr<_ReturnType>::_Type & _Impl)
+    {
+        _CONCRT_ASSERT(_M_Impl == nullptr);
+        _M_Impl = _Impl;
+    }
+
+    /// <summary>
+    ///     Set the implementation of the task to be the supplied implementaion using a move instead of a copy.
+    /// </summary>
+    void _SetImpl(typename details::_Task_ptr<_ReturnType>::_Type && _Impl)
+    {
+        _CONCRT_ASSERT(_M_Impl == nullptr);
+        _M_Impl = std::move(_Impl);
+    }
+
+    /// <summary>
+    ///     Sets a property determining whether the task is apartment aware.
+    /// </summary>
+    void _SetAsync(bool _Async = true)
+    {
+        _GetImpl()->_SetAsync(_Async);
+    }
+
+    /// <summary>
+    ///     Sets a field in the task impl to the return address for calls to the task constructors and the then method.
+    /// </summary>
+    void _SetTaskCreationAddressHint(void* _Address)
+    {
+        _GetImpl()->_SetTaskCreationAddressHint(_Address);
+    }
+
+    /// <summary>
+    ///     An internal version of then that takes additional flags and always execute the continuation inline by default.
+    ///     When _ForceInline is set to false, continuations inlining will be limited to default _DefaultAutoInline.
+    ///     This function is Used for runtime internal continuations only.
+    /// </summary>
+    template<typename _Function>
+    auto _Then(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState, bool _Aggregating,
+        Concurrency::details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
+    {
+        return _ThenImpl<_ReturnType, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Aggregating, _InliningMode);
+    }
+
+private:
+    template <typename T> friend class task;
+
+    // A helper class template that transforms an intial task lambda returns void into a lambda that returns a non-void type (details::_Unit_type is used
+    // to substitute for void). This is to minimize the special handling required for 'void'.
+    template<typename _RetType>
+    class _Init_func_transformer
+    {
+    public:
+        static auto _Perform(std::function<_RetType(void)> _Func) -> decltype(_Func)
+        {
+            return _Func;
+        }
+    };
+
+    template<>
+    class _Init_func_transformer<void>
+    {
+    public:
+        static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeVoidToUnitFunc(_Func))
+        {
+            return details::_MakeVoidToUnitFunc(_Func);
+        }
+    };
+
+    // The task handle type used to construct an 'initial task' - a task with no dependents.
+    template <typename _InternalReturnType, typename _Function, typename _TypeSelection>
+    struct _InitialTaskHandle :
+        details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, Concurrency::details::_UnrealizedChore>
+    {
+        _Function _M_function;
+        _InitialTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _TaskImpl, const _Function & _Function) : _M_function(_Function), _PPLTaskHandle(_TaskImpl)
+        {
+        }
+        virtual ~_InitialTaskHandle() {}
+
+        void _Perform() const
+        {
+            _Init(_TypeSelection());
+        }
+
+        //
+        // Overload 0: returns _InternalReturnType
+        //
+        // This is the most basic task with no unwrapping
+        //
+        void _Init(details::_TypeSelectorNoAsync) const
+        {
+            _M_pTask->_FinalizeAndRunContinuations(_Init_func_transformer<_InternalReturnType>::_Perform(_M_function)());
+        }
+
+        //
+        // Overload 1: returns IAsyncOperation<_InternalReturnType>^ (only uder /ZW)
+        //                   or
+        //             returns task<_InternalReturnType>
+        //
+        // This is task whose functor returns an async operation or a task which will be unwrapped for continuation
+        // Depending on the output type, the right _AsyncInit gets invoked
+        //
+        void _Init(details::_TypeSelectorAsyncOperationOrTask) const
+        {
+            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask, _M_function());
+        }
+
+        //
+        // Overload 2: returns IAsyncAction*
+        //
+        // This is task whose functor returns an async action which will be unwrapped for continuation
+        //
+        void _Init(details::_TypeSelectorAsyncAction) const
+        {
+            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask, Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(_M_function()));
+        }
+
+        //
+        // Overload 3: returns IAsyncOperationWithProgress<_InternalReturnType, _ProgressType>*
+        //
+        // This is task whose functor returns an async operation with progress which will be unwrapped for continuation
+        //
+        void _Init(details::_TypeSelectorAsyncOperationWithProgress) const
+        {
+            typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;
+
+            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask,
+                Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_InternalReturnType, _ProgressType>>(_M_function()));
+        }
+
+        //
+        // Overload 4: returns IAsyncActionWithProgress<_ProgressType>*
+        //
+        // This is task whose functor returns an async action with progress which will be unwrapped for continuation
+        //
+        void _Init(details::_TypeSelectorAsyncActionWithProgress) const
+        {
+            typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;
+
+            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask,
+                Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(_M_function()));
+        }
+    };
+
+    /// <summary>
+    ///     A helper class template that transforms a continuation lambda that either takes or returns void, or both, into a lambda that takes and returns a
+    ///     non-void type (details::_Unit_type is used to substitute for void). This is to minimize the special handling required for 'void'.
+    /// </summary>
+    template<typename _InpType, typename _OutType>
+    class _Continuation_func_transformer
+    {
+    public:
+        static auto _Perform(std::function<_OutType(_InpType)> _Func) -> decltype(_Func)
+        {
+            return _Func;
+        }
+    };
+
+    template<typename _OutType>
+    class _Continuation_func_transformer<void, _OutType>
+    {
+    public:
+        static auto _Perform(std::function<_OutType(void)> _Func) -> decltype(details::_MakeUnitToTFunc<_OutType>(_Func))
+        {
+            return details::_MakeUnitToTFunc<_OutType>(_Func);
+        }
+    };
+
+    template<typename _InType>
+    class _Continuation_func_transformer<_InType, void>
+    {
+    public:
+        static auto _Perform(std::function<void(_InType)> _Func) -> decltype(details::_MakeTToUnitFunc<_InType>(_Func))
+        {
+            return details::_MakeTToUnitFunc<_InType>(_Func);
+        }
+    };
+
+    template<>
+    class _Continuation_func_transformer<void, void>
+    {
+    public:
+        static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeUnitToUnitFunc(_Func))
+        {
+            return details::_MakeUnitToUnitFunc(_Func);
+        }
+    };
+    /// <summary>
+    ///     The task handle type used to create a 'continuation task'.
+    /// </summary>
+    template <typename _InternalReturnType, typename _ContinuationReturnType, typename _Function, typename _IsTaskBased, typename _TypeSelection>
+    struct _ContinuationTaskHandle :
+        details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,
+        _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>
+    {
+        typedef typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type _NormalizedContinuationReturnType;
+
+        typename details::_Task_ptr<_ReturnType>::_Type _M_ancestorTaskImpl;
+        _Function _M_function;
+
+        _ContinuationTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _AncestorImpl,
+            const typename details::_Task_ptr<_NormalizedContinuationReturnType>::_Type & _ContinuationImpl,
+            const _Function & _Func, const task_continuation_context & _Context, Concurrency::details::_TaskInliningMode _InliningMode) :
+            _M_ancestorTaskImpl(_AncestorImpl), _PPLTaskHandle(_ContinuationImpl), _M_function(_Func)
+        {
+            _M_isTaskBasedContinuation = _IsTaskBased::value;
+            _M_continuationContext = _Context;
+            _M_continuationContext._Resolve(_AncestorImpl->_IsApartmentAware());
+            _M_inliningMode = _InliningMode;
+        }
+
+        virtual ~_ContinuationTaskHandle() {}
+
+        void _Perform() const
+        {
+            _Continue(_IsTaskBased(), _TypeSelection());
+        }
+
+        //
+        // Overload 0-0: _InternalReturnType -> _TaskType
+        //
+        // This is a straight task continuation which simply invokes its target with the ancestor's completion argument
+        //
+        void _Continue(std::false_type, details::_TypeSelectorNoAsync) const
+        {
+            _M_pTask->_FinalizeAndRunContinuations(_Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult()));
+        }
+
+        //
+        // Overload 0-1: _InternalReturnType -> IAsyncOperation<_TaskType>^ (only uder /ZW)
+        //               or
+        //               _InternalReturnType -> task<_TaskType>
+        //
+        // This is a straight task continuation which returns an async operation or a task which will be unwrapped for continuation
+        // Depending on the output type, the right _AsyncInit gets invoked
+        //
+        void _Continue(std::false_type, details::_TypeSelectorAsyncOperationOrTask) const
+        {
+            typedef typename details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
+
+            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
+                _M_pTask,
+                _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult())
+                );
+        }
+
+        //
+        // Overload 0-2: _InternalReturnType -> IAsyncAction*
+        //
+        // This is a straight task continuation which returns an async action which will be unwrapped for continuation
+        //
+        void _Continue(std::false_type, details::_TypeSelectorAsyncAction) const
+        {
+            typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
+
+            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
+                _M_pTask,
+                Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(
+                _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult())));
+        }
+
+        //
+        // Overload 0-3: _InternalReturnType -> IAsyncOperationWithProgress<_TaskType, _ProgressType>*
+        //
+        // This is a straight task continuation which returns an async operation with progress which will be unwrapped for continuation
+        //
+        void _Continue(std::false_type, details::_TypeSelectorAsyncOperationWithProgress) const
+        {
+            typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
+
+            auto _OpWithProgress = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult());
+            typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;
+
+            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
+                _M_pTask,
+                Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>>(_OpWithProgress));
+        }
+
+        //
+        // Overload 0-4: _InternalReturnType -> IAsyncActionWithProgress<_ProgressType>*
+        //
+        // This is a straight task continuation which returns an async action with progress which will be unwrapped for continuation
+        //
+        void _Continue(std::false_type, details::_TypeSelectorAsyncActionWithProgress) const
+        {
+            typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
+
+            auto _OpWithProgress = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult());
+            typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;
+
+            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
+                _M_pTask,
+                Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(_OpWithProgress));
+        }
+
+
+        //
+        // Overload 1-0: task<_InternalReturnType> -> _TaskType
+        //
+        // This is an exception handling type of continuation which takes the task rather than the task's result.
+        //
+        void _Continue(std::true_type, details::_TypeSelectorNoAsync) const
+        {
+            typedef task<_InternalReturnType> _FuncInputType;
+            task<_InternalReturnType> _ResultTask;
+            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
+            _M_pTask->_FinalizeAndRunContinuations(_Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function)(std::move(_ResultTask)));
+        }
+
+        //
+        // Overload 1-1: task<_InternalReturnType> -> IAsyncOperation<_TaskType>^
+        //                                            or
+        //                                            task<_TaskType>
+        //
+        // This is an exception handling type of continuation which takes the task rather than
+        // the task's result. It also returns an async operation or a task which will be unwrapped
+        // for continuation
+        //
+        void _Continue(std::true_type, details::_TypeSelectorAsyncOperationOrTask) const
+        {
+            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
+            task<_InternalReturnType> _ResultTask;
+            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
+            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask, _M_function(std::move(_ResultTask)));
+        }
+
+        //
+        // Overload 1-2: task<_InternalReturnType> -> IAsyncAction*
+        //
+        // This is an exception handling type of continuation which takes the task rather than
+        // the task's result. It also returns an async action which will be unwrapped for continuation
+        //
+        void _Continue(std::true_type, details::_TypeSelectorAsyncAction) const
+        {
+            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
+            task<_InternalReturnType> _ResultTask;
+            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
+            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask,
+                Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(_M_function(std::move(_ResultTask))));
+        }
+
+        //
+        // Overload 1-3: task<_InternalReturnType> -> IAsyncOperationWithProgress<_TaskType, _ProgressType>*
+        //
+        // This is an exception handling type of continuation which takes the task rather than
+        // the task's result. It also returns an async operation with progress which will be unwrapped
+        // for continuation
+        //
+        void _Continue(std::true_type, details::_TypeSelectorAsyncOperationWithProgress) const
+        {
+            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
+            task<_InternalReturnType> _ResultTask;
+            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
+
+            typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;
+
+            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask,
+                Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>>(_M_function(std::move(_ResultTask))));
+        }
+
+        //
+        // Overload 1-4: task<_InternalReturnType> -> IAsyncActionWithProgress<_ProgressType>*
+        //
+        // This is an exception handling type of continuation which takes the task rather than
+        // the task's result. It also returns an async operation with progress which will be unwrapped
+        // for continuation
+        //
+        void _Continue(std::true_type, details::_TypeSelectorAsyncActionWithProgress) const
+        {
+            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
+            task<_InternalReturnType> _ResultTask;
+            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
+
+            typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;
+
+            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask,
+                Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(_M_function(std::move(_ResultTask))));
+        }
+    };
+    /// <summary>
+    ///     Initializes a task using a lambda, function pointer or function object.
+    /// </summary>
+    template<typename _InternalReturnType, typename _Function>
+    void _TaskInitWithFunctor(const _Function& _Func)
+    {
+        typedef details::_InitFunctorTypeTraits<_InternalReturnType, decltype(_Func())> _Async_type_traits;
+
+        _M_Impl->_M_fFromAsync = _Async_type_traits::_IsAsyncTask;
+        _M_Impl->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;
+
+        _M_Impl->_ScheduleTask(new _InitialTaskHandle<_InternalReturnType, _Function, typename _Async_type_traits::_AsyncKind>(_GetImpl(), _Func), Concurrency::details::_NoInline);
+    }
+
+    /// <summary>
+    ///     Initializes a task using a task completion event.
+    /// </summary>
+    void _TaskInitNoFunctor(task_completion_event<_ReturnType>& _Event)
+    {
+        _Event._RegisterTask(_M_Impl);
+    }
+    /// <summary>
+    ///     Initializes a task using an asynchronous action IAsyncAction*
+    /// </summary>
+    void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncAction* _AsyncAction)
+    {
+        _TaskInitAsyncOp((ABI::Windows::Foundation::IAsyncOperation<details::_Unit_type>*)Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(_AsyncAction).Detach());
+    }
+
+    /// <summary>
+    ///     Initializes a task using an asynchronous action with progress IAsyncActionWithProgress<_P>*
+    /// </summary>
+    template<typename _P>
+    void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncActionWithProgress<_P>* _AsyncActionWithProgress)
+    {
+        _TaskInitAsyncOp(Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_P>>(_AsyncActionWithProgress).Detach());
+    }
+    /// <summary>
+    ///     Initializes a task using an asynchronous operation IAsyncOperation<T>*
+    /// </summary>
+    template<typename _Result>
+    void _TaskInitAsyncOp(ABI::Windows::Foundation::IAsyncOperation<_Result>* _AsyncOp)
+    {
+        _M_Impl->_M_fFromAsync = true;
+        _M_Impl->_SetScheduledEvent();
+        // Mark this task as started here since we can set the state in the constructor without acquiring a lock. Once _AsyncInit
+        // returns a completion could execute concurrently and the task must be fully initialized before that happens.
+        _M_Impl->_M_TaskState = details::_Task_impl_base::_Started;
+        // Pass the shared pointer into _AsyncInit for storage in the Async Callback.
+        details::_Task_impl_base::_AsyncInit<_ReturnType, _Result>(_M_Impl, _AsyncOp);
+    }
+
+    /// <summary>
+    ///     Initializes a task using an asynchronous operation IAsyncOperation<T>*
+    /// </summary>
+    template<typename _Result>
+    void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncOperation<_Result>* _AsyncOp)
+    {
+        _TaskInitAsyncOp(_AsyncOp);
+    }
+
+    /// <summary>
+    ///     Initializes a task using an asynchronous operation with progress IAsyncOperationWithProgress<T, P>*
+    /// </summary>
+    template<typename _Result, typename _Progress>
+    void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>* _AsyncOp)
+    {
+        _TaskInitAsyncOp(Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_Result, _Progress>>(_AsyncOp).Detach());
+    }
+    /// <summary>
+    ///     Initializes a task using a callable object.
+    /// </summary>
+    template<typename _Function>
+    void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)
+    {
+        _TaskInitWithFunctor<_ReturnType, _Function>(_Func);
+    }
+
+    /// <summary>
+    ///     Initializes a task using a non-callable object.
+    /// </summary>
+    template<typename _Ty>
+    void _TaskInitMaybeFunctor(_Ty & _Param, std::false_type)
+    {
+        _TaskInitNoFunctor(_Param);
+    }
+
+    /// <summary>
+    ///     The one and only implementation of then for void and non-void tasks.
+    /// </summary>
+    template<typename _InternalReturnType, typename _Function>
+    auto _ThenImpl(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState, const task_continuation_context& _ContinuationContext,
+        bool _Aggregating = false, Concurrency::details::_TaskInliningMode _InliningMode = Concurrency::details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
+    {
+        if (_M_Impl == nullptr)
+        {
+            throw Concurrency::invalid_operation("then() cannot be called on a default constructed task.");
+        }
+
+        typedef details::_FunctionTypeTraits<_Function, _InternalReturnType> _Function_type_traits;
+        typedef details::_TaskTypeTraits<typename _Function_type_traits::_FuncRetType> _Async_type_traits;
+        typedef typename _Async_type_traits::_TaskRetType _TaskType;
+
+        //
+        // A **nullptr** token state indicates that it was not provided by the user. In this case, we inherit the antecedent's token UNLESS this is a
+        // an exception handling continuation. In that case, we break the chain with a _None. That continuation is never canceled unless the user
+        // explicitly passes the same token.
+        //
+        if (_PTokenState == nullptr)
+        {
+            if (_Function_type_traits::_Takes_task())
+            {
+                _PTokenState = Concurrency::details::_CancellationTokenState::_None();
+            }
+            else
+            {
+                _PTokenState = _GetImpl()->_M_pTokenState;
+            }
+        }
+
+        task<_TaskType> _ContinuationTask;
+        _ContinuationTask._CreateImpl(_PTokenState);
+
+        _ContinuationTask._GetImpl()->_M_fFromAsync = (_GetImpl()->_M_fFromAsync || _Async_type_traits::_IsAsyncTask);
+        _ContinuationTask._GetImpl()->_M_fRuntimeAggregate = _Aggregating;
+        _ContinuationTask._GetImpl()->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;
+
+        _GetImpl()->_ScheduleContinuation(new _ContinuationTaskHandle<_InternalReturnType, _TaskType, _Function, typename _Function_type_traits::_Takes_task, typename _Async_type_traits::_AsyncKind>(
+            _GetImpl(), _ContinuationTask._GetImpl(), _Func, _ContinuationContext, _InliningMode));
+
+        return _ContinuationTask;
+    }
+
+    // The underlying implementation for this task
+    typename details::_Task_ptr<_ReturnType>::_Type _M_Impl;
+};
+
+/// <summary>
+///     The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously,
+///     and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces
+///     a result of type <typeparamref name="_ResultType"/> on successful completion. Tasks of type <c>task&lt;void&gt;</c> produce no result.
+///     A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using
+///     continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns.
+/// </summary>
+/// <remarks>
+///     For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.
+/// </remarks>
+/**/
+template<>
+class task<void>
+{
+public:
+    /// <summary>
+    ///     Constructs a <c>task</c> object.
+    /// </summary>
+    /// <remarks>
+    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
+    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
+    ///     will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
+    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
+    ///     completion event is set.</para>
+    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
+    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
+    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
+    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
+    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,
+    ///     and not when the lamda returns.</para>
+    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
+    ///     without the need for locks.</para>
+    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
+    ///     to Windows Store apps.</para>
+    ///     <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    task() : _M_unitTask()
+    {
+        // The default constructor should create a task with a nullptr impl. This is a signal that the
+        // task is not usable and should throw if any wait(), get() or then() APIs are used.
+    }
+
+    /// <summary>
+    ///     Constructs a <c>task</c> object.
+    /// </summary>
+    /// <typeparam name="_Ty">
+    ///     The type of the parameter from which the task is to be constructed.
+    /// </typeparam>
+    /// <param name="_Param">
+    ///     The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event&lt;result_type&gt;</c>
+    ///     object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
+    ///     object should be a type equivalent to <c>std::function&lt;X(void)&gt;</c>, where X can be a variable of type <c>result_type</c>,
+    ///     <c>task&lt;result_type&gt;</c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
+    /// </param>
+    /// <remarks>
+    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
+    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
+    ///     will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
+    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
+    ///     completion event is set.</para>
+    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
+    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
+    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
+    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
+    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,
+    ///     and not when the lamda returns.</para>
+    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
+    ///     without the need for locks.</para>
+    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
+    ///     to Windows Store apps.</para>
+    ///     <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Ty>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        explicit task(_Ty _Param)
+    {
+        details::_ValidateTaskConstructorArgs<void, _Ty>(_Param);
+
+        _M_unitTask._CreateImpl(Concurrency::cancellation_token::none()._GetImplValue());
+        // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor.
+        _M_unitTask._SetTaskCreationAddressHint(_ReturnAddress());
+
+        _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param, 0));
+    }
+
+    /// <summary>
+    ///     Constructs a <c>task</c> object.
+    /// </summary>
+    /// <typeparam name="_Ty">
+    ///     The type of the parameter from which the task is to be constructed.
+    /// </typeparam>
+    /// <param name="_Param">
+    ///     The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event&lt;result_type&gt;</c>
+    ///     object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
+    ///     object should be a type equivalent to <c>std::function&lt;X(void)&gt;</c>, where X can be a variable of type <c>result_type</c>,
+    ///     <c>task&lt;result_type&gt;</c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
+    /// </param>
+    /// <param name="_Token">
+    ///     The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives
+    ///     the token <c>cancellation_token::none()</c>.
+    /// </param>
+    /// <remarks>
+    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
+    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
+    ///     will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
+    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
+    ///     completion event is set.</para>
+    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
+    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
+    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
+    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
+    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,
+    ///     and not when the lamda returns.</para>
+    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
+    ///     without the need for locks.</para>
+    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
+    ///     to Windows Store apps.</para>
+    ///     <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Ty>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        explicit task(_Ty _Param, Concurrency::cancellation_token _CancellationToken)
+    {
+            details::_ValidateTaskConstructorArgs<void, _Ty>(_Param);
+
+            _M_unitTask._CreateImpl(_CancellationToken._GetImplValue());
+            // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor.
+            _M_unitTask._SetTaskCreationAddressHint(_ReturnAddress());
+
+            _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param, 0));
+        }
+
+    /// <summary>
+    ///     Constructs a <c>task</c> object.
+    /// </summary>
+    /// <param name="_Other">
+    ///     The source <c>task</c> object.
+    /// </param>
+    /// <remarks>
+    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
+    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
+    ///     will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
+    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
+    ///     completion event is set.</para>
+    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
+    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
+    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
+    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
+    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,
+    ///     and not when the lamda returns.</para>
+    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
+    ///     without the need for locks.</para>
+    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
+    ///     to Windows Store apps.</para>
+    ///     <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    task(const task& _Other) : _M_unitTask(_Other._M_unitTask){}
+
+    /// <summary>
+    ///     Constructs a <c>task</c> object.
+    /// </summary>
+    /// <param name="_Other">
+    ///     The source <c>task</c> object.
+    /// </param>
+    /// <remarks>
+    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
+    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
+    ///     will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
+    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
+    ///     completion event is set.</para>
+    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
+    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
+    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
+    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
+    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,
+    ///     and not when the lamda returns.</para>
+    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
+    ///     without the need for locks.</para>
+    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
+    ///     to Windows Store apps.</para>
+    ///     <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    task(task&& _Other) : _M_unitTask(std::move(_Other._M_unitTask)) {}
+
+    /// <summary>
+    ///     Replaces the contents of one <c>task</c> object with another.
+    /// </summary>
+    /// <param name="_Other">
+    ///     The source <c>task</c> object.
+    /// </param>
+    /// <remarks>
+    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
+    ///     actual task as <paramref name="_Other"/> does.
+    /// </remarks>
+    /**/
+    task& operator=(const task& _Other)
+    {
+        if (this != &_Other)
+        {
+            _M_unitTask = _Other._M_unitTask;
+        }
+        return *this;
+    }
+
+    /// <summary>
+    ///     Replaces the contents of one <c>task</c> object with another.
+    /// </summary>
+    /// <param name="_Other">
+    ///     The source <c>task</c> object.
+    /// </param>
+    /// <remarks>
+    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
+    ///     actual task as <paramref name="_Other"/> does.
+    /// </remarks>
+    /**/
+    task& operator=(task&& _Other)
+    {
+        if (this != &_Other)
+        {
+            _M_unitTask = std::move(_Other._M_unitTask);
+        }
+        return *this;
+    }
+    /// <summary>
+    ///     Adds a continuation task to this task.
+    /// </summary>
+    /// <typeparam name="_Function">
+    ///     The type of the function object that will be invoked by this task.
+    /// </typeparam>
+    /// <param name="_Func">
+    ///     The continuation function to execute when this task completes. This continuation function must take as input
+    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type
+    ///     of the result this task produces.
+    /// </param>
+    /// <returns>
+    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
+    /// </returns>
+    /// <remarks>
+    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
+    ///     to Windows Store apps.
+    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Function>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        auto then(const _Function& _Func) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
+    {
+        auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, nullptr, task_continuation_context::use_default());
+        // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
+        _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
+        return _ContinuationTask;
+    }
+    /// <summary>
+    ///     Adds a continuation task to this task.
+    /// </summary>
+    /// <typeparam name="_Function">
+    ///     The type of the function object that will be invoked by this task.
+    /// </typeparam>
+    /// <param name="_Func">
+    ///     The continuation function to execute when this task completes. This continuation function must take as input
+    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type
+    ///     of the result this task produces.
+    /// </param>
+    /// <param name="_CancellationToken">
+    ///     The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
+    ///     the token of its antecedent task.
+    /// </param>
+    /// <returns>
+    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
+    /// </returns>
+    /// <remarks>
+    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
+    ///     to Windows Store apps.
+    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Function>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
+    {
+        auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, _CancellationToken._GetImplValue(), task_continuation_context::use_default());
+        // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
+        _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
+        return _ContinuationTask;
+    }
+    /// <summary>
+    ///     Adds a continuation task to this task.
+    /// </summary>
+    /// <typeparam name="_Function">
+    ///     The type of the function object that will be invoked by this task.
+    /// </typeparam>
+    /// <param name="_Func">
+    ///     The continuation function to execute when this task completes. This continuation function must take as input
+    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type
+    ///     of the result this task produces.
+    /// </param>
+    /// <param name="_ContinuationContext">
+    ///     A variable that specifies where the continuation should execute. This variable is only useful when used in a
+    ///     Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
+    /// </param>
+    /// <returns>
+    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
+    /// </returns>
+    /// <remarks>
+    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
+    ///     to Windows Store apps.
+    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Function>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        auto then(const _Function& _Func, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
+    {
+        auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, nullptr, _ContinuationContext);
+        // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
+        _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
+        return _ContinuationTask;
+
+    }
+    /// <summary>
+    ///     Adds a continuation task to this task.
+    /// </summary>
+    /// <typeparam name="_Function">
+    ///     The type of the function object that will be invoked by this task.
+    /// </typeparam>
+    /// <param name="_Func">
+    ///     The continuation function to execute when this task completes. This continuation function must take as input
+    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type
+    ///     of the result this task produces.
+    /// </param>
+    /// <param name="_CancellationToken">
+    ///     The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
+    ///     the token of its antecedent task.
+    /// </param>
+    /// <param name="_ContinuationContext">
+    ///     A variable that specifies where the continuation should execute. This variable is only useful when used in a
+    ///     Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
+    /// </param>
+    /// <returns>
+    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
+    /// </returns>
+    /// <remarks>
+    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
+    ///     to Windows Store apps.
+    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
+    /// </remarks>
+    /**/
+    template<typename _Function>
+    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+        auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
+    {
+            auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, _CancellationToken._GetImplValue(), _ContinuationContext);
+            // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
+            _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
+            return _ContinuationTask;
+        }
+
+    /// <summary>
+    ///     Waits for this task to reach a terminal state. It is possible for <c>wait</c> to execute the task inline, if all of the tasks
+    ///     dependencies are satisfied, and it has not already been picked up for execution by a background worker.
+    /// </summary>
+    /// <returns>
+    ///     A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception
+    ///     during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception.
+    /// </returns>
+    /**/
+    task_status wait() const
+    {
+        return _M_unitTask.wait();
+    }
+
+    /// <summary>
+    ///     Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to
+    ///     finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>.
+    /// </summary>
+    /// <remarks>
+    ///     If the task is canceled, a call to <c>get</c> will throw a <see cref="task_canceled Class">task_canceled</see> exception. If the task
+    ///     encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception.
+    /// </remarks>
+    /**/
+    void get() const
+    {
+        _M_unitTask.get();
+    }
+
+    /// <summary>
+    ///     Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task.
+    /// </summary>
+    /// <returns>
+    ///     <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise.
+    /// </returns>
+    /**/
+    bool is_apartment_aware() const
+    {
+        return _M_unitTask.is_apartment_aware();
+    }
+
+    /// <summary>
+    ///     Determines whether two <c>task</c> objects represent the same internal task.
+    /// </summary>
+    /// <returns>
+    ///     <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise.
+    /// </returns>
+    /**/
+    bool operator==(const task<void>& _Rhs) const
+    {
+        return (_M_unitTask == _Rhs._M_unitTask);
+    }
+
+    /// <summary>
+    ///     Determines whether two <c>task</c> objects represent different internal tasks.
+    /// </summary>
+    /// <returns>
+    ///     <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise.
+    /// </returns>
+    /**/
+    bool operator!=(const task<void>& _Rhs) const
+    {
+        return !operator==(_Rhs);
+    }
+
+    /// <summary>
+    ///     Create an underlying task implementation.
+    /// </summary>
+    void _CreateImpl(Concurrency::details::_CancellationTokenState * _Ct)
+    {
+        _M_unitTask._CreateImpl(_Ct);
+    }
+
+    /// <summary>
+    ///     Return the underlying implementation for this task.
+    /// </summary>
+    const details::_Task_ptr<details::_Unit_type>::_Type & _GetImpl() const
+    {
+        return _M_unitTask._M_Impl;
+    }
+
+    /// <summary>
+    ///     Set the implementation of the task to be the supplied implementaion.
+    /// </summary>
+    void _SetImpl(const details::_Task_ptr<details::_Unit_type>::_Type & _Impl)
+    {
+        _M_unitTask._SetImpl(_Impl);
+    }
+
+    /// <summary>
+    ///     Set the implementation of the task to be the supplied implementaion using a move instead of a copy.
+    /// </summary>
+    void _SetImpl(details::_Task_ptr<details::_Unit_type>::_Type && _Impl)
+    {
+        _M_unitTask._SetImpl(std::move(_Impl));
+    }
+
+    /// <summary>
+    ///     Sets a property determining whether the task is apartment aware.
+    /// </summary>
+    void _SetAsync(bool _Async = true)
+    {
+        _M_unitTask._SetAsync(_Async);
+    }
+
+    /// <summary>
+    ///     Sets a field in the task impl to the return address for calls to the task constructors and the then method.
+    /// </summary>
+    void _SetTaskCreationAddressHint(void* _Address)
+    {
+        _M_unitTask._SetTaskCreationAddressHint(_Address);
+    }
+
+    /// <summary>
+    ///     An internal version of then that takes additional flags and executes the continuation inline. Used for runtime internal continuations only.
+    /// </summary>
+    template<typename _Function>
+    auto _Then(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState,
+        bool _Aggregating, Concurrency::details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
+    {
+        return _M_unitTask._ThenImpl<void, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Aggregating, _InliningMode);
+    }
+
+private:
+    template <typename T> friend class task;
+    template <typename T> friend class task_completion_event;
+
+    /// <summary>
+    ///     Initializes a task using a task completion event.
+    /// </summary>
+    void _TaskInitNoFunctor(task_completion_event<void>& _Event)
+    {
+        _M_unitTask._TaskInitNoFunctor(_Event._M_unitEvent);
+    }
+    /// <summary>
+    ///     Initializes a task using a callable object.
+    /// </summary>
+    template<typename _Function>
+    void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)
+    {
+        _M_unitTask._TaskInitWithFunctor<void, _Function>(_Func);
+    }
+
+    /// <summary>
+    ///     Initializes a task using a non-callable object.
+    /// </summary>
+    template<typename _T>
+    void _TaskInitMaybeFunctor(_T & _Param, std::false_type)
+    {
+        _TaskInitNoFunctor(_Param);
+    }
+
+    // The void task contains a task of a dummy type so common code can be used for tasks with void and non-void results.
+    task<details::_Unit_type> _M_unitTask;
+};
+
+namespace details
+{
+
+    /// <summary>
+    ///   The following type traits are used for the create_task function.
+    /// </summary>
+
+    // Unwrap functions for asyncOperations
+    template<typename _Ty>
+    HRESULT _GetUnwrappedType(ABI::Windows::Foundation::IAsyncOperation<_Ty>*);
+
+    HRESULT _GetUnwrappedType(ABI::Windows::Foundation::IAsyncAction*);
+
+    template<typename _Ty, typename _Progress>
+    HRESULT _GetUnwrappedType(ABI::Windows::Foundation::IAsyncOperationWithProgress<_Ty, _Progress>*);
+
+    template<typename _Progress>
+    HRESULT _GetUnwrappedType(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>*);
+
+    // Unwrap task<T>
+    template<typename _Ty>
+    _Ty _GetUnwrappedType(task<_Ty>);
+
+    // Unwrap all supportted types
+    template<typename _Ty>
+    auto _GetUnwrappedReturnType(_Ty _Arg, int) -> decltype(_GetUnwrappedType(_Arg));
+    // fallback
+    template<typename _Ty>
+    _Ty _GetUnwrappedReturnType(_Ty, ...);
+
+    /// <summary>
+    ///   <c>_GetTaskType</c> functions will retrieve task type <c>T</c> in <c>task[T](Arg)</c>,
+    ///   for given constructor argument <c>Arg</c> and its property "callable".
+    ///   It will automatically unwrap argument to get the final return type if necessary.
+    /// </summary>
+
+    // Non-Callable
+    template<typename _Ty>
+    _Ty _GetTaskType(task_completion_event<_Ty>, std::false_type);
+
+    // Non-Callable
+    template<typename _Ty>
+    auto _GetTaskType(_Ty _NonFunc, std::false_type) -> decltype(_GetUnwrappedType(_NonFunc));
+
+    // Callable
+    template<typename _Ty>
+    auto _GetTaskType(_Ty _Func, std::true_type) -> decltype(_GetUnwrappedReturnType(_Func(), 0));
+
+    // Special callable returns void
+    void _GetTaskType(std::function<void()>, std::true_type);
+    struct _BadArgType{};
+
+    template<typename _Ty>
+    auto _FilterValidTaskType(_Ty _Param, int) -> decltype(_GetTaskType(_Param, _IsCallable(_Param, 0)));
+
+    template<typename _Ty>
+    _BadArgType _FilterValidTaskType(_Ty _Param, ...);
+
+    template<typename _Ty>
+    struct _TaskTypeFromParam
+    {
+        typedef decltype(_FilterValidTaskType(std::declval<_Ty>(), 0)) _Type;
+    };
+}
+
+
+/// <summary>
+///     Creates a PPL <see cref="task Class">task</c> object. <c>create_task</c> can be used anywhere you would have used a task constructor.
+///     It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks.
+/// </summary>
+/// <typeparam name="_Ty">
+///     The type of the parameter from which the task is to be constructed.
+/// </typeparam>
+/// <param name="_Param">
+///     The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c>
+///     object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app.
+/// </param>
+/// <returns>
+///     A new task of type <c>T</c>, that is inferred from <paramref name="_Param"/>.
+/// </returns>
+/// <remarks>
+///     The first overload behaves like a task constructor that takes a single parameter.
+///     <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not
+///     allowed to pass in a different <c>task</c> object as the first parameter.</para>
+///     <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name="_Param"/> is a <c>task_completion_event&lt;T&gt;</c>,
+///     a <c>task&lt;T&gt;</c>, or a functor that returns either type <c>T</c> or <c>task&lt;T&gt;</c>, the type of the created task is <c>task&lt;T&gt;</c>.
+///     <para>In a Windows Store app, if <paramref name="_Param"/> is of type Windows::Foundation::IAsyncOperation&ltT&gt^ or
+///     Windows::Foundation::IAsyncOperationWithProgress&ltT,P&gt^, or a functor that returns either of those types, the created task will be of type <c>task&lt;T&gt;</c>.
+///     If <paramref name="_Param"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress&lt;P&gt;^, or a functor
+///     that returns either of those types, the created task will have type <c>task&lt;void&gt;</c>.</para>
+/// </remarks>
+/// <seealso cref="task Class"/>
+/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
+/**/
+template<typename _Ty>
+__declspec(noinline)
+auto create_task(_Ty _Param) -> task<typename details::_TaskTypeFromParam<_Ty>::_Type>
+{
+    static_assert(!std::is_same<typename details::_TaskTypeFromParam<_Ty>::_Type, details::_BadArgType>::value,
+        "incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event"
+        );
+
+    task<typename details::_TaskTypeFromParam<_Ty>::_Type> _CreatedTask(_Param);
+    // Ideally we would like to forceinline create_task, but __forceinline does nothing on debug builds. Therefore, we ask for no inlining
+    // and overwrite the creation address hint set by the task constructor. DO NOT REMOVE this next line from create_task. It is
+    // essential that _ReturnAddress() evaluate to the instruction right after the call to create_task in client code.
+    _CreatedTask._SetTaskCreationAddressHint(_ReturnAddress());
+    return _CreatedTask;
+}
+
+/// <summary>
+///     Creates a PPL <see cref="task Class">task</c> object. <c>create_task</c> can be used anywhere you would have used a task constructor.
+///     It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks.
+/// </summary>
+/// <typeparam name="_Ty">
+///     The type of the parameter from which the task is to be constructed.
+/// </typeparam>
+/// <param name="_Param">
+///     The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c>
+///     object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app.
+/// </param>
+/// <param name="_Token">
+///     The cancellation token to associate with the task. When the source for this token is canceled, cancellation will be requested on the task.
+/// </param>
+/// <returns>
+///     A new task of type <c>T</c>, that is inferred from <paramref name="_Param"/>.
+/// </returns>
+/// <remarks>
+///     The first overload behaves like a task constructor that takes a single parameter.
+///     <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not
+///     allowed to pass in a different <c>task</c> object as the first parameter.</para>
+///     <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name="_Param"/> is a <c>task_completion_event&lt;T&gt;</c>,
+///     a <c>task&lt;T&gt;</c>, or a functor that returns either type <c>T</c> or <c>task&lt;T&gt;</c>, the type of the created task is <c>task&lt;T&gt;</c>.
+///     <para>In a Windows Store app, if <paramref name="_Param"/> is of type Windows::Foundation::IAsyncOperation&ltT&gt^ or
+///     Windows::Foundation::IAsyncOperationWithProgress&ltT,P&gt^, or a functor that returns either of those types, the created task will be of type <c>task&lt;T&gt;</c>.
+///     If <paramref name="_Param"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress&lt;P&gt;^, or a functor
+///     that returns either of those types, the created task will have type <c>task&lt;void&gt;</c>.</para>
+/// </remarks>
+/// <seealso cref="task Class"/>
+/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
+/**/
+template<typename _Ty>
+__declspec(noinline)
+auto create_task(_Ty _Param, Concurrency::cancellation_token _Token) -> task<typename details::_TaskTypeFromParam<_Ty>::_Type>
+{
+    static_assert(!std::is_same<typename details::_TaskTypeFromParam<_Ty>::_Type, details::_BadArgType>::value,
+        "incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event"
+        );
+    task<typename details::_TaskTypeFromParam<_Ty>::_Type> _CreatedTask(_Param, _Token);
+    // Ideally we would like to forceinline create_task, but __forceinline does nothing on debug builds. Therefore, we ask for no inlining
+    // and overwrite the creation address hint set by the task constructor. DO NOT REMOVE this next line from create_task. It is
+    // essential that _ReturnAddress() evaluate to the instruction right after the call to create_task in client code.
+    _CreatedTask._SetTaskCreationAddressHint(_ReturnAddress());
+    return _CreatedTask;
+}
+
+namespace details
+{
+    template<typename _T>
+    task<HRESULT> _To_task_helper(ABI::Windows::Foundation::IAsyncOperation<_T>* op)
+    {
+        return task<HRESULT>(op);
+    }
+
+    template<typename _T, typename _Progress>
+    task<HRESULT> _To_task_helper(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T, _Progress>* op)
+    {
+        return task<HRESULT>(op);
+    }
+
+    inline task<HRESULT> _To_task_helper(ABI::Windows::Foundation::IAsyncAction* op)
+    {
+        return task<HRESULT>(op);
+    }
+
+    template<typename _Progress>
+    task<HRESULT> _To_task_helper(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>* op)
+    {
+        return task<HRESULT>(op);
+    }
+
+    template<typename _ProgressType>
+    class _ProgressDispatcherBase
+    {
+    public:
+
+        virtual ~_ProgressDispatcherBase()
+        {
+        }
+
+        virtual void _Report(const _ProgressType& _Val) = 0;
+    };
+
+    template<typename _ProgressType, typename _ClassPtrType>
+    class _ProgressDispatcher : public _ProgressDispatcherBase<_ProgressType>
+    {
+    public:
+
+        virtual ~_ProgressDispatcher()
+        {
+        }
+
+        _ProgressDispatcher(_ClassPtrType _Ptr) : _M_ptr(_Ptr)
+        {
+        }
+
+        virtual void _Report(const _ProgressType& _Val)
+        {
+            _M_ptr->_FireProgress(_Val);
+        }
+
+    private:
+
+        _ClassPtrType _M_ptr;
+    };
+} // namespace details
+
+
+/// <summary>
+///     The progress reporter class allows reporting progress notifications of a specific type. Each progress_reporter object is bound
+///     to a particular asynchronous action or operation.
+/// </summary>
+/// <typeparam name="_ProgressType">
+///     The payload type of each progress notification reported through the progress reporter.
+/// </typeparam>
+/// <remarks>
+///     This type is only available to Windows Store apps.
+/// </remarks>
+/// <seealso cref="create_async Function"/>
+/**/
+template<typename _ProgressType>
+class progress_reporter
+{
+    typedef std::shared_ptr<details::_ProgressDispatcherBase<_ProgressType>> _PtrType;
+
+public:
+
+    /// <summary>
+    ///     Sends a progress report to the asynchronous action or operation to which this progress reporter is bound.
+    /// </summary>
+    /// <param name="_Val">
+    ///     The payload to report through a progress notification.
+    /// </param>
+    /**/
+    void report(const _ProgressType& _Val) const
+    {
+        _M_dispatcher->_Report(_Val);
+    }
+
+    template<typename _ClassPtrType>
+    static progress_reporter _CreateReporter(_ClassPtrType _Ptr)
+    {
+        progress_reporter _Reporter;
+        details::_ProgressDispatcherBase<_ProgressType> *_PDispatcher = new details::_ProgressDispatcher<_ProgressType, _ClassPtrType>(_Ptr);
+        _Reporter._M_dispatcher = _PtrType(_PDispatcher);
+        return _Reporter;
+    }
+    progress_reporter() {}
+
+private:
+    progress_reporter(details::_ProgressReporterCtorArgType);
+
+    _PtrType _M_dispatcher;
+};
+
+namespace details
+{
+    //
+    // maps internal definitions for AsyncStatus and defines states that are not client visible
+    //
+    enum _AsyncStatusInternal
+    {
+        _AsyncCreated = -1,  // externally invisible
+        // client visible states (must match AsyncStatus exactly)
+        _AsyncStarted = ABI::Windows::Foundation::AsyncStatus::Started, // 0
+        _AsyncCompleted = ABI::Windows::Foundation::AsyncStatus::Completed, // 1
+        _AsyncCanceled = ABI::Windows::Foundation::AsyncStatus::Canceled, // 2
+        _AsyncError = ABI::Windows::Foundation::AsyncStatus::Error, // 3
+        // non-client visible internal states
+        _AsyncCancelPending,
+        _AsyncClosed,
+        _AsyncUndefined
+    };
+
+    //
+    // designates whether the "GetResults" method returns a single result (after complete fires) or multiple results
+    // (which are progressively consumable between Start state and before Close is called)
+    //
+    enum _AsyncResultType
+    {
+        SingleResult = 0x0001,
+        MultipleResults = 0x0002
+    };
+
+    // ***************************************************************************
+    // Template type traits and helpers for async production APIs:
+    //
+
+    struct _ZeroArgumentFunctor { };
+    struct _OneArgumentFunctor { };
+    struct _TwoArgumentFunctor { };
+    struct _ThreeArgumentFunctor { };
+
+    // ****************************************
+    // CLASS TYPES:
+
+    // ********************
+    // THREE ARGUMENTS:
+
+    // non-void arg:
+    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const);
+
+    // non-void arg:
+    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const);
+
+    // non-void arg:
+    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg3 _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const);
+
+    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const);
+
+    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const);
+
+    // ********************
+    // TWO ARGUMENTS:
+
+    // non-void arg:
+    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
+    _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const);
+
+    // non-void arg:
+    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
+    _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const);
+
+    // non-void arg:
+    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
+    void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const);
+
+    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
+    _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const);
+
+    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
+    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2) const);
+
+    // ********************
+    // ONE ARGUMENT:
+
+    // non-void arg:
+    template<typename _Class, typename _ReturnType, typename _Arg1>
+    _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const);
+
+    // non-void arg:
+    template<typename _Class, typename _ReturnType, typename _Arg1>
+    void _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const);
+
+    // non-void arg:
+    template<typename _Class, typename _ReturnType, typename _Arg1>
+    void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const);
+
+    template<typename _Class, typename _ReturnType, typename _Arg1>
+    _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const);
+
+    template<typename _Class, typename _ReturnType, typename _Arg1>
+    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1) const);
+
+    // ********************
+    // ZERO ARGUMENT:
+
+    // void arg:
+    template<typename _Class, typename _ReturnType>
+    void _Arg1ClassHelperThunk(_ReturnType(_Class::*)() const);
+
+    // void arg:
+    template<typename _Class, typename _ReturnType>
+    void _Arg2ClassHelperThunk(_ReturnType(_Class::*)() const);
+
+    // void arg:
+    template<typename _Class, typename _ReturnType>
+    void _Arg3ClassHelperThunk(_ReturnType(_Class::*)() const);
+
+    // void arg:
+    template<typename _Class, typename _ReturnType>
+    _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)() const);
+
+    template<typename _Class, typename _ReturnType>
+    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)() const);
+
+    // ****************************************
+    // POINTER TYPES:
+
+    // ********************
+    // THREE ARGUMENTS:
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg3 _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg3 _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _Arg3 _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+    _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
+
+    // ********************
+    // TWO ARGUMENTS:
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
+
+    template<typename _ReturnType, typename _Arg1, typename _Arg2>
+    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2));
+
+    // ********************
+    // ONE ARGUMENT:
+
+    template<typename _ReturnType, typename _Arg1>
+    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
+
+    template<typename _ReturnType, typename _Arg1>
+    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1));
+
+    // ********************
+    // ZERO ARGUMENT:
+
+    template<typename _ReturnType>
+    void _Arg1PFNHelperThunk(_ReturnType(__cdecl *)());
+
+    template<typename _ReturnType>
+    void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)());
+
+    template<typename _ReturnType>
+    void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)());
+
+    template<typename _ReturnType>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)());
+
+    template<typename _ReturnType>
+    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)());
+
+    template<typename _ReturnType>
+    void _Arg1PFNHelperThunk(_ReturnType(__stdcall *)());
+
+    template<typename _ReturnType>
+    void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)());
+
+    template<typename _ReturnType>
+    void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)());
+
+    template<typename _ReturnType>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)());
+
+    template<typename _ReturnType>
+    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)());
+
+    template<typename _ReturnType>
+    void _Arg1PFNHelperThunk(_ReturnType(__fastcall *)());
+
+    template<typename _ReturnType>
+    void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)());
+
+    template<typename _ReturnType>
+    void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)());
+
+    template<typename _ReturnType>
+    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)());
+
+    template<typename _ReturnType>
+    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)());
+
+    template<typename _T>
+    struct _FunctorArguments
+    {
+        static const size_t _Count = 0;
+    };
+
+    template<>
+    struct _FunctorArguments<_OneArgumentFunctor>
+    {
+        static const size_t _Count = 1;
+    };
+
+    template<>
+    struct _FunctorArguments<_TwoArgumentFunctor>
+    {
+        static const size_t _Count = 2;
+    };
+
+    template<>
+    struct _FunctorArguments<_ThreeArgumentFunctor>
+    {
+        static const size_t _Count = 3;
+    };
+
+    template<typename _T>
+    struct _FunctorTypeTraits
+    {
+        typedef decltype(_ArgumentCountHelper(&(_T::operator()))) _ArgumentCountType;
+        static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;
+
+        typedef decltype(_ReturnTypeClassHelperThunk(&(_T::operator()))) _ReturnType;
+        typedef decltype(_Arg1ClassHelperThunk(&(_T::operator()))) _Argument1Type;
+        typedef decltype(_Arg2ClassHelperThunk(&(_T::operator()))) _Argument2Type;
+        typedef decltype(_Arg3ClassHelperThunk(&(_T::operator()))) _Argument3Type;
+    };
+
+    template<typename _T>
+    struct _FunctorTypeTraits<_T *>
+    {
+        typedef decltype(_ArgumentCountHelper(std::declval<_T*>())) _ArgumentCountType;
+        static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;
+
+        typedef decltype(_ReturnTypePFNHelperThunk(std::declval<_T*>())) _ReturnType;
+        typedef decltype(_Arg1PFNHelperThunk(std::declval<_T*>())) _Argument1Type;
+        typedef decltype(_Arg2PFNHelperThunk(std::declval<_T*>())) _Argument2Type;
+        typedef decltype(_Arg3PFNHelperThunk(std::declval<_T*>())) _Argument3Type;
+    };
+
+    template<typename _T>
+    struct _ProgressTypeTraits
+    {
+        static const bool _TakesProgress = false;
+        typedef void _ProgressType;
+    };
+
+    template<typename _T>
+    struct _ProgressTypeTraits<progress_reporter<_T>>
+    {
+        static const bool _TakesProgress = true;
+        typedef typename _T _ProgressType;
+    };
+
+    template<typename _T, bool bTakesToken = std::is_same<_T, Concurrency::cancellation_token_source>::value>
+    struct _TokenTypeTraits
+    {
+        static const bool _TakesToken = false;
+        typedef typename _T _ReturnType;
+    };
+
+    template<typename _T>
+    struct _TokenTypeTraits<_T, true>
+    {
+        static const bool _TakesToken = true;
+        typedef void _ReturnType;
+    };
+
+    template<typename _T, size_t count = _FunctorTypeTraits<_T>::_ArgumentCount>
+    struct _CAFunctorOptions
+    {
+        static const bool _TakesProgress = false;
+        static const bool _TakesToken = false;
+        typedef void _ProgressType;
+        typedef void _ReturnType;
+    };
+
+    template<typename _T>
+    struct _CAFunctorOptions<_T, 1>
+    {
+    private:
+
+        typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
+
+    public:
+
+        static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress;
+        static const bool _TakesToken = _TokenTypeTraits<_Argument1Type>::_TakesToken;
+        typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
+        typedef typename _TokenTypeTraits<_Argument1Type>::_TakesToken::_ReturnType _ReturnType;
+    };
+
+    template<typename _T>
+    struct _CAFunctorOptions<_T, 2>
+    {
+    private:
+
+        typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
+        typedef typename _FunctorTypeTraits<_T>::_Argument2Type _Argument2Type;
+
+    public:
+
+        static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress;
+        static const bool _TakesToken = !_TakesProgress ? true : _TokenTypeTraits<_Argument2Type>::_TakesToken;
+        typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
+        typedef typename _TokenTypeTraits<_Argument2Type>::_TakesToken::_ReturnType _ReturnType;
+    };
+
+    template<typename _T>
+    struct _CAFunctorOptions<_T, 3>
+    {
+    private:
+
+        typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
+
+    public:
+
+        static const bool _TakesProgress = true;
+        static const bool _TakesToken = true;
+        typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
+        typedef typename _FunctorTypeTraits<_T>::_Argument3Type _ReturnType;
+    };
+
+    class _Zip
+    {
+    };
+
+    // ***************************************************************************
+    // Async Operation Task Generators
+    //
+
+    //
+    // Functor returns an IAsyncInfo - result needs to be wrapped in a task:
+    //
+    template<typename _AsyncSelector, typename _ReturnType>
+    struct _SelectorTaskGenerator
+    {
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return task<HRESULT>(_Func(_pRet), _Cts.get_token());
+        }
+
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return task<HRESULT>(_Func(_Cts.get_token(), _pRet), _Cts.get_token());
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return task<HRESULT>(_Func(_Progress, _pRet), _Cts.get_token());
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return task<HRESULT>(_Func(_Progress, _Cts.get_token(), _pRet), _Cts.get_token());
+        }
+    };
+
+    template<typename _AsyncSelector>
+    struct _SelectorTaskGenerator<_AsyncSelector, void>
+    {
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
+        {
+            return task<HRESULT>(_Func(), _Cts.get_token());
+        }
+
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
+        {
+            return task<HRESULT>(_Func(_Cts.get_token()), _Cts.get_token());
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
+        {
+            return task<HRESULT>(_Func(_Progress), _Cts.get_token());
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
+        {
+            return task<HRESULT>(_Func(_Progress, _Cts.get_token()), _Cts.get_token());
+        }
+    };
+
+    // For create_async lambdas that return a (non-task) result, we oversubscriber the current task for the duration of the
+    // lambda.
+    struct _Task_generator_oversubscriber
+    {
+        _Task_generator_oversubscriber()
+        {
+            Concurrency::details::_Context::_Oversubscribe(true);
+        }
+
+        ~_Task_generator_oversubscriber()
+        {
+            Concurrency::details::_Context::_Oversubscribe(false);
+        }
+    };
+
+    //
+    // Functor returns a result - it needs to be wrapped in a task:
+    //
+    template<typename _ReturnType>
+    struct _SelectorTaskGenerator<details::_TypeSelectorNoAsync, _ReturnType>
+    {
+
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return task<HRESULT>([=]() -> HRESULT {
+                _Task_generator_oversubscriber _Oversubscriber;
+                return _Func(_pRet);
+            }, _Cts.get_token());
+        }
+
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return task<HRESULT>([=]() -> HRESULT {
+                _Task_generator_oversubscriber _Oversubscriber;
+                return _Func(_Cts.get_token(), _pRet);
+            }, _Cts.get_token());
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return task<HRESULT>([=]() -> HRESULT {
+                _Task_generator_oversubscriber _Oversubscriber;
+                return _Func(_Progress, _pRet);
+            }, _Cts.get_token());
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return task<HRESULT>([=]() -> HRESULT {
+                _Task_generator_oversubscriber _Oversubscriber;
+                return _Func(_Progress, _Cts.get_token(), _pRet);
+            }, _Cts.get_token());
+        }
+    };
+
+    template<>
+    struct _SelectorTaskGenerator<details::_TypeSelectorNoAsync, void>
+    {
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
+        {
+            return task<HRESULT>([=]() -> HRESULT {
+                _Task_generator_oversubscriber _Oversubscriber;
+                return _Func();
+            }, _Cts.get_token());
+        }
+
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
+        {
+            return task<HRESULT>([=]() -> HRESULT {
+                _Task_generator_oversubscriber _Oversubscriber;
+                return _Func(_Cts.get_token());
+            }, _Cts.get_token());
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
+        {
+            return task<HRESULT>([=]() -> HRESULT {
+                _Task_generator_oversubscriber _Oversubscriber;
+                return _Func(_Progress);
+            }, _Cts.get_token());
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
+        {
+            return task<HRESULT>([=]() -> HRESULT {
+                _Task_generator_oversubscriber _Oversubscriber;
+                return _Func(_Progress, _Cts.get_token());
+            }, _Cts.get_token());
+        }
+    };
+
+    //
+    // Functor returns a task - the task can directly be returned:
+    //
+    template<typename _ReturnType>
+    struct _SelectorTaskGenerator<details::_TypeSelectorAsyncTask, _ReturnType>
+    {
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return _Func(_pRet);
+        }
+
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return _Func(_Cts.get_token(), _pRet);
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return _Func(_Progress, _pRet);
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return _Func(_Progress, _Cts.get_token(), _pRet);
+        }
+    };
+
+    template<>
+    struct _SelectorTaskGenerator<details::_TypeSelectorAsyncTask, void>
+    {
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
+        {
+            return _Func();
+        }
+
+        template<typename _Function>
+        static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
+        {
+            return _Func(_Cts.get_token());
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
+        {
+            return _Func(_Progress);
+        }
+
+        template<typename _Function, typename _ProgressObject>
+        static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
+        {
+            return _Func(_Progress, _Cts.get_token());
+        }
+    };
+
+    template<typename _Generator, bool _TakesToken, bool TakesProgress>
+    struct _TaskGenerator
+    {
+    };
+
+    template<typename _Generator>
+    struct _TaskGenerator<_Generator, false, false>
+    {
+        template<typename _Function, typename _ClassPtr, typename _ProgressType>
+        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
+            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts))
+        {
+            (void)_Ptr;
+            return _Generator::_GenerateTask_0(_Func, _Cts);
+        }
+
+        template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
+        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet))
+        {
+            return _Generator::_GenerateTask_0(_Func, _Cts, _pRet);
+        }
+    };
+
+    template<typename _Generator>
+    struct _TaskGenerator<_Generator, true, false>
+    {
+        template<typename _Function, typename _ClassPtr, typename _ProgressType>
+        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
+            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts))
+        {
+            return _Generator::_GenerateTask_1C(_Func, _Cts);
+        }
+
+        template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
+        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet))
+        {
+            return _Generator::_GenerateTask_1C(_Func, _Cts, _pRet);
+        }
+    };
+
+    template<typename _Generator>
+    struct _TaskGenerator<_Generator, false, true>
+    {
+        template<typename _Function, typename _ClassPtr, typename _ProgressType>
+        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
+            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts))
+        {
+            return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts);
+        }
+
+        template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
+        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet))
+        {
+            return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _pRet);
+        }
+    };
+
+    template<typename _Generator>
+    struct _TaskGenerator<_Generator, true, true>
+    {
+        template<typename _Function, typename _ClassPtr, typename _ProgressType>
+        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
+            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts))
+        {
+            return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts);
+        }
+
+        template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
+        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet))
+        {
+            return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _pRet);
+        }
+    };
+
+    // ***************************************************************************
+    // Async Operation Attributes Classes
+    //
+    // These classes are passed through the hierarchy of async base classes in order to hold multiple attributes of a given async construct in
+    // a single container. An attribute class must define:
+    //
+    // Mandatory:
+    // -------------------------
+    //
+    // _AsyncBaseType           : The Windows Runtime interface which is being implemented.
+    // _CompletionDelegateType  : The Windows Runtime completion delegate type for the interface.
+    // _ProgressDelegateType    : If _TakesProgress is true, the Windows Runtime progress delegate type for the interface. If it is false, an empty Windows Runtime type.
+    // _ReturnType              : The return type of the async construct (void for actions / non-void for operations)
+    //
+    // _TakesProgress           : An indication as to whether or not
+    //
+    // _Generate_Task           : A function adapting the user's function into what's necessary to produce the appropriate task
+    //
+    // Optional:
+    // -------------------------
+    //
+
+    template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken, bool _TakesProgress>
+    struct _AsyncAttributes
+    {
+    };
+
+    template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>
+    struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, true>
+    {
+        typedef typename ABI::Windows::Foundation::IAsyncOperationWithProgress<_ReturnType, _ProgressType> _AsyncBaseType;
+        typedef typename ABI::Windows::Foundation::IAsyncOperationProgressHandler<_ReturnType, _ProgressType> _ProgressDelegateType;
+        typedef typename ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<_ReturnType, _ProgressType> _CompletionDelegateType;
+        typedef typename _ReturnType _ReturnType;
+        typedef typename _ProgressType _ProgressType;
+        typedef typename _TaskTraits::_AsyncKind _AsyncKind;
+        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
+        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;
+
+        static const bool _TakesProgress = true;
+        static const bool _TakesToken = _TakesToken;
+
+        template<typename _Function, typename _ClassPtr>
+        static task<HRESULT> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType, _ReturnType>(_Func, _Ptr, _Cts, _pRet);
+        }
+    };
+
+    template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>
+    struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, false>
+    {
+        typedef typename ABI::Windows::Foundation::IAsyncOperation<_ReturnType> _AsyncBaseType;
+        typedef _Zip _ProgressDelegateType;
+        typedef typename ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_ReturnType> _CompletionDelegateType;
+        typedef typename _ReturnType _ReturnType;
+        typedef typename _TaskTraits::_AsyncKind _AsyncKind;
+        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
+        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;
+
+        static const bool _TakesProgress = false;
+        static const bool _TakesToken = _TakesToken;
+
+        template<typename _Function, typename _ClassPtr>
+        static task<HRESULT> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+        {
+            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType, _ReturnType>(_Func, _Ptr, _Cts, _pRet);
+        }
+    };
+
+    template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>
+    struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, true>
+    {
+        typedef typename ABI::Windows::Foundation::IAsyncActionWithProgress<_ProgressType> _AsyncBaseType;
+        typedef typename ABI::Windows::Foundation::IAsyncActionProgressHandler<_ProgressType> _ProgressDelegateType;
+        typedef typename ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler<_ProgressType> _CompletionDelegateType;
+        typedef void _ReturnType;
+        typedef typename _ProgressType _ProgressType;
+        typedef typename _TaskTraits::_AsyncKind _AsyncKind;
+        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
+        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;
+
+        static const bool _TakesProgress = true;
+        static const bool _TakesToken = _TakesToken;
+
+        template<typename _Function, typename _ClassPtr>
+        static task<HRESULT> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
+        {
+            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts);
+        }
+    };
+
+    template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>
+    struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, false>
+    {
+        typedef typename ABI::Windows::Foundation::IAsyncAction _AsyncBaseType;
+        typedef _Zip _ProgressDelegateType;
+        typedef typename ABI::Windows::Foundation::IAsyncActionCompletedHandler _CompletionDelegateType;
+        typedef void _ReturnType;
+        typedef typename _TaskTraits::_AsyncKind _AsyncKind;
+        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
+        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;
+
+        static const bool _TakesProgress = false;
+        static const bool _TakesToken = _TakesToken;
+
+        template<typename _Function, typename _ClassPtr>
+        static task<HRESULT> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
+        {
+            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts);
+        }
+    };
+
+    template<typename _Function>
+    struct _AsyncLambdaTypeTraits
+    {
+        typedef typename _CAFunctorOptions<_Function>::_ReturnType _ReturnType;
+        typedef typename _FunctorTypeTraits<_Function>::_Argument1Type _Argument1Type;
+        typedef typename _CAFunctorOptions<_Function>::_ProgressType _ProgressType;
+
+        static const bool _TakesProgress = _CAFunctorOptions<_Function>::_TakesProgress;
+        static const bool _TakesToken = _CAFunctorOptions<_Function>::_TakesToken;
+
+        typedef typename _TaskTypeTraits<_ReturnType> _TaskTraits;
+        typedef typename _AsyncAttributes<_Function, _ProgressType, typename _TaskTraits::_TaskRetType, _TaskTraits, _TakesToken, _TakesProgress> _AsyncAttributes;
+    };
+    // ***************************************************************************
+    // AsyncInfo (and completion) Layer:
+    //
+
+    //
+    // Internal base class implementation for async operations (based on internal Windows representation for ABI level async operations)
+    //
+    template < typename _Attributes, _AsyncResultType resultType = SingleResult >
+    class _AsyncInfoBase abstract : public Microsoft::WRL::RuntimeClass<
+        Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRt>, Microsoft::WRL::Implements<typename _Attributes::_AsyncBaseType, ABI::Windows::Foundation::IAsyncInfo>>
+    {
+    public:
+        _AsyncInfoBase() :
+            _M_currentStatus(_AsyncStatusInternal::_AsyncCreated),
+            _M_errorCode(S_OK),
+            _M_completeDelegate(nullptr),
+            _M_CompleteDelegateAssigned(0),
+            _M_CallbackMade(0)
+        {
+            _M_id = Concurrency::details::_GetNextAsyncId();
+        }
+
+        virtual STDMETHODIMP GetResults(typename _Attributes::_ReturnType* results)
+        {
+            (void)results;
+            return E_UNEXPECTED;
+        }
+
+    public:
+        STDMETHODIMP get_Id(unsigned int* id)
+        {
+            HRESULT hr = _CheckValidStateForAsyncInfoCall();
+            if (FAILED(hr)) return hr;
+            if (!id) return E_POINTER;
+            *id = _M_id;
+            return S_OK;
+        }
+
+        STDMETHODIMP put_Id(unsigned int id)
+        {
+            HRESULT hr = _CheckValidStateForAsyncInfoCall();
+            if (FAILED(hr)) return hr;
+
+            if (id == 0)
+            {
+                return E_INVALIDARG;
+            }
+            else if (_M_currentStatus != _AsyncStatusInternal::_AsyncCreated)
+            {
+                return E_ILLEGAL_METHOD_CALL;
+            }
+
+            _M_id = id;
+            return S_OK;
+        }
+        STDMETHODIMP get_Status(ABI::Windows::Foundation::AsyncStatus* status)
+        {
+            HRESULT hr = _CheckValidStateForAsyncInfoCall();
+            if (FAILED(hr)) return hr;
+            if (!status) return E_POINTER;
+
+            _AsyncStatusInternal _Current = _M_currentStatus;
+            //
+            // Map our internal cancel pending to cancelled. This way "pending cancelled" looks to the outside as "cancelled" but
+            // can still transition to "completed" if the operation completes without acknowledging the cancellation request
+            //
+            switch (_Current)
+            {
+            case _AsyncCancelPending:
+                _Current = _AsyncCanceled;
+                break;
+            case _AsyncCreated:
+                _Current = _AsyncStarted;
+                break;
+            default:
+                break;
+            }
+
+            *status = static_cast<ABI::Windows::Foundation::AsyncStatus>(_Current);
+            return S_OK;
+        }
+
+        STDMETHODIMP get_ErrorCode(HRESULT* errorCode)
+        {
+            HRESULT hr = _CheckValidStateForAsyncInfoCall();
+            if (FAILED(hr)) return hr;
+            if (!hr) return hr;
+            *errorCode = _M_errorCode;
+            return S_OK;
+        }
+
+        STDMETHODIMP get_Progress(typename _Attributes::_ProgressDelegateType** _ProgressHandler)
+        {
+            return _GetOnProgress(_ProgressHandler);
+        }
+
+        STDMETHODIMP put_Progress(typename _Attributes::_ProgressDelegateType* _ProgressHandler)
+        {
+            return _PutOnProgress(_ProgressHandler);
+        }
+
+        STDMETHODIMP Cancel()
+        {
+            if (_TransitionToState(_AsyncCancelPending))
+            {
+                _OnCancel();
+            }
+            return S_OK;
+        }
+
+        STDMETHODIMP Close()
+        {
+            if (_TransitionToState(_AsyncClosed))
+            {
+                _OnClose();
+            }
+            else
+            {
+                if (_M_currentStatus != _AsyncClosed) // Closed => Closed transition is just ignored
+                {
+                    return E_ILLEGAL_STATE_CHANGE;
+                }
+            }
+            return S_OK;
+        }
+
+        virtual STDMETHODIMP get_Completed(typename _Attributes::_CompletionDelegateType** _CompleteHandler)
+        {
+            _CheckValidStateForDelegateCall();
+            if (!_CompleteHandler) return E_POINTER;
+            *_CompleteHandler = _M_completeDelegate;
+            return S_OK;
+        }
+
+        virtual STDMETHODIMP put_Completed(typename _Attributes::_CompletionDelegateType* _CompleteHandler)
+        {
+            _CheckValidStateForDelegateCall();
+            // this delegate property is "write once"
+            if (InterlockedIncrement(&_M_CompleteDelegateAssigned) == 1)
+            {
+                _M_completeDelegateContext = _ContextCallback::_CaptureCurrent();
+                _M_completeDelegate = _CompleteHandler;
+                // Guarantee that the write of _M_completeDelegate is ordered with respect to the read of state below
+                // as perceived from _FireCompletion on another thread.
+                MemoryBarrier();
+                if (_IsTerminalState())
+                {
+                    _FireCompletion();
+                }
+            }
+            else
+            {
+                return E_ILLEGAL_DELEGATE_ASSIGNMENT;
+            }
+            return S_OK;
+        }
+
+    protected:
+        // _Start - this is not externally visible since async operations "hot start" before returning to the caller
+        STDMETHODIMP _Start()
+        {
+            if (_TransitionToState(_AsyncStarted))
+            {
+                _OnStart();
+            }
+            else
+            {
+                return E_ILLEGAL_STATE_CHANGE;
+            }
+            return S_OK;
+        }
+
+        void _FireCompletion()
+        {
+            _TryTransitionToCompleted();
+
+            // we guarantee that completion can only ever be fired once
+            if (_M_completeDelegate != nullptr && InterlockedIncrement(&_M_CallbackMade) == 1)
+            {
+                _M_completeDelegateContext._CallInContext([=]() -> HRESULT {
+                    ABI::Windows::Foundation::AsyncStatus status;
+                    if (SUCCEEDED(this->get_Status(&status)))
+                        _M_completeDelegate->Invoke((_Attributes::_AsyncBaseType*)this, status);
+                    _M_completeDelegate = nullptr;
+                    return S_OK;
+                });
+            }
+        }
+
+        virtual STDMETHODIMP _GetOnProgress(typename _Attributes::_ProgressDelegateType** _ProgressHandler)
+        {
+            (void)_ProgressHandler;
+            return E_UNEXPECTED;
+        }
+
+        virtual STDMETHODIMP _PutOnProgress(typename _Attributes::_ProgressDelegateType* _ProgressHandler)
+        {
+            (void)_ProgressHandler;
+            return E_UNEXPECTED;
+        }
+
+
+        bool _TryTransitionToCompleted()
+        {
+            return _TransitionToState(_AsyncStatusInternal::_AsyncCompleted);
+        }
+
+        bool _TryTransitionToCancelled()
+        {
+            return _TransitionToState(_AsyncStatusInternal::_AsyncCanceled);
+        }
+
+        bool _TryTransitionToError(const HRESULT error)
+        {
+            _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_errorCode), error, S_OK);
+            return _TransitionToState(_AsyncStatusInternal::_AsyncError);
+        }
+
+        // This method checks to see if the delegate properties can be
+        // modified in the current state and generates the appropriate
+        // error hr in the case of violation.
+        inline HRESULT _CheckValidStateForDelegateCall()
+        {
+            if (_M_currentStatus == _AsyncClosed)
+            {
+                return E_ILLEGAL_METHOD_CALL;
+            }
+            return S_OK;
+        }
+
+        // This method checks to see if results can be collected in the
+        // current state and generates the appropriate error hr in
+        // the case of a violation.
+        inline HRESULT _CheckValidStateForResultsCall()
+        {
+            _AsyncStatusInternal _Current = _M_currentStatus;
+
+            if (_Current == _AsyncError)
+            {
+                return _M_errorCode;
+            }
+#pragma warning(push)
+#pragma warning(disable: 4127) // Conditional expression is constant
+            // single result illegal before transition to Completed or Cancelled state
+            if (resultType == SingleResult)
+#pragma warning(pop)
+            {
+                if (_Current != _AsyncCompleted)
+                {
+                    return E_ILLEGAL_METHOD_CALL;
+                }
+            }
+            // multiple results can be called after Start has been called and before/after Completed
+            else if (_Current != _AsyncStarted &&
+                _Current != _AsyncCancelPending &&
+                _Current != _AsyncCanceled &&
+                _Current != _AsyncCompleted)
+            {
+                return E_ILLEGAL_METHOD_CALL;
+            }
+            return S_OK;
+        }
+
+        // This method can be called by derived classes periodically to determine
+        // whether the asynchronous operation should continue processing or should
+        // be halted.
+        inline bool _ContinueAsyncOperation()
+        {
+            return _M_currentStatus == _AsyncStarted;
+        }
+
+        // These two methods are used to allow the async worker implementation do work on
+        // state transitions. No real "work" should be done in these methods. In other words
+        // they should not block for a long time on UI timescales.
+        virtual void _OnStart() = 0;
+        virtual void _OnClose() = 0;
+        virtual void _OnCancel() = 0;
+
+    private:
+
+        // This method is used to check if calls to the AsyncInfo properties
+        // (id, status, errorcode) are legal in the current state. It also
+        // generates the appropriate error hr to return in the case of an
+        // illegal call.
+        inline HRESULT _CheckValidStateForAsyncInfoCall()
+        {
+            _AsyncStatusInternal _Current = _M_currentStatus;
+            if (_Current == _AsyncClosed)
+            {
+                return E_ILLEGAL_METHOD_CALL;
+            }
+            else if (_Current == _AsyncCreated)
+            {
+                return E_ASYNC_OPERATION_NOT_STARTED;
+            }
+            return S_OK;
+        }
+
+        inline bool _TransitionToState(const _AsyncStatusInternal _NewState)
+        {
+            _AsyncStatusInternal _Current = _M_currentStatus;
+
+            // This enforces the valid state transitions of the asynchronous worker object
+            // state machine.
+            switch (_NewState)
+            {
+            case _AsyncStatusInternal::_AsyncStarted:
+                if (_Current != _AsyncCreated)
+                {
+                    return false;
+                }
+                break;
+            case _AsyncStatusInternal::_AsyncCompleted:
+                if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
+                {
+                    return false;
+                }
+                break;
+            case _AsyncStatusInternal::_AsyncCancelPending:
+                if (_Current != _AsyncStarted)
+                {
+                    return false;
+                }
+                break;
+            case _AsyncStatusInternal::_AsyncCanceled:
+                if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
+                {
+                    return false;
+                }
+                break;
+            case _AsyncStatusInternal::_AsyncError:
+                if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
+                {
+                    return false;
+                }
+                break;
+            case _AsyncStatusInternal::_AsyncClosed:
+                if (!_IsTerminalState(_Current))
+                {
+                    return false;
+                }
+                break;
+            default:
+                return false;
+                break;
+            }
+
+            // attempt the transition to the new state
+            // Note: if currentStatus_ == _Current, then there was no intervening write
+            // by the async work object and the swap succeeded.
+            _AsyncStatusInternal _RetState = static_cast<_AsyncStatusInternal>(
+                _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_currentStatus),
+                _NewState,
+                static_cast<LONG>(_Current)));
+
+            // ICE returns the former state, if the returned state and the
+            // state we captured at the beginning of this method are the same,
+            // the swap succeeded.
+            return (_RetState == _Current);
+        }
+
+        inline bool _IsTerminalState()
+        {
+            return _IsTerminalState(_M_currentStatus);
+        }
+
+        inline bool _IsTerminalState(_AsyncStatusInternal status)
+        {
+            return (status == _AsyncError ||
+                status == _AsyncCanceled ||
+                status == _AsyncCompleted ||
+                status == _AsyncClosed);
+        }
+
+    private:
+
+        _ContextCallback        _M_completeDelegateContext;
+        typename _Attributes::_CompletionDelegateType*  volatile _M_completeDelegate;
+        _AsyncStatusInternal volatile                   _M_currentStatus;
+        HRESULT volatile                                _M_errorCode;
+        unsigned int                                    _M_id;
+        long volatile                                   _M_CompleteDelegateAssigned;
+        long volatile                                   _M_CallbackMade;
+    };
+
+    // ***************************************************************************
+    // Progress Layer (optional):
+    //
+
+    template< typename _Attributes, bool _HasProgress, _AsyncResultType _ResultType = SingleResult >
+    class _AsyncProgressBase abstract : public _AsyncInfoBase<_Attributes, _ResultType>
+    {
+    };
+
+    template< typename _Attributes, _AsyncResultType _ResultType>
+    class _AsyncProgressBase<_Attributes, true, _ResultType> abstract : public _AsyncInfoBase<_Attributes, _ResultType>
+    {
+    public:
+
+        _AsyncProgressBase() : _AsyncInfoBase<_Attributes, _ResultType>(),
+            _M_progressDelegate(nullptr)
+        {
+        }
+
+        virtual STDMETHODIMP _GetOnProgress(typename _Attributes::_ProgressDelegateType** _ProgressHandler) override
+        {
+            HRESULT hr = _CheckValidStateForDelegateCall();
+            if (FAILED(hr)) return hr;
+            *_ProgressHandler = _M_progressDelegate;
+            return S_OK;
+        }
+
+        virtual STDMETHODIMP _PutOnProgress(typename _Attributes::_ProgressDelegateType* _ProgressHandler) override
+        {
+            HRESULT hr = _CheckValidStateForDelegateCall();
+            if (FAILED(hr)) return hr;
+            _M_progressDelegate = _ProgressHandler;
+            _M_progressDelegateContext = _ContextCallback::_CaptureCurrent();
+            return S_OK;
+        }
+
+    public:
+
+        void _FireProgress(const typename _Attributes::_ProgressType& _ProgressValue)
+        {
+            if (_M_progressDelegate != nullptr)
+            {
+                _M_progressDelegateContext._CallInContext([=] -> HRESULT {
+                    _M_progressDelegate((_Attributes::_AsyncBaseType*)this, _ProgressValue);
+                    return S_OK;
+                });
+            }
+        }
+
+    private:
+
+        _ContextCallback _M_progressDelegateContext;
+        typename _Attributes::_ProgressDelegateType* _M_progressDelegate;
+    };
+
+    template<typename _Attributes, _AsyncResultType _ResultType = SingleResult>
+    class _AsyncBaseProgressLayer abstract : public _AsyncProgressBase<_Attributes, _Attributes::_TakesProgress, _ResultType>
+    {
+    };
+
+    // ***************************************************************************
+    // Task Adaptation Layer:
+    //
+
+    //
+    // _AsyncTaskThunkBase provides a bridge between IAsync<Action/Operation> and task.
+    //
+    template<typename _Attributes, typename _ReturnType>
+    class _AsyncTaskThunkBase abstract : public _AsyncBaseProgressLayer<_Attributes>
+    {
+    public:
+        STDMETHODIMP GetResults(_ReturnType* results)
+        {
+            HRESULT hr = _CheckValidStateForResultsCall();
+            if (FAILED(hr)) return hr;
+            hr = _M_task.get();
+            if (SUCCEEDED(hr)) *results = _M_results;
+            return hr;
+        }
+
+    public:
+        typedef task<HRESULT> _TaskType;
+
+        _AsyncTaskThunkBase(const _TaskType& _Task)
+            : _M_task(_Task)
+        {
+        }
+
+        _AsyncTaskThunkBase()
+        {
+        }
+
+        void _SetTaskCreationAddressHint(void* _SourceAddressHint)
+        {
+            if (!(std::is_same<_Attributes::_AsyncKind, _TypeSelectorAsyncTask>::value))
+            {
+                // Overwrite the creation address with the return address of create_async unless the
+                // lambda returned a task. If the create async lambda returns a task, that task is reused and
+                // we want to preserve its creation address hint.
+                _M_task._SetTaskCreationAddressHint(_SourceAddressHint);
+            }
+        }
+        template <typename _Function>
+        void DoCreateTask(_Function _func)
+        {
+            _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results);
+        }
+
+    protected:
+        virtual void _OnStart() override
+        {
+            _M_task.then([=](_TaskType _Antecedent) {
+                try
+                {
+                    _Antecedent.get();
+                }
+                catch (Concurrency::task_canceled&)
+                {
+                    _TryTransitionToCancelled();
+                }
+                catch(const _com_error& _Ex)
+                {
+                    _TryTransitionToError(_Ex->HResult);
+                }
+                catch (...)
+                {
+                    _TryTransitionToError(E_FAIL);
+                }
+                _FireCompletion();
+            });
+        }
+
+    protected:
+        _TaskType _M_task;
+        _ReturnType _M_results;
+        Concurrency::cancellation_token_source _M_cts;
+    };
+
+    template<typename _Attributes>
+    class _AsyncTaskThunkBase<_Attributes, void> abstract : public _AsyncBaseProgressLayer<_Attributes>
+    {
+    public:
+        STDMETHODIMP GetResults()
+        {
+            HRESULT hr = _CheckValidStateForResultsCall();
+            if (FAILED(hr)) return hr;
+            hr = _M_task.get();
+            return hr;
+        }
+    public:
+        typedef task<HRESULT> _TaskType;
+
+        _AsyncTaskThunkBase(const _TaskType& _Task)
+            : _M_task(_Task)
+        {
+        }
+
+        _AsyncTaskThunkBase()
+        {
+        }
+
+        void _SetTaskCreationAddressHint(void* _SourceAddressHint)
+        {
+            if (!(std::is_same<_Attributes::_AsyncKind, _TypeSelectorAsyncTask>::value))
+            {
+                // Overwrite the creation address with the return address of create_async unless the
+                // lambda returned a task. If the create async lambda returns a task, that task is reused and
+                // we want to preserve its creation address hint.
+                _M_task._SetTaskCreationAddressHint(_SourceAddressHint);
+            }
+        }
+        template <typename _Function>
+        void DoCreateTask(_Function _func)
+        {
+            _M_task = _Attributes::_Generate_Task(_func, this, _M_cts);
+        }
+    protected:
+        virtual void _OnStart() override
+        {
+            _M_task.then([=](_TaskType _Antecedent) -> void {
+                try
+                {
+                    _Antecedent.get();
+                }
+                catch (Concurrency::task_canceled&)
+                {
+                    _TryTransitionToCancelled();
+                }
+                catch (...)
+                {
+                    _TryTransitionToError(E_FAIL);
+                }
+                _FireCompletion();
+            });
+        }
+
+    protected:
+        _TaskType _M_task;
+        Concurrency::cancellation_token_source _M_cts;
+    };
+
+    template<typename _Attributes>
+    class _AsyncTaskThunk : public _AsyncTaskThunkBase<_Attributes, typename _Attributes::_ReturnType>
+    {
+    public:
+
+        _AsyncTaskThunk(const _TaskType& _Task) :
+            _AsyncTaskThunkBase(_Task)
+        {
+        }
+
+        _AsyncTaskThunk()
+        {
+        }
+
+    protected:
+
+        virtual void _OnClose() override
+        {
+        }
+
+        virtual void _OnCancel() override
+        {
+            _M_cts.cancel();
+        }
+    };
+
+    // ***************************************************************************
+    // Async Creation Layer:
+    //
+    template<typename _Function>
+    class _AsyncTaskGeneratorThunk : public _AsyncTaskThunk<typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes>
+    {
+    public:
+
+        typedef typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes _Attributes;
+        typedef typename _AsyncTaskThunk<_Attributes> _Base;
+        typedef typename _Attributes::_AsyncBaseType _AsyncBaseType;
+
+        _AsyncTaskGeneratorThunk(const _Function& _Func) : _M_func(_Func)
+        {
+            // Virtual call here is safe as the class is declared 'sealed'
+            _Start();
+        }
+
+    protected:
+
+        //
+        // The only thing we must do different from the base class is we must spin the hot task on transition from Created->Started. Otherwise,
+        // let the base thunk handle everything.
+        //
+
+        virtual void _OnStart() override
+        {
+            //
+            // Call the appropriate task generator to actually produce a task of the expected type. This might adapt the user lambda for progress reports,
+            // wrap the return result in a task, or allow for direct return of a task depending on the form of the lambda.
+            //
+            DoCreateTask<_Function>(_M_func);
+            _Base::_OnStart();
+        }
+
+        virtual void _OnCancel() override
+        {
+            _Base::_OnCancel();
+        }
+
+    private:
+
+        _Function _M_func;
+    };
+} // namespace details
+
+/// <summary>
+///     Creates a Windows Runtime asynchronous construct based on a user supplied lambda or function object. The return type of <c>create_async</c> is
+///     one of either <c>IAsyncAction^</c>, <c>IAsyncActionWithProgress&lt;TProgress&gt;^</c>, <c>IAsyncOperation&lt;TResult&gt;^</c>, or
+///     <c>IAsyncOperationWithProgress&lt;TResult, TProgress&gt;^</c> based on the signature of the lambda passed to the method.
+/// </summary>
+/// <param name="_Func">
+///     The lambda or function object from which to create a Windows Runtime asynchronous construct.
+/// </param>
+/// <returns>
+///     An asynchronous construct represented by an IAsyncAction^, IAsyncActionWithProgress&lt;TProgress&gt;^, IAsyncOperation&lt;TResult&gt;^, or an
+///     IAsyncOperationWithProgress&lt;TResult, TProgress&gt;^. The interface returned depends on the signature of the lambda passed into the function.
+/// </returns>
+/// <remarks>
+///     The return type of the lambda determines whether the construct is an action or an operation.
+///     <para>Lambdas that return void cause the creation of actions. Lambdas that return a result of type <c>TResult</c> cause the creation of
+///     operations of TResult.</para>
+///     <para>The lambda may also return a <c>task&lt;TResult&gt;</c> which encapsulates the aysnchronous work within itself or is the continuation of
+///     a chain of tasks that represent the asynchronous work. In this case, the lambda itself is executed inline, since the tasks are the ones that
+///     execute asynchronously, and the return type of the lambda is unwrapped to produce the asynchronous construct returned by <c>create_async</c>.
+///     This implies that a lambda that returns a task&lt;void&gt; will cause the creation of actions, and a lambda that returns a task&lt;TResult&gt; will
+///     cause the creation of operations of TResult.</para>
+///     <para>The lambda may take either zero, one or two arguments. The valid arguments are <c>progress_reporter&lt;TProgress&gt;</c> and
+///     <c>cancellation_token</c>, in that order if both are used. A lambda without arguments causes the creation of an asynchronous construct without
+///     the capability for progress reporting. A lambda that takes a progress_reporter&lt;TProgress&gt; will cause <c>create_async</c> to return an asynchronous
+///     construct which reports progress of type TProgress each time the <c>report</c> method of the progress_reporter object is called. A lambda that
+///     takes a cancellation_token may use that token to check for cancellation, or pass it to tasks that it creates so that cancellation of the
+///     asynchronous construct causes cancellation of those tasks.</para>
+///     <para>If the body of the lambda or function object returns a result (and not a task&lt;TResult&gt;), the lamdba will be executed
+///     asynchronously within the process MTA in the context of a task the Runtime implicitly creates for it. The <c>IAsyncInfo::Cancel</c> method will
+///     cause cancellation of the implicit task.</para>
+///     <para>If the body of the lambda returns a task, the lamba executes inline, and by declaring the lambda to take an argument of type
+///     <c>cancellation_token</c> you can trigger cancellation of any tasks you create within the lambda by passing that token in when you create them.
+///     You may also use the <c>register_callback</c> method on the token to cause the Runtime to invoke a callback when you call <c>IAsyncInfo::Cancel</c> on
+///     the async operation or action produced..</para>
+///     <para>This function is only available to Windows Store apps.</para>
+/// </remarks>
+/// <seealso cref="task Class"/>
+/// <seealso cref="progress_reporter Class"/>
+/// <seealso cref="cancelation_token Class"/>
+/**/
+template<typename _Function>
+__declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
+details::_AsyncTaskGeneratorThunk<_Function>* create_async(const _Function& _Func)
+{
+    static_assert(std::is_same<decltype(details::_IsValidCreateAsync(_Func, 0, 0, 0, 0)), std::true_type>::value,
+        "argument to create_async must be a callable object taking zero, one or two arguments");
+    Microsoft::WRL::ComPtr<details::_AsyncTaskGeneratorThunk<_Function>> _AsyncInfo = Microsoft::WRL::Make<details::_AsyncTaskGeneratorThunk<_Function>>(_Func);
+    _AsyncInfo->_SetTaskCreationAddressHint(_ReturnAddress());
+    return _AsyncInfo.Detach();
+}
+} // namespace Concurrency_winrt
+
+namespace concurrency_winrt = Concurrency_winrt;
+
+#pragma pop_macro("new")
+#pragma warning(pop)
+#pragma pack(pop)
+#endif
diff --git a/modules/imgproc/perf/opencl/perf_3vs4.cpp b/modules/imgproc/perf/opencl/perf_3vs4.cpp
new file mode 100644 (file)
index 0000000..f6601e1
--- /dev/null
@@ -0,0 +1,137 @@
+// 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.
+
+// Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+#include "perf_precomp.hpp"
+#include "opencv2/ts/ocl_perf.hpp"
+
+#ifdef HAVE_OPENCL
+
+namespace cvtest {
+namespace ocl {
+
+///////////// 3 channels Vs 4 ////////////////////////
+
+enum
+{
+    Pure = 0, Split, Convert
+};
+
+CV_ENUM(Modes, Pure, Split, Convert)
+
+typedef tuple <Size, MatType, Modes> _3vs4Params;
+typedef TestBaseWithParam<_3vs4Params> _3vs4_Fixture;
+
+OCL_PERF_TEST_P(_3vs4_Fixture, Resize,
+                ::testing::Combine(OCL_TEST_SIZES, OCL_PERF_ENUM(CV_8UC3, CV_32FC3), Modes::all()))
+{
+    _3vs4Params params = GetParam();
+    const Size srcSize = get<0>(params);
+    const int type = get<1>(params), depth = CV_MAT_DEPTH(type);
+    const int mode = get<2>(params);
+
+    checkDeviceMaxMemoryAllocSize(srcSize, type);
+
+    UMat src(srcSize, type), dst(srcSize, type);
+    declare.in(src, WARMUP_RNG).out(dst);
+
+    if (mode == Pure)
+    {
+        OCL_TEST_CYCLE() resize(src, dst, Size(), 0.5, 0.5, INTER_LINEAR);
+    }
+    else if (mode == Split)
+    {
+        std::vector<UMat> srcs(3), dsts(3);
+
+        for (int i = 0; i < 3; ++i)
+        {
+            dsts[i] = UMat(srcSize, depth);
+            srcs[i] = UMat(srcSize, depth);
+        }
+
+        OCL_TEST_CYCLE()
+        {
+            split(src, srcs);
+
+            for (size_t i = 0; i < srcs.size(); ++i)
+                resize(srcs[i], dsts[i], Size(), 0.5, 0.5, INTER_LINEAR);
+
+            merge(dsts, dst);
+        }
+    }
+    else if (mode == Convert)
+    {
+        int type4 = CV_MAKE_TYPE(depth, 4);
+        UMat src4(srcSize, type4), dst4(srcSize, type4);
+
+        OCL_TEST_CYCLE()
+        {
+            cvtColor(src, src4, COLOR_RGB2RGBA);
+            resize(src4, dst4, Size(), 0.5, 0.5, INTER_LINEAR);
+            cvtColor(dst4, dst, COLOR_RGBA2RGB);
+        }
+    }
+
+    SANITY_CHECK_NOTHING();
+}
+
+OCL_PERF_TEST_P(_3vs4_Fixture, Subtract,
+                ::testing::Combine(OCL_TEST_SIZES, OCL_PERF_ENUM(CV_8UC3, CV_32FC3), Modes::all()))
+{
+    _3vs4Params params = GetParam();
+    const Size srcSize = get<0>(params);
+    const int type = get<1>(params), depth = CV_MAT_DEPTH(type);
+    const int mode = get<2>(params);
+
+    checkDeviceMaxMemoryAllocSize(srcSize, type);
+
+    Scalar s(14);
+    UMat src(srcSize, type), dst(srcSize, type);
+    declare.in(src, WARMUP_RNG).out(dst);
+
+    if (mode == Pure)
+    {
+        OCL_TEST_CYCLE() subtract(src, s, dst);
+    }
+    else if (mode == Split)
+    {
+        std::vector<UMat> srcs(3), dsts(3);
+
+        for (int i = 0; i < 3; ++i)
+        {
+            dsts[i] = UMat(srcSize, depth);
+            srcs[i] = UMat(srcSize, depth);
+        }
+
+        OCL_TEST_CYCLE()
+        {
+            split(src, srcs);
+
+            for (size_t i = 0; i < srcs.size(); ++i)
+                subtract(srcs[i], s, dsts[i]);
+
+            merge(dsts, dst);
+        }
+    }
+    else if (mode == Convert)
+    {
+        int type4 = CV_MAKE_TYPE(depth, 4);
+        UMat src4(srcSize, type4), dst4(srcSize, type4);
+
+        OCL_TEST_CYCLE()
+        {
+            cvtColor(src, src4, COLOR_RGB2RGBA);
+            subtract(src4, s, dst4);
+            cvtColor(dst4, dst, COLOR_RGBA2RGB);
+        }
+    }
+
+    SANITY_CHECK_NOTHING();
+}
+
+} } // namespace cvtest::ocl
+
+#endif // HAVE_OPENCL
index ae6112e..0d63e94 100644 (file)
@@ -103,7 +103,7 @@ typedef tuple<Size, MatType, Border> CopyMakeBorderParamType;
 typedef TestBaseWithParam<CopyMakeBorderParamType> CopyMakeBorderFixture;
 
 OCL_PERF_TEST_P(CopyMakeBorderFixture, CopyMakeBorder,
-            ::testing::Combine(OCL_TEST_SIZES, OCL_TEST_TYPES, Border::all()))
+            ::testing::Combine(OCL_TEST_SIZES, OCL_TEST_TYPES_134, Border::all()))
 {
     const CopyMakeBorderParamType params = GetParam();
     const Size srcSize = get<0>(params);
index ac958fc..b4011ee 100644 (file)
@@ -42,7 +42,6 @@
 
 #include "precomp.hpp"
 #include <limits.h>
-#include <stdio.h>
 #include "opencl_kernels.hpp"
 
 /****************************************************************************************\
@@ -1291,9 +1290,10 @@ static bool ocl_morphology_op(InputArray _src, OutputArray _dst, Mat kernel,
 {
     CV_Assert(op == MORPH_ERODE || op == MORPH_DILATE);
 
+    int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
     bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0;
 
-    if (_src.depth() == CV_64F && !doubleSupport)
+    if (depth == CV_64F && !doubleSupport)
         return false;
 
     UMat kernel8U;
@@ -1324,13 +1324,14 @@ static bool ocl_morphology_op(InputArray _src, OutputArray _dst, Mat kernel,
         return false;
 
     static const char * const op2str[] = { "ERODE", "DILATE" };
-    String buildOptions = format("-D RADIUSX=%d -D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D %s%s%s -D GENTYPE=%s -D DEPTH_%d",
-                                 anchor.x, anchor.y, (int)localThreads[0], (int)localThreads[1], op2str[op],
+    String buildOptions = format("-D RADIUSX=%d -D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D %s%s%s"
+                                 " -D T=%s -D DEPTH_%d -D cn=%d -D T1=%s", anchor.x, anchor.y,
+                                 (int)localThreads[0], (int)localThreads[1], op2str[op],
                                  doubleSupport ? " -D DOUBLE_SUPPORT" : "", rectKernel ? " -D RECTKERNEL" : "",
-                                 ocl::typeToStr(_src.type()), _src.depth() );
+                                 ocl::typeToStr(_src.type()), _src.depth(), cn, ocl::typeToStr(depth));
 
     std::vector<ocl::Kernel> kernels;
-    for (int i = 0; i<iterations; i++)
+    for (int i = 0; i < iterations; i++)
     {
         ocl::Kernel k("morph", ocl::imgproc::morph_oclsrc, buildOptions);
         if (k.empty())
@@ -1341,33 +1342,27 @@ static bool ocl_morphology_op(InputArray _src, OutputArray _dst, Mat kernel,
     _dst.create(src.size(), src.type());
     UMat dst = _dst.getUMat();
 
-    if( iterations== 1 && src.u != dst.u)
+    if (iterations == 1 && src.u != dst.u)
     {
         Size wholesize;
         Point ofs;
         src.locateROI(wholesize, ofs);
         int wholecols = wholesize.width, wholerows = wholesize.height;
 
-        int idxArg = 0;
-        idxArg = kernels[0].set(idxArg, ocl::KernelArg::ReadOnlyNoSize(src));
-        idxArg = kernels[0].set(idxArg, ocl::KernelArg::WriteOnlyNoSize(dst));
-        idxArg = kernels[0].set(idxArg, ofs.x);
-        idxArg = kernels[0].set(idxArg, ofs.y);
-        idxArg = kernels[0].set(idxArg, src.cols);
-        idxArg = kernels[0].set(idxArg, src.rows);
-        idxArg = kernels[0].set(idxArg, ocl::KernelArg::PtrReadOnly(kernel8U));
-        idxArg = kernels[0].set(idxArg, wholecols);
-        idxArg = kernels[0].set(idxArg, wholerows);
+        kernels[0].args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnlyNoSize(dst),
+                        ofs.x, ofs.y, src.cols, src.rows, ocl::KernelArg::PtrReadOnly(kernel8U),
+                        wholecols, wholerows);
 
         return kernels[0].run(2, globalThreads, localThreads, false);
     }
 
-    for(int i = 0; i< iterations; i++)
+    for (int i = 0; i < iterations; i++)
     {
         UMat source;
         Size wholesize;
         Point ofs;
-        if( i == 0)
+
+        if (i == 0)
         {
             int cols =  src.cols, rows = src.rows;
             src.locateROI(wholesize,ofs);
@@ -1385,20 +1380,11 @@ static bool ocl_morphology_op(InputArray _src, OutputArray _dst, Mat kernel,
             dst.adjustROI(-ofs.y, -wholesize.height + rows + ofs.y, -ofs.x, -wholesize.width + cols + ofs.x);
             source.adjustROI(-ofs.y, -wholesize.height + rows + ofs.y, -ofs.x, -wholesize.width + cols + ofs.x);
         }
-
         source.locateROI(wholesize, ofs);
-        int wholecols = wholesize.width, wholerows = wholesize.height;
 
-        int idxArg = 0;
-        idxArg = kernels[i].set(idxArg, ocl::KernelArg::ReadOnlyNoSize(source));
-        idxArg = kernels[i].set(idxArg, ocl::KernelArg::WriteOnlyNoSize(dst));
-        idxArg = kernels[i].set(idxArg, ofs.x);
-        idxArg = kernels[i].set(idxArg, ofs.y);
-        idxArg = kernels[i].set(idxArg, source.cols);
-        idxArg = kernels[i].set(idxArg, source.rows);
-        idxArg = kernels[i].set(idxArg, ocl::KernelArg::PtrReadOnly(kernel8U));
-        idxArg = kernels[i].set(idxArg, wholecols);
-        idxArg = kernels[i].set(idxArg, wholerows);
+        kernels[i].args(ocl::KernelArg::ReadOnlyNoSize(source), ocl::KernelArg::WriteOnlyNoSize(dst),
+                        ofs.x, ofs.y, source.cols, source.rows, ocl::KernelArg::PtrReadOnly(kernel8U),
+                        wholesize.width, wholesize.height);
 
         if (!kernels[i].run(2, globalThreads, localThreads, false))
             return false;
@@ -1427,13 +1413,13 @@ static void morphOp( int op, InputArray _src, OutputArray _dst,
         return;
 #endif
 
-    if( iterations == 0 || kernel.rows*kernel.cols == 1 )
+    if (iterations == 0 || kernel.rows*kernel.cols == 1)
     {
         _src.copyTo(_dst);
         return;
     }
 
-    if( !kernel.data )
+    if (!kernel.data)
     {
         kernel = getStructuringElement(MORPH_RECT, Size(1+iterations*2,1+iterations*2));
         anchor = Point(iterations, iterations);
@@ -1450,7 +1436,7 @@ static void morphOp( int op, InputArray _src, OutputArray _dst,
     }
 
     CV_OCL_RUN(_dst.isUMat() && _src.size() == _dst.size() && src_type == dst_type &&
-               _src.dims() <= 2 && (src_cn == 1 || src_cn == 4) &&
+               _src.dims() <= 2 && src_cn <= 4 &&
                (src_depth == CV_8U || src_depth == CV_32F || src_depth == CV_64F ) &&
                borderType == cv::BORDER_CONSTANT && borderValue == morphologyDefaultBorderValue() &&
                (op == MORPH_ERODE || op == MORPH_DILATE),
index 35c0a27..fe11b49 100644 (file)
 #endif
 #endif
 
+#if cn != 3
+#define loadpix(addr) *(__global const T *)(addr)
+#define storepix(val, addr)  *(__global T *)(addr) = val
+#define TSIZE (int)sizeof(T)
+#else
+#define loadpix(addr) vload3(0, (__global const T1 *)(addr))
+#define storepix(val, addr) vstore3(val, 0, (__global T1 *)(addr))
+#define TSIZE ((int)sizeof(T1)*3)
+#endif
+
 #ifdef DEPTH_0
 #ifdef ERODE
 #define VAL 255
 #ifdef DILATE
 #define VAL 0
 #endif
-#endif
-#ifdef DEPTH_5
+#elif defined DEPTH_5
 #ifdef ERODE
 #define VAL FLT_MAX
 #endif
 #ifdef DILATE
 #define VAL -FLT_MAX
 #endif
-#endif
-#ifdef DEPTH_6
+#elif defined DEPTH_6
 #ifdef ERODE
 #define VAL DBL_MAX
 #endif
 #ifdef DILATE
 #define MORPH_OP(A,B) max((A),(B))
 #endif
-//BORDER_CONSTANT:      iiiiii|abcdefgh|iiiiiii
-#define ELEM(i,l_edge,r_edge,elem1,elem2) (i)<(l_edge) | (i) >= (r_edge) ? (elem1) : (elem2)
 
-__kernel void morph(__global const uchar * restrict srcptr, int src_step, int src_offset,
+// BORDER_CONSTANT:      iiiiii|abcdefgh|iiiiiii
+#define ELEM(i, l_edge, r_edge, elem1, elem2) (i) < (l_edge) | (i) >= (r_edge) ? (elem1) : (elem2)
+
+__kernel void morph(__global const uchar * srcptr, int src_step, int src_offset,
                     __global uchar * dstptr, int dst_step, int dst_offset,
-                    int src_offset_x, int src_offset_y,
-                    int cols, int rows,
-                    __constant uchar * mat_kernel,
-                    int src_whole_cols, int src_whole_rows)
+                    int src_offset_x, int src_offset_y, int cols, int rows,
+                    __constant uchar * mat_kernel, int src_whole_cols, int src_whole_rows)
 {
-    int l_x = get_local_id(0);
-    int l_y = get_local_id(1);
-    int x = get_group_id(0)*LSIZE0;
-    int y = get_group_id(1)*LSIZE1;
-    int start_x = x+src_offset_x-RADIUSX;
-    int end_x = x + src_offset_x+LSIZE0+RADIUSX;
-    int width = end_x -(x+src_offset_x-RADIUSX)+1;
-    int start_y = y+src_offset_y-RADIUSY;
-    int point1 = mad24(l_y,LSIZE0,l_x);
-    int point2 = point1 + LSIZE0*LSIZE1;
-    int tl_x = point1 % width;
-    int tl_y = point1 / width;
-    int tl_x2 = point2 % width;
-    int tl_y2 = point2 / width;
-    int cur_x = start_x + tl_x;
-    int cur_y = start_y + tl_y;
-    int cur_x2 = start_x + tl_x2;
-    int cur_y2 = start_y + tl_y2;
-    int start_addr = mad24(cur_y,src_step, cur_x*(int)sizeof(GENTYPE));
-    int start_addr2 = mad24(cur_y2,src_step, cur_x2*(int)sizeof(GENTYPE));
-    GENTYPE temp0,temp1;
-    __local GENTYPE LDS_DAT[2*LSIZE1*LSIZE0];
+    int gidx = get_global_id(0), gidy = get_global_id(1);
+    int l_x = get_local_id(0), l_y = get_local_id(1);
+    int x = get_group_id(0) * LSIZE0, y = get_group_id(1) * LSIZE1;
+    int start_x = x + src_offset_x - RADIUSX;
+    int end_x = x + src_offset_x + LSIZE0 + RADIUSX;
+    int width = end_x - (x + src_offset_x - RADIUSX) + 1;
+    int start_y = y + src_offset_y - RADIUSY;
+    int point1 = mad24(l_y, LSIZE0, l_x);
+    int point2 = point1 + LSIZE0 * LSIZE1;
+    int tl_x = point1 % width, tl_y = point1 / width;
+    int tl_x2 = point2 % width, tl_y2 = point2 / width;
+    int cur_x = start_x + tl_x, cur_y = start_y + tl_y;
+    int cur_x2 = start_x + tl_x2, cur_y2 = start_y + tl_y2;
+    int start_addr = mad24(cur_y, src_step, cur_x * TSIZE);
+    int start_addr2 = mad24(cur_y2, src_step, cur_x2 * TSIZE);
 
-    int end_addr = mad24(src_whole_rows - 1,src_step,src_whole_cols*(int)sizeof(GENTYPE));
-    //read pixels from src
-    start_addr = ((start_addr < end_addr) && (start_addr > 0)) ? start_addr : 0;
-    start_addr2 = ((start_addr2 < end_addr) && (start_addr2 > 0)) ? start_addr2 : 0;
-    __global const GENTYPE * src;
-    src = (__global const GENTYPE *)(srcptr+start_addr);
-    temp0 = src[0];
-    src = (__global const GENTYPE *)(srcptr+start_addr2);
-    temp1 = src[0];
-    //judge if read out of boundary
-    temp0= ELEM(cur_x,0,src_whole_cols,(GENTYPE)VAL,temp0);
-    temp0= ELEM(cur_y,0,src_whole_rows,(GENTYPE)VAL,temp0);
+    __local T LDS_DAT[2*LSIZE1*LSIZE0];
 
-    temp1= ELEM(cur_x2,0,src_whole_cols,(GENTYPE)VAL,temp1);
-    temp1= ELEM(cur_y2,0,src_whole_rows,(GENTYPE)VAL,temp1);
+    // read pixels from src
+    int end_addr = mad24(src_whole_rows - 1, src_step, src_whole_cols * TSIZE);
+    start_addr = start_addr < end_addr && start_addr > 0 ? start_addr : 0;
+    start_addr2 = start_addr2 < end_addr && start_addr2 > 0 ? start_addr2 : 0;
+
+    T temp0 = loadpix(srcptr + start_addr);
+    T temp1 = loadpix(srcptr + start_addr2);
+
+    // judge if read out of boundary
+    temp0 = ELEM(cur_x, 0, src_whole_cols, (T)(VAL),temp0);
+    temp0 = ELEM(cur_y, 0, src_whole_rows, (T)(VAL),temp0);
+
+    temp1 = ELEM(cur_x2, 0, src_whole_cols, (T)(VAL), temp1);
+    temp1 = ELEM(cur_y2, 0, src_whole_rows, (T)(VAL), temp1);
 
     LDS_DAT[point1] = temp0;
     LDS_DAT[point2] = temp1;
     barrier(CLK_LOCAL_MEM_FENCE);
-    GENTYPE res = (GENTYPE)VAL;
-    for(int i=0; i<2*RADIUSY+1; i++)
-        for(int j=0; j<2*RADIUSX+1; j++)
+
+    T res = (T)(VAL);
+    for (int i = 0, sizey = 2 * RADIUSY + 1; i < sizey; i++)
+        for (int j = 0, sizex = 2 * RADIUSX + 1; j < sizex; j++)
         {
             res =
 #ifndef RECTKERNEL
                 mat_kernel[i*(2*RADIUSX+1)+j] ?
 #endif
-                MORPH_OP(res,LDS_DAT[mad24(l_y+i,width,l_x+j)])
+                MORPH_OP(res, LDS_DAT[mad24(l_y + i, width, l_x + j)])
 #ifndef RECTKERNEL
-                :res
+                : res
 #endif
                 ;
         }
-    int gidx = get_global_id(0);
-    int gidy = get_global_id(1);
-    if(gidx<cols && gidy<rows)
+
+    if (gidx < cols && gidy < rows)
     {
-        int dst_index = mad24(gidy, dst_step, dst_offset + gidx * (int)sizeof(GENTYPE));
-        __global GENTYPE * dst = (__global GENTYPE *)(dstptr + dst_index);
-        dst[0] = res;
+        int dst_index = mad24(gidy, dst_step, mad24(gidx, TSIZE, dst_offset));
+        storepix(res, dstptr + dst_index);
     }
-
 }
index 586c34b..50c9085 100644 (file)
@@ -58,10 +58,10 @@ PARAM_TEST_CASE(AccumulateBase, std::pair<MatDepth, MatDepth>, Channels, bool)
     bool useRoi;
     double alpha;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_INPUT_PARAMETER(mask)
-    TEST_DECLARE_INPUT_PARAMETER(src2)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_INPUT_PARAMETER(mask);
+    TEST_DECLARE_INPUT_PARAMETER(src2);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -90,10 +90,10 @@ PARAM_TEST_CASE(AccumulateBase, std::pair<MatDepth, MatDepth>, Channels, bool)
         Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, dtype, -MAX_VALUE, MAX_VALUE);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_INPUT_PARAMETER(mask)
-        UMAT_UPLOAD_INPUT_PARAMETER(src2)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_INPUT_PARAMETER(mask);
+        UMAT_UPLOAD_INPUT_PARAMETER(src2);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
 
         alpha = randomDouble(-5, 5);
     }
index 17c0b13..7b62b97 100644 (file)
@@ -57,11 +57,11 @@ PARAM_TEST_CASE(BlendLinear, MatDepth, Channels, bool)
     int depth, channels;
     bool useRoi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src1)
-    TEST_DECLARE_INPUT_PARAMETER(src2)
-    TEST_DECLARE_INPUT_PARAMETER(weights2)
-    TEST_DECLARE_INPUT_PARAMETER(weights1)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src1);
+    TEST_DECLARE_INPUT_PARAMETER(src2);
+    TEST_DECLARE_INPUT_PARAMETER(weights2);
+    TEST_DECLARE_INPUT_PARAMETER(weights1);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -89,22 +89,22 @@ PARAM_TEST_CASE(BlendLinear, MatDepth, Channels, bool)
         randomSubMat(weights2, weights2_roi, roiSize, weights2Border, CV_32FC1, 1e-2, upValue);
 
         weights2_roi -= weights1_roi;
-        CV_Assert(checkNorm(weights2_roi, weights2(Rect(weights2Border.lef, weights2Border.top,
+        CV_Assert(checkNorm2(weights2_roi, weights2(Rect(weights2Border.lef, weights2Border.top,
                                                         roiSize.width, roiSize.height))) < 1e-6);
 
         Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, type, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src1)
-        UMAT_UPLOAD_INPUT_PARAMETER(src2)
-        UMAT_UPLOAD_INPUT_PARAMETER(weights1)
-        UMAT_UPLOAD_INPUT_PARAMETER(weights2)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src1);
+        UMAT_UPLOAD_INPUT_PARAMETER(src2);
+        UMAT_UPLOAD_INPUT_PARAMETER(weights1);
+        UMAT_UPLOAD_INPUT_PARAMETER(weights2);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double eps = 0.0)
     {
-        OCL_EXPECT_MATS_NEAR(dst, eps)
+        OCL_EXPECT_MATS_NEAR(dst, eps);
     }
 };
 
index c95657c..e1e936a 100644 (file)
@@ -61,8 +61,8 @@ PARAM_TEST_CASE(BoxFilterBase, MatDepth, Channels, BorderType, bool, bool)
     Point anchor;
     bool normalize, useRoi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -76,7 +76,6 @@ PARAM_TEST_CASE(BoxFilterBase, MatDepth, Channels, BorderType, bool, bool)
     void random_roi()
     {
         int type = CV_MAKE_TYPE(depth, cn);
-        dsize = randomSize(1, MAX_VALUE);
         ksize = randomSize(kernelMinSize, kernelMaxSize);
 
         Size roiSize = randomSize(ksize.width, MAX_VALUE, ksize.height, MAX_VALUE);
@@ -84,18 +83,18 @@ PARAM_TEST_CASE(BoxFilterBase, MatDepth, Channels, BorderType, bool, bool)
         randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
 
         Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
-        randomSubMat(dst, dst_roi, dsize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
+        randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
 
         anchor.x = randomInt(-1, ksize.width);
         anchor.y = randomInt(-1, ksize.height);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double threshold = 0.0)
     {
-        OCL_EXPECT_MATS_NEAR(dst, threshold)
+        OCL_EXPECT_MATS_NEAR(dst, threshold);
     }
 };
 
index e328d2a..f791cac 100644 (file)
@@ -63,8 +63,8 @@ PARAM_TEST_CASE(Canny, AppertureSize, L2gradient, UseRoi)
     int apperture_size;
     bool useL2gradient, use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -89,8 +89,8 @@ PARAM_TEST_CASE(Canny, AppertureSize, L2gradient, UseRoi)
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, type, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 };
 
index ffd392a..fcf270f 100644 (file)
@@ -59,8 +59,8 @@ PARAM_TEST_CASE(CvtColor, MatDepth, bool)
     int depth;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -80,13 +80,13 @@ PARAM_TEST_CASE(CvtColor, MatDepth, bool)
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, dstType, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double threshold)
     {
-        OCL_EXPECT_MATS_NEAR(dst, threshold)
+        OCL_EXPECT_MATS_NEAR(dst, threshold);
     }
 
     void performTest(int channelsIn, int channelsOut, int code, double threshold = 1e-3)
@@ -287,8 +287,8 @@ struct CvtColor_YUV420 :
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, dstType, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 };
 
index 54d6545..21b3fff 100644 (file)
@@ -63,8 +63,8 @@ PARAM_TEST_CASE(Filter2D, MatDepth, Channels, BorderType, bool, bool)
     bool useRoi;
     Mat kernel;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -91,8 +91,8 @@ PARAM_TEST_CASE(Filter2D, MatDepth, Channels, BorderType, bool, bool)
         anchor.x = randomInt(-1, ksize.width);
         anchor.y = randomInt(-1, ksize.height);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double threshold = 0.0)
index fe16fe8..a72258c 100644 (file)
@@ -69,8 +69,8 @@ PARAM_TEST_CASE(FilterTestBase, MatType,
     double param;
     bool useRoi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -94,8 +94,8 @@ PARAM_TEST_CASE(FilterTestBase, MatType,
         Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -60, 70);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near()
@@ -112,15 +112,9 @@ PARAM_TEST_CASE(FilterTestBase, MatType,
     void Near(double threshold, bool relative)
     {
         if (relative)
-        {
-            EXPECT_MAT_NEAR_RELATIVE(dst, udst, threshold);
-            EXPECT_MAT_NEAR_RELATIVE(dst_roi, udst_roi, threshold);
-        }
+            OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
         else
-        {
-            EXPECT_MAT_NEAR(dst, udst, threshold);
-            EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold);
-        }
+            OCL_EXPECT_MATS_NEAR(dst, threshold);
     }
 };
 
@@ -355,28 +349,28 @@ OCL_INSTANTIATE_TEST_CASE_P(Filter, GaussianBlurTest, Combine(
                             Bool()));
 
 OCL_INSTANTIATE_TEST_CASE_P(Filter, Erode, Combine(
-                            Values(CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4, CV_64FC1, CV_64FC4),
+                            Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4, CV_64FC1, CV_64FC4),
                             Values(3, 5, 7),
                             Values(Size(0,0)),//not used
                             Values((BorderType)BORDER_CONSTANT),//not used
                             Values(1.0, 2.0, 3.0),
-                            Bool() ) );
+                            Bool()));
 
 OCL_INSTANTIATE_TEST_CASE_P(Filter, Dilate, Combine(
-                            Values(CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4, CV_64FC1, CV_64FC4),
+                            Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4, CV_64FC1, CV_64FC4),
                             Values(3, 5, 7),
                             Values(Size(0,0)),//not used
                             Values((BorderType)BORDER_CONSTANT),//not used
                             Values(1.0, 2.0, 3.0),
-                            Bool() ) );
+                            Bool()));
 
 OCL_INSTANTIATE_TEST_CASE_P(Filter, MorphologyEx, Combine(
-                            Values(CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4, CV_64FC1, CV_64FC4),
+                            Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4, CV_64FC1, CV_64FC4),
                             Values(3, 5, 7),
-                            Values(Size(0,0), Size(0,1), Size(0,2), Size(0,3), Size(0,4), Size(0,5),Size(0,6)),//uses as generator of operations
-                            Values((BorderType)BORDER_CONSTANT),//not used
+                            Values(Size(0, 0), Size(0, 1), Size(0, 2), Size(0, 3), Size(0, 4), Size(0, 5), Size(0, 6)), // used as generator of operations
+                            Values((BorderType)BORDER_CONSTANT),// not used
                             Values(1.0, 2.0, 3.0),
-                            Bool() ) );
+                            Bool()));
 
 
 } } // namespace cvtest::ocl
index e479976..6e65f90 100644 (file)
@@ -60,7 +60,7 @@ PARAM_TEST_CASE(GoodFeaturesToTrack, double, bool)
     static const int maxCorners;
     static const double qualityLevel;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
+    TEST_DECLARE_INPUT_PARAMETER(src);
     UMat points, upoints;
 
     virtual void SetUp()
@@ -79,7 +79,7 @@ PARAM_TEST_CASE(GoodFeaturesToTrack, double, bool)
         randomSubMat(src, src_roi, roiSize, srcBorder, frame.type(), 5, 256);
         src_roi.copyTo(frame);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
     }
 
     void UMatToVector(const UMat & um, std::vector<Point2f> & v) const
index b0837ee..0a27907 100644 (file)
@@ -76,8 +76,8 @@ PARAM_TEST_CASE(CalcBackProject, MatDepth, int, bool)
     std::vector<UMat> uimages;
     std::vector<UMat> uimages_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(hist)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(hist);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -139,8 +139,8 @@ PARAM_TEST_CASE(CalcBackProject, MatDepth, int, bool)
             uimages_roi[i] = uimages[i](Rect(ofs.x, ofs.y, images_roi[i].cols, images_roi[i].rows));
         }
 
-        UMAT_UPLOAD_INPUT_PARAMETER(hist)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(hist);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
 
         scale = randomDouble(0.1, 1);
     }
@@ -157,7 +157,7 @@ OCL_TEST_P(CalcBackProject, Mat)
         OCL_OFF(cv::calcBackProject(images_roi, channels, hist_roi, dst_roi, ranges, scale));
         OCL_ON(cv::calcBackProject(uimages_roi, channels, uhist_roi, udst_roi, ranges, scale));
 
-        OCL_EXPECT_MATS_NEAR(dst, 0.0)
+        OCL_EXPECT_MATS_NEAR(dst, 0.0);
     }
 }
 
@@ -167,8 +167,8 @@ PARAM_TEST_CASE(CalcHist, bool)
 {
     bool useRoi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(hist)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(hist);
 
     virtual void SetUp()
     {
@@ -185,8 +185,8 @@ PARAM_TEST_CASE(CalcHist, bool)
         Border histBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
         randomSubMat(hist, hist_roi, Size(1, 256), histBorder, CV_32SC1, 0, MAX_VALUE);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(hist)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(hist);
     }
 };
 
@@ -205,7 +205,7 @@ OCL_TEST_P(CalcHist, Mat)
         OCL_OFF(cv::calcHist(std::vector<Mat>(1, src_roi), channels, noArray(), hist_roi, histSize, ranges, false));
         OCL_ON(cv::calcHist(std::vector<UMat>(1, usrc_roi), channels, noArray(), uhist_roi, histSize, ranges, false));
 
-        OCL_EXPECT_MATS_NEAR(hist, 0.0)
+        OCL_EXPECT_MATS_NEAR(hist, 0.0);
     }
 }
 
index 78b2e57..ad8e26c 100644 (file)
@@ -70,8 +70,8 @@ PARAM_TEST_CASE(ImgprocTestBase, MatType,
     int type, borderType, blockSize;
     bool useRoi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -90,16 +90,16 @@ PARAM_TEST_CASE(ImgprocTestBase, MatType,
         Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, type, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double threshold = 0.0, bool relative = false)
     {
         if (relative)
-            OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold)
+            OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
         else
-            OCL_EXPECT_MATS_NEAR(dst, threshold)
+            OCL_EXPECT_MATS_NEAR(dst, threshold);
     }
 };
 
@@ -117,8 +117,8 @@ PARAM_TEST_CASE(CopyMakeBorder, MatDepth, // depth
     TestUtils::Border border;
     Scalar val;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -148,13 +148,13 @@ PARAM_TEST_CASE(CopyMakeBorder, MatDepth, // depth
 
         randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near()
     {
-        OCL_EXPECT_MATS_NEAR(dst, 0)
+        OCL_EXPECT_MATS_NEAR(dst, 0);
     }
 };
 
@@ -217,8 +217,8 @@ struct CornerTestBase :
         Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, CV_32FC1, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 };
 
@@ -286,7 +286,7 @@ struct Integral :
 {
     int sdepth, sqdepth;
 
-    TEST_DECLARE_OUTPUT_PARAMETER(dst2)
+    TEST_DECLARE_OUTPUT_PARAMETER(dst2);
 
     virtual void SetUp()
     {
@@ -310,17 +310,17 @@ struct Integral :
         Border dst2Border = randomBorder(0, useRoi ? 2 : 0);
         randomSubMat(dst2, dst2_roi, isize, dst2Border, sqdepth, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst2)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst2);
     }
 
     void Near2(double threshold = 0.0, bool relative = false)
     {
         if (relative)
-            OCL_EXPECT_MATS_NEAR_RELATIVE(dst2, threshold)
+            OCL_EXPECT_MATS_NEAR_RELATIVE(dst2, threshold);
         else
-            OCL_EXPECT_MATS_NEAR(dst2, threshold)
+            OCL_EXPECT_MATS_NEAR(dst2, threshold);
     }
 };
 
@@ -390,8 +390,8 @@ PARAM_TEST_CASE(CLAHETest, Size, double, bool)
     double clipLimit;
     bool useRoi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -409,13 +409,13 @@ PARAM_TEST_CASE(CLAHETest, Size, double, bool)
         Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, CV_8UC1, 5, 16);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double threshold = 0.0)
     {
-        OCL_EXPECT_MATS_NEAR(dst, threshold)
+        OCL_EXPECT_MATS_NEAR(dst, threshold);
     }
 };
 
index c283b8c..f0a6130 100644 (file)
@@ -62,9 +62,9 @@ PARAM_TEST_CASE(MatchTemplate, MatDepth, Channels, MatchTemplType, bool)
     int method;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(image)
-    TEST_DECLARE_INPUT_PARAMETER(templ)
-    TEST_DECLARE_OUTPUT_PARAMETER(result)
+    TEST_DECLARE_INPUT_PARAMETER(image);
+    TEST_DECLARE_INPUT_PARAMETER(templ);
+    TEST_DECLARE_OUTPUT_PARAMETER(result);
 
     virtual void SetUp()
     {
@@ -92,9 +92,9 @@ PARAM_TEST_CASE(MatchTemplate, MatDepth, Channels, MatchTemplType, bool)
         Border resultBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(result, result_roi, result_roiSize, resultBorder, CV_32FC1, -upValue, upValue);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(image)
-        UMAT_UPLOAD_INPUT_PARAMETER(templ)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(result)
+        UMAT_UPLOAD_INPUT_PARAMETER(image);
+        UMAT_UPLOAD_INPUT_PARAMETER(templ);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(result);
     }
 
     void Near(double threshold = 0.0)
index 0116197..6369087 100644 (file)
@@ -57,8 +57,8 @@ PARAM_TEST_CASE(MedianFilter, MatDepth, Channels, int, bool)
     int ksize;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -76,8 +76,8 @@ PARAM_TEST_CASE(MedianFilter, MatDepth, Channels, int, bool)
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double threshold = 0.0)
index d6174a5..113349b 100644 (file)
@@ -57,8 +57,8 @@ PARAM_TEST_CASE(PyrTestBase, MatDepth, Channels, bool)
     int depth, channels;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -75,8 +75,8 @@ PARAM_TEST_CASE(PyrTestBase, MatDepth, Channels, bool)
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, dst_roiSize, dstBorder, CV_MAKETYPE(depth, channels), -MAX_VALUE, MAX_VALUE);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double threshold = 0.0)
index 5e824d6..d242a73 100644 (file)
@@ -62,8 +62,8 @@ PARAM_TEST_CASE(SepFilter2D, MatDepth, Channels, BorderType, bool, bool)
     bool useRoi;
     Mat kernelX, kernelY;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -103,8 +103,8 @@ PARAM_TEST_CASE(SepFilter2D, MatDepth, Channels, BorderType, bool, bool)
         anchor.x = -1;
         anchor.y = -1;
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double threshold = 0.0)
index 3963b67..8c82d82 100644 (file)
@@ -73,8 +73,8 @@ PARAM_TEST_CASE(WarpTestBase, MatType, Interpolation, bool, bool)
     Size dsize;
     bool useRoi, mapInverse;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -98,13 +98,13 @@ PARAM_TEST_CASE(WarpTestBase, MatType, Interpolation, bool, bool)
         Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, dsize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 
     void Near(double threshold = 0.0)
     {
-        OCL_EXPECT_MATS_NEAR(dst, threshold)
+        OCL_EXPECT_MATS_NEAR(dst, threshold);
     }
 };
 
@@ -164,8 +164,8 @@ PARAM_TEST_CASE(Resize, MatType, double, double, Interpolation, bool)
     double fx, fy;
     bool useRoi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -202,7 +202,7 @@ PARAM_TEST_CASE(Resize, MatType, double, double, Interpolation, bool)
 
     void Near(double threshold = 0.0)
     {
-        OCL_EXPECT_MATS_NEAR(dst, threshold)
+        OCL_EXPECT_MATS_NEAR(dst, threshold);
     }
 };
 
@@ -230,10 +230,10 @@ PARAM_TEST_CASE(Remap, MatDepth, Channels, std::pair<MatType, MatType>, BorderTy
 
     Scalar val;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_INPUT_PARAMETER(map1)
-    TEST_DECLARE_INPUT_PARAMETER(map2)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_INPUT_PARAMETER(map1);
+    TEST_DECLARE_INPUT_PARAMETER(map2);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -269,16 +269,16 @@ PARAM_TEST_CASE(Remap, MatDepth, Channels, std::pair<MatType, MatType>, BorderTy
             randomSubMat(map2, map2_roi, dstROISize, map2Border, map2Type, mapMinValue, mapMaxValue);
         }
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_INPUT_PARAMETER(map1)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_INPUT_PARAMETER(map1);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
         if (noType != map2Type)
-            UMAT_UPLOAD_INPUT_PARAMETER(map2)
+            UMAT_UPLOAD_INPUT_PARAMETER(map2);
     }
 
     void Near(double threshold = 0.0)
     {
-        OCL_EXPECT_MATS_NEAR(dst, threshold)
+        OCL_EXPECT_MATS_NEAR(dst, threshold);
     }
 };
 
index b660f59..dd61cdb 100644 (file)
@@ -18,8 +18,6 @@ OCL_PERF_TEST_P(Cascade_Image_MinSize, CascadeClassifier,
                  testing::Combine(
                     testing::Values( string("cv/cascadeandhog/cascades/haarcascade_frontalface_alt.xml"),
                                      string("cv/cascadeandhog/cascades/haarcascade_frontalface_alt2.xml"),
-                                     string("cv/cascadeandhog/cascades/haarcascade_frontalface_alt_old.xml"),
-                                     string("cv/cascadeandhog/cascades/haarcascade_frontalface_alt2_old.xml"),
                                      string("cv/cascadeandhog/cascades/lbpcascade_frontalface.xml") ),
                     testing::Values( string("cv/shared/lena.png"),
                                      string("cv/cascadeandhog/images/bttf301.png"),
index 3f0e6e3..2d5c079 100644 (file)
@@ -765,11 +765,8 @@ bool LBPEvaluator::read( const FileNode& node, Size _origWinSize )
     nchannels = 1;
     localSize = lbufSize = Size(0, 0);
     if (ocl::haveOpenCL())
-    {
-        const ocl::Device& device = ocl::Device::getDefault();
-        if (device.isAMD() && !device.hostUnifiedMemory())
-            localSize = Size(8, 8);
-    }
+        localSize = Size(8, 8);
+
     return true;
 }
 
index 18bb7af..0f4456a 100644 (file)
@@ -1085,8 +1085,8 @@ static bool ocl_compute_gradients_8UC1(int height, int width, InputArray _img, f
     size_t globalThreads[3] = { width, height, 1 };
     char correctGamma = (correct_gamma) ? 1 : 0;
     int grad_quadstep = (int)grad.step >> 3;
-    int qangle_step_shift = 0;
-    int qangle_step = (int)qangle.step >> (1 + qangle_step_shift);
+    int qangle_elem_size = CV_ELEM_SIZE1(qangle.type());
+    int qangle_step = (int)qangle.step / (2 * qangle_elem_size);
 
     int idx = 0;
     idx = k.set(idx, height);
@@ -1137,9 +1137,9 @@ static bool ocl_compute_hists(int nbins, int block_stride_x, int block_stride_y,
     int img_block_height = (height - CELLS_PER_BLOCK_Y * CELL_HEIGHT + block_stride_y)/block_stride_y;
     int blocks_total = img_block_width * img_block_height;
 
-    int qangle_step_shift = 0;
+    int qangle_elem_size = CV_ELEM_SIZE1(qangle.type());
     int grad_quadstep = (int)grad.step >> 2;
-    int qangle_step = (int)qangle.step >> qangle_step_shift;
+    int qangle_step = (int)qangle.step / qangle_elem_size;
 
     int blocks_in_group = 4;
     size_t localThreads[3] = { blocks_in_group * 24, 2, 1 };
@@ -1316,11 +1316,12 @@ static bool ocl_extract_descrs_by_cols(int win_height, int win_width, int block_
 static bool ocl_compute(InputArray _img, Size win_stride, std::vector<float>& _descriptors, int descr_format, Size blockSize,
                         Size cellSize, int nbins, Size blockStride, Size winSize, float sigma, bool gammaCorrection, double L2HysThreshold)
 {
-     Size imgSize = _img.size();
+    Size imgSize = _img.size();
     Size effect_size = imgSize;
 
     UMat grad(imgSize, CV_32FC2);
-    UMat qangle(imgSize, CV_8UC2);
+    int qangle_type = ocl::Device::getDefault().isIntel() ? CV_32SC2 : CV_8UC2;
+    UMat qangle(imgSize, qangle_type);
 
     const size_t block_hist_size = getBlockHistogramSize(blockSize, cellSize, nbins);
     const Size blocks_per_img = numPartsWithin(imgSize, blockSize, blockStride);
@@ -1720,7 +1721,8 @@ static bool ocl_detect(InputArray img, std::vector<Point> &hits, double hit_thre
     Size imgSize = img.size();
     Size effect_size = imgSize;
     UMat grad(imgSize, CV_32FC2);
-    UMat qangle(imgSize, CV_8UC2);
+    int qangle_type = ocl::Device::getDefault().isIntel() ? CV_32SC2 : CV_8UC2;
+    UMat qangle(imgSize, qangle_type);
 
     const size_t block_hist_size = getBlockHistogramSize(blockSize, cellSize, nbins);
     const Size blocks_per_img = numPartsWithin(imgSize, blockSize, blockStride);
index e931e82..704dec4 100644 (file)
 #define CV_PI_F 3.1415926535897932384626433832795f
 
 #ifdef INTEL_DEVICE
-#define QANGLE_TYPE            int
-#define QANGLE_TYPE2   int2
+#define QANGLE_TYPE     int
+#define QANGLE_TYPE2    int2
 #else
-#define QANGLE_TYPE            uchar
-#define QANGLE_TYPE2   uchar2
+#define QANGLE_TYPE     uchar
+#define QANGLE_TYPE2    uchar2
 #endif
 
 //----------------------------------------------------------------------------
@@ -141,9 +141,8 @@ __kernel void compute_hists_lut_kernel(
             final_hist[(cell_x * 2 + cell_y) * cnbins + bin_id] =
                 hist_[0] + hist_[1] + hist_[2];
     }
-#ifdef CPU
+
     barrier(CLK_LOCAL_MEM_FENCE);
-#endif
 
     int tid = (cell_y * CELLS_PER_BLOCK_Y + cell_x) * 12 + cell_thread_x;
     if ((tid < cblock_hist_size) && (gid < blocks_total))
index 8568352..b3ef6b4 100644 (file)
@@ -110,7 +110,7 @@ OCL_TEST_P(HOG, Detect)
     OCL_OFF(hog.detectMultiScale(img, cpu_found, 0, Size(8, 8), Size(0, 0), 1.05, 6));
     OCL_ON(hog.detectMultiScale(uimg, gpu_found, 0, Size(8, 8), Size(0, 0), 1.05, 6));
 
-    EXPECT_LT(checkRectSimilarity(img.size(), cpu_found, gpu_found), 1.0);
+    EXPECT_LT(checkRectSimilarity(img.size(), cpu_found, gpu_found), 0.05);
 }
 
 INSTANTIATE_TEST_CASE_P(OCL_ObjDetect, HOG, testing::Combine(
index 98bb4fc..51aa4fe 100644 (file)
@@ -86,7 +86,9 @@ void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
                                       float h, float hForColorComponents,
                                       int templateWindowSize, int searchWindowSize)
 {
-    if (_src.type() != CV_8UC3)
+    int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+
+    if (type != CV_8UC3 && type != CV_8UC4)
     {
         CV_Error(Error::StsBadArg, "Type of input image should be CV_8UC3!");
         return;
@@ -97,7 +99,7 @@ void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
                                                 templateWindowSize, searchWindowSize))
 
     Mat src = _src.getMat();
-    _dst.create(src.size(), src.type());
+    _dst.create(src.size(), type);
     Mat dst = _dst.getMat();
 
     Mat src_lab;
@@ -113,10 +115,10 @@ void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
     fastNlMeansDenoising(ab, ab, hForColorComponents, templateWindowSize, searchWindowSize);
 
     Mat l_ab_denoised[] = { l, ab };
-    Mat dst_lab(src.size(), src.type());
+    Mat dst_lab(src.size(), CV_MAKE_TYPE(depth, 3));
     mixChannels(l_ab_denoised, 2, &dst_lab, 1, from_to, 3);
 
-    cvtColor(dst_lab, dst, COLOR_Lab2LBGR);
+    cvtColor(dst_lab, dst, COLOR_Lab2LBGR, cn);
 }
 
 static void fastNlMeansDenoisingMultiCheckPreconditions(
index ad1d942..5152379 100644 (file)
@@ -149,10 +149,10 @@ static bool ocl_fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
     fastNlMeansDenoising(l_ab[0], l_ab_denoised[0], h, templateWindowSize, searchWindowSize);
     fastNlMeansDenoising(l_ab[1], l_ab_denoised[1], hForColorComponents, templateWindowSize, searchWindowSize);
 
-    UMat dst_lab(src.size(), src.type());
+    UMat dst_lab(src.size(), CV_8UC3);
     mixChannels(l_ab_denoised, std::vector<UMat>(1, dst_lab), from_to, 3);
 
-    cvtColor(dst_lab, dst, COLOR_Lab2LBGR);
+    cvtColor(dst_lab, dst, COLOR_Lab2LBGR, src.channels());
     return true;
 }
 
index 745a457..b533399 100644 (file)
@@ -19,8 +19,8 @@ PARAM_TEST_CASE(FastNlMeansDenoisingTestBase, Channels, bool)
     float h;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(src)
-    TEST_DECLARE_OUTPUT_PARAMETER(dst)
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
 
     virtual void SetUp()
     {
@@ -52,8 +52,8 @@ PARAM_TEST_CASE(FastNlMeansDenoisingTestBase, Channels, bool)
         Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
         randomSubMat(dst, dst_roi, roiSize, dstBorder, type, 0, 255);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(src)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(dst)
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
     }
 };
 
@@ -68,13 +68,13 @@ OCL_TEST_P(FastNlMeansDenoising, Mat)
         OCL_OFF(cv::fastNlMeansDenoising(src_roi, dst_roi, h, templateWindowSize, searchWindowSize));
         OCL_ON(cv::fastNlMeansDenoising(usrc_roi, udst_roi, h, templateWindowSize, searchWindowSize));
 
-        OCL_EXPECT_MATS_NEAR(dst, 1)
+        OCL_EXPECT_MATS_NEAR(dst, 1);
     }
 }
 
-typedef FastNlMeansDenoisingTestBase fastNlMeansDenoisingColored;
+typedef FastNlMeansDenoisingTestBase FastNlMeansDenoisingColored;
 
-OCL_TEST_P(fastNlMeansDenoisingColored, Mat)
+OCL_TEST_P(FastNlMeansDenoisingColored, Mat)
 {
     for (int j = 0; j < test_loop_times; j++)
     {
@@ -83,12 +83,12 @@ OCL_TEST_P(fastNlMeansDenoisingColored, Mat)
         OCL_OFF(cv::fastNlMeansDenoisingColored(src_roi, dst_roi, h, h, templateWindowSize, searchWindowSize));
         OCL_ON(cv::fastNlMeansDenoisingColored(usrc_roi, udst_roi, h, h, templateWindowSize, searchWindowSize));
 
-        OCL_EXPECT_MATS_NEAR(dst, 1)
+        OCL_EXPECT_MATS_NEAR(dst, 1);
     }
 }
 
 OCL_INSTANTIATE_TEST_CASE_P(Photo, FastNlMeansDenoising, Combine(Values(1, 2), Bool()));
-OCL_INSTANTIATE_TEST_CASE_P(Photo, fastNlMeansDenoisingColored, Combine(Values(Channels(3)), Bool()));
+OCL_INSTANTIATE_TEST_CASE_P(Photo, FastNlMeansDenoisingColored, Combine(Values(3, 4), Bool()));
 
 } } // namespace cvtest::ocl
 
index 169e34f..0f0d965 100644 (file)
@@ -62,53 +62,73 @@ extern int test_loop_times;
 #define MAX_VALUE 357
 
 #define EXPECT_MAT_NORM(mat, eps) \
+do \
 { \
-    EXPECT_LE(TestUtils::checkNorm(mat), eps) \
-}
+    EXPECT_LE(TestUtils::checkNorm1(mat), eps) \
+} while ((void)0, 0)
 
 #define EXPECT_MAT_NEAR(mat1, mat2, eps) \
+do \
 { \
     ASSERT_EQ(mat1.type(), mat2.type()); \
     ASSERT_EQ(mat1.size(), mat2.size()); \
-    EXPECT_LE(TestUtils::checkNorm(mat1, mat2), eps) \
+    EXPECT_LE(TestUtils::checkNorm2(mat1, mat2), eps) \
         << "Size: " << mat1.size() << std::endl; \
-}
+} while ((void)0, 0)
 
 #define EXPECT_MAT_NEAR_RELATIVE(mat1, mat2, eps) \
+do \
 { \
     ASSERT_EQ(mat1.type(), mat2.type()); \
     ASSERT_EQ(mat1.size(), mat2.size()); \
     EXPECT_LE(TestUtils::checkNormRelative(mat1, mat2), eps) \
         << "Size: " << mat1.size() << std::endl; \
-}
+} while ((void)0, 0)
 
 #define OCL_EXPECT_MATS_NEAR(name, eps) \
+do \
 { \
-    EXPECT_MAT_NEAR(name ## _roi, u ## name ## _roi, eps); \
-    int nextValue = rng.next(); \
-    RNG dataRng1(nextValue), dataRng2(nextValue); \
-    dataRng1.fill(name ## _roi, RNG::UNIFORM, Scalar::all(-MAX_VALUE), Scalar::all(MAX_VALUE)); \
-    dataRng2.fill(u ## name ## _roi, RNG::UNIFORM, Scalar::all(-MAX_VALUE), Scalar::all(MAX_VALUE)); \
-    EXPECT_MAT_NEAR(name, u ## name, 0/*FLT_EPSILON*/); \
-}
+    ASSERT_EQ(name ## _roi.type(), u ## name ## _roi.type()); \
+    ASSERT_EQ(name ## _roi.size(), u ## name ## _roi.size()); \
+    EXPECT_LE(TestUtils::checkNorm2(name ## _roi, u ## name ## _roi), eps) \
+        << "Size: " << name ## _roi.size() << std::endl; \
+    Point _offset; \
+    Size _wholeSize; \
+    u ## name ## _roi.locateROI(_wholeSize, _offset); \
+    Mat _mask(name.size(), CV_8UC1, Scalar::all(255)); \
+    _mask(Rect(_offset, name ## _roi.size())).setTo(Scalar::all(0)); \
+    ASSERT_EQ(name.type(), u ## name.type()); \
+    ASSERT_EQ(name.size(), u ## name.size()); \
+    EXPECT_LE(TestUtils::checkNorm2(name, u ## name, _mask), eps) \
+        << "Size: " << name ## _roi.size() << std::endl; \
+} while ((void)0, 0)
 
 #define OCL_EXPECT_MATS_NEAR_RELATIVE(name, eps) \
+do \
 { \
-    EXPECT_MAT_NEAR_RELATIVE(name ## _roi, u ## name ## _roi, eps); \
-    int nextValue = rng.next(); \
-    RNG dataRng1(nextValue), dataRng2(nextValue); \
-    dataRng1.fill(name ## _roi, RNG::UNIFORM, Scalar::all(-MAX_VALUE), Scalar::all(MAX_VALUE)); \
-    dataRng2.fill(u ## name ## _roi, RNG::UNIFORM, Scalar::all(-MAX_VALUE), Scalar::all(MAX_VALUE)); \
-    EXPECT_MAT_NEAR_RELATIVE(name, u ## name, 0/*FLT_EPSILON*/); \
-}
+    ASSERT_EQ(name ## _roi.type(), u ## name ## _roi.type()); \
+    ASSERT_EQ(name ## _roi.size(), u ## name ## _roi.size()); \
+    EXPECT_LE(TestUtils::checkNormRelative(name ## _roi, u ## name ## _roi), eps) \
+        << "Size: " << name ## _roi.size() << std::endl; \
+    Point _offset; \
+    Size _wholeSize; \
+    name ## _roi.locateROI(_wholeSize, _offset); \
+    Mat _mask(name.size(), CV_8UC1, Scalar::all(255)); \
+    _mask(Rect(_offset, name ## _roi.size())).setTo(Scalar::all(0)); \
+    ASSERT_EQ(name.type(), u ## name.type()); \
+    ASSERT_EQ(name.size(), u ## name.size()); \
+    EXPECT_LE(TestUtils::checkNormRelative(name, u ## name, _mask), eps) \
+        << "Size: " << name ## _roi.size() << std::endl; \
+} while ((void)0, 0)
 
 #define EXPECT_MAT_SIMILAR(mat1, mat2, eps) \
+do \
 { \
     ASSERT_EQ(mat1.type(), mat2.type()); \
     ASSERT_EQ(mat1.size(), mat2.size()); \
     EXPECT_LE(checkSimilarity(mat1, mat2), eps) \
         << "Size: " << mat1.size() << std::endl; \
-}
+} while ((void)0, 0)
 
 using perf::MatDepth;
 using perf::MatType;
@@ -205,28 +225,30 @@ struct CV_EXPORTS TestUtils
     static cv::Mat readImage(const String &fileName, int flags = cv::IMREAD_COLOR);
     static cv::Mat readImageType(const String &fname, int type);
 
-    static double checkNorm(InputArray m);
-    static double checkNorm(InputArray m1, InputArray m2);
+    static double checkNorm1(InputArray m, InputArray mask = noArray());
+    static double checkNorm2(InputArray m1, InputArray m2, InputArray mask = noArray());
     static double checkSimilarity(InputArray m1, InputArray m2);
     static void showDiff(InputArray _src, InputArray _gold, InputArray _actual, double eps, bool alwaysShow);
 
-    static inline double checkNormRelative(InputArray m1, InputArray m2)
+    static inline double checkNormRelative(InputArray m1, InputArray m2, InputArray mask = noArray())
     {
-        return cv::norm(m1.getMat(), m2.getMat(), cv::NORM_INF) /
+        return cv::norm(m1.getMat(), m2.getMat(), cv::NORM_INF, mask) /
                 std::max((double)std::numeric_limits<float>::epsilon(),
                          (double)std::max(cv::norm(m1.getMat(), cv::NORM_INF), norm(m2.getMat(), cv::NORM_INF)));
     }
 };
 
-#define TEST_DECLARE_INPUT_PARAMETER(name) Mat name, name ## _roi; UMat u ## name, u ## name ## _roi;
+#define TEST_DECLARE_INPUT_PARAMETER(name) Mat name, name ## _roi; UMat u ## name, u ## name ## _roi
 #define TEST_DECLARE_OUTPUT_PARAMETER(name) TEST_DECLARE_INPUT_PARAMETER(name)
 
 #define UMAT_UPLOAD_INPUT_PARAMETER(name) \
+do \
 { \
     name.copyTo(u ## name); \
     Size _wholeSize; Point ofs; name ## _roi.locateROI(_wholeSize, ofs); \
     u ## name ## _roi = u ## name(Rect(ofs.x, ofs.y, name ## _roi.size().width, name ## _roi.size().height)); \
-}
+} while ((void)0, 0)
+
 #define UMAT_UPLOAD_OUTPUT_PARAMETER(name) UMAT_UPLOAD_INPUT_PARAMETER(name)
 
 template <typename T>
index caf5bf4..0291cad 100644 (file)
@@ -223,14 +223,14 @@ Mat TestUtils::readImageType(const String &fname, int type)
     return src;
 }
 
-double TestUtils::checkNorm(InputArray m)
+double TestUtils::checkNorm1(InputArray m, InputArray mask)
 {
-    return norm(m.getMat(), NORM_INF);
+    return norm(m.getMat(), NORM_INF, mask);
 }
 
-double TestUtils::checkNorm(InputArray m1, InputArray m2)
+double TestUtils::checkNorm2(InputArray m1, InputArray m2, InputArray mask)
 {
-    return norm(m1.getMat(), m2.getMat(), NORM_INF);
+    return norm(m1.getMat(), m2.getMat(), NORM_INF, mask);
 }
 
 double TestUtils::checkSimilarity(InputArray m1, InputArray m2)
index bfb1621..0a52227 100644 (file)
@@ -70,7 +70,7 @@ OCL_TEST_P(Mog2_Update, Accuracy)
         OCL_ON (mog2_ocl->apply(frame, u_foreground));
 
         if (detectShadow)
-            EXPECT_MAT_SIMILAR(foreground, u_foreground, 15e-3)
+            EXPECT_MAT_SIMILAR(foreground, u_foreground, 15e-3);
         else
             EXPECT_MAT_NEAR(foreground, u_foreground, 0);
     }
@@ -133,4 +133,4 @@ OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_getBackgroundImage, (Values(DetectSh
 }}// namespace cvtest::ocl
 
     #endif
-#endif
\ No newline at end of file
+#endif
index 7b4c227..91053d9 100644 (file)
@@ -18,8 +18,8 @@ PARAM_TEST_CASE(UpdateMotionHistory, bool)
     double timestamp, duration;
     bool use_roi;
 
-    TEST_DECLARE_INPUT_PARAMETER(silhouette)
-    TEST_DECLARE_OUTPUT_PARAMETER(mhi)
+    TEST_DECLARE_INPUT_PARAMETER(silhouette);
+    TEST_DECLARE_OUTPUT_PARAMETER(mhi);
 
     virtual void SetUp()
     {
@@ -40,8 +40,8 @@ PARAM_TEST_CASE(UpdateMotionHistory, bool)
         if (timestamp < duration)
             std::swap(timestamp, duration);
 
-        UMAT_UPLOAD_INPUT_PARAMETER(silhouette)
-        UMAT_UPLOAD_OUTPUT_PARAMETER(mhi)
+        UMAT_UPLOAD_INPUT_PARAMETER(silhouette);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(mhi);
     }
 };
 
@@ -54,7 +54,7 @@ OCL_TEST_P(UpdateMotionHistory, Mat)
         OCL_OFF(cv::updateMotionHistory(silhouette_roi, mhi_roi, timestamp, duration));
         OCL_ON(cv::updateMotionHistory(usilhouette_roi, umhi_roi, timestamp, duration));
 
-        OCL_EXPECT_MATS_NEAR(mhi, 0)
+        OCL_EXPECT_MATS_NEAR(mhi, 0);
     }
 }
 
index c2d13e0..cc40f74 100644 (file)
@@ -101,7 +101,7 @@ OCL_TEST_P(FarnebackOpticalFlow, Mat)
     OCL_OFF(cv::calcOpticalFlowFarneback(frame0, frame1, flow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags));
     OCL_ON(cv::calcOpticalFlowFarneback(frame0, frame1, uflow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags));
 
-    EXPECT_MAT_SIMILAR(flow, uflow, 0.1)
+    EXPECT_MAT_SIMILAR(flow, uflow, 0.1);
 }
 
 
@@ -117,4 +117,4 @@ OCL_INSTANTIATE_TEST_CASE_P(Video, FarnebackOpticalFlow,
 
 } } // namespace cvtest::ocl
 
-#endif // HAVE_OPENCL
\ No newline at end of file
+#endif // HAVE_OPENCL
index 227b261..2f4cfd0 100644 (file)
@@ -56,7 +56,7 @@ float calcBlurriness(const Mat &frame)
     Sobel(frame, Gx, CV_32F, 1, 0);
     Sobel(frame, Gy, CV_32F, 0, 1);
     double normGx = norm(Gx);
-    double normGy = norm(Gx);
+    double normGy = norm(Gy);
     double sumSq = normGx*normGx + normGy*normGy;
     return static_cast<float>(1. / (sumSq / frame.size().area() + 1e-6));
 }
index 7ccd079..d839491 100644 (file)
@@ -9,3 +9,7 @@ ocv_define_module(viz opencv_core ${VTK_LIBRARIES})
 if(APPLE AND BUILD_opencv_viz)
   target_link_libraries(opencv_viz "-framework Cocoa")
 endif()
+
+if(TARGET opencv_test_viz)
+  set_target_properties(opencv_test_viz PROPERTIES MACOSX_BUNDLE TRUE)
+endif()
index bdcf3a4..a8d9ac6 100644 (file)
@@ -935,6 +935,8 @@ This 3D Widget defines a collection of clouds. ::
         void addCloud(InputArray cloud, InputArray colors, const Affine3d &pose = Affine3d::Identity());
         //! All points in cloud have the same color
         void addCloud(InputArray cloud, const Color &color = Color::white(), Affine3d &pose = Affine3d::Identity());
+        //! Repacks internal structure to single cloud
+        void finalize();
     };
 
 viz::WCloudCollection::WCloudCollection
@@ -965,6 +967,12 @@ Adds a cloud to the collection.
 
 .. note:: In case there are four channels in the cloud, fourth channel is ignored.
 
+viz::WCloudCollection::finalize
+-------------------------------
+Finalizes cloud data by repacking to single cloud. Useful for large cloud collections to reduce memory usage
+
+.. ocv:function:: void finalize()
+
 viz::WCloudNormals
 ------------------
 .. ocv:class:: WCloudNormals
@@ -1018,3 +1026,43 @@ Constructs a WMesh.
     :param polygons: Points of the mesh object.
     :param colors: Point colors.
     :param normals: Point normals.
+
+viz::WWidgetMerger
+---------------------
+.. ocv:class:: WWidgetMerger
+
+This class allows to merge several widgets to single one. It has quite limited functionality and can't merge widgets with different attributes. For instance,
+if widgetA has color array and widgetB has only global color defined, then result of merge won't have color at all. The class is suitable for merging large amount of similar widgets. ::
+
+    class CV_EXPORTS WWidgetMerger : public Widget3D
+    {
+    public:
+        WWidgetMerger();
+
+        //! Add widget to merge with optional position change
+        void addWidget(const Widget3D& widget, const Affine3d &pose = Affine3d::Identity());
+
+        //! Repacks internal structure to single widget
+        void finalize();
+    };
+
+viz::WWidgetMerger::WWidgetMerger
+---------------------------------------
+Constructs a WWidgetMerger.
+
+.. ocv:WWidgetMerger:: WWidgetMerger()
+
+viz::WWidgetMerger::addCloud
+-------------------------------
+Adds a cloud to the collection.
+
+.. ocv:function:: void addWidget(const Widget3D& widget, const Affine3d &pose = Affine3d::Identity())
+
+    :param widget: Widget to merge.
+    :param pose: Pose of the widget.
+
+viz::WWidgetMerger::finalize
+-------------------------------
+Finalizes merger data and constructs final merged widget
+
+.. ocv:function:: void finalize()
index 3c3571b..0e638a9 100644 (file)
@@ -63,6 +63,8 @@ namespace cv
 
             Color(const Scalar& color);
 
+            operator Vec3b() const;
+
             static Color black();
             static Color blue();
             static Color green();
@@ -193,6 +195,8 @@ inline cv::viz::Color::Color(double _gray) : Scalar(_gray, _gray, _gray) {}
 inline cv::viz::Color::Color(double _blue, double _green, double _red) : Scalar(_blue, _green, _red) {}
 inline cv::viz::Color::Color(const Scalar& color) : Scalar(color) {}
 
+inline cv::viz::Color::operator cv::Vec3b() const { return cv::Vec3d(val); }
+
 inline cv::viz::Color cv::viz::Color::black()   { return Color(  0,   0,   0); }
 inline cv::viz::Color cv::viz::Color::green()   { return Color(  0, 255,   0); }
 inline cv::viz::Color cv::viz::Color::blue()    { return Color(255,   0,   0); }
index 7cb7d0c..9917213 100644 (file)
@@ -114,6 +114,8 @@ namespace cv
             double getRenderingProperty(const String &id, int property);
 
             void setRepresentation(int representation);
+
+            void setGlobalWarnings(bool enabled = false);
         private:
 
             struct VizImpl;
index 2c49b9d..2949598 100644 (file)
@@ -201,6 +201,7 @@ namespace cv
         class CV_EXPORTS WPolyLine : public Widget3D
         {
         public:
+            WPolyLine(InputArray points, InputArray colors);
             WPolyLine(InputArray points, const Color &color = Color::white());
         };
 
@@ -345,6 +346,8 @@ namespace cv
             void addCloud(InputArray cloud, InputArray colors, const Affine3d &pose = Affine3d::Identity());
             //! All points in cloud have the same color
             void addCloud(InputArray cloud, const Color &color = Color::white(), const Affine3d &pose = Affine3d::Identity());
+            //! Repacks internal structure to single cloud
+            void finalize();
         };
 
         class CV_EXPORTS WCloudNormals : public Widget3D
@@ -360,6 +363,18 @@ namespace cv
             WMesh(InputArray cloud, InputArray polygons, InputArray colors = noArray(), InputArray normals = noArray());
         };
 
+        class CV_EXPORTS WWidgetMerger : public Widget3D
+        {
+        public:
+            WWidgetMerger();
+
+            //! Add widget to merge with optional position change
+            void addWidget(const Widget3D& widget, const Affine3d &pose = Affine3d::Identity());
+
+            //! Repacks internal structure to single widget
+            void finalize();
+        };
+
         /////////////////////////////////////////////////////////////////////////////
         /// Utility exports
 
@@ -389,6 +404,7 @@ namespace cv
         template<> CV_EXPORTS WCloudCollection Widget::cast<WCloudCollection>();
         template<> CV_EXPORTS WCloudNormals Widget::cast<WCloudNormals>();
         template<> CV_EXPORTS WMesh Widget::cast<WMesh>();
+        template<> CV_EXPORTS WWidgetMerger Widget::cast<WWidgetMerger>();
 
     } /* namespace viz */
 } /* namespace cv */
index 4b84e8e..eec0263 100644 (file)
@@ -193,8 +193,21 @@ template<> cv::viz::WPaintedCloud cv::viz::Widget::cast<cv::viz::WPaintedCloud>(
 
 cv::viz::WCloudCollection::WCloudCollection()
 {
-    // Just create the actor
+    vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
+
+    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+    mapper->SetInputConnection(append_filter->GetOutputPort());
+    mapper->SetScalarModeToUsePointData();
+    mapper->ImmediateModeRenderingOff();
+    mapper->SetScalarRange(0, 255);
+    mapper->ScalarVisibilityOn();
+
     vtkSmartPointer<vtkLODActor> actor = vtkSmartPointer<vtkLODActor>::New();
+    actor->SetNumberOfCloudPoints(1);
+    actor->GetProperty()->SetInterpolationToFlat();
+    actor->GetProperty()->BackfaceCullingOn();
+    actor->SetMapper(mapper);
+
     WidgetAccessor::setProp(*this, actor);
 }
 
@@ -206,35 +219,11 @@ void cv::viz::WCloudCollection::addCloud(InputArray cloud, InputArray colors, co
     vtkSmartPointer<vtkPolyData> polydata = VtkUtils::TransformPolydata(source->GetOutputPort(), pose);
 
     vtkSmartPointer<vtkLODActor> actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this));
-    CV_Assert("Incompatible widget type." && actor);
+    CV_Assert("Correctness check." && actor);
 
-    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
-    if (!mapper)
-    {
-        // This is the first cloud
-        mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        mapper->SetScalarRange(0, 255);
-        mapper->SetScalarModeToUsePointData();
-        mapper->ScalarVisibilityOn();
-        mapper->ImmediateModeRenderingOff();
-        VtkUtils::SetInputData(mapper, polydata);
-
-        actor->SetNumberOfCloudPoints(std::max<vtkIdType>(1, polydata->GetNumberOfPoints()/10));
-        actor->GetProperty()->SetInterpolationToFlat();
-        actor->GetProperty()->BackfaceCullingOn();
-        actor->SetMapper(mapper);
-        return;
-    }
-
-    vtkPolyData *currdata = vtkPolyData::SafeDownCast(mapper->GetInput());
-    CV_Assert("Cloud Widget without data" && currdata);
-
-    vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
-    VtkUtils::AddInputData(append_filter, currdata);
+    vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
+    vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
     VtkUtils::AddInputData(append_filter, polydata);
-    append_filter->Update();
-
-    VtkUtils::SetInputData(mapper, append_filter->GetOutput());
 
     actor->SetNumberOfCloudPoints(std::max<vtkIdType>(1, actor->GetNumberOfCloudPoints() + polydata->GetNumberOfPoints()/10));
 }
@@ -244,6 +233,23 @@ void cv::viz::WCloudCollection::addCloud(InputArray cloud, const Color &color, c
     addCloud(cloud, Mat(cloud.size(), CV_8UC3, color), pose);
 }
 
+void cv::viz::WCloudCollection::finalize()
+{
+    vtkSmartPointer<vtkLODActor> actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this));
+    CV_Assert("Incompatible widget type." && actor);
+
+    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
+    CV_Assert("Need to add at least one cloud." && mapper);
+
+    vtkSmartPointer<vtkAlgorithm> producer = mapper->GetInputConnection(0, 0)->GetProducer();
+    vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
+    append_filter->Update();
+
+    vtkSmartPointer<vtkPolyData> polydata = append_filter->GetOutput();
+    mapper->RemoveInputConnection(0, 0);
+    VtkUtils::SetInputData(mapper, polydata);
+}
+
 template<> cv::viz::WCloudCollection cv::viz::Widget::cast<cv::viz::WCloudCollection>()
 {
     Widget3D widget = this->cast<Widget3D>();
@@ -316,20 +322,18 @@ cv::viz::WCloudNormals::WCloudNormals(InputArray _cloud, InputArray _normals, in
         }
     }
 
-    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
-    polyData->SetPoints(points);
-    polyData->SetLines(lines);
+    vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
+    polydata->SetPoints(points);
+    polydata->SetLines(lines);
+    VtkUtils::FillScalars(polydata, color);
 
     vtkSmartPointer<vtkDataSetMapper> mapper = vtkSmartPointer<vtkDataSetMapper>::New();
-    mapper->SetColorModeToMapScalars();
-    mapper->SetScalarModeToUsePointData();
-    VtkUtils::SetInputData(mapper, polyData);
+    VtkUtils::SetInputData(mapper, polydata);
 
     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 template<> cv::viz::WCloudNormals cv::viz::Widget::cast<cv::viz::WCloudNormals>()
@@ -349,7 +353,7 @@ cv::viz::WMesh::WMesh(const Mesh &mesh)
     source->SetColorCloudNormalsTCoords(mesh.cloud, mesh.colors, mesh.normals, mesh.tcoords);
     source->Update();
 
-    Mat lookup_buffer(1, mesh.cloud.total(), CV_32SC1);
+    Mat lookup_buffer(1, (int)mesh.cloud.total(), CV_32SC1);
     int *lookup = lookup_buffer.ptr<int>();
     for(int y = 0, index = 0; y < mesh.cloud.rows; ++y)
     {
@@ -439,3 +443,63 @@ template<> CV_EXPORTS cv::viz::WMesh cv::viz::Widget::cast<cv::viz::WMesh>()
     Widget3D widget = this->cast<Widget3D>();
     return static_cast<WMesh&>(widget);
 }
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/// Widget Merger implementation
+
+cv::viz::WWidgetMerger::WWidgetMerger()
+{
+    vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
+
+    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+    mapper->SetInputConnection(append_filter->GetOutputPort());
+    mapper->SetScalarModeToUsePointData();
+    mapper->ImmediateModeRenderingOff();
+    mapper->SetScalarRange(0, 255);
+    mapper->ScalarVisibilityOn();
+
+    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
+    actor->GetProperty()->SetInterpolationToFlat();
+    actor->GetProperty()->BackfaceCullingOn();
+    actor->SetMapper(mapper);
+
+    WidgetAccessor::setProp(*this, actor);
+}
+
+void cv::viz::WWidgetMerger::addWidget(const Widget3D& widget, const Affine3d &pose)
+{
+    vtkActor *widget_actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(widget));
+    CV_Assert("Widget is not 3D actor." && widget_actor);
+
+    vtkSmartPointer<vtkPolyDataMapper> widget_mapper = vtkPolyDataMapper::SafeDownCast(widget_actor->GetMapper());
+    CV_Assert("Widget doesn't have a polydata mapper" && widget_mapper);
+    widget_mapper->Update();
+
+    vtkSmartPointer<vtkActor> actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
+    vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
+    vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
+    CV_Assert("Correctness check" && append_filter);
+
+    VtkUtils::AddInputData(append_filter, VtkUtils::TransformPolydata(widget_mapper->GetInput(), pose));
+}
+
+void cv::viz::WWidgetMerger::finalize()
+{
+    vtkSmartPointer<vtkActor> actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
+    vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
+    vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
+    CV_Assert("Correctness check" && append_filter);
+    append_filter->Update();
+
+    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
+    mapper->RemoveInputConnection(0, 0);
+    VtkUtils::SetInputData(mapper, append_filter->GetOutput());
+    mapper->Modified();
+}
+
+template<> CV_EXPORTS cv::viz::WWidgetMerger cv::viz::Widget::cast<cv::viz::WWidgetMerger>()
+{
+    Widget3D widget = this->cast<Widget3D>();
+    return static_cast<WWidgetMerger&>(widget);
+}
diff --git a/modules/viz/src/interactor_style.cpp b/modules/viz/src/interactor_style.cpp
deleted file mode 100644 (file)
index 75003a2..0000000
+++ /dev/null
@@ -1,639 +0,0 @@
-/*M///////////////////////////////////////////////////////////////////////////////////////
-//
-//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
-//
-//  By downloading, copying, installing or using the software you agree to this license.
-//  If you do not agree to this license, do not download, install,
-//  copy or use the software.
-//
-//
-//                           License Agreement
-//                For Open Source Computer Vision Library
-//
-// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
-// Third party copyrights are property of their respective owners.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-//   * Redistribution's of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//
-//   * Redistribution's in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//
-//   * The name of the copyright holders may not be used to endorse or promote products
-//     derived from this software without specific prior written permission.
-//
-// This software is provided by the copyright holders and contributors "as is" and
-// any express or implied warranties, including, but not limited to, the implied
-// warranties of merchantability and fitness for a particular purpose are disclaimed.
-// In no event shall the Intel Corporation or contributors be liable for any direct,
-// indirect, incidental, special, exemplary, or consequential damages
-// (including, but not limited to, procurement of substitute goods or services;
-// loss of use, data, or profits; or business interruption) however caused
-// and on any theory of liability, whether in contract, strict liability,
-// or tort (including negligence or otherwise) arising in any way out of
-// the use of this software, even if advised of the possibility of such damage.
-//
-// Authors:
-//  * Ozan Tonkal, ozantonkal@gmail.com
-//  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
-//
-//  OpenCV Viz module is complete rewrite of
-//  PCL visualization module (www.pointclouds.org)
-//
-//M*/
-
-#include "precomp.hpp"
-
-
-namespace cv { namespace viz
-{
-    vtkStandardNewMacro(InteractorStyle)
-}}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::Initialize()
-{
-    // Set windows size (width, height) to unknown (-1)
-    win_size_ = Vec2i(-1, -1);
-    win_pos_ = Vec2i(0, 0);
-    max_win_size_ = Vec2i(-1, -1);
-
-    init_ = true;
-    stereo_anaglyph_mask_default_ = true;
-
-    // Initialize the keyboard event callback as none
-    keyboardCallback_ = 0;
-    keyboard_callback_cookie_ = 0;
-
-    // Initialize the mouse event callback as none
-    mouseCallback_ = 0;
-    mouse_callback_cookie_ = 0;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::saveScreenshot(const String &file)
-{
-    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
-
-    vtkSmartPointer<vtkWindowToImageFilter> wif = vtkSmartPointer<vtkWindowToImageFilter>::New();
-    wif->SetInput(Interactor->GetRenderWindow());
-
-    vtkSmartPointer<vtkPNGWriter> snapshot_writer = vtkSmartPointer<vtkPNGWriter>::New();
-    snapshot_writer->SetInputConnection(wif->GetOutputPort());
-    snapshot_writer->SetFileName(file.c_str());
-    snapshot_writer->Write();
-
-    cout << "Screenshot successfully captured (" << file.c_str() << ")" << endl;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::exportScene(const String &file)
-{
-    vtkSmartPointer<vtkExporter> exporter;
-    if (file.size() > 5 && file.substr(file.size() - 5) == ".vrml")
-    {
-        exporter = vtkSmartPointer<vtkVRMLExporter>::New();
-        vtkVRMLExporter::SafeDownCast(exporter)->SetFileName(file.c_str());
-    }
-    else
-    {
-        exporter = vtkSmartPointer<vtkOBJExporter>::New();
-        vtkOBJExporter::SafeDownCast(exporter)->SetFilePrefix(file.c_str());
-    }
-
-    exporter->SetInput(Interactor->GetRenderWindow());
-    exporter->Write();
-
-    cout << "Scene successfully exported (" << file.c_str() << ")" << endl;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::zoomIn()
-{
-    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
-    // Zoom in
-    StartDolly();
-    double factor = 10.0 * 0.2 * .5;
-    Dolly(std::pow(1.1, factor));
-    EndDolly();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::zoomOut()
-{
-    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
-    // Zoom out
-    StartDolly();
-    double factor = 10.0 * -0.2 * .5;
-    Dolly(std::pow(1.1, factor));
-    EndDolly();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnChar()
-{
-    // Make sure we ignore the same events we handle in OnKeyDown to avoid calling things twice
-    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
-    if (Interactor->GetKeyCode() >= '0' && Interactor->GetKeyCode() <= '9')
-        return;
-
-    String key(Interactor->GetKeySym());
-    if (key.find("XF86ZoomIn") != String::npos)
-        zoomIn();
-    else if (key.find("XF86ZoomOut") != String::npos)
-        zoomOut();
-
-    int keymod = Interactor->GetAltKey();
-
-    switch (Interactor->GetKeyCode())
-    {
-    // All of the options below simply exit
-    case 'h': case 'H':
-    case 'l': case 'L':
-    case 'p': case 'P':
-    case 'j': case 'J':
-    case 'c': case 'C':
-    case 43:        // KEY_PLUS
-    case 45:        // KEY_MINUS
-    case 'f': case 'F':
-    case 'g': case 'G':
-    case 'o': case 'O':
-    case 'u': case 'U':
-    case 'q': case 'Q':
-    {
-        break;
-    }
-        // S and R have a special !ALT case
-    case 'r': case 'R':
-    case 's': case 'S':
-    {
-        if (!keymod)
-            Superclass::OnChar();
-        break;
-    }
-    default:
-    {
-        Superclass::OnChar();
-        break;
-    }
-    }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::registerMouseCallback(void (*callback)(const MouseEvent&, void*), void* cookie)
-{
-    // Register the callback function and store the user data
-    mouseCallback_ = callback;
-    mouse_callback_cookie_ = cookie;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::registerKeyboardCallback(void (*callback)(const KeyboardEvent&, void*), void *cookie)
-{
-    // Register the callback function and store the user data
-    keyboardCallback_ = callback;
-    keyboard_callback_cookie_ = cookie;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-int cv::viz::InteractorStyle::getModifiers()
-{
-    int modifiers = KeyboardEvent::NONE;
-
-    if (Interactor->GetAltKey())
-        modifiers |= KeyboardEvent::ALT;
-
-    if (Interactor->GetControlKey())
-        modifiers |= KeyboardEvent::CTRL;
-
-    if (Interactor->GetShiftKey())
-        modifiers |= KeyboardEvent::SHIFT;
-    return modifiers;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnKeyDown()
-{
-    CV_Assert("Interactor style not initialized. Please call Initialize() before continuing" && init_);
-    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
-
-    // Save the initial windows width/height
-    if (win_size_[0] == -1 || win_size_[1] == -1)
-        win_size_ = Vec2i(Interactor->GetRenderWindow()->GetSize());
-
-    bool alt = Interactor->GetAltKey() != 0;
-
-    std::string key(Interactor->GetKeySym());
-    if (key.find("XF86ZoomIn") != std::string::npos)
-        zoomIn();
-    else if (key.find("XF86ZoomOut") != std::string::npos)
-        zoomOut();
-
-    switch (Interactor->GetKeyCode())
-    {
-    case 'h': case 'H':
-    {
-        std::cout << "| Help:\n"
-                     "-------\n"
-                     "          p, P   : switch to a point-based representation\n"
-                     "          w, W   : switch to a wireframe-based representation (where available)\n"
-                     "          s, S   : switch to a surface-based representation (where available)\n"
-                     "\n"
-                     "          j, J   : take a .PNG snapshot of the current window view\n"
-                     "          k, K   : export scene to Wavefront .obj format\n"
-                     "    ALT + k, K   : export scene to VRML format\n"
-                     "          c, C   : display current camera/window parameters\n"
-                     "          f, F   : fly to point mode, hold the key and move mouse where to fly\n"
-                     "\n"
-                     "          e, E   : exit the interactor\n"
-                     "          q, Q   : stop and call VTK's TerminateApp\n"
-                     "\n"
-                     "           +/-   : increment/decrement overall point size\n"
-                     "     +/- [+ ALT] : zoom in/out \n"
-                     "\n"
-                     "    r, R [+ ALT] : reset camera [to viewpoint = {0, 0, 0} -> center_{x, y, z}]\n"
-                     "\n"
-                     "    ALT + s, S   : turn stereo mode on/off\n"
-                     "    ALT + f, F   : switch between maximized window mode and original size\n"
-                     "\n"
-                  << std::endl;
-        break;
-    }
-
-        // Switch representation to points
-    case 'p': case 'P':
-    {
-        vtkSmartPointer<vtkActorCollection> ac = CurrentRenderer->GetActors();
-        vtkCollectionSimpleIterator ait;
-        for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); )
-            for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); )
-            {
-                vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp());
-                apart->GetProperty()->SetRepresentationToPoints();
-            }
-        break;
-    }
-
-        // Save a PNG snapshot
-    case 'j': case 'J':
-        saveScreenshot(cv::format("screenshot-%d.png", (unsigned int)time(0))); break;
-
-        // Export scene as in obj or vrml format
-    case 'k': case 'K':
-    {
-        String format = alt ? "scene-%d.vrml" : "scene-%d";
-        exportScene(cv::format(format.c_str(), (unsigned int)time(0)));
-        break;
-    }
-
-        // display current camera settings/parameters
-    case 'c': case 'C':
-    {
-        vtkSmartPointer<vtkCamera> cam = Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera();
-
-        Vec2d clip(cam->GetClippingRange());
-        Vec3d focal(cam->GetFocalPoint()), pos(cam->GetPosition()), view(cam->GetViewUp());
-        Vec2i win_pos(Interactor->GetRenderWindow()->GetPosition());
-        Vec2i win_size(Interactor->GetRenderWindow()->GetSize());
-        double angle = cam->GetViewAngle () / 180.0 * CV_PI;
-
-        String data = cv::format("clip(%f,%f) focal(%f,%f,%f) pos(%f,%f,%f) view(%f,%f,%f) angle(%f) winsz(%d,%d) winpos(%d,%d)",
-                                 clip[0], clip[1], focal[0], focal[1], focal[2], pos[0], pos[1], pos[2], view[0], view[1], view[2],
-                                 angle, win_size[0], win_size[1], win_pos[0], win_pos[1]);
-
-        std::cout << data.c_str() << std::endl;
-
-        break;
-    }
-    case '=':
-    {
-        zoomIn();
-        break;
-    }
-    case 43:        // KEY_PLUS
-    {
-        if (alt)
-            zoomIn();
-        else
-        {
-            vtkSmartPointer<vtkActorCollection> ac = CurrentRenderer->GetActors();
-            vtkCollectionSimpleIterator ait;
-            for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); )
-                for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); )
-                {
-                    vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp());
-                    float psize = apart->GetProperty()->GetPointSize();
-                    if (psize < 63.0f)
-                        apart->GetProperty()->SetPointSize(psize + 1.0f);
-                }
-        }
-        break;
-    }
-    case 45:        // KEY_MINUS
-    {
-        if (alt)
-            zoomOut();
-        else
-        {
-            vtkSmartPointer<vtkActorCollection> ac = CurrentRenderer->GetActors();
-            vtkCollectionSimpleIterator ait;
-            for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); )
-                for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); )
-                {
-                    vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp());
-                    float psize = apart->GetProperty()->GetPointSize();
-                    if (psize > 1.0f)
-                        apart->GetProperty()->SetPointSize(psize - 1.0f);
-                }
-        }
-        break;
-    }
-        // Switch between maximize and original window size
-    case 'f': case 'F':
-    {
-        if (alt)
-        {
-            Vec2i screen_size(Interactor->GetRenderWindow()->GetScreenSize());
-            Vec2i win_size(Interactor->GetRenderWindow()->GetSize());
-
-            // Is window size = max?
-            if (win_size == max_win_size_)
-            {
-                Interactor->GetRenderWindow()->SetSize(win_size_.val);
-                Interactor->GetRenderWindow()->SetPosition(win_pos_.val);
-                Interactor->GetRenderWindow()->Render();
-                Interactor->Render();
-            }
-            // Set to max
-            else
-            {
-                win_pos_ = Vec2i(Interactor->GetRenderWindow()->GetPosition());
-                win_size_ = win_size;
-
-                Interactor->GetRenderWindow()->SetSize(screen_size.val);
-                Interactor->GetRenderWindow()->Render();
-                Interactor->Render();
-                max_win_size_ = Vec2i(Interactor->GetRenderWindow()->GetSize());
-            }
-        }
-        else
-        {
-            AnimState = VTKIS_ANIM_ON;
-            Interactor->GetPicker()->Pick(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1], 0.0, CurrentRenderer);
-            vtkSmartPointer<vtkAbstractPropPicker> picker = vtkAbstractPropPicker::SafeDownCast(Interactor->GetPicker());
-            if (picker)
-                if (picker->GetPath())
-                    Interactor->FlyTo(CurrentRenderer, picker->GetPickPosition());
-            AnimState = VTKIS_ANIM_OFF;
-        }
-        break;
-    }
-        // 's'/'S' w/out ALT
-    case 's': case 'S':
-    {
-        if (alt)
-        {
-            vtkSmartPointer<vtkRenderWindow> window = Interactor->GetRenderWindow();
-            if (!window->GetStereoRender())
-            {
-                static Vec2i red_blue(4, 3), magenta_green(2, 5);
-                window->SetAnaglyphColorMask (stereo_anaglyph_mask_default_ ? red_blue.val : magenta_green.val);
-                stereo_anaglyph_mask_default_ = !stereo_anaglyph_mask_default_;
-            }
-            window->SetStereoRender(!window->GetStereoRender());
-            Interactor->Render();
-        }
-        else
-            Superclass::OnKeyDown();
-        break;
-    }
-
-    case 'o': case 'O':
-    {
-        vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
-        cam->SetParallelProjection(!cam->GetParallelProjection());
-        CurrentRenderer->Render();
-        break;
-    }
-
-        // Overwrite the camera reset
-    case 'r': case 'R':
-    {
-        if (!alt)
-        {
-            Superclass::OnKeyDown();
-            break;
-        }
-
-        WidgetActorMap::iterator it = widget_actor_map_->begin();
-        // it might be that some actors don't have a valid transformation set -> we skip them to avoid a seg fault.
-        for (; it != widget_actor_map_->end();  ++it)
-        {
-            vtkProp3D * actor = vtkProp3D::SafeDownCast(it->second);
-            if (actor && actor->GetUserMatrix())
-                break;
-        }
-
-        vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
-
-        // if a valid transformation was found, use it otherwise fall back to default view point.
-        if (it != widget_actor_map_->end())
-        {
-            vtkMatrix4x4* m = vtkProp3D::SafeDownCast(it->second)->GetUserMatrix();
-
-            cam->SetFocalPoint(m->GetElement(0, 3) - m->GetElement(0, 2),
-                               m->GetElement(1, 3) - m->GetElement(1, 2),
-                               m->GetElement(2, 3) - m->GetElement(2, 2));
-
-            cam->SetViewUp  (m->GetElement(0, 1), m->GetElement(1, 1), m->GetElement(2, 1));
-            cam->SetPosition(m->GetElement(0, 3), m->GetElement(1, 3), m->GetElement(2, 3));
-        }
-        else
-        {
-            cam->SetPosition(0, 0, 0);
-            cam->SetFocalPoint(0, 0, 1);
-            cam->SetViewUp(0, -1, 0);
-        }
-
-        // go to the next actor for the next key-press event.
-        if (it != widget_actor_map_->end())
-            ++it;
-        else
-            it = widget_actor_map_->begin();
-
-        CurrentRenderer->SetActiveCamera(cam);
-        CurrentRenderer->ResetCameraClippingRange();
-        CurrentRenderer->Render();
-        break;
-    }
-
-    case 'q': case 'Q':
-    {
-        Interactor->ExitCallback();
-        return;
-    }
-    default:
-    {
-        Superclass::OnKeyDown();
-        break;
-    }
-    }
-
-    KeyboardEvent event(KeyboardEvent::KEY_DOWN, Interactor->GetKeySym(), Interactor->GetKeyCode(), getModifiers());
-    if (keyboardCallback_)
-        keyboardCallback_(event, keyboard_callback_cookie_);
-    Interactor->Render();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnKeyUp()
-{
-    KeyboardEvent event(KeyboardEvent::KEY_UP, Interactor->GetKeySym(), Interactor->GetKeyCode(), getModifiers());
-    if (keyboardCallback_)
-        keyboardCallback_(event, keyboard_callback_cookie_);
-    Superclass::OnKeyUp();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnMouseMove()
-{
-    Vec2i p(Interactor->GetEventPosition());
-    MouseEvent event(MouseEvent::MouseMove, MouseEvent::NoButton, p, getModifiers());
-    if (mouseCallback_)
-        mouseCallback_(event, mouse_callback_cookie_);
-    Superclass::OnMouseMove();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnLeftButtonDown()
-{
-    Vec2i p(Interactor->GetEventPosition());
-    MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick;
-    MouseEvent event(type, MouseEvent::LeftButton, p, getModifiers());
-    if (mouseCallback_)
-        mouseCallback_(event, mouse_callback_cookie_);
-    Superclass::OnLeftButtonDown();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnLeftButtonUp()
-{
-    Vec2i p(Interactor->GetEventPosition());
-    MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::LeftButton, p, getModifiers());
-    if (mouseCallback_)
-        mouseCallback_(event, mouse_callback_cookie_);
-    Superclass::OnLeftButtonUp();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnMiddleButtonDown()
-{
-    Vec2i p(Interactor->GetEventPosition());
-    MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick;
-    MouseEvent event(type, MouseEvent::MiddleButton, p, getModifiers());
-    if (mouseCallback_)
-        mouseCallback_(event, mouse_callback_cookie_);
-    Superclass::OnMiddleButtonDown();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnMiddleButtonUp()
-{
-    Vec2i p(Interactor->GetEventPosition());
-    MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::MiddleButton, p, getModifiers());
-    if (mouseCallback_)
-        mouseCallback_(event, mouse_callback_cookie_);
-    Superclass::OnMiddleButtonUp();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnRightButtonDown()
-{
-    Vec2i p(Interactor->GetEventPosition());
-    MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick;
-    MouseEvent event(type, MouseEvent::RightButton, p, getModifiers());
-    if (mouseCallback_)
-        mouseCallback_(event, mouse_callback_cookie_);
-    Superclass::OnRightButtonDown();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnRightButtonUp()
-{
-    Vec2i p(Interactor->GetEventPosition());
-    MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::RightButton, p, getModifiers());
-    if (mouseCallback_)
-        mouseCallback_(event, mouse_callback_cookie_);
-    Superclass::OnRightButtonUp();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnMouseWheelForward()
-{
-    Vec2i p(Interactor->GetEventPosition());
-    MouseEvent event(MouseEvent::MouseScrollUp, MouseEvent::VScroll, p, getModifiers());
-    if (mouseCallback_)
-        mouseCallback_(event, mouse_callback_cookie_);
-    if (Interactor->GetRepeatCount() && mouseCallback_)
-        mouseCallback_(event, mouse_callback_cookie_);
-
-    if (Interactor->GetAltKey())
-    {
-        // zoom
-        vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
-        double opening_angle = cam->GetViewAngle();
-        if (opening_angle > 15.0)
-            opening_angle -= 1.0;
-
-        cam->SetViewAngle(opening_angle);
-        cam->Modified();
-        CurrentRenderer->ResetCameraClippingRange();
-        CurrentRenderer->Modified();
-        CurrentRenderer->Render();
-        Interactor->Render();
-    }
-    else
-        Superclass::OnMouseWheelForward();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnMouseWheelBackward()
-{
-    Vec2i p(Interactor->GetEventPosition());
-    MouseEvent event(MouseEvent::MouseScrollDown, MouseEvent::VScroll, p, getModifiers());
-    if (mouseCallback_)
-        mouseCallback_(event, mouse_callback_cookie_);
-
-    if (Interactor->GetRepeatCount() && mouseCallback_)
-        mouseCallback_(event, mouse_callback_cookie_);
-
-    if (Interactor->GetAltKey())
-    {
-        // zoom
-        vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
-        double opening_angle = cam->GetViewAngle();
-        if (opening_angle < 170.0)
-            opening_angle += 1.0;
-
-        cam->SetViewAngle(opening_angle);
-        cam->Modified();
-        CurrentRenderer->ResetCameraClippingRange();
-        CurrentRenderer->Modified();
-        CurrentRenderer->Render();
-        Interactor->Render();
-    }
-    else
-        Superclass::OnMouseWheelBackward();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-void cv::viz::InteractorStyle::OnTimer()
-{
-    CV_Assert("Interactor style not initialized." && init_);
-    Interactor->Render();
-}
index de5346e..50cc1ca 100644 (file)
@@ -76,7 +76,6 @@
 #include <vtkDoubleArray.h>
 #include <vtkPointData.h>
 #include <vtkPolyData.h>
-#include <vtkPolyDataReader.h>
 #include <vtkPolyDataMapper.h>
 #include <vtkDataSetMapper.h>
 #include <vtkCellArray.h>
 #include <vtkObjectFactory.h>
 #include <vtkPolyDataAlgorithm.h>
 #include <vtkMergeFilter.h>
-#include <vtkDataSetWriter.h>
 #include <vtkErrorCode.h>
 #include <vtkPLYWriter.h>
 #include <vtkSTLWriter.h>
-#include <vtkSimplePointsReader.h>
 #include <vtkPLYReader.h>
 #include <vtkOBJReader.h>
 #include <vtkSTLReader.h>
 #include <vtkElevationFilter.h>
 #include <vtkColorTransferFunction.h>
 #include <vtkStreamingDemandDrivenPipeline.h>
+#include "vtkCallbackCommand.h"
 
 #if !defined(_WIN32) || defined(__CYGWIN__)
 # include <unistd.h> /* unlink */
 
 #include <vtk/vtkOBJWriter.h>
 #include <vtk/vtkXYZWriter.h>
+#include <vtk/vtkXYZReader.h>
 #include <vtk/vtkCloudMatSink.h>
 #include <vtk/vtkCloudMatSource.h>
 #include <vtk/vtkTrajectorySource.h>
 #include <vtk/vtkImageMatSource.h>
 
+
 #include <opencv2/core.hpp>
 #include <opencv2/viz.hpp>
 #include <opencv2/viz/widget_accessor.hpp>
@@ -158,7 +158,16 @@ namespace cv
     namespace viz
     {
         typedef std::map<String, vtkSmartPointer<vtkProp> > WidgetActorMap;
-        typedef std::map<String, Viz3d> VizMap;
+
+        struct VizMap
+        {
+            typedef std::map<String, Viz3d> type;
+            typedef type::iterator iterator;
+
+            type m;
+            ~VizMap();
+            void replace_clear();
+        };
 
         class VizStorage
         {
@@ -170,7 +179,6 @@ namespace cv
 
         private:
             VizStorage(); // Static
-            ~VizStorage();
 
             static void add(const Viz3d& window);
             static Viz3d& get(const String &window_name);
@@ -180,6 +188,8 @@ namespace cv
 
             static VizMap storage;
             friend class Viz3d;
+
+            static VizStorage init;
         };
 
         template<typename _Tp> inline _Tp normalized(const _Tp& v) { return v * 1/norm(v); }
@@ -270,11 +280,16 @@ namespace cv
                 vtkSmartPointer<vtkUnsignedCharArray> scalars = vtkSmartPointer<vtkUnsignedCharArray>::New();
                 scalars->SetName("Colors");
                 scalars->SetNumberOfComponents(3);
-                scalars->SetNumberOfTuples(size);
-                scalars->SetArray(color_data->val, size * 3, 0);
+                scalars->SetNumberOfTuples((vtkIdType)size);
+                scalars->SetArray(color_data->val, (vtkIdType)(size * 3), 0);
                 return scalars;
             }
 
+            static vtkSmartPointer<vtkPolyData> FillScalars(vtkSmartPointer<vtkPolyData> polydata, const Color& color)
+            {
+                return polydata->GetPointData()->SetScalars(FillScalars(polydata->GetNumberOfPoints(), color)), polydata;
+            }
+
             static vtkSmartPointer<vtkPolyData> ComputeNormals(vtkSmartPointer<vtkPolyData> polydata)
             {
                 vtkSmartPointer<vtkPolyDataNormals> normals_generator = vtkSmartPointer<vtkPolyDataNormals>::New();
@@ -315,11 +330,12 @@ namespace cv
                 return transform_filter->GetOutput();
             }
         };
+
+        vtkSmartPointer<vtkRenderWindowInteractor> vtkCocoaRenderWindowInteractorNew();
     }
 }
 
-#include "interactor_style.hpp"
+#include "vtk/vtkVizInteractorStyle.hpp"
 #include "vizimpl.hpp"
 
-
 #endif
index cc3a51c..e42a7ab 100644 (file)
@@ -54,14 +54,16 @@ cv::viz::WLine::WLine(const Point3d &pt1, const Point3d &pt2, const Color &color
     line->SetPoint2(pt2.x, pt2.y, pt2.z);
     line->Update();
 
+    vtkSmartPointer<vtkPolyData> polydata = line->GetOutput();
+    VtkUtils::FillScalars(polydata, color);
+
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-    VtkUtils::SetInputData(mapper, line->GetOutput());
+    VtkUtils::SetInputData(mapper, polydata);
 
     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 template<> cv::viz::WLine cv::viz::Widget::cast<cv::viz::WLine>()
@@ -83,14 +85,16 @@ cv::viz::WSphere::WSphere(const Point3d &center, double radius, int sphere_resol
     sphere->LatLongTessellationOff();
     sphere->Update();
 
+    vtkSmartPointer<vtkPolyData> polydata = sphere->GetOutput();
+    VtkUtils::FillScalars(polydata, color);
+
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-    VtkUtils::SetInputData(mapper, sphere->GetOutput());
+    VtkUtils::SetInputData(mapper, polydata);
 
     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 template<> cv::viz::WSphere cv::viz::Widget::cast<cv::viz::WSphere>()
@@ -110,15 +114,17 @@ cv::viz::WPlane::WPlane(const Size2d& size, const Color &color)
     plane->SetPoint2(-0.5 * size.width,  0.5 * size.height, 0.0);
     plane->Update();
 
+    vtkSmartPointer<vtkPolyData> polydata = plane->GetOutput();
+    VtkUtils::FillScalars(polydata, color);
+
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-    VtkUtils::SetInputData(mapper, plane->GetOutput());
+    VtkUtils::SetInputData(mapper, polydata);
 
     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     actor->SetMapper(mapper);
     actor->GetProperty()->LightingOff();
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 cv::viz::WPlane::WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Size2d& size, const Color &color)
@@ -161,6 +167,7 @@ cv::viz::WArrow::WArrow(const Point3d& pt1, const Point3d& pt2, double thickness
     Affine3d transform_with_scale(R * length, start_point);
 
     vtkSmartPointer<vtkPolyData> polydata = VtkUtils::TransformPolydata(arrow_source->GetOutputPort(), transform_with_scale);
+    VtkUtils::FillScalars(polydata, color);
 
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
     VtkUtils::SetInputData(mapper, polydata);
@@ -169,7 +176,6 @@ cv::viz::WArrow::WArrow(const Point3d& pt1, const Point3d& pt2, double thickness
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 template<> cv::viz::WArrow cv::viz::Widget::cast<cv::viz::WArrow>()
@@ -189,16 +195,17 @@ cv::viz::WCircle::WCircle(double radius, double thickness, const Color &color)
     disk->SetOuterRadius(radius + thickness);
     disk->Update();
 
+    vtkSmartPointer<vtkPolyData> polydata = disk->GetOutput();
+    VtkUtils::FillScalars(polydata, color);
+
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-    VtkUtils::SetInputData(mapper, disk->GetOutput());
+    VtkUtils::SetInputData(mapper, polydata);
 
     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     actor->GetProperty()->LightingOff();
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
-
 }
 
 cv::viz::WCircle::WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness, const Color &color)
@@ -231,14 +238,16 @@ cv::viz::WCone::WCone(double length, double radius, int resolution, const Color
     cone_source->SetResolution(resolution);
     cone_source->Update();
 
+    vtkSmartPointer<vtkPolyData> polydata = cone_source->GetOutput();
+    VtkUtils::FillScalars(polydata, color);
+
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-    VtkUtils::SetInputData(mapper, cone_source->GetOutput());
+    VtkUtils::SetInputData(mapper, polydata);
 
     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 cv::viz::WCone::WCone(double radius, const Point3d& center, const Point3d& tip, int resolution, const Color &color)
@@ -274,14 +283,16 @@ cv::viz::WCylinder::WCylinder(const Point3d& axis_point1, const Point3d& axis_po
     tuber->SetRadius(radius);
     tuber->Update();
 
+    vtkSmartPointer<vtkPolyData> polydata = tuber->GetOutput();
+    VtkUtils::FillScalars(polydata, color);
+
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-    VtkUtils::SetInputData(mapper, tuber->GetOutput());
+    VtkUtils::SetInputData(mapper, polydata);
 
     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 template<> cv::viz::WCylinder cv::viz::Widget::cast<cv::viz::WCylinder>()
@@ -315,15 +326,16 @@ cv::viz::WCube::WCube(const Point3d& min_point, const Point3d& max_point, bool w
         vtkCubeSource::SafeDownCast(cube)->SetBounds(bounds);
     }
     cube->Update();
+    vtkSmartPointer<vtkPolyData> polydata =cube->GetOutput();
+    VtkUtils::FillScalars(polydata, color);
 
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-    VtkUtils::SetInputData(mapper, cube->GetOutput());
+    VtkUtils::SetInputData(mapper, polydata);
 
     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 template<> cv::viz::WCube cv::viz::Widget::cast<cv::viz::WCube>()
@@ -379,40 +391,21 @@ template<> cv::viz::WCoordinateSystem cv::viz::Widget::cast<cv::viz::WCoordinate
 ///////////////////////////////////////////////////////////////////////////////////////////////
 /// polyline widget implementation
 
-cv::viz::WPolyLine::WPolyLine(InputArray _points, const Color &color)
+cv::viz::WPolyLine::WPolyLine(InputArray points, InputArray colors)
 {
-    CV_Assert(_points.type() == CV_32FC3 || _points.type() == CV_32FC4 || _points.type() == CV_64FC3 || _points.type() == CV_64FC4);
-
-    const float *fpoints = _points.getMat().ptr<float>();
-    const double *dpoints = _points.getMat().ptr<double>();
-    size_t total = _points.total();
-    int s_chs = _points.channels();
-
-    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
-    points->SetDataType(_points.depth() == CV_32F ? VTK_FLOAT : VTK_DOUBLE);
-    points->SetNumberOfPoints(total);
+    vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
+    cloud_source->SetColorCloud(points, colors);
+    cloud_source->Update();
 
-    if (_points.depth() == CV_32F)
-        for(size_t i = 0; i < total; ++i, fpoints += s_chs)
-            points->SetPoint(i, fpoints);
-
-    if (_points.depth() == CV_64F)
-        for(size_t i = 0; i < total; ++i, dpoints += s_chs)
-            points->SetPoint(i, dpoints);
+    vtkSmartPointer<vtkPolyData> polydata = cloud_source->GetOutput();
 
     vtkSmartPointer<vtkCellArray> cell_array = vtkSmartPointer<vtkCellArray>::New();
-    cell_array->Allocate(cell_array->EstimateSize(1, total));
-    cell_array->InsertNextCell(total);
-    for(size_t i = 0; i < total; ++i)
+    cell_array->Allocate(cell_array->EstimateSize(1, polydata->GetNumberOfPoints()));
+    cell_array->InsertNextCell(polydata->GetNumberOfPoints());
+    for(vtkIdType i = 0; i < polydata->GetNumberOfPoints(); ++i)
         cell_array->InsertCellPoint(i);
 
-    vtkSmartPointer<vtkUnsignedCharArray> scalars =  VtkUtils::FillScalars(total, color);
-
-    vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
-    polydata->SetPoints(points);
     polydata->SetLines(cell_array);
-    polydata->GetPointData()->SetScalars(scalars);
-
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
     VtkUtils::SetInputData(mapper, polydata);
     mapper->SetScalarRange(0, 255);
@@ -423,6 +416,12 @@ cv::viz::WPolyLine::WPolyLine(InputArray _points, const Color &color)
     WidgetAccessor::setProp(*this, actor);
 }
 
+cv::viz::WPolyLine::WPolyLine(InputArray points, const Color &color)
+{
+    WPolyLine polyline(points, Mat(points.size(), CV_8UC3, color));
+    *this = polyline;
+}
+
 template<> cv::viz::WPolyLine cv::viz::Widget::cast<cv::viz::WPolyLine>()
 {
     Widget3D widget = this->cast<Widget3D>();
@@ -450,14 +449,16 @@ cv::viz::WGrid::WGrid(const Vec2i &cells, const Vec2d &cells_spacing, const Colo
     VtkUtils::SetInputData(extract_edges, grid_data);
     extract_edges->Update();
 
+    vtkSmartPointer<vtkPolyData> polydata = extract_edges->GetOutput();
+    VtkUtils::FillScalars(polydata, color);
+
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-    VtkUtils::SetInputData(mapper, extract_edges->GetOutput());
+    VtkUtils::SetInputData(mapper, polydata);
 
     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 cv::viz::WGrid::WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Vec2i &cells, const Vec2d &cells_spacing, const Color &color)
@@ -807,6 +808,7 @@ cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, double scale, const
     double aspect_ratio = f_y / f_x;
 
     vtkSmartPointer<vtkPolyData> polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
+    VtkUtils::FillScalars(polydata, color);
 
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
     VtkUtils::SetInputData(mapper, polydata);
@@ -815,7 +817,6 @@ cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, double scale, const
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const Color &color)
@@ -824,6 +825,7 @@ cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const
     double fovy = fov[1] * 180 / CV_PI;
 
     vtkSmartPointer<vtkPolyData> polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
+    VtkUtils::FillScalars(polydata, color);
 
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
     VtkUtils::SetInputData(mapper, polydata);
@@ -832,7 +834,6 @@ cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, InputArray _image, double scale, const Color &color)
@@ -967,6 +968,7 @@ cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Matx33
     source->SetTrajectory(_path);
 
     vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCameraPosition(K, scale));
+    VtkUtils::FillScalars(glyph, color);
 
     vtkSmartPointer<vtkTensorGlyph> tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
     tensor_glyph->SetInputConnection(source->GetOutputPort());
@@ -984,7 +986,6 @@ cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Matx33
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Vec2d &fov, double scale, const Color &color)
@@ -993,6 +994,7 @@ cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Vec2d
     source->SetTrajectory(_path);
 
     vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCameraPosition(fov, scale));
+    VtkUtils::FillScalars(glyph, color);
 
     vtkSmartPointer<vtkTensorGlyph> tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
     tensor_glyph->SetInputConnection(source->GetOutputPort());
@@ -1010,7 +1012,6 @@ cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Vec2d
     actor->SetMapper(mapper);
 
     WidgetAccessor::setProp(*this, actor);
-    setColor(color);
 }
 
 template<> cv::viz::WTrajectoryFrustums cv::viz::Widget::cast<cv::viz::WTrajectoryFrustums>()
index 56f978c..6e7dfca 100644 (file)
@@ -146,3 +146,5 @@ void cv::viz::Viz3d::setRenderingProperty(const String &id, int property, double
 double cv::viz::Viz3d::getRenderingProperty(const String &id, int property) { return getWidget(id).getRenderingProperty(property); }
 
 void cv::viz::Viz3d::setRepresentation(int representation) { impl_->setRepresentation(representation); }
+
+void cv::viz::Viz3d::setGlobalWarnings(bool enabled) { vtkObject::SetGlobalWarningDisplay(enabled ? 1 : 0); }
index 29d4b46..a33a192 100644 (file)
@@ -67,36 +67,71 @@ cv::Affine3d cv::viz::makeCameraPose(const Vec3d& position, const Vec3d& focal_p
 ///////////////////////////////////////////////////////////////////////////////////////////////
 /// VizStorage implementation
 
+#if defined(_WIN32) && !defined(__CYGWIN__)
+
+    #include <windows.h>
+
+    static BOOL WINAPI ConsoleHandlerRoutine(DWORD /*dwCtrlType*/)
+    {
+        vtkObject::GlobalWarningDisplayOff();
+        return FALSE;
+    }
+
+    static void register_console_handler()
+    {
+        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+        CONSOLE_SCREEN_BUFFER_INFO hOutInfo;
+        if (GetConsoleScreenBufferInfo(hOut, &hOutInfo))
+            SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE);
+    }
+
+#else
+
+    void register_console_handler();
+    void register_console_handler() {}
+
+#endif
+
+
+cv::viz::VizStorage cv::viz::VizStorage::init;
 cv::viz::VizMap cv::viz::VizStorage::storage;
-void cv::viz::VizStorage::unregisterAll() { storage.clear(); }
+
+void cv::viz::VizMap::replace_clear() { type().swap(m); }
+cv::viz::VizMap::~VizMap() { replace_clear(); }
+
+cv::viz::VizStorage::VizStorage()
+{
+    register_console_handler();
+}
+void cv::viz::VizStorage::unregisterAll() { storage.replace_clear(); }
 
 cv::viz::Viz3d& cv::viz::VizStorage::get(const String &window_name)
 {
     String name = generateWindowName(window_name);
-    VizMap::iterator vm_itr = storage.find(name);
-    CV_Assert(vm_itr != storage.end());
+    VizMap::iterator vm_itr = storage.m.find(name);
+    CV_Assert(vm_itr != storage.m.end());
     return vm_itr->second;
 }
 
 void cv::viz::VizStorage::add(const Viz3d& window)
 {
     String window_name = window.getWindowName();
-    VizMap::iterator vm_itr = storage.find(window_name);
-    CV_Assert(vm_itr == storage.end());
-    storage.insert(std::make_pair(window_name, window));
+    VizMap::iterator vm_itr = storage.m.find(window_name);
+    CV_Assert(vm_itr == storage.m.end());
+    storage.m.insert(std::make_pair(window_name, window));
 }
 
 bool cv::viz::VizStorage::windowExists(const String &window_name)
 {
     String name = generateWindowName(window_name);
-    return storage.find(name) != storage.end();
+    return storage.m.find(name) != storage.m.end();
 }
 
 void cv::viz::VizStorage::removeUnreferenced()
 {
-    for(VizMap::iterator pos = storage.begin(); pos != storage.end();)
+    for(VizMap::iterator pos = storage.m.begin(); pos != storage.m.end();)
         if(pos->second.impl_->ref_counter == 1)
-            storage.erase(pos++);
+            storage.m.erase(pos++);
         else
             ++pos;
 }
@@ -173,8 +208,8 @@ cv::Mat cv::viz::readCloud(const String& file, OutputArray colors, OutputArray n
     vtkSmartPointer<vtkPolyDataAlgorithm> reader;
     if (extention == ".xyz")
     {
-        reader = vtkSmartPointer<vtkSimplePointsReader>::New();
-        vtkSimplePointsReader::SafeDownCast(reader)->SetFileName(file.c_str());
+        reader = vtkSmartPointer<vtkXYZReader>::New();
+        vtkXYZReader::SafeDownCast(reader)->SetFileName(file.c_str());
     }
     else if (extention == ".ply")
     {
@@ -257,7 +292,11 @@ void cv::viz::writeTrajectory(InputArray _traj, const String& files_format, int
 {
     if (_traj.kind() == _InputArray::STD_VECTOR_MAT)
     {
+#if CV_MAJOR_VERSION < 3
+        std::vector<Mat>& v = *(std::vector<Mat>*)_traj.obj;
+#else
         std::vector<Mat>& v = *(std::vector<Mat>*)_traj.getObj();
+#endif
 
         for(size_t i = 0, index = max(0, start); i < v.size(); ++i, ++index)
         {
@@ -278,11 +317,12 @@ void cv::viz::writeTrajectory(InputArray _traj, const String& files_format, int
 
         if (traj.depth() == CV_32F)
             for(size_t i = 0, index = max(0, start); i < traj.total(); ++i, ++index)
-                writePose(cv::format(files_format.c_str(), index), traj.at<Affine3f>(i), tag);
+                writePose(cv::format(files_format.c_str(), index), traj.at<Affine3f>((int)i), tag);
 
         if (traj.depth() == CV_64F)
             for(size_t i = 0, index = max(0, start); i < traj.total(); ++i, ++index)
-                writePose(cv::format(files_format.c_str(), index), traj.at<Affine3d>(i), tag);
+                writePose(cv::format(files_format.c_str(), index), traj.at<Affine3d>((int)i), tag);
+        return;
     }
 
     CV_Assert(!"Unsupported array kind");
index 5fa49e2..ab621ad 100644 (file)
@@ -60,16 +60,19 @@ cv::viz::Viz3d::VizImpl::VizImpl(const String &name) : spin_once_state_(false),
     window_->AddRenderer(renderer_);
 
     // Create the interactor style
-    style_ = vtkSmartPointer<InteractorStyle>::New();
+    style_ = vtkSmartPointer<vtkVizInteractorStyle>::New();
     style_->setWidgetActorMap(widget_actor_map_);
     style_->UseTimersOn();
-    style_->Initialize();
 
     timer_callback_ = vtkSmartPointer<TimerCallback>::New();
     exit_callback_ = vtkSmartPointer<ExitCallback>::New();
     exit_callback_->viz = this;
+
+    setBackgroundMeshLab();
 }
 
+cv::viz::Viz3d::VizImpl::~VizImpl() { close(); }
+
 /////////////////////////////////////////////////////////////////////////////////////////////
 void cv::viz::Viz3d::VizImpl::TimerCallback::Execute(vtkObject* caller, unsigned long event_id, void* cookie)
 {
@@ -109,11 +112,12 @@ void cv::viz::Viz3d::VizImpl::close()
 
 void cv::viz::Viz3d::VizImpl::recreateRenderWindow()
 {
-#if !defined _MSC_VER
+#if !defined _MSC_VER && !defined __APPLE__
     //recreating is workaround for Ubuntu -- a crash in x-server
     Vec2i window_size(window_->GetSize());
     int fullscreen = window_->GetFullScreen();
 
+    window_->Finalize();
     window_ = vtkSmartPointer<vtkRenderWindow>::New();
     if (window_position_[0] != std::numeric_limits<int>::min()) //also workaround
         window_->SetPosition(window_position_.val);
@@ -124,12 +128,15 @@ void cv::viz::Viz3d::VizImpl::recreateRenderWindow()
 #endif
 }
 
-
 /////////////////////////////////////////////////////////////////////////////////////////////
 void cv::viz::Viz3d::VizImpl::spin()
 {
     recreateRenderWindow();
+#if defined __APPLE__
+    interactor_ = vtkCocoaRenderWindowInteractorNew();
+#else
     interactor_ = vtkSmartPointer<vtkRenderWindowInteractor>::New();
+#endif
     interactor_->SetRenderWindow(window_);
     interactor_->SetInteractorStyle(style_);
     window_->AlphaBitPlanesOff();
@@ -151,7 +158,11 @@ void cv::viz::Viz3d::VizImpl::spinOnce(int time, bool force_redraw)
     {
         spin_once_state_ = true;
         recreateRenderWindow();
+#if defined __APPLE__
+        interactor_ = vtkCocoaRenderWindowInteractorNew();
+#else
         interactor_ = vtkSmartPointer<vtkRenderWindowInteractor>::New();
+#endif
         interactor_->SetRenderWindow(window_);
         interactor_->SetInteractorStyle(style_);
         interactor_->AddObserver(vtkCommand::TimerEvent, timer_callback_);
@@ -416,12 +427,12 @@ void cv::viz::Viz3d::VizImpl::setViewerPose(const Affine3d &pose)
 
     // Rotate the view vector
     cv::Matx33d rotation = pose.rotation();
-    cv::Vec3d y_axis(0.0, 1.0, 0.0);
+    cv::Vec3d y_axis(0.0, -1.0, 0.0); // In Computer Vision Camera Y-axis is oriented down
     cv::Vec3d up_vec(rotation * y_axis);
 
     // Compute the new focal point
     cv::Vec3d z_axis(0.0, 0.0, 1.0);
-    cv::Vec3d focal_vec = pos_vec + rotation * z_axis;
+    cv::Vec3d focal_vec = pose * z_axis;
 
     camera.SetPosition(pos_vec.val);
     camera.SetFocalPoint(focal_vec.val);
@@ -439,7 +450,7 @@ cv::Affine3d cv::viz::Viz3d::VizImpl::getViewerPose()
     Vec3d view_up(camera.GetViewUp());
     Vec3d focal(camera.GetFocalPoint());
 
-    Vec3d y_axis = normalized(view_up);
+    Vec3d y_axis = normalized(-view_up); // In Computer Vision Camera Y-axis is oriented down
     Vec3d z_axis = normalized(focal - pos);
     Vec3d x_axis = normalized(y_axis.cross(z_axis));
 
index 02675e0..92113af 100644 (file)
@@ -55,7 +55,7 @@ public:
     int ref_counter;
 
     VizImpl(const String &name);
-    virtual ~VizImpl() {}
+    virtual ~VizImpl();
 
     bool wasStopped() const;
     void close();
@@ -128,7 +128,7 @@ private:
     vtkSmartPointer<ExitCallback> exit_callback_;
 
     vtkSmartPointer<vtkRenderer> renderer_;
-    vtkSmartPointer<InteractorStyle> style_;
+    vtkSmartPointer<vtkVizInteractorStyle> style_;
     Ptr<WidgetActorMap> widget_actor_map_;
 
     bool removeActorFromRenderer(vtkSmartPointer<vtkProp> actor);
index 09ef0cc..8bd1011 100644 (file)
@@ -79,11 +79,11 @@ void cv::viz::vtkCloudMatSink::WriteData()
 
         if (cloud.depth() == CV_32F)
             for(size_t i = 0; i < cloud.total(); ++i)
-                *fdata++ = Vec3d(points_Data->GetPoint(i));
+                *fdata++ = Vec3d(points_Data->GetPoint((vtkIdType)i));
 
         if (cloud.depth() == CV_64F)
             for(size_t i = 0; i < cloud.total(); ++i)
-                *ddata++ = Vec3d(points_Data->GetPoint(i));
+                *ddata++ = Vec3d(points_Data->GetPoint((vtkIdType)i));
     }
     else
         cloud.release();
@@ -101,7 +101,7 @@ void cv::viz::vtkCloudMatSink::WriteData()
         Mat buffer(cloud.size(), CV_64FC(channels));
         Vec3d *cptr = buffer.ptr<Vec3d>();
         for(size_t i = 0; i < buffer.total(); ++i)
-            *cptr++ = Vec3d(scalars_data->GetTuple(i));
+            *cptr++ = Vec3d(scalars_data->GetTuple((vtkIdType)i));
 
         buffer.convertTo(colors, CV_8U, vtktype == VTK_FLOAT || VTK_FLOAT == VTK_DOUBLE ?  255.0 : 1.0);
     }
@@ -121,7 +121,7 @@ void cv::viz::vtkCloudMatSink::WriteData()
         Mat buffer(cloud.size(), CV_64FC(channels));
         Vec3d *cptr = buffer.ptr<Vec3d>();
         for(size_t i = 0; i < buffer.total(); ++i)
-            *cptr++ = Vec3d(normals_data->GetTuple(i));
+            *cptr++ = Vec3d(normals_data->GetTuple((vtkIdType)i));
 
         buffer.convertTo(normals, vtktype == VTK_FLOAT ? CV_32F : CV_64F);
     }
@@ -140,7 +140,7 @@ void cv::viz::vtkCloudMatSink::WriteData()
         Mat buffer(cloud.size(), CV_64FC2);
         Vec2d *cptr = buffer.ptr<Vec2d>();
         for(size_t i = 0; i < buffer.total(); ++i)
-            *cptr++ = Vec2d(coords_data->GetTuple(i));
+            *cptr++ = Vec2d(coords_data->GetTuple((vtkIdType)i));
 
         buffer.convertTo(tcoords, vtktype == VTK_FLOAT ? CV_32F : CV_64F);
 
@@ -156,3 +156,19 @@ void cv::viz::vtkCloudMatSink::PrintSelf(ostream& os, vtkIndent indent)
   os << indent << "Colors: " << colors.needed() << "\n";
   os << indent << "Normals: " << normals.needed() << "\n";
 }
+
+int cv::viz::vtkCloudMatSink::FillInputPortInformation(int, vtkInformation *info)
+{
+    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
+    return 1;
+}
+
+vtkPolyData* cv::viz::vtkCloudMatSink::GetInput()
+{
+    return vtkPolyData::SafeDownCast(this->Superclass::GetInput());
+}
+
+vtkPolyData* cv::viz::vtkCloudMatSink::GetInput(int port)
+{
+    return vtkPolyData::SafeDownCast(this->Superclass::GetInput(port));
+}
index 3af9e65..fc778f0 100644 (file)
 #define __vtkCloudMatSink_h
 
 #include <opencv2/core.hpp>
-#include <vtkPolyDataWriter.h>
+#include <vtkWriter.h>
 
 namespace cv
 {
     namespace viz
     {
-        class vtkCloudMatSink : public vtkPolyDataWriter
+        class vtkCloudMatSink : public vtkWriter
         {
         public:
           static vtkCloudMatSink *New();
-          vtkTypeMacro(vtkCloudMatSink,vtkPolyDataWriter)
+          vtkTypeMacro(vtkCloudMatSink,vtkWriter)
           void PrintSelf(ostream& os, vtkIndent indent);
 
           void SetOutput(OutputArray cloud, OutputArray colors = noArray(), OutputArray normals = noArray(), OutputArray tcoords = noArray());
 
+          // Description:
+          // Get the input to this writer.
+          vtkPolyData* GetInput();
+          vtkPolyData* GetInput(int port);
+
         protected:
           vtkCloudMatSink();
           ~vtkCloudMatSink();
 
           void WriteData();
+          int FillInputPortInformation(int port, vtkInformation *info);
 
           _OutputArray cloud, colors, normals, tcoords;
 
index 74d01bb..1d8ab78 100644 (file)
@@ -185,8 +185,8 @@ int cv::viz::vtkCloudMatSource::filterNanCopy(const Mat& cloud)
     CV_DbgAssert(DataType<_Tp>::depth == cloud.depth());
     points = vtkSmartPointer<vtkPoints>::New();
     points->SetDataType(VtkDepthTraits<_Tp>::data_type);
-    points->Allocate(cloud.total());
-    points->SetNumberOfPoints(cloud.total());
+    points->Allocate((vtkIdType)cloud.total());
+    points->SetNumberOfPoints((vtkIdType)cloud.total());
 
     int s_chs = cloud.channels();
     int total = 0;
diff --git a/modules/viz/src/vtk/vtkCocoaInteractorFix.mm b/modules/viz/src/vtk/vtkCocoaInteractorFix.mm
new file mode 100644 (file)
index 0000000..dad41b0
--- /dev/null
@@ -0,0 +1,211 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+// Authors:
+//  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
+//
+//  This workaround code was taken from PCL library(www.pointclouds.org)
+//
+//M*/
+
+#import <Cocoa/Cocoa.h>
+#include <vtkCocoaRenderWindow.h>
+#include <vtkCocoaRenderWindowInteractor.h>
+#include <vtkObjectFactory.h>
+#include <vtkSmartPointer.h>
+
+//----------------------------------------------------------------------------
+@interface vtkCocoaServerFix : NSObject
+{
+    vtkCocoaRenderWindow* renWin;
+}
+
++ (id)cocoaServerWithRenderWindow:(vtkCocoaRenderWindow*)inRenderWindow;
+
+- (void)start;
+- (void)stop;
+- (void)breakEventLoop;
+
+@end
+
+//----------------------------------------------------------------------------
+@implementation vtkCocoaServerFix
+
+//----------------------------------------------------------------------------
+- (id)initWithRenderWindow:(vtkCocoaRenderWindow *)inRenderWindow
+{
+    self = [super init];
+    if (self)
+        renWin = inRenderWindow;
+    return self;
+}
+
+//----------------------------------------------------------------------------
++ (id)cocoaServerWithRenderWindow:(vtkCocoaRenderWindow *)inRenderWindow
+{
+    vtkCocoaServerFix *server = [[[vtkCocoaServerFix alloc] initWithRenderWindow:inRenderWindow] autorelease];
+    return server;
+}
+
+//----------------------------------------------------------------------------
+- (void)start
+{
+    // Retrieve the NSWindow.
+    NSWindow *win = nil;
+    if (renWin)
+    {
+        win = reinterpret_cast<NSWindow*> (renWin->GetRootWindow ());
+
+        // We don't want to be informed of every window closing, so check for nil.
+        if (win != nil)
+        {
+            // Register for the windowWillClose notification in order to stop the run loop if the window closes.
+            NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+            [nc addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:win];
+        }
+    }
+    // Start the NSApplication's run loop
+    NSApplication* application = [NSApplication sharedApplication];
+    [application run];
+}
+
+//----------------------------------------------------------------------------
+- (void)stop
+{
+    [self breakEventLoop];
+}
+
+//----------------------------------------------------------------------------
+- (void)breakEventLoop
+{
+    NSApplication* application = [NSApplication sharedApplication];
+    [application stop:application];
+
+    NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined
+            location:NSMakePoint(0.0,0.0)
+            modifierFlags:0
+            timestamp:0
+            windowNumber:-1
+            context:nil
+            subtype:0
+            data1:0
+            data2:0];
+    [application postEvent:event atStart:YES];
+}
+
+//----------------------------------------------------------------------------
+- (void)windowWillClose:(NSNotification*)aNotification
+{
+    (void)aNotification;
+
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+    [nc removeObserver:self name:NSWindowWillCloseNotification object:nil];
+
+    if (renWin)
+    {
+        int windowCreated = renWin->GetWindowCreated ();
+        if (windowCreated)
+        {
+            [self breakEventLoop];
+
+            // The NSWindow is closing, so prevent anyone from accidently using it
+            renWin->SetRootWindow(NULL);
+        }
+    }
+}
+
+@end
+
+//----------------------------------------------------------------------------
+
+namespace cv { namespace viz
+{
+    class vtkCocoaRenderWindowInteractorFix : public vtkCocoaRenderWindowInteractor
+    {
+    public:
+        static vtkCocoaRenderWindowInteractorFix *New ();
+        vtkTypeMacro (vtkCocoaRenderWindowInteractorFix, vtkCocoaRenderWindowInteractor)
+
+        virtual void Start ();
+        virtual void TerminateApp ();
+
+    protected:
+        vtkCocoaRenderWindowInteractorFix () {}
+        ~vtkCocoaRenderWindowInteractorFix () {}
+
+    private:
+        vtkCocoaRenderWindowInteractorFix (const vtkCocoaRenderWindowInteractorFix&);  // Not implemented.
+        void operator = (const vtkCocoaRenderWindowInteractorFix&);  // Not implemented.
+    };
+
+    vtkStandardNewMacro (vtkCocoaRenderWindowInteractorFix)
+
+    vtkSmartPointer<vtkRenderWindowInteractor> vtkCocoaRenderWindowInteractorNew();
+}}
+
+void cv::viz::vtkCocoaRenderWindowInteractorFix::Start ()
+{
+    vtkCocoaRenderWindow* renWin = vtkCocoaRenderWindow::SafeDownCast(this->GetRenderWindow ());
+    if (renWin != NULL)
+    {
+        vtkCocoaServerFix *server = reinterpret_cast<vtkCocoaServerFix*> (this->GetCocoaServer ());
+        if (!this->GetCocoaServer ())
+        {
+            server = [vtkCocoaServerFix cocoaServerWithRenderWindow:renWin];
+            this->SetCocoaServer (reinterpret_cast<void*> (server));
+        }
+
+        [server start];
+    }
+}
+
+void cv::viz::vtkCocoaRenderWindowInteractorFix::TerminateApp ()
+{
+    vtkCocoaRenderWindow *renWin = vtkCocoaRenderWindow::SafeDownCast (this->RenderWindow);
+    if (renWin)
+    {
+        vtkCocoaServerFix *server = reinterpret_cast<vtkCocoaServerFix*> (this->GetCocoaServer ());
+        [server stop];
+    }
+}
+
+vtkSmartPointer<vtkRenderWindowInteractor> cv::viz::vtkCocoaRenderWindowInteractorNew()
+{
+    return vtkSmartPointer<vtkCocoaRenderWindowInteractorFix>::New();
+}
index 452ad19..7480b11 100644 (file)
@@ -54,7 +54,6 @@ cv::viz::vtkOBJWriter::vtkOBJWriter()
     std::ofstream fout; // only used to extract the default precision
     this->DecimalPrecision = fout.precision();
     this->FileName = NULL;
-    this->FileType = VTK_ASCII;
 }
 
 cv::viz::vtkOBJWriter::~vtkOBJWriter(){}
@@ -65,14 +64,27 @@ void cv::viz::vtkOBJWriter::WriteData()
     if (!input)
         return;
 
-    std::ostream *outfilep = this->OpenVTKFile();
-    if (!outfilep)
+    if (!this->FileName )
+    {
+        vtkErrorMacro(<< "No FileName specified! Can't write!");
+        this->SetErrorCode(vtkErrorCode::NoFileNameError);
+        return;
+    }
+
+    vtkDebugMacro(<<"Opening vtk file for writing...");
+    ostream *outfilep = new ofstream(this->FileName, ios::out);
+    if (outfilep->fail())
+    {
+        vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
+        this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
+        delete outfilep;
         return;
+    }
 
     std::ostream& outfile = *outfilep;
 
     //write header
-    outfile << "# wavefront obj file written by the visualization toolkit" << std::endl << std::endl;
+    outfile << "# wavefront obj file written by opencv viz module" << std::endl << std::endl;
     outfile << "mtllib NONE" << std::endl << std::endl;
 
     // write out the points
@@ -224,7 +236,8 @@ void cv::viz::vtkOBJWriter::WriteData()
         }
     } /* if (input->GetNumberOfStrips() > 0) */
 
-    this->CloseVTKFile(outfilep);
+    vtkDebugMacro(<<"Closing vtk file\n");
+    delete outfilep;
 
     // Delete the file if an error occurred
     if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
@@ -239,3 +252,19 @@ void cv::viz::vtkOBJWriter::PrintSelf(ostream& os, vtkIndent indent)
     Superclass::PrintSelf(os, indent);
     os << indent << "DecimalPrecision: " << DecimalPrecision << "\n";
 }
+
+int cv::viz::vtkOBJWriter::FillInputPortInformation(int, vtkInformation *info)
+{
+    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
+    return 1;
+}
+
+vtkPolyData* cv::viz::vtkOBJWriter::GetInput()
+{
+    return vtkPolyData::SafeDownCast(this->Superclass::GetInput());
+}
+
+vtkPolyData* cv::viz::vtkOBJWriter::GetInput(int port)
+{
+    return vtkPolyData::SafeDownCast(this->Superclass::GetInput(port));
+}
index f888988..7ad0f17 100644 (file)
 #ifndef __vtkOBJWriter_h
 #define __vtkOBJWriter_h
 
-#include <vtkPolyDataWriter.h>
+#include <vtkWriter.h>
 
 namespace cv
 {
     namespace viz
     {
-        class vtkOBJWriter : public vtkPolyDataWriter
+        class vtkOBJWriter : public vtkWriter
         {
         public:
           static vtkOBJWriter *New();
-          vtkTypeMacro(vtkOBJWriter,vtkPolyDataWriter)
+          vtkTypeMacro(vtkOBJWriter,vtkWriter)
           void PrintSelf(ostream& os, vtkIndent indent);
 
-          vtkGetMacro(DecimalPrecision, int);
-          vtkSetMacro(DecimalPrecision, int);
+          vtkGetMacro(DecimalPrecision, int)
+          vtkSetMacro(DecimalPrecision, int)
+
+          // Description:
+          // Specify file name of data file to write.
+          vtkSetStringMacro(FileName)
+          vtkGetStringMacro(FileName)
+
+          // Description:
+          // Get the input to this writer.
+          vtkPolyData* GetInput();
+          vtkPolyData* GetInput(int port);
 
         protected:
           vtkOBJWriter();
           ~vtkOBJWriter();
 
           void WriteData();
+          int FillInputPortInformation(int port, vtkInformation *info);
 
           int DecimalPrecision;
+          char *FileName;
 
         private:
           vtkOBJWriter(const vtkOBJWriter&);  // Not implemented.
index e098a1d..2036e09 100644 (file)
@@ -64,19 +64,19 @@ void cv::viz::vtkTrajectorySource::SetTrajectory(InputArray _traj)
 
     points = vtkSmartPointer<vtkPoints>::New();
     points->SetDataType(VTK_DOUBLE);
-    points->SetNumberOfPoints(total);
+    points->SetNumberOfPoints((vtkIdType)total);
 
     tensors = vtkSmartPointer<vtkDoubleArray>::New();
     tensors->SetNumberOfComponents(9);
-    tensors->SetNumberOfTuples(total);
+    tensors->SetNumberOfTuples((vtkIdType)total);
 
     for(size_t i = 0; i < total; ++i, ++dpath)
     {
         Matx33d R = dpath->rotation().t();  // transposed because of
-        tensors->SetTuple(i, R.val);        // column major order
+        tensors->SetTuple((vtkIdType)i, R.val);        // column major order
 
         Vec3d p = dpath->translation();
-        points->SetPoint(i, p.val);
+        points->SetPoint((vtkIdType)i, p.val);
     }
 }
 
@@ -85,7 +85,7 @@ cv::Mat cv::viz::vtkTrajectorySource::ExtractPoints(InputArray _traj)
     CV_Assert(_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT);
     CV_Assert(_traj.type() == CV_32FC(16) || _traj.type() == CV_64FC(16));
 
-    Mat points(1, _traj.total(), CV_MAKETYPE(_traj.depth(), 3));
+    Mat points(1, (int)_traj.total(), CV_MAKETYPE(_traj.depth(), 3));
     const Affine3d* dpath = _traj.getMat().ptr<Affine3d>();
     const Affine3f* fpath = _traj.getMat().ptr<Affine3f>();
 
diff --git a/modules/viz/src/vtk/vtkVizInteractorStyle.cpp b/modules/viz/src/vtk/vtkVizInteractorStyle.cpp
new file mode 100644 (file)
index 0000000..9b5eca2
--- /dev/null
@@ -0,0 +1,1076 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+// Authors:
+//  * Ozan Tonkal, ozantonkal@gmail.com
+//  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
+//
+//M*/
+
+#include "precomp.hpp"
+
+namespace cv { namespace viz
+{
+    vtkStandardNewMacro(vtkVizInteractorStyle)
+}}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+cv::viz::vtkVizInteractorStyle::vtkVizInteractorStyle()
+{
+    FlyMode = false;
+    MotionFactor = 10.0;
+
+    keyboardCallback_ = 0;
+    keyboard_callback_cookie_ = 0;
+
+    mouseCallback_ = 0;
+    mouse_callback_cookie_ = 0;
+
+    // Set windows size (width, height) to unknown (-1)
+    win_size_ = Vec2i(-1, -1);
+    win_pos_ = Vec2i(0, 0);
+    max_win_size_ = Vec2i(-1, -1);
+
+    stereo_anaglyph_redblue_ = true;
+
+    //from fly
+    KeysDown     = 0;
+    UseTimers    = 1;
+
+    DiagonalLength           = 1.0;
+    MotionStepSize           = 1.0/100.0;
+    MotionUserScale          = 1.0;  // +/- key adjustment
+    MotionAccelerationFactor = 10.0;
+    AngleStepSize            = 1.0;
+}
+
+cv::viz::vtkVizInteractorStyle::~vtkVizInteractorStyle() {}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::saveScreenshot(const String &file)
+{
+    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
+
+    vtkSmartPointer<vtkWindowToImageFilter> wif = vtkSmartPointer<vtkWindowToImageFilter>::New();
+    wif->SetInput(Interactor->GetRenderWindow());
+
+    vtkSmartPointer<vtkPNGWriter> snapshot_writer = vtkSmartPointer<vtkPNGWriter>::New();
+    snapshot_writer->SetInputConnection(wif->GetOutputPort());
+    snapshot_writer->SetFileName(file.c_str());
+    snapshot_writer->Write();
+
+    cout << "Screenshot successfully captured (" << file.c_str() << ")" << endl;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void cv::viz::vtkVizInteractorStyle::exportScene(const String &file)
+{
+    vtkSmartPointer<vtkExporter> exporter;
+    if (file.size() > 5 && file.substr(file.size() - 5) == ".vrml")
+    {
+        exporter = vtkSmartPointer<vtkVRMLExporter>::New();
+        vtkVRMLExporter::SafeDownCast(exporter)->SetFileName(file.c_str());
+    }
+    else
+    {
+        exporter = vtkSmartPointer<vtkOBJExporter>::New();
+        vtkOBJExporter::SafeDownCast(exporter)->SetFilePrefix(file.c_str());
+    }
+
+    exporter->SetInput(Interactor->GetRenderWindow());
+    exporter->Write();
+
+    cout << "Scene successfully exported (" << file.c_str() << ")" << endl;
+}
+
+void cv::viz::vtkVizInteractorStyle::exportScene()
+{
+    // Export scene as in obj or vrml format
+    String format = Interactor->GetAltKey() ? "scene-%d.vrml" : "scene-%d";
+    exportScene(cv::format(format.c_str(), (unsigned int)time(0)));
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void cv::viz::vtkVizInteractorStyle::changePointsSize(float delta)
+{
+    vtkSmartPointer<vtkActorCollection> ac = CurrentRenderer->GetActors();
+    vtkCollectionSimpleIterator ait;
+
+    for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); )
+        for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); )
+        {
+            vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp());
+            float psize = apart->GetProperty()->GetPointSize() + delta;
+            psize = std::max(1.f, std::min(63.f, psize));
+            apart->GetProperty()->SetPointSize(psize);
+        }
+}
+
+void cv::viz::vtkVizInteractorStyle::setRepresentationToPoints()
+{
+    vtkSmartPointer<vtkActorCollection> ac = CurrentRenderer->GetActors();
+    vtkCollectionSimpleIterator ait;
+    for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); )
+        for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); )
+        {
+            vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp());
+            apart->GetProperty()->SetRepresentationToPoints();
+        }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void cv::viz::vtkVizInteractorStyle::printCameraParams()
+{
+    vtkSmartPointer<vtkCamera> cam = Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera();
+
+    Vec2d clip(cam->GetClippingRange());
+    Vec3d focal(cam->GetFocalPoint()), pos(cam->GetPosition()), view(cam->GetViewUp());
+    Vec2i win_pos(Interactor->GetRenderWindow()->GetPosition());
+    Vec2i win_size(Interactor->GetRenderWindow()->GetSize());
+    double angle = cam->GetViewAngle () / 180.0 * CV_PI;
+
+    String data = cv::format("clip(%f,%f) focal(%f,%f,%f) pos(%f,%f,%f) view(%f,%f,%f) angle(%f) winsz(%d,%d) winpos(%d,%d)",
+                             clip[0], clip[1], focal[0], focal[1], focal[2], pos[0], pos[1], pos[2], view[0], view[1], view[2],
+                             angle, win_size[0], win_size[1], win_pos[0], win_pos[1]);
+
+    std::cout << data.c_str() << std::endl;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void cv::viz::vtkVizInteractorStyle::toggleFullScreen()
+{
+    Vec2i screen_size(Interactor->GetRenderWindow()->GetScreenSize());
+    Vec2i win_size(Interactor->GetRenderWindow()->GetSize());
+
+    // Is window size = max?
+    if (win_size == max_win_size_)
+    {
+        Interactor->GetRenderWindow()->SetSize(win_size_.val);
+        Interactor->GetRenderWindow()->SetPosition(win_pos_.val);
+        Interactor->Render();
+    }
+    // Set to max
+    else
+    {
+        win_pos_ = Vec2i(Interactor->GetRenderWindow()->GetPosition());
+        win_size_ = win_size;
+
+        Interactor->GetRenderWindow()->SetSize(screen_size.val);
+        Interactor->Render();
+        max_win_size_ = Vec2i(Interactor->GetRenderWindow()->GetSize());
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void cv::viz::vtkVizInteractorStyle::resetViewerPose()
+{
+    WidgetActorMap::iterator it = widget_actor_map_->begin();
+    // it might be that some actors don't have a valid transformation set -> we skip them to avoid a seg fault.
+    for (; it != widget_actor_map_->end();  ++it)
+    {
+        vtkProp3D * actor = vtkProp3D::SafeDownCast(it->second);
+        if (actor && actor->GetUserMatrix())
+            break;
+    }
+
+    vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
+
+    // if a valid transformation was found, use it otherwise fall back to default view point.
+    if (it != widget_actor_map_->end())
+    {
+        vtkMatrix4x4* m = vtkProp3D::SafeDownCast(it->second)->GetUserMatrix();
+
+        cam->SetFocalPoint(m->GetElement(0, 3) - m->GetElement(0, 2),
+                           m->GetElement(1, 3) - m->GetElement(1, 2),
+                           m->GetElement(2, 3) - m->GetElement(2, 2));
+
+        cam->SetViewUp  (m->GetElement(0, 1), m->GetElement(1, 1), m->GetElement(2, 1));
+        cam->SetPosition(m->GetElement(0, 3), m->GetElement(1, 3), m->GetElement(2, 3));
+    }
+    else
+    {
+        cam->SetPosition(0, 0, 0);
+        cam->SetFocalPoint(0, 0, 1);
+        cam->SetViewUp(0, -1, 0);
+    }
+
+    // go to the next actor for the next key-press event.
+    if (it != widget_actor_map_->end())
+        ++it;
+    else
+        it = widget_actor_map_->begin();
+
+    CurrentRenderer->SetActiveCamera(cam);
+    CurrentRenderer->ResetCameraClippingRange();
+    Interactor->Render();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void cv::viz::vtkVizInteractorStyle::toggleStereo()
+{
+    vtkSmartPointer<vtkRenderWindow> window = Interactor->GetRenderWindow();
+    if (!window->GetStereoRender())
+    {
+        static Vec2i red_blue(4, 3), magenta_green(2, 5);
+        window->SetAnaglyphColorMask (stereo_anaglyph_redblue_ ? red_blue.val : magenta_green.val);
+        stereo_anaglyph_redblue_ = !stereo_anaglyph_redblue_;
+    }
+    window->SetStereoRender(!window->GetStereoRender());
+    Interactor->Render();
+
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void cv::viz::vtkVizInteractorStyle::printHelp()
+{
+    std::cout << "| Help:\n"
+                 "-------\n"
+                 "          p, P   : switch to a point-based representation\n"
+                 "          w, W   : switch to a wireframe-based representation (where available)\n"
+                 "          s, S   : switch to a surface-based representation (where available)\n"
+                 "\n"
+                 "          j, J   : take a .PNG snapshot of the current window view\n"
+                 "          k, K   : export scene to Wavefront .obj format\n"
+                 "    ALT + k, K   : export scene to VRML format\n"
+                 "          c, C   : display current camera/window parameters\n"
+                 "          F5     : enable/disable fly mode (changes control style)\n"
+                 "\n"
+                 "          e, E   : exit the interactor\n"
+                 "          q, Q   : stop and call VTK's TerminateApp\n"
+                 "\n"
+                 "           +/-   : increment/decrement overall point size\n"
+                 "     +/- [+ ALT] : zoom in/out \n"
+                 "\n"
+                 "    r, R [+ ALT] : reset camera [to viewpoint = {0, 0, 0} -> center_{x, y, z}]\n"
+                 "\n"
+                 "    ALT + s, S   : turn stereo mode on/off\n"
+                 "    ALT + f, F   : switch between maximized window mode and original size\n"
+                 "\n"
+              << std::endl;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::zoomIn()
+{
+    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
+    // Zoom in
+    StartDolly();
+    double factor = 10.0 * 0.2 * .5;
+    Dolly(std::pow(1.1, factor));
+    EndDolly();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::zoomOut()
+{
+    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
+    // Zoom out
+    StartDolly();
+    double factor = 10.0 * -0.2 * .5;
+    Dolly(std::pow(1.1, factor));
+    EndDolly();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnChar()
+{
+    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
+
+    String key(Interactor->GetKeySym());
+    if (key.find("XF86ZoomIn") != String::npos)
+        zoomIn();
+    else if (key.find("XF86ZoomOut") != String::npos)
+        zoomOut();
+
+    switch (Interactor->GetKeyCode())
+    {
+//    // All of the options below simply exit
+//    case 'l': case 'L': case 'j': case 'J': case 'c': case 'C': case 'q': case 'Q':
+//    case 'f': case 'F': case 'g': case 'G': case 'o': case 'O': case 'u': case 'U':
+    case 'p': case 'P':
+        break;
+
+    case '+':
+        if (FlyMode)
+            MotionUserScale = std::min(16.0, MotionUserScale*2.0);
+        break;
+    case '-':
+        if (FlyMode)
+            MotionUserScale = std::max(MotionUserScale * 0.5, 0.0625);
+        break;
+
+    case 'r': case 'R': case 's': case 'S':
+        if (!Interactor->GetAltKey())
+            Superclass::OnChar();
+        break;
+    default:
+        Superclass::OnChar();
+        break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::registerMouseCallback(void (*callback)(const MouseEvent&, void*), void* cookie)
+{
+    mouseCallback_ = callback;
+    mouse_callback_cookie_ = cookie;
+}
+
+void cv::viz::vtkVizInteractorStyle::registerKeyboardCallback(void (*callback)(const KeyboardEvent&, void*), void *cookie)
+{
+    keyboardCallback_ = callback;
+    keyboard_callback_cookie_ = cookie;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+int cv::viz::vtkVizInteractorStyle::getModifiers()
+{
+    int modifiers = KeyboardEvent::NONE;
+
+    if (Interactor->GetAltKey())
+        modifiers |= KeyboardEvent::ALT;
+
+    if (Interactor->GetControlKey())
+        modifiers |= KeyboardEvent::CTRL;
+
+    if (Interactor->GetShiftKey())
+        modifiers |= KeyboardEvent::SHIFT;
+    return modifiers;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnKeyDown()
+{
+    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
+
+    String key(Interactor->GetKeySym());
+    if (key.find("XF86ZoomIn") != String::npos)
+        zoomIn();
+    else if (key.find("XF86ZoomOut") != String::npos)
+        zoomOut();
+    else if (key.find("F5") != String::npos)
+    {
+        FlyMode = !FlyMode;
+        std::cout << (FlyMode ? "Fly mode: on" : "Fly mode: off") << std::endl;
+    }
+
+    // Save the initial windows width/height
+    if (win_size_[0] == -1 || win_size_[1] == -1)
+        win_size_ = Vec2i(Interactor->GetRenderWindow()->GetSize());
+
+    switch (Interactor->GetKeyCode())
+    {
+    case 'a': case 'A' : KeysDown |=16; break;
+    case 'z': case 'Z' : KeysDown |=32; break;
+    case 'h': case 'H' : printHelp();   break;
+    case 'p': case 'P' : setRepresentationToPoints(); break;
+    case 'k': case 'K' : exportScene(); break;
+    case 'j': case 'J' : saveScreenshot(cv::format("screenshot-%d.png", (unsigned int)time(0))); break;
+    case 'c': case 'C' : printCameraParams(); break;
+    case '=':           zoomIn();            break;
+    case 43:        // KEY_PLUS
+    {
+        if (FlyMode)
+            break;
+        if (Interactor->GetAltKey())
+            zoomIn();
+        else
+            changePointsSize(+1.f);
+        break;
+    }
+    case 45:        // KEY_MINUS
+    {
+        if (FlyMode)
+            break;
+        if (Interactor->GetAltKey())
+            zoomOut();
+        else
+           changePointsSize(-1.f);
+        break;
+    }
+        // Switch between maximize and original window size
+    case 'f': case 'F':
+    {
+        if (Interactor->GetAltKey())
+            toggleFullScreen();
+        break;
+    }
+        // 's'/'S' w/out ALT
+    case 's': case 'S':
+    {
+        if (Interactor->GetAltKey())
+            toggleStereo();
+        break;
+    }
+
+    case 'o': case 'O':
+    {
+        vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
+        cam->SetParallelProjection(!cam->GetParallelProjection());
+        Interactor->Render();
+        break;
+    }
+
+    // Overwrite the camera reset
+    case 'r': case 'R':
+    {
+        if (Interactor->GetAltKey())
+            resetViewerPose();
+        break;
+    }
+    case 'q': case 'Q':
+        Interactor->ExitCallback(); return;
+    default:
+        Superclass::OnKeyDown(); break;
+    }
+
+    KeyboardEvent event(KeyboardEvent::KEY_DOWN, Interactor->GetKeySym(), Interactor->GetKeyCode(), getModifiers());
+    if (keyboardCallback_)
+        keyboardCallback_(event, keyboard_callback_cookie_);
+
+    if (FlyMode && (KeysDown & (32+16)) == (32+16))
+    {
+        if (State == VTKIS_FORWARDFLY || State == VTKIS_REVERSEFLY)
+            StopState();
+    }
+    else if (FlyMode && (KeysDown & 32) == 32)
+    {
+        if (State == VTKIS_FORWARDFLY)
+            StopState();
+
+        if (State == VTKIS_NONE)
+            StartState(VTKIS_REVERSEFLY);
+    }
+    else if (FlyMode && (KeysDown & 16) == 16)
+    {
+        if (State == VTKIS_REVERSEFLY)
+            StopState();
+
+        if (State == VTKIS_NONE)
+            StartState(VTKIS_FORWARDFLY);
+    }
+
+    Interactor->Render();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnKeyUp()
+{
+    KeyboardEvent event(KeyboardEvent::KEY_UP, Interactor->GetKeySym(), Interactor->GetKeyCode(), getModifiers());
+    if (keyboardCallback_)
+        keyboardCallback_(event, keyboard_callback_cookie_);
+
+    switch (Interactor->GetKeyCode())
+    {
+    case 'a': case 'A' : KeysDown &= ~16; break;
+    case 'z': case 'Z' : KeysDown &= ~32; break;
+    }
+
+    if (State == VTKIS_FORWARDFLY && (KeysDown & 16) == 0)
+        StopState();
+
+    if (State == VTKIS_REVERSEFLY && (KeysDown & 32) == 0)
+        StopState();
+
+    Superclass::OnKeyUp();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnMouseMove()
+{
+    Vec2i p(Interactor->GetEventPosition());
+    MouseEvent event(MouseEvent::MouseMove, MouseEvent::NoButton, p, getModifiers());
+    if (mouseCallback_)
+        mouseCallback_(event, mouse_callback_cookie_);
+
+    FindPokedRenderer(p[0], p[1]);
+
+    if (State == VTKIS_ROTATE || State == VTKIS_PAN || State == VTKIS_DOLLY || State == VTKIS_SPIN)
+    {
+        switch (State)
+        {
+        case VTKIS_ROTATE: Rotate(); break;
+        case VTKIS_PAN:    Pan();    break;
+        case VTKIS_DOLLY:  Dolly();  break;
+        case VTKIS_SPIN:   Spin();   break;
+        }
+
+        InvokeEvent(vtkCommand::InteractionEvent, NULL);
+    }
+
+    if (State == VTKIS_FORWARDFLY || State == VTKIS_REVERSEFLY)
+    {
+        vtkCamera *cam = CurrentRenderer->GetActiveCamera();
+        Vec2i thispos(Interactor->GetEventPosition());
+        Vec2i lastpos(Interactor->GetLastEventPosition());
+
+        // we want to steer by an amount proportional to window viewangle and size
+        // compute dx and dy increments relative to last mouse click
+        Vec2i size(Interactor->GetSize());
+        double scalefactor = 5*cam->GetViewAngle()/size[0];
+
+        double dx = - (thispos[0] - lastpos[0])*scalefactor*AngleStepSize;
+        double dy =   (thispos[1] - lastpos[1])*scalefactor*AngleStepSize;
+
+        // Temporary until I get smooth flight working
+        DeltaPitch = dy;
+        DeltaYaw = dx;
+
+        InvokeEvent(vtkCommand::InteractionEvent, NULL);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnLeftButtonDown()
+{
+    Vec2i p(Interactor->GetEventPosition());
+    MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick;
+    MouseEvent event(type, MouseEvent::LeftButton, p, getModifiers());
+    if (mouseCallback_)
+        mouseCallback_(event, mouse_callback_cookie_);
+
+    FindPokedRenderer(p[0], p[1]);
+    if (!CurrentRenderer)
+        return;
+
+    GrabFocus(EventCallbackCommand);
+
+    if (FlyMode)
+    {
+        if(State == VTKIS_REVERSEFLY)
+            State = VTKIS_FORWARDFLY;
+        else
+        {
+            SetupMotionVars();
+            if (State == VTKIS_NONE)
+                StartState(VTKIS_FORWARDFLY);
+        }
+    }
+    else
+    {
+        if (Interactor->GetShiftKey())
+        {
+            if (Interactor->GetControlKey())
+                StartDolly();
+            else
+                StartPan();
+        }
+        else
+        {
+            if (Interactor->GetControlKey())
+                StartSpin();
+            else
+                StartRotate();
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnLeftButtonUp()
+{
+    Vec2i p(Interactor->GetEventPosition());
+    MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::LeftButton, p, getModifiers());
+    if (mouseCallback_)
+        mouseCallback_(event, mouse_callback_cookie_);
+
+    switch (State)
+    {
+    case VTKIS_DOLLY:      EndDolly();  break;
+    case VTKIS_PAN:        EndPan();    break;
+    case VTKIS_SPIN:       EndSpin();   break;
+    case VTKIS_ROTATE:     EndRotate(); break;
+    case VTKIS_FORWARDFLY: StopState(); break;
+    }
+
+    if (Interactor )
+        ReleaseFocus();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnMiddleButtonDown()
+{
+    Vec2i p(Interactor->GetEventPosition());
+    MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick;
+    MouseEvent event(type, MouseEvent::MiddleButton, p, getModifiers());
+    if (mouseCallback_)
+        mouseCallback_(event, mouse_callback_cookie_);
+
+    FindPokedRenderer(p[0], p[1]);
+    if (!CurrentRenderer)
+        return;
+
+    GrabFocus(EventCallbackCommand);
+    StartPan();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnMiddleButtonUp()
+{
+    Vec2i p(Interactor->GetEventPosition());
+    MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::MiddleButton, p, getModifiers());
+    if (mouseCallback_)
+        mouseCallback_(event, mouse_callback_cookie_);
+
+    if (State == VTKIS_PAN)
+    {
+        EndPan();
+        if (Interactor)
+            ReleaseFocus();
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnRightButtonDown()
+{
+    Vec2i p(Interactor->GetEventPosition());
+    MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick;
+    MouseEvent event(type, MouseEvent::RightButton, p, getModifiers());
+    if (mouseCallback_)
+        mouseCallback_(event, mouse_callback_cookie_);
+
+    FindPokedRenderer(p[0], p[1]);
+    if (!CurrentRenderer)
+        return;
+
+    GrabFocus(EventCallbackCommand);
+
+    if (FlyMode)
+    {
+        if (State == VTKIS_FORWARDFLY)
+            State = VTKIS_REVERSEFLY;
+        else
+        {
+            SetupMotionVars();
+            if (State == VTKIS_NONE)
+                StartState(VTKIS_REVERSEFLY);
+        }
+
+    }
+    else
+        StartDolly();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnRightButtonUp()
+{
+    Vec2i p(Interactor->GetEventPosition());
+    MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::RightButton, p, getModifiers());
+    if (mouseCallback_)
+        mouseCallback_(event, mouse_callback_cookie_);
+
+    if(State == VTKIS_DOLLY)
+    {
+        EndDolly();
+        if (Interactor)
+            ReleaseFocus();
+    }
+
+    if (State == VTKIS_REVERSEFLY)
+    {
+        StopState();
+        if (Interactor)
+            ReleaseFocus();
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnMouseWheelForward()
+{
+    Vec2i p(Interactor->GetEventPosition());
+    MouseEvent event(MouseEvent::MouseScrollUp, MouseEvent::VScroll, p, getModifiers());
+    if (mouseCallback_)
+        mouseCallback_(event, mouse_callback_cookie_);
+    if (Interactor->GetRepeatCount() && mouseCallback_)
+        mouseCallback_(event, mouse_callback_cookie_);
+
+    if (Interactor->GetAltKey())
+    {
+        // zoom
+        vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
+        double opening_angle = cam->GetViewAngle();
+        if (opening_angle > 15.0)
+            opening_angle -= 1.0;
+
+        cam->SetViewAngle(opening_angle);
+        cam->Modified();
+        CurrentRenderer->ResetCameraClippingRange();
+        CurrentRenderer->Modified();
+        Interactor->Render();
+    }
+    else
+    {
+        FindPokedRenderer(p[0], p[1]);
+        if (!CurrentRenderer)
+            return;
+
+        GrabFocus(EventCallbackCommand);
+        StartDolly();
+        Dolly(pow(1.1, MotionFactor * 0.2 * MouseWheelMotionFactor));
+        EndDolly();
+        ReleaseFocus();
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnMouseWheelBackward()
+{
+    Vec2i p(Interactor->GetEventPosition());
+    MouseEvent event(MouseEvent::MouseScrollDown, MouseEvent::VScroll, p, getModifiers());
+    if (mouseCallback_)
+        mouseCallback_(event, mouse_callback_cookie_);
+
+    if (Interactor->GetRepeatCount() && mouseCallback_)
+        mouseCallback_(event, mouse_callback_cookie_);
+
+    if (Interactor->GetAltKey())
+    {
+        // zoom
+        vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
+        double opening_angle = cam->GetViewAngle();
+        if (opening_angle < 170.0)
+            opening_angle += 1.0;
+
+        cam->SetViewAngle(opening_angle);
+        cam->Modified();
+        CurrentRenderer->ResetCameraClippingRange();
+        CurrentRenderer->Modified();
+        Interactor->Render();
+    }
+    else
+    {
+        FindPokedRenderer(p[0], p[1]);
+        if (!CurrentRenderer)
+            return;
+
+        GrabFocus(EventCallbackCommand);
+        StartDolly();
+        Dolly(pow(1.1, MotionFactor * -0.2 * MouseWheelMotionFactor));
+        EndDolly();
+        ReleaseFocus();
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::OnTimer()
+{
+    if  (State == VTKIS_FORWARDFLY || State == VTKIS_REVERSEFLY)
+        Fly();
+
+    Interactor->Render();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void cv::viz::vtkVizInteractorStyle::Rotate()
+{
+    if (!CurrentRenderer)
+        return;
+
+    Vec2i dxy = Vec2i(Interactor->GetEventPosition()) - Vec2i(Interactor->GetLastEventPosition());
+    Vec2i size(CurrentRenderer->GetRenderWindow()->GetSize());
+
+    double delta_elevation = -20.0 / size[1];
+    double delta_azimuth   = -20.0 / size[0];
+
+    double rxf = dxy[0] * delta_azimuth * MotionFactor;
+    double ryf = dxy[1] * delta_elevation * MotionFactor;
+
+    vtkCamera *camera = CurrentRenderer->GetActiveCamera();
+    camera->Azimuth(rxf);
+    camera->Elevation(ryf);
+    camera->OrthogonalizeViewUp();
+
+    if (AutoAdjustCameraClippingRange)
+        CurrentRenderer->ResetCameraClippingRange();
+
+    if (Interactor->GetLightFollowCamera())
+        CurrentRenderer->UpdateLightsGeometryToFollowCamera();
+
+    Interactor->Render();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::Spin()
+{
+    if (!CurrentRenderer)
+        return;
+
+    vtkRenderWindowInteractor *rwi = Interactor;
+
+    double *center = CurrentRenderer->GetCenter();
+
+    double newAngle = vtkMath::DegreesFromRadians( atan2( rwi->GetEventPosition()[1]     - center[1], rwi->GetEventPosition()[0]     - center[0] ) );
+    double oldAngle = vtkMath::DegreesFromRadians( atan2( rwi->GetLastEventPosition()[1] - center[1], rwi->GetLastEventPosition()[0] - center[0] ) );
+
+    vtkCamera *camera = CurrentRenderer->GetActiveCamera();
+    camera->Roll( newAngle - oldAngle );
+    camera->OrthogonalizeViewUp();
+
+    rwi->Render();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+void cv::viz::vtkVizInteractorStyle::Pan()
+{
+    if (!CurrentRenderer)
+        return;
+
+    vtkRenderWindowInteractor *rwi = Interactor;
+
+    double viewFocus[4], focalDepth, viewPoint[3];
+    double newPickPoint[4], oldPickPoint[4], motionVector[3];
+
+    // Calculate the focal depth since we'll be using it a lot
+
+    vtkCamera *camera = CurrentRenderer->GetActiveCamera();
+    camera->GetFocalPoint(viewFocus);
+    ComputeWorldToDisplay(viewFocus[0], viewFocus[1], viewFocus[2], viewFocus);
+    focalDepth = viewFocus[2];
+
+    ComputeDisplayToWorld(rwi->GetEventPosition()[0], rwi->GetEventPosition()[1], focalDepth, newPickPoint);
+
+    // Has to recalc old mouse point since the viewport has moved, so can't move it outside the loop
+    ComputeDisplayToWorld(rwi->GetLastEventPosition()[0], rwi->GetLastEventPosition()[1], focalDepth, oldPickPoint);
+
+    // Camera motion is reversed
+    motionVector[0] = oldPickPoint[0] - newPickPoint[0];
+    motionVector[1] = oldPickPoint[1] - newPickPoint[1];
+    motionVector[2] = oldPickPoint[2] - newPickPoint[2];
+
+    camera->GetFocalPoint(viewFocus);
+    camera->GetPosition(viewPoint);
+    camera->SetFocalPoint(motionVector[0] + viewFocus[0], motionVector[1] + viewFocus[1], motionVector[2] + viewFocus[2]);
+    camera->SetPosition(  motionVector[0] + viewPoint[0], motionVector[1] + viewPoint[1], motionVector[2] + viewPoint[2]);
+
+    if (Interactor->GetLightFollowCamera())
+        CurrentRenderer->UpdateLightsGeometryToFollowCamera();
+
+    Interactor->Render();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void cv::viz::vtkVizInteractorStyle::Dolly()
+{
+    if (!CurrentRenderer)
+        return;
+
+    int dy = Interactor->GetEventPosition()[1] - Interactor->GetLastEventPosition()[1];
+    Dolly(pow(1.1, MotionFactor * dy / CurrentRenderer->GetCenter()[1]));
+}
+
+void cv::viz::vtkVizInteractorStyle::Dolly(double factor)
+{
+    if (!CurrentRenderer)
+        return;
+
+    vtkCamera *camera = CurrentRenderer->GetActiveCamera();
+    if (camera->GetParallelProjection())
+        camera->SetParallelScale(camera->GetParallelScale() / factor);
+    else
+    {
+        camera->Dolly(factor);
+        if (AutoAdjustCameraClippingRange)
+            CurrentRenderer->ResetCameraClippingRange();
+    }
+
+    if (Interactor->GetLightFollowCamera())
+        CurrentRenderer->UpdateLightsGeometryToFollowCamera();
+
+    Interactor->Render();
+}
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void cv::viz::vtkVizInteractorStyle::Fly()
+{
+    if (CurrentRenderer == NULL)
+        return;
+
+    if (KeysDown)
+        FlyByKey();
+    else
+        FlyByMouse();
+
+    CurrentRenderer->GetActiveCamera()->OrthogonalizeViewUp();
+
+    if (AutoAdjustCameraClippingRange)
+        CurrentRenderer->ResetCameraClippingRange();
+
+    if (Interactor->GetLightFollowCamera())
+        CurrentRenderer->UpdateLightsGeometryToFollowCamera();
+}
+
+void cv::viz::vtkVizInteractorStyle::SetupMotionVars()
+{
+    Vec6d bounds;
+    CurrentRenderer->ComputeVisiblePropBounds(bounds.val);
+
+    if ( !vtkMath::AreBoundsInitialized(bounds.val) )
+        DiagonalLength = 1.0;
+    else
+        DiagonalLength = norm(Vec3d(bounds[0], bounds[2], bounds[4]) - Vec3d(bounds[1], bounds[3], bounds[5]));
+}
+
+void cv::viz::vtkVizInteractorStyle::MotionAlongVector(const Vec3d& vector, double amount, vtkCamera* cam)
+{
+    // move camera and focus along DirectionOfProjection
+    Vec3d campos = Vec3d(cam->GetPosition())   - amount * vector;
+    Vec3d camfoc = Vec3d(cam->GetFocalPoint()) - amount * vector;
+
+    cam->SetPosition(campos.val);
+    cam->SetFocalPoint(camfoc.val);
+}
+
+void cv::viz::vtkVizInteractorStyle::FlyByMouse()
+{
+    vtkCamera* cam = CurrentRenderer->GetActiveCamera();
+    double speed  = DiagonalLength * MotionStepSize * MotionUserScale;
+    speed = speed * ( Interactor->GetShiftKey() ? MotionAccelerationFactor : 1.0);
+
+    // Sidestep
+    if (Interactor->GetAltKey())
+    {
+        if (DeltaYaw!=0.0)
+        {
+            vtkMatrix4x4 *vtm = cam->GetViewTransformMatrix();
+            Vec3d a_vector(vtm->GetElement(0,0), vtm->GetElement(0,1), vtm->GetElement(0,2));
+
+            MotionAlongVector(a_vector, -DeltaYaw*speed, cam);
+        }
+        if (DeltaPitch!=0.0)
+        {
+            Vec3d a_vector(cam->GetViewUp());
+            MotionAlongVector(a_vector, DeltaPitch*speed, cam);
+        }
+    }
+    else
+    {
+        cam->Yaw(DeltaYaw);
+        cam->Pitch(DeltaPitch);
+        DeltaYaw = 0;
+        DeltaPitch = 0;
+    }
+    //
+    if (!Interactor->GetControlKey())
+    {
+        Vec3d a_vector(cam->GetDirectionOfProjection()); // reversed (use -speed)
+        switch (State)
+        {
+        case VTKIS_FORWARDFLY: MotionAlongVector(a_vector, -speed, cam); break;
+        case VTKIS_REVERSEFLY: MotionAlongVector(a_vector, speed, cam); break;
+        }
+    }
+}
+
+void cv::viz::vtkVizInteractorStyle::FlyByKey()
+{
+    vtkCamera* cam = CurrentRenderer->GetActiveCamera();
+
+    double speed  = DiagonalLength * MotionStepSize * MotionUserScale;
+    speed = speed * ( Interactor->GetShiftKey() ? MotionAccelerationFactor : 1.0);
+
+    // Left and right
+    if (Interactor->GetAltKey())
+    { // Sidestep
+        vtkMatrix4x4 *vtm = cam->GetViewTransformMatrix();
+        Vec3d a_vector(vtm->GetElement(0,0), vtm->GetElement(0,1), vtm->GetElement(0,2));
+
+        if (KeysDown & 1)
+            MotionAlongVector(a_vector, -speed, cam);
+
+        if (KeysDown & 2)
+            MotionAlongVector(a_vector,  speed, cam);
+    }
+    else
+    {
+        if (KeysDown & 1)
+            cam->Yaw( AngleStepSize);
+
+        if (KeysDown & 2)
+            cam->Yaw(-AngleStepSize);
+    }
+
+    // Up and Down
+    if (Interactor->GetControlKey())
+    { // Sidestep
+        Vec3d a_vector = Vec3d(cam->GetViewUp());
+        if (KeysDown & 4)
+            MotionAlongVector(a_vector,-speed, cam);
+
+        if (KeysDown & 8)
+            MotionAlongVector(a_vector, speed, cam);
+    }
+    else
+    {
+        if (KeysDown & 4)
+            cam->Pitch(-AngleStepSize);
+
+        if (KeysDown & 8)
+            cam->Pitch( AngleStepSize);
+    }
+
+    // forward and backward
+    Vec3d a_vector(cam->GetDirectionOfProjection());
+    if (KeysDown & 16)
+        MotionAlongVector(a_vector, speed, cam);
+
+    if (KeysDown & 32)
+        MotionAlongVector(a_vector,-speed, cam);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void cv::viz::vtkVizInteractorStyle::PrintSelf(ostream& os, vtkIndent indent)
+{
+    Superclass::PrintSelf(os, indent);
+    os << indent << "MotionFactor: " << MotionFactor << "\n";
+    os << indent << "MotionStepSize: " << MotionStepSize << "\n";
+    os << indent << "MotionAccelerationFactor: "<< MotionAccelerationFactor << "\n";
+    os << indent << "AngleStepSize: " << AngleStepSize << "\n";
+    os << indent << "MotionUserScale: "<< MotionUserScale << "\n";
+}
similarity index 61%
rename from modules/viz/src/interactor_style.hpp
rename to modules/viz/src/vtk/vtkVizInteractorStyle.hpp
index 8d01697..3588a3b 100644 (file)
 #ifndef __OPENCV_VIZ_INTERACTOR_STYLE_H__
 #define __OPENCV_VIZ_INTERACTOR_STYLE_H__
 
+#include <vtkInteractorStyle.h>
+
 namespace cv
 {
     namespace viz
     {
-        class InteractorStyle : public vtkInteractorStyleTrackballCamera
+        class vtkVizInteractorStyle : public vtkInteractorStyle
         {
         public:
-            static InteractorStyle *New();
-            virtual ~InteractorStyle() {}
+            static vtkVizInteractorStyle *New();
+            vtkTypeMacro(vtkVizInteractorStyle, vtkInteractorStyle)
+            void PrintSelf(ostream& os, vtkIndent indent);
 
-            // this macro defines Superclass, the isA functionality and the safe downcast method
-            vtkTypeMacro(InteractorStyle, vtkInteractorStyleTrackballCamera)
+            virtual void OnChar();
+            virtual void OnKeyDown();
+            virtual void OnKeyUp();
 
-            /** \brief Initialization routine. Must be called before anything else. */
-            virtual void Initialize();
+            virtual void OnMouseMove();
+            virtual void OnLeftButtonDown();
+            virtual void OnLeftButtonUp();
+            virtual void OnMiddleButtonDown();
+            virtual void OnMiddleButtonUp();
+            virtual void OnRightButtonDown();
+            virtual void OnRightButtonUp();
+            virtual void OnMouseWheelForward();
+            virtual void OnMouseWheelBackward();
+            virtual void OnTimer();
+
+            virtual void Rotate();
+            virtual void Spin();
+            virtual void Pan();
+            virtual void Dolly();
+
+            vtkSetMacro(FlyMode,bool)
+            vtkGetMacro(FlyMode,bool)
+
+
+            vtkSetMacro(MotionFactor, double)
+            vtkGetMacro(MotionFactor, double)
 
-            void setWidgetActorMap(const Ptr<WidgetActorMap>& actors) { widget_actor_map_ = actors; }
             void registerMouseCallback(void (*callback)(const MouseEvent&, void*), void* cookie = 0);
             void registerKeyboardCallback(void (*callback)(const KeyboardEvent&, void*), void * cookie = 0);
+
+            void setWidgetActorMap(const Ptr<WidgetActorMap>& actors) { widget_actor_map_ = actors; }
             void saveScreenshot(const String &file);
             void exportScene(const String &file);
+            void exportScene();
+            void changePointsSize(float delta);
+            void setRepresentationToPoints();
+            void printCameraParams();
+            void toggleFullScreen();
+            void resetViewerPose();
+            void toggleStereo();
+            void printHelp();
+
+            // Set the basic unit step size : by default 1/250 of bounding diagonal
+            vtkSetMacro(MotionStepSize,double)
+            vtkGetMacro(MotionStepSize,double)
+
+            // Set acceleration factor when shift key is applied : default 10
+            vtkSetMacro(MotionAccelerationFactor,double)
+            vtkGetMacro(MotionAccelerationFactor,double)
+
+            // Set the basic angular unit for turning : efault 1 degree
+            vtkSetMacro(AngleStepSize,double)
+            vtkGetMacro(AngleStepSize,double)
 
         private:
-            /** \brief Set to true after initialization is complete. */
-            bool init_;
-
             Ptr<WidgetActorMap> widget_actor_map_;
 
             Vec2i win_size_;
             Vec2i win_pos_;
             Vec2i max_win_size_;
 
-            /** \brief Interactor style internal method. Gets called whenever a key is pressed. */
-            virtual void OnChar();
+            void zoomIn();
+            void zoomOut();
 
-            // Keyboard events
-            virtual void OnKeyDown();
-            virtual void OnKeyUp();
+        protected:
+            vtkVizInteractorStyle();
+            ~vtkVizInteractorStyle();
 
-            // mouse button events
-            virtual void OnMouseMove();
-            virtual void OnLeftButtonDown();
-            virtual void OnLeftButtonUp();
-            virtual void OnMiddleButtonDown();
-            virtual void OnMiddleButtonUp();
-            virtual void OnRightButtonDown();
-            virtual void OnRightButtonUp();
-            virtual void OnMouseWheelForward();
-            virtual void OnMouseWheelBackward();
+            virtual void Dolly(double factor);
 
-            /** \brief Interactor style internal method. Gets called periodically if a timer is set. */
-            virtual void OnTimer();
+            void Fly();
+            void FlyByMouse();
+            void FlyByKey();
+            void SetupMotionVars();
+            void MotionAlongVector(const Vec3d& vector, double amount, vtkCamera* cam);
 
-            void zoomIn();
-            void zoomOut();
+        private:
+            vtkVizInteractorStyle(const vtkVizInteractorStyle&);
+            vtkVizInteractorStyle& operator=(const vtkVizInteractorStyle&);
 
-            /** \brief True if we're using red-blue colors for anaglyphic stereo, false if magenta-green. */
-            bool stereo_anaglyph_mask_default_;
+            //! True for red-blue colors, false for magenta-green.
+            bool stereo_anaglyph_redblue_;
 
             void (*keyboardCallback_)(const KeyboardEvent&, void*);
             void *keyboard_callback_cookie_;
@@ -111,7 +148,20 @@ namespace cv
             void (*mouseCallback_)(const MouseEvent&, void*);
             void *mouse_callback_cookie_;
 
+            bool FlyMode;
+            double MotionFactor;
+
             int getModifiers();
+
+            // from fly
+            unsigned char KeysDown;
+            double        DiagonalLength;
+            double        MotionStepSize;
+            double        MotionUserScale;
+            double        MotionAccelerationFactor;
+            double        AngleStepSize;
+            double        DeltaYaw;
+            double        DeltaPitch;
         };
     }
 }
diff --git a/modules/viz/src/vtk/vtkXYZReader.cpp b/modules/viz/src/vtk/vtkXYZReader.cpp
new file mode 100644 (file)
index 0000000..283a592
--- /dev/null
@@ -0,0 +1,107 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+// Authors:
+//  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
+//
+//M*/
+
+#include "precomp.hpp"
+
+namespace cv { namespace viz
+{
+    vtkStandardNewMacro(vtkXYZReader);
+}}
+
+
+cv::viz::vtkXYZReader::vtkXYZReader()
+{
+    this->FileName = 0;
+    this->SetNumberOfInputPorts(0);
+}
+
+cv::viz::vtkXYZReader::~vtkXYZReader()
+{
+    this->SetFileName(0);
+}
+
+void cv::viz::vtkXYZReader::PrintSelf(ostream& os, vtkIndent indent)
+{
+    this->Superclass::PrintSelf(os,indent);
+    os << indent << "FileName: " << (this->FileName ? this->FileName : "(none)") << "\n";
+}
+
+int cv::viz::vtkXYZReader::RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector)
+{
+    // Make sure we have a file to read.
+    if(!this->FileName)
+    {
+        vtkErrorMacro("A FileName must be specified.");
+        return 0;
+    }
+
+    // Open the input file.
+    ifstream fin(this->FileName);
+    if(!fin)
+    {
+        vtkErrorMacro("Error opening file " << this->FileName);
+        return 0;
+    }
+
+    // Allocate objects to hold points and vertex cells.
+    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
+    vtkSmartPointer<vtkCellArray> verts = vtkSmartPointer<vtkCellArray>::New();
+
+    // Read points from the file.
+    vtkDebugMacro("Reading points from file " << this->FileName);
+    double x[3];
+    while(fin >> x[0] >> x[1] >> x[2])
+    {
+        vtkIdType id = points->InsertNextPoint(x);
+        verts->InsertNextCell(1, &id);
+    }
+    vtkDebugMacro("Read " << points->GetNumberOfPoints() << " points.");
+
+    // Store the points and cells in the output data object.
+    vtkPolyData* output = vtkPolyData::GetData(outputVector);
+    output->SetPoints(points);
+    output->SetVerts(verts);
+
+    return 1;
+}
diff --git a/modules/viz/src/vtk/vtkXYZReader.h b/modules/viz/src/vtk/vtkXYZReader.h
new file mode 100644 (file)
index 0000000..13ae048
--- /dev/null
@@ -0,0 +1,80 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+// Authors:
+//  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
+//
+//M*/
+
+#ifndef __vtkXYZReader_h
+#define __vtkXYZReader_h
+
+#include "vtkPolyDataAlgorithm.h"
+
+namespace cv
+{
+    namespace viz
+    {
+        class vtkXYZReader : public vtkPolyDataAlgorithm
+        {
+        public:
+          static vtkXYZReader* New();
+          vtkTypeMacro(vtkXYZReader,vtkPolyDataAlgorithm)
+          void PrintSelf(ostream& os, vtkIndent indent);
+
+          // Description:
+          // Set/Get the name of the file from which to read points.
+          vtkSetStringMacro(FileName)
+          vtkGetStringMacro(FileName)
+
+        protected:
+          vtkXYZReader();
+          ~vtkXYZReader();
+
+          char* FileName;
+
+          int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*);
+        private:
+          vtkXYZReader(const vtkXYZReader&);  // Not implemented.
+          void operator=(const vtkXYZReader&);  // Not implemented.
+        };
+    }
+}
+
+#endif
index 4518a01..5a3d7d5 100644 (file)
@@ -61,10 +61,22 @@ void cv::viz::vtkXYZWriter::WriteData()
     if (!input)
         return;
 
-    // OpenVTKFile() will report any errors that happen
-    ostream *outfilep = this->OpenVTKFile();
-    if (!outfilep)
+    if (!this->FileName )
+    {
+        vtkErrorMacro(<< "No FileName specified! Can't write!");
+        this->SetErrorCode(vtkErrorCode::NoFileNameError);
+        return;
+    }
+
+    vtkDebugMacro(<<"Opening vtk file for writing...");
+    ostream *outfilep = new ofstream(this->FileName, ios::out);
+    if (outfilep->fail())
+    {
+        vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
+        this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
+        delete outfilep;
         return;
+    }
 
     ostream &outfile = *outfilep;
 
@@ -76,7 +88,8 @@ void cv::viz::vtkXYZWriter::WriteData()
     }
 
     // Close the file
-    this->CloseVTKFile(outfilep);
+    vtkDebugMacro(<<"Closing vtk file\n");
+    delete outfilep;
 
     // Delete the file if an error occurred
     if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
@@ -86,8 +99,24 @@ void cv::viz::vtkXYZWriter::WriteData()
     }
 }
 
+int cv::viz::vtkXYZWriter::FillInputPortInformation(int, vtkInformation *info)
+{
+    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
+    return 1;
+}
+
 void cv::viz::vtkXYZWriter::PrintSelf(ostream& os, vtkIndent indent)
 {
     this->Superclass::PrintSelf(os,indent);
     os << indent << "DecimalPrecision: " << this->DecimalPrecision << "\n";
 }
+
+vtkPolyData* cv::viz::vtkXYZWriter::GetInput()
+{
+    return vtkPolyData::SafeDownCast(this->Superclass::GetInput());
+}
+
+vtkPolyData* cv::viz::vtkXYZWriter::GetInput(int port)
+{
+    return vtkPolyData::SafeDownCast(this->Superclass::GetInput(port));
+}
index 3db18b7..91d0c8f 100644 (file)
 #ifndef __vtkXYZWriter_h
 #define __vtkXYZWriter_h
 
-#include "vtkPolyDataWriter.h"
+#include "vtkWriter.h"
 
 namespace cv
 {
     namespace viz
     {
-        class vtkXYZWriter : public vtkPolyDataWriter
+        class vtkXYZWriter : public vtkWriter
         {
         public:
             static vtkXYZWriter *New();
-            vtkTypeMacro(vtkXYZWriter,vtkPolyDataWriter)
+            vtkTypeMacro(vtkXYZWriter,vtkWriter)
             void PrintSelf(ostream& os, vtkIndent indent);
 
             vtkGetMacro(DecimalPrecision, int)
             vtkSetMacro(DecimalPrecision, int)
 
+            // Description:
+            // Specify file name of data file to write.
+            vtkSetStringMacro(FileName)
+            vtkGetStringMacro(FileName)
+
+            // Description:
+            // Get the input to this writer.
+            vtkPolyData* GetInput();
+            vtkPolyData* GetInput(int port);
+
         protected:
             vtkXYZWriter();
             ~vtkXYZWriter(){}
 
             void WriteData();
+            int FillInputPortInformation(int port, vtkInformation *info);
 
             int DecimalPrecision;
+            char *FileName;
 
         private:
             vtkXYZWriter(const vtkXYZWriter&);  // Not implemented.
index 1a5c4fe..05914e2 100644 (file)
 #ifndef __OPENCV_TEST_PRECOMP_HPP__
 #define __OPENCV_TEST_PRECOMP_HPP__
 
-#include "opencv2/ts.hpp"
-#include <opencv2/core.hpp>
-#include <opencv2/imgproc.hpp>
-#include <opencv2/highgui.hpp>
-#include <opencv2/viz.hpp>
+#include <opencv2/core/version.hpp>
+#include <opencv2/viz/vizcore.hpp>
+
+namespace cv
+{
+    Mat imread(const String& filename, int flags = 1);
+}
+
+#if CV_MAJOR_VERSION < 3
+    #include "opencv2/ts/ts.hpp"
+#else
+    #include "opencv2/ts.hpp"
+#endif
 
 #include <iostream>
 #include <fstream>
index 590e29e..b20e8d7 100644 (file)
@@ -15,50 +15,46 @@ void tutorial3(bool camera_pov)
     myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem());
 
     /// Let's assume camera has the following properties
-    Point3d cam_pos(3.0, 3.0, 3.0), cam_focal_point(3.0, 3.0, 2.0), cam_y_dir(-1.0, 0.0, 0.0);
+    Point3d cam_origin(3.0, 3.0, 3.0), cam_focal_point(3.0, 3.0, 2.0), cam_y_dir(-1.0, 0.0, 0.0);
 
     /// We can get the pose of the cam using makeCameraPose
-    Affine3d cam_pose = viz::makeCameraPose(cam_pos, cam_focal_point, cam_y_dir);
+    Affine3d camera_pose = viz::makeCameraPose(cam_origin, cam_focal_point, cam_y_dir);
 
     /// We can get the transformation matrix from camera coordinate system to global using
     /// - makeTransformToGlobal. We need the axes of the camera
-    Affine3d transform = viz::makeTransformToGlobal(Vec3d(0.0, -1.0, 0.0), Vec3d(-1.0, 0.0, 0.0), Vec3d(0.0, 0.0, -1.0), cam_pos);
+    Affine3d transform = viz::makeTransformToGlobal(Vec3d(0.0, -1.0, 0.0), Vec3d(-1.0, 0.0, 0.0), Vec3d(0.0, 0.0, -1.0), cam_origin);
 
     /// Create a cloud widget.
     Mat dragon_cloud = viz::readCloud(get_dragon_ply_file_path());
     viz::WCloud cloud_widget(dragon_cloud, viz::Color::green());
 
     /// Pose of the widget in camera frame
-    Affine3d cloud_pose = Affine3d().translate(Vec3d(0.0, 0.0, 3.0));
+    Affine3d cloud_pose = Affine3d().rotate(Vec3d(0.0, CV_PI/2, 0.0)).rotate(Vec3d(0.0, 0.0, CV_PI)).translate(Vec3d(0.0, 0.0, 3.0));
     /// Pose of the widget in global frame
     Affine3d cloud_pose_global = transform * cloud_pose;
 
     /// Visualize camera frame
+    myWindow.showWidget("CPW_FRUSTUM", viz::WCameraPosition(Vec2f(0.889484f, 0.523599f)), camera_pose);
     if (!camera_pov)
-    {
-        viz::WCameraPosition cpw(0.5); // Coordinate axes
-        viz::WCameraPosition cpw_frustum(Vec2f(0.889484f, 0.523599f)); // Camera frustum
-        myWindow.showWidget("CPW", cpw, cam_pose);
-        myWindow.showWidget("CPW_FRUSTUM", cpw_frustum, cam_pose);
-    }
+        myWindow.showWidget("CPW", viz::WCameraPosition(0.5), camera_pose);
 
     /// Visualize widget
     myWindow.showWidget("bunny", cloud_widget, cloud_pose_global);
 
     /// Set the viewer pose to that of camera
     if (camera_pov)
-        myWindow.setViewerPose(cam_pose);
+        myWindow.setViewerPose(camera_pose);
 
     /// Start event loop.
     myWindow.spin();
 }
 
-TEST(Viz, DISABLED_tutorial3_global_view)
+TEST(Viz, tutorial3_global_view)
 {
     tutorial3(false);
 }
 
-TEST(Viz, DISABLED_tutorial3_camera_view)
+TEST(Viz, tutorial3_camera_view)
 {
     tutorial3(true);
 }
index 45d3cdc..45128df 100644 (file)
@@ -59,6 +59,5 @@ TEST(Viz_viz3d, DISABLED_develop)
     //cv::Mat cloud = cv::viz::readCloud(get_dragon_ply_file_path());
     //---->>>>> </to_test_in_future>
 
-
     viz.spin();
 }
index aae468e..8c944bb 100644 (file)
@@ -52,6 +52,7 @@ TEST(Viz, show_cloud_bluberry)
     Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0));
 
     Viz3d viz("show_cloud_bluberry");
+    viz.setBackgroundColor(Color::black());
     viz.showWidget("coosys", WCoordinateSystem());
     viz.showWidget("dragon", WCloud(dragon_cloud, Color::bluberry()), pose);
 
@@ -81,7 +82,7 @@ TEST(Viz, show_cloud_masked)
     Mat dragon_cloud = readCloud(get_dragon_ply_file_path());
 
     Vec3f qnan = Vec3f::all(std::numeric_limits<float>::quiet_NaN());
-    for(size_t i = 0; i < dragon_cloud.total(); ++i)
+    for(int i = 0; i < (int)dragon_cloud.total(); ++i)
         if (i % 15 != 0)
             dragon_cloud.at<Vec3f>(i) = qnan;
 
@@ -102,6 +103,7 @@ TEST(Viz, show_cloud_collection)
     ccol.addCloud(cloud, Color::white(), Affine3d().translate(Vec3d(0, 0, 0)).rotate(Vec3d(CV_PI/2, 0, 0)));
     ccol.addCloud(cloud, Color::blue(),  Affine3d().translate(Vec3d(1, 0, 0)));
     ccol.addCloud(cloud, Color::red(),   Affine3d().translate(Vec3d(2, 0, 0)));
+    ccol.finalize();
 
     Viz3d viz("show_cloud_collection");
     viz.setBackgroundColor(Color::mlab());
@@ -154,6 +156,27 @@ TEST(Viz, show_mesh_random_colors)
     viz.spin();
 }
 
+TEST(Viz, show_widget_merger)
+{
+    WWidgetMerger merger;
+    merger.addWidget(WCube(Vec3d::all(0.0), Vec3d::all(1.0), true, Color::gold()));
+
+    RNG& rng = theRNG();
+    for(int i = 0; i < 77; ++i)
+    {
+        Vec3b c;
+        rng.fill(c, RNG::NORMAL, Scalar::all(128), Scalar::all(48), true);
+        merger.addWidget(WSphere(Vec3d(c)*(1.0/255.0), 7.0/255.0, 10, Color(c[2], c[1], c[0])));
+    }
+    merger.finalize();
+
+    Viz3d viz("show_mesh_random_color");
+    viz.showWidget("coo", WCoordinateSystem());
+    viz.showWidget("merger", merger);
+    viz.showWidget("text2d", WText("Widget merger", Point(20, 20), 20, Color::green()));
+    viz.spin();
+}
+
 TEST(Viz, show_textured_mesh)
 {
     Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png"));
@@ -170,7 +193,7 @@ TEST(Viz, show_textured_mesh)
         tcoords.push_back(Vec2d(1.0, i/64.0));
     }
 
-    for(size_t i = 0; i < points.size()/2-1; ++i)
+    for(int i = 0; i < (int)points.size()/2-1; ++i)
     {
         int polys[] = {3, 2*i, 2*i+1, 2*i+2, 3, 2*i+1, 2*i+2, 2*i+3};
         polygons.insert(polygons.end(), polys, polys + sizeof(polys)/sizeof(polys[0]));
@@ -193,12 +216,18 @@ TEST(Viz, show_textured_mesh)
 
 TEST(Viz, show_polyline)
 {
-    Mat polyline(1, 32, CV_64FC3);
-    for(size_t i = 0; i < polyline.total(); ++i)
+    const Color palette[] = { Color::red(), Color::green(), Color::blue(), Color::gold(), Color::raspberry(), Color::bluberry(), Color::lime() };
+    size_t palette_size = sizeof(palette)/sizeof(palette[0]);
+
+    Mat polyline(1, 32, CV_64FC3), colors(1, 32, CV_8UC3);
+    for(int i = 0; i < (int)polyline.total(); ++i)
+    {
         polyline.at<Vec3d>(i) = Vec3d(i/16.0, cos(i * CV_PI/6), sin(i * CV_PI/6));
+        colors.at<Vec3b>(i) = palette[i & palette_size];
+    }
 
     Viz3d viz("show_polyline");
-    viz.showWidget("polyline", WPolyLine(Mat(polyline), Color::apricot()));
+    viz.showWidget("polyline", WPolyLine(polyline, colors));
     viz.showWidget("coosys", WCoordinateSystem());
     viz.showWidget("text2d", WText("Polyline", Point(20, 20), 20, Color::green()));
     viz.spin();
@@ -222,13 +251,14 @@ TEST(Viz, show_sampled_normals)
 TEST(Viz, show_trajectories)
 {
     std::vector<Affine3d> path = generate_test_trajectory<double>(), sub0, sub1, sub2, sub3, sub4, sub5;
-
-    Mat(path).rowRange(0, path.size()/10+1).copyTo(sub0);
-    Mat(path).rowRange(path.size()/10, path.size()/5+1).copyTo(sub1);
-    Mat(path).rowRange(path.size()/5, 11*path.size()/12).copyTo(sub2);
-    Mat(path).rowRange(11*path.size()/12, path.size()).copyTo(sub3);
-    Mat(path).rowRange(3*path.size()/4, 33*path.size()/40).copyTo(sub4);
-    Mat(path).rowRange(33*path.size()/40, 9*path.size()/10).copyTo(sub5);
+    int size =(int)path.size();
+
+    Mat(path).rowRange(0, size/10+1).copyTo(sub0);
+    Mat(path).rowRange(size/10, size/5+1).copyTo(sub1);
+    Mat(path).rowRange(size/5, 11*size/12).copyTo(sub2);
+    Mat(path).rowRange(11*size/12, size).copyTo(sub3);
+    Mat(path).rowRange(3*size/4, 33*size/40).copyTo(sub4);
+    Mat(path).rowRange(33*size/40, 9*size/10).copyTo(sub5);
     Matx33d K(1024.0, 0.0, 320.0, 0.0, 1024.0, 240.0, 0.0, 0.0, 1.0);
 
     Viz3d viz("show_trajectories");
@@ -259,7 +289,7 @@ TEST(Viz, show_trajectory_reposition)
 
     Viz3d viz("show_trajectory_reposition_to_origin");
     viz.showWidget("coos", WCoordinateSystem());
-    viz.showWidget("sub3", WTrajectory(Mat(path).rowRange(0, path.size()/3), WTrajectory::BOTH, 0.2, Color::brown()), path.front().inv());
+    viz.showWidget("sub3", WTrajectory(Mat(path).rowRange(0, (int)path.size()/3), WTrajectory::BOTH, 0.2, Color::brown()), path.front().inv());
     viz.showWidget("text2d", WText("Trajectory resposition to origin", Point(20, 20), 20, Color::green()));
     viz.spin();
 }