From 37b1a7560cc132abc0cae800a4b042d543248cb9 Mon Sep 17 00:00:00 2001 From: Dmitriy Anisimov Date: Mon, 18 Aug 2014 22:40:31 +0400 Subject: [PATCH 01/72] first version of moving KDTree from core to ml --- modules/core/include/opencv2/core.hpp | 87 ------------------- modules/features2d/CMakeLists.txt | 2 +- .../features2d/test/test_nearestneighbors.cpp | 5 +- modules/features2d/test/test_precomp.hpp | 1 + modules/ml/include/opencv2/ml.hpp | 84 ++++++++++++++++++ modules/{core => ml}/src/kdtree.cpp | 8 +- 6 files changed, 94 insertions(+), 93 deletions(-) rename modules/{core => ml}/src/kdtree.cpp (99%) diff --git a/modules/core/include/opencv2/core.hpp b/modules/core/include/opencv2/core.hpp index 6d3d0255c..a258e8c4d 100644 --- a/modules/core/include/opencv2/core.hpp +++ b/modules/core/include/opencv2/core.hpp @@ -747,93 +747,6 @@ public: int minusStep, plusStep; }; - - -/*! - Fast Nearest Neighbor Search Class. - - The class implements D. Lowe BBF (Best-Bin-First) algorithm for the last - approximate (or accurate) nearest neighbor search in multi-dimensional spaces. - - First, a set of vectors is passed to KDTree::KDTree() constructor - or KDTree::build() method, where it is reordered. - - Then arbitrary vectors can be passed to KDTree::findNearest() methods, which - find the K nearest neighbors among the vectors from the initial set. - The user can balance between the speed and accuracy of the search by varying Emax - parameter, which is the number of leaves that the algorithm checks. - The larger parameter values yield more accurate results at the expense of lower processing speed. - - \code - KDTree T(points, false); - const int K = 3, Emax = INT_MAX; - int idx[K]; - float dist[K]; - T.findNearest(query_vec, K, Emax, idx, 0, dist); - CV_Assert(dist[0] <= dist[1] && dist[1] <= dist[2]); - \endcode -*/ -class CV_EXPORTS_W KDTree -{ -public: - /*! - The node of the search tree. - */ - struct Node - { - Node() : idx(-1), left(-1), right(-1), boundary(0.f) {} - Node(int _idx, int _left, int _right, float _boundary) - : idx(_idx), left(_left), right(_right), boundary(_boundary) {} - - //! split dimension; >=0 for nodes (dim), < 0 for leaves (index of the point) - int idx; - //! node indices of the left and the right branches - int left, right; - //! go to the left if query_vec[node.idx]<=node.boundary, otherwise go to the right - float boundary; - }; - - //! the default constructor - CV_WRAP KDTree(); - //! the full constructor that builds the search tree - CV_WRAP KDTree(InputArray points, bool copyAndReorderPoints = false); - //! the full constructor that builds the search tree - CV_WRAP KDTree(InputArray points, InputArray _labels, - bool copyAndReorderPoints = false); - //! builds the search tree - CV_WRAP void build(InputArray points, bool copyAndReorderPoints = false); - //! builds the search tree - CV_WRAP void build(InputArray points, InputArray labels, - bool copyAndReorderPoints = false); - //! finds the K nearest neighbors of "vec" while looking at Emax (at most) leaves - CV_WRAP int findNearest(InputArray vec, int K, int Emax, - OutputArray neighborsIdx, - OutputArray neighbors = noArray(), - OutputArray dist = noArray(), - OutputArray labels = noArray()) const; - //! finds all the points from the initial set that belong to the specified box - CV_WRAP void findOrthoRange(InputArray minBounds, - InputArray maxBounds, - OutputArray neighborsIdx, - OutputArray neighbors = noArray(), - OutputArray labels = noArray()) const; - //! returns vectors with the specified indices - CV_WRAP void getPoints(InputArray idx, OutputArray pts, - OutputArray labels = noArray()) const; - //! return a vector with the specified index - const float* getPoint(int ptidx, int* label = 0) const; - //! returns the search space dimensionality - CV_WRAP int dims() const; - - std::vector nodes; //!< all the tree nodes - CV_PROP Mat points; //!< all the points. It can be a reordered copy of the input vector set or the original vector set. - CV_PROP std::vector labels; //!< the parallel array of labels. - CV_PROP int maxDepth; //!< maximum depth of the search tree. Do not modify it - CV_PROP_RW int normType; //!< type of the distance (cv::NORM_L1 or cv::NORM_L2) used for search. Initially set to cv::NORM_L2, but you can modify it -}; - - - /*! Random Number Generator diff --git a/modules/features2d/CMakeLists.txt b/modules/features2d/CMakeLists.txt index 0b080cfb9..ad6df9414 100644 --- a/modules/features2d/CMakeLists.txt +++ b/modules/features2d/CMakeLists.txt @@ -1,2 +1,2 @@ set(the_description "2D Features Framework") -ocv_define_module(features2d opencv_imgproc opencv_flann OPTIONAL opencv_highgui) +ocv_define_module(features2d opencv_imgproc opencv_ml opencv_flann OPTIONAL opencv_highgui) diff --git a/modules/features2d/test/test_nearestneighbors.cpp b/modules/features2d/test/test_nearestneighbors.cpp index 0c2c70b7d..8dd333ce8 100644 --- a/modules/features2d/test/test_nearestneighbors.cpp +++ b/modules/features2d/test/test_nearestneighbors.cpp @@ -12,6 +12,7 @@ // // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2014, Itseez 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, @@ -167,13 +168,13 @@ protected: virtual int findNeighbors( Mat& points, Mat& neighbors ); virtual int checkFindBoxed(); virtual void releaseModel(); - KDTree* tr; + ml::KDTree* tr; }; void CV_KDTreeTest_CPP::createModel( const Mat& data ) { - tr = new KDTree( data, false ); + tr = new ml::KDTree( data, false ); } int CV_KDTreeTest_CPP::checkGetPoins( const Mat& data ) diff --git a/modules/features2d/test/test_precomp.hpp b/modules/features2d/test/test_precomp.hpp index bce72f729..893b29b69 100644 --- a/modules/features2d/test/test_precomp.hpp +++ b/modules/features2d/test/test_precomp.hpp @@ -13,6 +13,7 @@ #include "opencv2/imgproc.hpp" #include "opencv2/features2d.hpp" #include "opencv2/imgcodecs.hpp" +#include "opencv2/ml.hpp" #include #endif diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index a5ce3010b..696facb40 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -12,6 +12,7 @@ // // Copyright (C) 2000, Intel Corporation, all rights reserved. // Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2014, Itseez 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, @@ -566,6 +567,89 @@ public: static Ptr create(const Params& params=Params()); }; +/*! + Fast Nearest Neighbor Search Class. + + The class implements D. Lowe BBF (Best-Bin-First) algorithm for the last + approximate (or accurate) nearest neighbor search in multi-dimensional spaces. + + First, a set of vectors is passed to KDTree::KDTree() constructor + or KDTree::build() method, where it is reordered. + + Then arbitrary vectors can be passed to KDTree::findNearest() methods, which + find the K nearest neighbors among the vectors from the initial set. + The user can balance between the speed and accuracy of the search by varying Emax + parameter, which is the number of leaves that the algorithm checks. + The larger parameter values yield more accurate results at the expense of lower processing speed. + + \code + KDTree T(points, false); + const int K = 3, Emax = INT_MAX; + int idx[K]; + float dist[K]; + T.findNearest(query_vec, K, Emax, idx, 0, dist); + CV_Assert(dist[0] <= dist[1] && dist[1] <= dist[2]); + \endcode +*/ +class CV_EXPORTS_W KDTree +{ +public: + /*! + The node of the search tree. + */ + struct Node + { + Node() : idx(-1), left(-1), right(-1), boundary(0.f) {} + Node(int _idx, int _left, int _right, float _boundary) + : idx(_idx), left(_left), right(_right), boundary(_boundary) {} + + //! split dimension; >=0 for nodes (dim), < 0 for leaves (index of the point) + int idx; + //! node indices of the left and the right branches + int left, right; + //! go to the left if query_vec[node.idx]<=node.boundary, otherwise go to the right + float boundary; + }; + + //! the default constructor + CV_WRAP KDTree(); + //! the full constructor that builds the search tree + CV_WRAP KDTree(InputArray points, bool copyAndReorderPoints = false); + //! the full constructor that builds the search tree + CV_WRAP KDTree(InputArray points, InputArray _labels, + bool copyAndReorderPoints = false); + //! builds the search tree + CV_WRAP void build(InputArray points, bool copyAndReorderPoints = false); + //! builds the search tree + CV_WRAP void build(InputArray points, InputArray labels, + bool copyAndReorderPoints = false); + //! finds the K nearest neighbors of "vec" while looking at Emax (at most) leaves + CV_WRAP int findNearest(InputArray vec, int K, int Emax, + OutputArray neighborsIdx, + OutputArray neighbors = noArray(), + OutputArray dist = noArray(), + OutputArray labels = noArray()) const; + //! finds all the points from the initial set that belong to the specified box + CV_WRAP void findOrthoRange(InputArray minBounds, + InputArray maxBounds, + OutputArray neighborsIdx, + OutputArray neighbors = noArray(), + OutputArray labels = noArray()) const; + //! returns vectors with the specified indices + CV_WRAP void getPoints(InputArray idx, OutputArray pts, + OutputArray labels = noArray()) const; + //! return a vector with the specified index + const float* getPoint(int ptidx, int* label = 0) const; + //! returns the search space dimensionality + CV_WRAP int dims() const; + + std::vector nodes; //!< all the tree nodes + CV_PROP Mat points; //!< all the points. It can be a reordered copy of the input vector set or the original vector set. + CV_PROP std::vector labels; //!< the parallel array of labels. + CV_PROP int maxDepth; //!< maximum depth of the search tree. Do not modify it + CV_PROP_RW int normType; //!< type of the distance (cv::NORM_L1 or cv::NORM_L2) used for search. Initially set to cv::NORM_L2, but you can modify it +}; + /****************************************************************************************\ * Auxilary functions declarations * \****************************************************************************************/ diff --git a/modules/core/src/kdtree.cpp b/modules/ml/src/kdtree.cpp similarity index 99% rename from modules/core/src/kdtree.cpp rename to modules/ml/src/kdtree.cpp index fc5338dea..f37d910fa 100644 --- a/modules/core/src/kdtree.cpp +++ b/modules/ml/src/kdtree.cpp @@ -13,6 +13,7 @@ // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2014, Itseez 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, @@ -45,10 +46,10 @@ namespace cv { - +namespace ml +{ // This is reimplementation of kd-trees from cvkdtree*.* by Xavier Delacour, cleaned-up and -// adopted to work with the new OpenCV data structures. It's in cxcore to be shared by -// both cv (CvFeatureTree) and ml (kNN). +// adopted to work with the new OpenCV data structures. // The algorithm is taken from: // J.S. Beis and D.G. Lowe. Shape indexing using approximate nearest-neighbor search @@ -529,3 +530,4 @@ int KDTree::dims() const } } +} From 9ddb23e02553ab1c117d581e31455fab039d714f Mon Sep 17 00:00:00 2001 From: Dmitriy Anisimov Date: Sat, 23 Aug 2014 18:41:32 +0400 Subject: [PATCH 02/72] first implementation KNearest wrapper on KDTree --- modules/ml/include/opencv2/ml.hpp | 8 +- modules/ml/src/knearest.cpp | 153 +++++++++++++++++++++- modules/ml/test/test_emknearestkmeans.cpp | 19 ++- 3 files changed, 173 insertions(+), 7 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 696facb40..ebd11c760 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -230,10 +230,11 @@ public: class CV_EXPORTS_W_MAP Params { public: - Params(int defaultK=10, bool isclassifier=true); + Params(int defaultK=10, bool isclassifier_=true, int Emax_=INT_MAX); CV_PROP_RW int defaultK; CV_PROP_RW bool isclassifier; + CV_PROP_RW int Emax; // for implementation with KDTree }; virtual void setParams(const Params& p) = 0; virtual Params getParams() const = 0; @@ -241,7 +242,10 @@ public: OutputArray results, OutputArray neighborResponses=noArray(), OutputArray dist=noArray() ) const = 0; - static Ptr create(const Params& params=Params()); + + enum { DEFAULT=1, KDTREE=2 }; + + static Ptr create(const Params& params=Params(), int type=DEFAULT); }; /****************************************************************************************\ diff --git a/modules/ml/src/knearest.cpp b/modules/ml/src/knearest.cpp index 3ead3228f..6d2bebff2 100644 --- a/modules/ml/src/knearest.cpp +++ b/modules/ml/src/knearest.cpp @@ -49,10 +49,11 @@ namespace cv { namespace ml { -KNearest::Params::Params(int k, bool isclassifier_) +KNearest::Params::Params(int k, bool isclassifier_, int Emax_) { defaultK = k; isclassifier = isclassifier_; + Emax = Emax_; } @@ -352,8 +353,156 @@ public: Params params; }; -Ptr KNearest::create(const Params& p) + +class KNearestKDTreeImpl : public KNearest { +public: + KNearestKDTreeImpl(const Params& p) + { + params = p; + } + + virtual ~KNearestKDTreeImpl() {} + + Params getParams() const { return params; } + void setParams(const Params& p) { params = p; } + + bool isClassifier() const { return params.isclassifier; } + bool isTrained() const { return !samples.empty(); } + + String getDefaultModelName() const { return "opencv_ml_knn_kd"; } + + void clear() + { + samples.release(); + responses.release(); + } + + int getVarCount() const { return samples.cols; } + + bool train( const Ptr& data, int flags ) + { + Mat new_samples = data->getTrainSamples(ROW_SAMPLE); + Mat new_responses; + data->getTrainResponses().convertTo(new_responses, CV_32F); + bool update = (flags & UPDATE_MODEL) != 0 && !samples.empty(); + + CV_Assert( new_samples.type() == CV_32F ); + + if( !update ) + { + clear(); + } + else + { + CV_Assert( new_samples.cols == samples.cols && + new_responses.cols == responses.cols ); + } + + samples.push_back(new_samples); + responses.push_back(new_responses); + + tr.build(samples); + + return true; + } + + float findNearest( InputArray _samples, int k, + OutputArray _results, + OutputArray _neighborResponses, + OutputArray _dists ) const + { + float result = 0.f; + CV_Assert( 0 < k ); + + Mat test_samples = _samples.getMat(); + CV_Assert( test_samples.type() == CV_32F && test_samples.cols == samples.cols ); + int testcount = test_samples.rows; + + if( testcount == 0 ) + { + _results.release(); + _neighborResponses.release(); + _dists.release(); + return 0.f; + } + + Mat res, nr, d; + if( _results.needed() ) + { + _results.create(testcount, 1, CV_32F); + res = _results.getMat(); + } + if( _neighborResponses.needed() ) + { + _neighborResponses.create(testcount, k, CV_32F); + nr = _neighborResponses.getMat(); + } + if( _dists.needed() ) + { + _dists.create(testcount, k, CV_32F); + d = _dists.getMat(); + } + + for (int i=0; ii) + { + _res = res.row(i); + } + if (nr.rows>i) + { + _nr = nr.row(i); + } + if (d.rows>i) + { + _d = d.row(i); + } + tr.findNearest(test_samples.row(i), k, params.Emax, _res, _nr, _d, noArray()); + } + + return result; // currently always 0 + } + + float predict(InputArray inputs, OutputArray outputs, int) const + { + return findNearest( inputs, params.defaultK, outputs, noArray(), noArray() ); + } + + void write( FileStorage& fs ) const + { + fs << "is_classifier" << (int)params.isclassifier; + fs << "default_k" << params.defaultK; + + fs << "samples" << samples; + fs << "responses" << responses; + } + + void read( const FileNode& fn ) + { + clear(); + params.isclassifier = (int)fn["is_classifier"] != 0; + params.defaultK = (int)fn["default_k"]; + + fn["samples"] >> samples; + fn["responses"] >> responses; + } + + KDTree tr; + + Mat samples; + Mat responses; + Params params; +}; + +Ptr KNearest::create(const Params& p, int type) +{ + if (KDTREE==type) + { + return makePtr(p); + } + return makePtr(p); } diff --git a/modules/ml/test/test_emknearestkmeans.cpp b/modules/ml/test/test_emknearestkmeans.cpp index 98b88c701..b40463430 100644 --- a/modules/ml/test/test_emknearestkmeans.cpp +++ b/modules/ml/test/test_emknearestkmeans.cpp @@ -312,9 +312,11 @@ void CV_KNearestTest::run( int /*start_from*/ ) generateData( testData, testLabels, sizes, means, covs, CV_32FC1, CV_32FC1 ); int code = cvtest::TS::OK; - Ptr knearest = KNearest::create(true); - knearest->train(trainData, cv::ml::ROW_SAMPLE, trainLabels); - knearest->findNearest( testData, 4, bestLabels); + + // KNearest default implementation + Ptr knearest = KNearest::create(); + knearest->train(trainData, ml::ROW_SAMPLE, trainLabels); + knearest->findNearest(testData, 4, bestLabels); float err; if( !calcErr( bestLabels, testLabels, sizes, err, true ) ) { @@ -326,6 +328,17 @@ void CV_KNearestTest::run( int /*start_from*/ ) ts->printf( cvtest::TS::LOG, "Bad accuracy (%f) on test data.\n", err ); code = cvtest::TS::FAIL_BAD_ACCURACY; } + + // KNearest KDTree implementation + Ptr knearestKdt = KNearest::create(ml::KNearest::Params(), ml::KNearest::KDTREE); + knearestKdt->train(trainData, ml::ROW_SAMPLE, trainLabels); + knearestKdt->findNearest(testData, 4, bestLabels); + if( !calcErr( bestLabels, testLabels, sizes, err, true ) ) + { + ts->printf( cvtest::TS::LOG, "Bad output labels.\n" ); + code = cvtest::TS::FAIL_INVALID_OUTPUT; + } + ts->set_failed_test_info( code ); } From 3334c06e8b7f449e6257e8c74df65279859a2c30 Mon Sep 17 00:00:00 2001 From: Dmitriy Anisimov Date: Sat, 30 Aug 2014 12:55:45 +0400 Subject: [PATCH 03/72] initial commit --- doc/_themes/sphinxdoc/layout.html | 274 +++++++++++ doc/_themes/sphinxdoc/static/bodybg.png | Bin 0 -> 513 bytes doc/_themes/sphinxdoc/static/default.css_t | 541 +++++++++++++++++++++ doc/_themes/sphinxdoc/static/footerbg.png | Bin 0 -> 220 bytes doc/_themes/sphinxdoc/static/headerbg.png | Bin 0 -> 230 bytes doc/_themes/sphinxdoc/static/listitem.png | Bin 0 -> 207 bytes doc/_themes/sphinxdoc/static/relbg.png | Bin 0 -> 223 bytes doc/_themes/sphinxdoc/theme.conf | 4 + doc/conf.py | 4 +- 9 files changed, 821 insertions(+), 2 deletions(-) create mode 100644 doc/_themes/sphinxdoc/layout.html create mode 100644 doc/_themes/sphinxdoc/static/bodybg.png create mode 100644 doc/_themes/sphinxdoc/static/default.css_t create mode 100644 doc/_themes/sphinxdoc/static/footerbg.png create mode 100644 doc/_themes/sphinxdoc/static/headerbg.png create mode 100644 doc/_themes/sphinxdoc/static/listitem.png create mode 100644 doc/_themes/sphinxdoc/static/relbg.png create mode 100644 doc/_themes/sphinxdoc/theme.conf diff --git a/doc/_themes/sphinxdoc/layout.html b/doc/_themes/sphinxdoc/layout.html new file mode 100644 index 000000000..c359d4084 --- /dev/null +++ b/doc/_themes/sphinxdoc/layout.html @@ -0,0 +1,274 @@ +{# + basic/layout.html + ~~~~~~~~~~~~~~~~~ + + Master layout template for Sphinx themes. + + :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{%- block doctype -%} + +{%- endblock %} +{% set script_files = script_files + [pathto("_static/insertIframe.js", 1)] %} +{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %} +{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %} +{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and + (sidebars != []) %} +{%- set url_root = pathto('', 1) %} +{# XXX necessary? #} +{%- if url_root == '#' %}{% set url_root = '' %}{% endif %} +{%- if not embedded and docstitle %} + {%- set titlesuffix = " — "|safe + docstitle|e %} +{%- else %} + {%- set titlesuffix = "" %} +{%- endif %} + +{%- macro relbar() %} + +{%- endmacro %} + +{%- macro sidebar() %} + {%- if render_sidebar %} +
+
+ {%- block sidebarlogo %} + {%- if logo %} + + {%- endif %} + {%- endblock %} + {%- if sidebars == None %} + {%- block sidebarsearch %} + {%- include "searchbox.html" %} + {%- endblock %} + {%- endif %} + {%- if sidebars != None %} + {#- new style sidebar: explicitly include/exclude templates #} + {%- for sidebartemplate in sidebars %} + {%- include sidebartemplate %} + {%- endfor %} + {%- else %} + {#- old style sidebars: using blocks -- should be deprecated #} + {%- block sidebartoc %} + {%- include "localtoc.html" %} + {%- endblock %} + {%- block sidebarrel %} + {%- include "relations.html" %} + {%- endblock %} + {%- if customsidebar %} + {%- include customsidebar %} + {%- endif %} + {%- endif %} +
+
+ {%- endif %} +{%- endmacro %} + +{%- macro script() %} + + {%- for scriptfile in script_files %} + + {%- endfor %} +{%- endmacro %} + +{%- macro css() %} + + + {%- for cssfile in css_files %} + + {%- endfor %} +{%- endmacro %} + + + + + {{ metatags }} + {%- block htmltitle %} + {{ title|striptags|e }}{{ titlesuffix }} + {%- endblock %} + {{ css() }} + {%- if not embedded %} + {{ script() }} + {%- if use_opensearch %} + + {%- endif %} + {%- if favicon %} + + {%- endif %} + {%- endif %} +{%- block linktags %} + {%- if hasdoc('about') %} + + {%- endif %} + {%- if hasdoc('genindex') %} + + {%- endif %} + {%- if hasdoc('search') %} + + {%- endif %} + {%- if hasdoc('copyright') %} + + {%- endif %} + + {%- if parents %} + + {%- endif %} + {%- if next %} + + {%- endif %} + {%- if prev %} + + {%- endif %} +{%- endblock %} +{%- block extrahead %} + +{%- if not embedded %} + + +{%- endif %} +{% endblock %} + +{%- block header %}{% endblock %} + +{%- block relbar1 %}{{ relbar() }}{% endblock %} + + {%- block sidebar1 %} {# possible location for sidebar #} {% endblock %} + {%- block sidebar2 %}{{ sidebar() }}{% endblock %} + + +{%- block content %} + +
+ {%- block document %} +
+ {%- if render_sidebar %} +
+ {%- endif %} +
+ {% block body %} {% endblock %} +
+ + {%- if render_sidebar %} +
+ {%- endif %} +
+ {%- endblock %} + +
+
+{%- endblock %} + +{%- block relbar2 %}{{ relbar() }}{% endblock %} + +{%- block footer %} + +{%- endblock %} + + diff --git a/doc/_themes/sphinxdoc/static/bodybg.png b/doc/_themes/sphinxdoc/static/bodybg.png new file mode 100644 index 0000000000000000000000000000000000000000..ebe92f66911ffc6a22a84b11ee8ad62b4b59cb03 GIT binary patch literal 513 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqJQaoCO|{#X$M%Ak65bF}ngN$X?>< z>&kwYQIMURA&{#$6euK{84^+AoS&PUnpXnkGB7w7r6!i7rYMwWmSiZnd-?{X=%um) z#WMqZLR^3Rc=zMS`=397=)=#SAAkP*^z-NEU%x*6`UNDv{QC9v_wO&ie*?*Hzkh%K z{rktCKi~fR`Tpk*kn!`+pI?9f{`mVBNdEr&_s_q7zyAIE{qG-;@%JAH{Qv*|&;S2_ z|NjTEmVOj@z`(%BY@#4Be3OsBNk{sLmtgK~rE$Z9%-&ro=N_X+s_9dD7 z#T@o$O7i-JZZ`h0;uMEn$C``PlfDc6DHKfPpKbB_`L2ye6{0O8m+*$H+35M2*Hep*$&tKAhf4(ShD(f+e44U=WqR7jp>0{`8UA3z@jNzeX7d*C3e&n~Q zQr-86`7+J8sF>S}kFtd7e0zCkS@*RD_Eih=O=g7Tv$f4-Su$a|z@a(D?TX9hBy&tT z$g250<8G)I*E#*58>W}ODQ|7A@i>0TBV*;YHybD3@~F^R{_xD}d&QB_=NskbZjpcD wZZua#{u1N9@Sp^>tm>NPsxNor|L=dyzt~PHh}m4}3Mg(oUHx3vIVCg!06iH8I{*Lx literal 0 HcmV?d00001 diff --git a/doc/_themes/sphinxdoc/static/default.css_t b/doc/_themes/sphinxdoc/static/default.css_t new file mode 100644 index 000000000..bca6eb154 --- /dev/null +++ b/doc/_themes/sphinxdoc/static/default.css_t @@ -0,0 +1,541 @@ +/* + * sphinx13.css + * ~~~~~~~~~~~~ + * + * Sphinx stylesheet -- sphinx13 theme. + * + * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', + 'Verdana', sans-serif; + font-size: 14px; + text-align: center; + background-image: url(bodybg.png); + color: black; + padding: 0; + border-right: 1px solid #0a507a; + border-left: 1px solid #0a507a; + + margin: 0 auto; + min-width: 780px; + max-width: 1080px; +} + +.pageheader { + background-image: url(headerbg.png); + text-align: left; + padding: 10px 15px; +} + +.pageheader ul { + float: right; + color: white; + list-style-type: none; + padding-left: 0; + margin-top: 30px; + margin-right: 10px; +} + +.pageheader li { + float: left; + margin: 0 0 0 10px; +} + +.pageheader li a { + border-radius: 1px; + padding: 8px 12px; + color: #f9f9f0; + text-shadow: 0 0 5px rgba(0, 0, 0, 0.5); +} + +.pageheader li a:hover { + background-color: #f9f9f0; + color: #0a507a; + text-shadow: none; +} + +div.document { + background-color: white; + text-align: left; +} + +div.bodywrapper { + margin: 0 240px 0 0; + border-right: 1px solid #0a507a; +} + +div.body { + margin: 0; + padding: 0.5em 20px 20px 20px; +} + +div.related { + font-size: 1em; + color: white; +} + +div.related ul { + background-image: url(relbg.png); + height: 1.9em; + border-top: 1px solid #002e50; + border-bottom: 1px solid #002e50; +} + +div.related ul li { + margin: 0 5px 0 0; + padding: 0; + float: left; +} + +div.related ul li.right { + float: right; + margin-right: 5px; +} + +div.related ul li a { + margin: 0; + padding: 0 5px 0 5px; + line-height: 1.75em; + color: #f9f9f0; + text-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5); +} + +div.related ul li a:hover { + color: white; + /*text-decoration: underline;*/ + text-shadow: 0px 0px 1px rgba(255, 255, 255, 0.5); +} + +div.sphinxsidebarwrapper { + position: relative; + top: 0px; + padding: 0; +} + +div.sphinxsidebar { + word-wrap: break-word; + margin: 0; + padding: 0 15px 15px 0; + width: 210px; + float: right; + font-size: 1em; + text-align: left; +} + +div.sphinxsidebar .logo { + font-size: 1.8em; + color: #0A507A; + font-weight: 300; + text-align: center; +} + +div.sphinxsidebar .logo img { + vertical-align: middle; +} + +div.sphinxsidebar input { + border: 1px solid #aaa; + font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', + 'Verdana', sans-serif; + font-size: 1em; +} + +div.sphinxsidebar h3 { + font-size: 1.5em; + border-top: 1px solid #0a507a; + margin-top: 1em; + margin-bottom: 0.5em; + padding-top: 0.5em; +} + +div.sphinxsidebar h4 { + font-size: 1.2em; + margin-bottom: 0; +} + +div.sphinxsidebar h3, div.sphinxsidebar h4 { + margin-right: -15px; + margin-left: -15px; + padding-right: 14px; + padding-left: 14px; + color: #333; + font-weight: 300; + /*text-shadow: 0px 0px 0.5px rgba(0, 0, 0, 0.4);*/ +} + +div.sphinxsidebarwrapper > h3:first-child { + margin-top: 0.5em; + border: none; +} + +div.sphinxsidebar h3 a { + color: #333; +} + +div.sphinxsidebar ul { + color: #444; + margin-top: 7px; + padding: 0; + line-height: 130%; +} + +div.sphinxsidebar ul ul { + margin-left: 20px; + list-style-image: url(listitem.png); +} + +div.footer { + background-image: url(footerbg.png); + color: #ccc; + text-shadow: 0 0 .2px rgba(255, 255, 255, 0.8); + padding: 3px 8px 3px 0; + clear: both; + font-size: 0.8em; + text-align: right; +} + +/* -- body styles ----------------------------------------------------------- */ + +p { + margin: 0.8em 0 0.5em 0; +} + +a { + color: #A2881D; + text-decoration: none; +} + +a:hover { + color: #E1C13F; +} + +div.body a { + text-decoration: underline; +} + +h1 { + margin: 10px 0 0 0; + font-size: 2.4em; + color: #0A507A; + font-weight: 300; +} + +h2 { + margin: 1.em 0 0.2em 0; + font-size: 1.5em; + font-weight: 300; + padding: 0; + color: #174967; +} + +h3 { + margin: 1em 0 -0.3em 0; + font-size: 1.3em; + font-weight: 300; +} + +div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { + text-decoration: none; +} + +div.body h1 a tt, div.body h2 a tt, div.body h3 a tt, div.body h4 a tt, div.body h5 a tt, div.body h6 a tt { + color: #0A507A !important; + font-size: inherit !important; +} + +a.headerlink { + color: #0A507A !important; + font-size: 12px; + margin-left: 6px; + padding: 0 4px 0 4px; + text-decoration: none !important; + float: right; +} + +a.headerlink:hover { + background-color: #ccc; + color: white!important; +} + +cite, code, tt { + font-family: 'Consolas', 'DejaVu Sans Mono', + 'Bitstream Vera Sans Mono', monospace; + font-size: 14px; + letter-spacing: -0.02em; +} + +tt { + background-color: #f2f2f2; + border: 1px solid #ddd; + border-radius: 2px; + color: #333; + padding: 1px; +} + +tt.descname, tt.descclassname, tt.xref { + border: 0; +} + +hr { + border: 1px solid #abc; + margin: 2em; +} + +a tt { + border: 0; + color: #a2881d; +} + +a tt:hover { + color: #e1c13f; +} + +pre { + font-family: 'Consolas', 'DejaVu Sans Mono', + 'Bitstream Vera Sans Mono', monospace; + font-size: 13px; + letter-spacing: 0.015em; + line-height: 120%; + padding: 0.5em; + border: 1px solid #ccc; + border-radius: 2px; + background-color: #f8f8f8; +} + +pre a { + color: inherit; + text-decoration: underline; +} + +td.linenos pre { + padding: 0.5em 0; +} + +div.quotebar { + background-color: #f8f8f8; + max-width: 250px; + float: right; + padding: 0px 7px; + border: 1px solid #ccc; + margin-left: 1em; +} + +div.topic { + background-color: #f8f8f8; +} + +table { + border-collapse: collapse; + margin: 0 -0.5em 0 -0.5em; +} + +table td, table th { + padding: 0.2em 0.5em 0.2em 0.5em; +} + +div.admonition, div.warning { + font-size: 0.9em; + margin: 1em 0 1em 0; + border: 1px solid #86989B; + border-radius: 2px; + background-color: #f7f7f7; + padding: 0; +} + +div.admonition p, div.warning p { + margin: 0.5em 1em 0.5em 1em; + padding: 0; +} + +div.admonition pre, div.warning pre { + margin: 0.4em 1em 0.4em 1em; +} + +div.admonition p.admonition-title, +div.warning p.admonition-title { + margin-top: 1em; + padding-top: 0.5em; + font-weight: bold; +} + +div.warning { + border: 1px solid #940000; +/* background-color: #FFCCCF;*/ +} + +div.warning p.admonition-title { +} + +div.admonition ul, div.admonition ol, +div.warning ul, div.warning ol { + margin: 0.1em 0.5em 0.5em 3em; + padding: 0; +} + +.viewcode-back { + font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', + 'Verdana', sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} + +/* ------------------ our styles ----------------*/ + +div.body p, div.body dd, div.body li { + text-align: justify; + line-height: 130%; + margin-top: 1em; + margin-bottom: 1em; +} + +div.toctree-wrapper li, ul.simple li { + margin:0; +} + +a.toc-backref, a.toc-backref:hover { + font-family: {{ theme_headfont }}; + background-color: {{ theme_headbgcolor }}; + font-weight: normal; + color: {{ theme_headtextcolor }}; + text-decoration: none; +} + +div.feedback { + background-color: {{ theme_feedbackbgcolor }}; + color: {{ theme_feedbacktextcolor }}; + padding: 20px 20px 30px 20px; +} + +div.feedback h2 { + margin: 10px 0 10px 0; +} + +div.feedback a { + color: {{ theme_feedbacklinkcolor }}; + font-weight: bold; +} + +img.logo { + width: 150px; +} + +tt, tt.descname { + color: {{ theme_headtextcolor }}; + /*background-color: #ecf0f3;*/ + padding: 0 1px 0 1px; + font-size: 1.4em; +} + +div.math p { + margin-top: 10px; + margin-bottom: 10px; +} + +dl.function > dt:first-child { + margin-bottom: 7px; +} + +dl.cfunction > dt:first-child { + margin-bottom: 7px; + color: #8080B0; +} + +dl.cfunction > dt:first-child tt.descname +{ + color: #8080B0; +} + + +dl.pyfunction > dt:first-child { + margin-bottom: 7px; +} + +dl.jfunction > dt:first-child { + margin-bottom: 7px; +} + +table.field-list { + margin-top: 20px; +} + +/*ul.simple { + list-style: none; +}*/ + +em.menuselection, em.guilabel { + font-family: {{ theme_guifont }}; +} + +.enumeratevisibleitemswithsquare ul { +list-style: square; +margin-bottom: 0px; +margin-left: 0px; +margin-right: 0px; +margin-top: 0px; +} + +.enumeratevisibleitemswithsquare li { +margin-bottom: 0.2em; +margin-left: 0px; +margin-right: 0px; +margin-top: 0.2em; + } + + .enumeratevisibleitemswithsquare p { + margin-bottom: 0pt; + margin-top: 1pt; + } + + .enumeratevisibleitemswithsquare dl{ +margin-bottom: 0px; +margin-left: 0px; +margin-right: 0px; +margin-top: 0px; + } + + .toctableopencv + { + width: 100% ; + table-layout: fixed; + } + + .toctableopencv colgroup col:first-child + { + width: 100pt !important; + max-width: 100pt !important; + min-width: 100pt !important; + } + + .toctableopencv colgroup col:nth-child(2) + { + width: 100% !important; + } + +div.body ul.search li { + text-align: left; +} + +div.linenodiv { + min-width: 1em; + text-align: right; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width:auto; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + width:auto; +} diff --git a/doc/_themes/sphinxdoc/static/footerbg.png b/doc/_themes/sphinxdoc/static/footerbg.png new file mode 100644 index 0000000000000000000000000000000000000000..df783e2c76c8c35bce0860368ba66bd6f398ef08 GIT binary patch literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAd3?%E9GuQzs&H|6fVxatW5N34Jm|X!BWH0gb zb!ETH$S-0fTsp033s6Wjz$e6&RmX)*&z()*gU!I3&B%w%*pJQF|LP_uTcCm{PZ!4! zj_BkB9`2L^??eG#(FB2_LLrkvv5>;R6pq9MPSFIO(u9IkkHiE|AhS53z*)>Ss5^xz zIYXg2o1-~n1w-@Z1sl2-P3T^@fO8Y4hmQ)Y$E_7FWf*pyP;zBX=7|T|!rxj3-^ literal 0 HcmV?d00001 diff --git a/doc/_themes/sphinxdoc/static/headerbg.png b/doc/_themes/sphinxdoc/static/headerbg.png new file mode 100644 index 0000000000000000000000000000000000000000..22830f99ef36d9b697e205470f09985bd3a5219a GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAd3?%E9GuQzs&H|6fVxatW5N34Jm|X!BWH0gb zb!ETH$S0;{@^ZgSFHlG>z$e6&!zF{mC6mJ?i_<-q(=(sbyO`6rlq;ZuE1;4qpench z!epSzXipc%5RT~Ngm*bU?R>KV* z=4aNGv&UGh(5%v^3ic2_Tqf;9+ScrKuZn^uU2H zQyfn*9&-yU`CQ%jRM<_jbEVs=+4%-On`#az=vrO%C^ha<()jUzeq*EHImaYp10cwd vh@M+!5EQwitFh7Z?ulO_J-(9;uViOPP?5c=x_{|>pv?@Pu6{1-oD!M<&SgTz literal 0 HcmV?d00001 diff --git a/doc/_themes/sphinxdoc/static/relbg.png b/doc/_themes/sphinxdoc/static/relbg.png new file mode 100644 index 0000000000000000000000000000000000000000..2006af7d2ac133a955f06828d0727f5a5519a9dd GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAd3?%E9GuQzs&H|6fVxatW5N34Jm|X!BWH0gb zb!ETH$Sg)3ms3ywO z#W92H9$K!A%KrJtcW+zh}Sg9LsY;wIKhiMg(q1fH9;51 Date: Sun, 31 Aug 2014 18:12:34 +0400 Subject: [PATCH 04/72] slight changes, theme become more similar with current --- doc/_themes/sphinxdoc/layout.html | 2 +- doc/_themes/sphinxdoc/searchbox.html | 21 +++++ doc/_themes/sphinxdoc/static/default.css_t | 93 +++++++++------------- 3 files changed, 61 insertions(+), 55 deletions(-) create mode 100644 doc/_themes/sphinxdoc/searchbox.html diff --git a/doc/_themes/sphinxdoc/layout.html b/doc/_themes/sphinxdoc/layout.html index c359d4084..106452767 100644 --- a/doc/_themes/sphinxdoc/layout.html +++ b/doc/_themes/sphinxdoc/layout.html @@ -266,7 +266,7 @@ {% trans sphinx_version=sphinx_version|e %}Created using Sphinx {{ sphinx_version }}.{% endtrans %} {%- endif %} {%- if show_source and has_source and sourcename %} - {{ _('Show This Page Source') }} + {{ _('Show this page source.') }} {%- endif %} {%- endblock %} diff --git a/doc/_themes/sphinxdoc/searchbox.html b/doc/_themes/sphinxdoc/searchbox.html new file mode 100644 index 000000000..73616d9ed --- /dev/null +++ b/doc/_themes/sphinxdoc/searchbox.html @@ -0,0 +1,21 @@ +{# + basic/searchbox.html + ~~~~~~~~~~~~~~~~~~~~ + + Sphinx sidebar template: quick search box. + + :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{%- if pagename != "search" and builder != "singlehtml" %} + + +{%- endif %} diff --git a/doc/_themes/sphinxdoc/static/default.css_t b/doc/_themes/sphinxdoc/static/default.css_t index bca6eb154..8b195de38 100644 --- a/doc/_themes/sphinxdoc/static/default.css_t +++ b/doc/_themes/sphinxdoc/static/default.css_t @@ -114,6 +114,16 @@ div.related ul li a:hover { text-shadow: 0px 0px 1px rgba(255, 255, 255, 0.5); } +div.footer { + background-image: url(footerbg.png); + color: #ccc; + text-shadow: 0 0 .2px rgba(255, 255, 255, 0.8); + padding: 3px 8px 3px 0; + clear: both; + font-size: 0.8em; + text-align: center; +} + div.sphinxsidebarwrapper { position: relative; top: 0px; @@ -192,16 +202,6 @@ div.sphinxsidebar ul ul { list-style-image: url(listitem.png); } -div.footer { - background-image: url(footerbg.png); - color: #ccc; - text-shadow: 0 0 .2px rgba(255, 255, 255, 0.8); - padding: 3px 8px 3px 0; - clear: both; - font-size: 0.8em; - text-align: right; -} - /* -- body styles ----------------------------------------------------------- */ p { @@ -416,6 +416,7 @@ div.feedback { background-color: {{ theme_feedbackbgcolor }}; color: {{ theme_feedbacktextcolor }}; padding: 20px 20px 30px 20px; + border-top: 1px solid #002e50; } div.feedback h2 { @@ -452,8 +453,7 @@ dl.cfunction > dt:first-child { color: #8080B0; } -dl.cfunction > dt:first-child tt.descname -{ +dl.cfunction > dt:first-child tt.descname { color: #8080B0; } @@ -470,58 +470,51 @@ table.field-list { margin-top: 20px; } -/*ul.simple { - list-style: none; -}*/ - em.menuselection, em.guilabel { font-family: {{ theme_guifont }}; } .enumeratevisibleitemswithsquare ul { -list-style: square; -margin-bottom: 0px; -margin-left: 0px; -margin-right: 0px; -margin-top: 0px; + list-style: square; + margin-bottom: 0px; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; } .enumeratevisibleitemswithsquare li { -margin-bottom: 0.2em; -margin-left: 0px; -margin-right: 0px; -margin-top: 0.2em; + margin-bottom: 0.2em; + margin-left: 0px; + margin-right: 0px; + margin-top: 0.2em; } - .enumeratevisibleitemswithsquare p { - margin-bottom: 0pt; - margin-top: 1pt; - } +.enumeratevisibleitemswithsquare p { + margin-bottom: 0pt; + margin-top: 1pt; +} - .enumeratevisibleitemswithsquare dl{ -margin-bottom: 0px; -margin-left: 0px; -margin-right: 0px; -margin-top: 0px; - } +.enumeratevisibleitemswithsquare dl { + margin-bottom: 0px; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; +} - .toctableopencv - { - width: 100% ; - table-layout: fixed; - } +.toctableopencv { + width: 100% ; + table-layout: fixed; +} - .toctableopencv colgroup col:first-child - { +.toctableopencv colgroup col:first-child { width: 100pt !important; max-width: 100pt !important; min-width: 100pt !important; - } +} - .toctableopencv colgroup col:nth-child(2) - { +.toctableopencv colgroup col:nth-child(2) { width: 100% !important; - } +} div.body ul.search li { text-align: left; @@ -531,11 +524,3 @@ div.linenodiv { min-width: 1em; text-align: right; } - -div.sphinxsidebar #searchbox input[type="text"] { - width:auto; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - width:auto; -} From 5f3ee657cee484619e8c7fb8577e4328b35b562b Mon Sep 17 00:00:00 2001 From: Dmitriy Anisimov Date: Sun, 31 Aug 2014 21:39:47 +0400 Subject: [PATCH 05/72] removed kdtree declaration from interface --- .../features2d/test/test_nearestneighbors.cpp | 86 ---------------- modules/ml/include/opencv2/ml.hpp | 83 ---------------- modules/ml/src/kdtree.cpp | 1 + modules/ml/src/kdtree.hpp | 97 +++++++++++++++++++ modules/ml/src/knearest.cpp | 1 + modules/ml/test/test_emknearestkmeans.cpp | 5 + 6 files changed, 104 insertions(+), 169 deletions(-) create mode 100644 modules/ml/src/kdtree.hpp diff --git a/modules/features2d/test/test_nearestneighbors.cpp b/modules/features2d/test/test_nearestneighbors.cpp index 8dd333ce8..df5602520 100644 --- a/modules/features2d/test/test_nearestneighbors.cpp +++ b/modules/features2d/test/test_nearestneighbors.cpp @@ -157,91 +157,6 @@ void NearestNeighborTest::run( int /*start_from*/ ) { ts->set_failed_test_info( code ); } -//-------------------------------------------------------------------------------- -class CV_KDTreeTest_CPP : public NearestNeighborTest -{ -public: - CV_KDTreeTest_CPP() {} -protected: - virtual void createModel( const Mat& data ); - virtual int checkGetPoins( const Mat& data ); - virtual int findNeighbors( Mat& points, Mat& neighbors ); - virtual int checkFindBoxed(); - virtual void releaseModel(); - ml::KDTree* tr; -}; - - -void CV_KDTreeTest_CPP::createModel( const Mat& data ) -{ - tr = new ml::KDTree( data, false ); -} - -int CV_KDTreeTest_CPP::checkGetPoins( const Mat& data ) -{ - Mat res1( data.size(), data.type() ), - res3( data.size(), data.type() ); - Mat idxs( 1, data.rows, CV_32SC1 ); - for( int pi = 0; pi < data.rows; pi++ ) - { - idxs.at(0, pi) = pi; - // 1st way - const float* point = tr->getPoint(pi); - for( int di = 0; di < data.cols; di++ ) - res1.at(pi, di) = point[di]; - } - - // 3d way - tr->getPoints( idxs, res3 ); - - if( cvtest::norm( res1, data, NORM_L1) != 0 || - cvtest::norm( res3, data, NORM_L1) != 0) - return cvtest::TS::FAIL_BAD_ACCURACY; - return cvtest::TS::OK; -} - -int CV_KDTreeTest_CPP::checkFindBoxed() -{ - vector min( dims, static_cast(minValue)), max(dims, static_cast(maxValue)); - vector indices; - tr->findOrthoRange( min, max, indices ); - // TODO check indices - if( (int)indices.size() != featuresCount) - return cvtest::TS::FAIL_BAD_ACCURACY; - return cvtest::TS::OK; -} - -int CV_KDTreeTest_CPP::findNeighbors( Mat& points, Mat& neighbors ) -{ - const int emax = 20; - Mat neighbors2( neighbors.size(), CV_32SC1 ); - int j; - for( int pi = 0; pi < points.rows; pi++ ) - { - // 1st way - Mat nrow = neighbors.row(pi); - tr->findNearest( points.row(pi), neighbors.cols, emax, nrow ); - - // 2nd way - vector neighborsIdx2( neighbors2.cols, 0 ); - tr->findNearest( points.row(pi), neighbors2.cols, emax, neighborsIdx2 ); - vector::const_iterator it2 = neighborsIdx2.begin(); - for( j = 0; it2 != neighborsIdx2.end(); ++it2, j++ ) - neighbors2.at(pi,j) = *it2; - } - - // compare results - if( cvtest::norm( neighbors, neighbors2, NORM_L1 ) != 0 ) - return cvtest::TS::FAIL_BAD_ACCURACY; - - return cvtest::TS::OK; -} - -void CV_KDTreeTest_CPP::releaseModel() -{ - delete tr; -} - //-------------------------------------------------------------------------------- class CV_FlannTest : public NearestNeighborTest { @@ -403,7 +318,6 @@ void CV_FlannSavedIndexTest::createModel(const cv::Mat &data) remove( filename.c_str() ); } -TEST(Features2d_KDTree_CPP, regression) { CV_KDTreeTest_CPP test; test.safe_run(); } TEST(Features2d_FLANN_Linear, regression) { CV_FlannLinearIndexTest test; test.safe_run(); } TEST(Features2d_FLANN_KMeans, regression) { CV_FlannKMeansIndexTest test; test.safe_run(); } TEST(Features2d_FLANN_KDTree, regression) { CV_FlannKDTreeIndexTest test; test.safe_run(); } diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index ebd11c760..0a8f01dd0 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -571,89 +571,6 @@ public: static Ptr create(const Params& params=Params()); }; -/*! - Fast Nearest Neighbor Search Class. - - The class implements D. Lowe BBF (Best-Bin-First) algorithm for the last - approximate (or accurate) nearest neighbor search in multi-dimensional spaces. - - First, a set of vectors is passed to KDTree::KDTree() constructor - or KDTree::build() method, where it is reordered. - - Then arbitrary vectors can be passed to KDTree::findNearest() methods, which - find the K nearest neighbors among the vectors from the initial set. - The user can balance between the speed and accuracy of the search by varying Emax - parameter, which is the number of leaves that the algorithm checks. - The larger parameter values yield more accurate results at the expense of lower processing speed. - - \code - KDTree T(points, false); - const int K = 3, Emax = INT_MAX; - int idx[K]; - float dist[K]; - T.findNearest(query_vec, K, Emax, idx, 0, dist); - CV_Assert(dist[0] <= dist[1] && dist[1] <= dist[2]); - \endcode -*/ -class CV_EXPORTS_W KDTree -{ -public: - /*! - The node of the search tree. - */ - struct Node - { - Node() : idx(-1), left(-1), right(-1), boundary(0.f) {} - Node(int _idx, int _left, int _right, float _boundary) - : idx(_idx), left(_left), right(_right), boundary(_boundary) {} - - //! split dimension; >=0 for nodes (dim), < 0 for leaves (index of the point) - int idx; - //! node indices of the left and the right branches - int left, right; - //! go to the left if query_vec[node.idx]<=node.boundary, otherwise go to the right - float boundary; - }; - - //! the default constructor - CV_WRAP KDTree(); - //! the full constructor that builds the search tree - CV_WRAP KDTree(InputArray points, bool copyAndReorderPoints = false); - //! the full constructor that builds the search tree - CV_WRAP KDTree(InputArray points, InputArray _labels, - bool copyAndReorderPoints = false); - //! builds the search tree - CV_WRAP void build(InputArray points, bool copyAndReorderPoints = false); - //! builds the search tree - CV_WRAP void build(InputArray points, InputArray labels, - bool copyAndReorderPoints = false); - //! finds the K nearest neighbors of "vec" while looking at Emax (at most) leaves - CV_WRAP int findNearest(InputArray vec, int K, int Emax, - OutputArray neighborsIdx, - OutputArray neighbors = noArray(), - OutputArray dist = noArray(), - OutputArray labels = noArray()) const; - //! finds all the points from the initial set that belong to the specified box - CV_WRAP void findOrthoRange(InputArray minBounds, - InputArray maxBounds, - OutputArray neighborsIdx, - OutputArray neighbors = noArray(), - OutputArray labels = noArray()) const; - //! returns vectors with the specified indices - CV_WRAP void getPoints(InputArray idx, OutputArray pts, - OutputArray labels = noArray()) const; - //! return a vector with the specified index - const float* getPoint(int ptidx, int* label = 0) const; - //! returns the search space dimensionality - CV_WRAP int dims() const; - - std::vector nodes; //!< all the tree nodes - CV_PROP Mat points; //!< all the points. It can be a reordered copy of the input vector set or the original vector set. - CV_PROP std::vector labels; //!< the parallel array of labels. - CV_PROP int maxDepth; //!< maximum depth of the search tree. Do not modify it - CV_PROP_RW int normType; //!< type of the distance (cv::NORM_L1 or cv::NORM_L2) used for search. Initially set to cv::NORM_L2, but you can modify it -}; - /****************************************************************************************\ * Auxilary functions declarations * \****************************************************************************************/ diff --git a/modules/ml/src/kdtree.cpp b/modules/ml/src/kdtree.cpp index f37d910fa..9ab61e4d6 100644 --- a/modules/ml/src/kdtree.cpp +++ b/modules/ml/src/kdtree.cpp @@ -43,6 +43,7 @@ //M*/ #include "precomp.hpp" +#include "kdtree.hpp" namespace cv { diff --git a/modules/ml/src/kdtree.hpp b/modules/ml/src/kdtree.hpp new file mode 100644 index 000000000..2975c7c75 --- /dev/null +++ b/modules/ml/src/kdtree.hpp @@ -0,0 +1,97 @@ +#ifndef KDTREE_H +#define KDTREE_H + +#include "precomp.hpp" + +namespace cv +{ +namespace ml +{ + +/*! + Fast Nearest Neighbor Search Class. + + The class implements D. Lowe BBF (Best-Bin-First) algorithm for the last + approximate (or accurate) nearest neighbor search in multi-dimensional spaces. + + First, a set of vectors is passed to KDTree::KDTree() constructor + or KDTree::build() method, where it is reordered. + + Then arbitrary vectors can be passed to KDTree::findNearest() methods, which + find the K nearest neighbors among the vectors from the initial set. + The user can balance between the speed and accuracy of the search by varying Emax + parameter, which is the number of leaves that the algorithm checks. + The larger parameter values yield more accurate results at the expense of lower processing speed. + + \code + KDTree T(points, false); + const int K = 3, Emax = INT_MAX; + int idx[K]; + float dist[K]; + T.findNearest(query_vec, K, Emax, idx, 0, dist); + CV_Assert(dist[0] <= dist[1] && dist[1] <= dist[2]); + \endcode +*/ +class CV_EXPORTS_W KDTree +{ +public: + /*! + The node of the search tree. + */ + struct Node + { + Node() : idx(-1), left(-1), right(-1), boundary(0.f) {} + Node(int _idx, int _left, int _right, float _boundary) + : idx(_idx), left(_left), right(_right), boundary(_boundary) {} + + //! split dimension; >=0 for nodes (dim), < 0 for leaves (index of the point) + int idx; + //! node indices of the left and the right branches + int left, right; + //! go to the left if query_vec[node.idx]<=node.boundary, otherwise go to the right + float boundary; + }; + + //! the default constructor + CV_WRAP KDTree(); + //! the full constructor that builds the search tree + CV_WRAP KDTree(InputArray points, bool copyAndReorderPoints = false); + //! the full constructor that builds the search tree + CV_WRAP KDTree(InputArray points, InputArray _labels, + bool copyAndReorderPoints = false); + //! builds the search tree + CV_WRAP void build(InputArray points, bool copyAndReorderPoints = false); + //! builds the search tree + CV_WRAP void build(InputArray points, InputArray labels, + bool copyAndReorderPoints = false); + //! finds the K nearest neighbors of "vec" while looking at Emax (at most) leaves + CV_WRAP int findNearest(InputArray vec, int K, int Emax, + OutputArray neighborsIdx, + OutputArray neighbors = noArray(), + OutputArray dist = noArray(), + OutputArray labels = noArray()) const; + //! finds all the points from the initial set that belong to the specified box + CV_WRAP void findOrthoRange(InputArray minBounds, + InputArray maxBounds, + OutputArray neighborsIdx, + OutputArray neighbors = noArray(), + OutputArray labels = noArray()) const; + //! returns vectors with the specified indices + CV_WRAP void getPoints(InputArray idx, OutputArray pts, + OutputArray labels = noArray()) const; + //! return a vector with the specified index + const float* getPoint(int ptidx, int* label = 0) const; + //! returns the search space dimensionality + CV_WRAP int dims() const; + + std::vector nodes; //!< all the tree nodes + CV_PROP Mat points; //!< all the points. It can be a reordered copy of the input vector set or the original vector set. + CV_PROP std::vector labels; //!< the parallel array of labels. + CV_PROP int maxDepth; //!< maximum depth of the search tree. Do not modify it + CV_PROP_RW int normType; //!< type of the distance (cv::NORM_L1 or cv::NORM_L2) used for search. Initially set to cv::NORM_L2, but you can modify it +}; + +} +} + +#endif diff --git a/modules/ml/src/knearest.cpp b/modules/ml/src/knearest.cpp index 6d2bebff2..14c799be5 100644 --- a/modules/ml/src/knearest.cpp +++ b/modules/ml/src/knearest.cpp @@ -41,6 +41,7 @@ //M*/ #include "precomp.hpp" +#include "kdtree.hpp" /****************************************************************************************\ * K-Nearest Neighbors Classifier * diff --git a/modules/ml/test/test_emknearestkmeans.cpp b/modules/ml/test/test_emknearestkmeans.cpp index b40463430..8e08170c3 100644 --- a/modules/ml/test/test_emknearestkmeans.cpp +++ b/modules/ml/test/test_emknearestkmeans.cpp @@ -338,6 +338,11 @@ void CV_KNearestTest::run( int /*start_from*/ ) ts->printf( cvtest::TS::LOG, "Bad output labels.\n" ); code = cvtest::TS::FAIL_INVALID_OUTPUT; } + else if( err > 0.01f ) + { + ts->printf( cvtest::TS::LOG, "Bad accuracy (%f) on test data.\n", err ); + code = cvtest::TS::FAIL_BAD_ACCURACY; + } ts->set_failed_test_info( code ); } From 66ed9ddbe3b9c2db182afb73683b16458a668dbc Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Fri, 29 Aug 2014 18:06:16 +0400 Subject: [PATCH 06/72] Added Ptr support to Java wrappers --- modules/java/generator/gen_java.py | 31 +++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/modules/java/generator/gen_java.py b/modules/java/generator/gen_java.py index a4df8175b..53b874979 100755 --- a/modules/java/generator/gen_java.py +++ b/modules/java/generator/gen_java.py @@ -879,6 +879,11 @@ public class %(jc)s { self.add_class_code_stream(name, classinfo.base) if classinfo.base: self.get_imports(name, classinfo.base) + type_dict["Ptr_"+name] = \ + { "j_type" : name, + "jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),), + "jni_name" : "Ptr<"+name+">(("+name+"*)%(n)s_nativeObj)", "jni_type" : "jlong", + "suffix" : "J" } def add_const(self, decl): # [ "const cname", val, [], [] ] @@ -1253,6 +1258,9 @@ extern "C" { j_prologue.append( j_type + ' retVal = new Array' + j_type+'();') self.classes[fi.classname or self.Module].imports.add('java.util.ArrayList') j_epilogue.append('Converters.Mat_to_' + ret_type + '(retValMat, retVal);') + elif ret_type.startswith("Ptr_"): + ret_val = type_dict[fi.ctype]["j_type"] + " retVal = new " + type_dict[ret_type]["j_type"] + "(" + tail = ")" elif ret_type == "void": ret_val = "" ret = "return;" @@ -1325,6 +1333,9 @@ extern "C" { default = 'return env->NewStringUTF("");' elif fi.ctype in self.classes: # wrapped class: ret = "return (jlong) new %s(_retval_);" % fi.ctype + elif fi.ctype.startswith('Ptr_'): + c_prologue.append("typedef Ptr<%s> %s;" % (fi.ctype[4:], fi.ctype)) + ret = "return (jlong)(new %(ctype)s(_retval_));" % { 'ctype':fi.ctype } elif ret_type in self.classes: # pointer to wrapped class: ret = "return (jlong) _retval_;" elif type_dict[fi.ctype]["jni_type"] == "jdoubleArray": @@ -1355,10 +1366,10 @@ extern "C" { elif fi.static: cvname = "%s::%s" % (fi.classname, name) else: - cvname = "me->" + name + cvname = ("me->" if not self.isSmartClass(fi.classname) else "(*me)->") + name c_prologue.append(\ "%(cls)s* me = (%(cls)s*) self; //TODO: check for NULL" \ - % { "cls" : fi.classname} \ + % { "cls" : self.smartWrap(fi.classname)} \ ) cvargs = [] for a in args: @@ -1511,9 +1522,23 @@ JNIEXPORT void JNICALL Java_org_opencv_%(module)s_%(j_cls)s_delete delete (%(cls)s*) self; } -""" % {"module" : module, "cls" : name, "j_cls" : ci.jname.replace('_', '_1')} +""" % {"module" : module, "cls" : self.smartWrap(name), "j_cls" : ci.jname.replace('_', '_1')} ) + def isSmartClass(self, classname): + ''' + Check if class stores Ptr* instead of T* in nativeObj field + ''' + return classname in self.classes and self.classes[classname].base + + def smartWrap(self, classname): + ''' + Wraps class name with Ptr<> if needed + ''' + if self.isSmartClass(classname): + return "Ptr<" + classname + ">" + return classname + if __name__ == "__main__": if len(sys.argv) < 4: From e7af509c86d61031b023839c3ae9d08a2a57f4a5 Mon Sep 17 00:00:00 2001 From: Dmitriy Anisimov Date: Wed, 3 Sep 2014 22:25:08 +0400 Subject: [PATCH 07/72] different enhancements --- doc/_themes/sphinxdoc/static/default.css_t | 158 ++++++--------------- 1 file changed, 45 insertions(+), 113 deletions(-) diff --git a/doc/_themes/sphinxdoc/static/default.css_t b/doc/_themes/sphinxdoc/static/default.css_t index 8b195de38..692f14162 100644 --- a/doc/_themes/sphinxdoc/static/default.css_t +++ b/doc/_themes/sphinxdoc/static/default.css_t @@ -1,8 +1,8 @@ /* - * sphinx13.css - * ~~~~~~~~~~~~ + * sphinxdoc.css_t + * ~~~~~~~~~~~~~~~ * - * Sphinx stylesheet -- sphinx13 theme. + * Sphinx stylesheet -- sphinxdoc theme. * * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. @@ -29,39 +29,6 @@ body { max-width: 1080px; } -.pageheader { - background-image: url(headerbg.png); - text-align: left; - padding: 10px 15px; -} - -.pageheader ul { - float: right; - color: white; - list-style-type: none; - padding-left: 0; - margin-top: 30px; - margin-right: 10px; -} - -.pageheader li { - float: left; - margin: 0 0 0 10px; -} - -.pageheader li a { - border-radius: 1px; - padding: 8px 12px; - color: #f9f9f0; - text-shadow: 0 0 5px rgba(0, 0, 0, 0.5); -} - -.pageheader li a:hover { - background-color: #f9f9f0; - color: #0a507a; - text-shadow: none; -} - div.document { background-color: white; text-align: left; @@ -110,7 +77,6 @@ div.related ul li a { div.related ul li a:hover { color: white; - /*text-decoration: underline;*/ text-shadow: 0px 0px 1px rgba(255, 255, 255, 0.5); } @@ -141,13 +107,11 @@ div.sphinxsidebar { } div.sphinxsidebar .logo { - font-size: 1.8em; - color: #0A507A; - font-weight: 300; text-align: center; } div.sphinxsidebar .logo img { + width: 150px; vertical-align: middle; } @@ -208,51 +172,55 @@ p { margin: 0.8em 0 0.5em 0; } -a { - color: #A2881D; - text-decoration: none; +a, a tt { + color: #2878a2; // a2881d } -a:hover { - color: #E1C13F; +a:hover, a tt:hover { + color: #68b8c2; // #e1c13f; } -div.body a { - text-decoration: underline; +a tt { + border: 0; +} + +h1, h2, h3, h4, h5, h6 { + color: #0a507a; + background-color: #f2f8fa; + font-weight: 300; } h1 { margin: 10px 0 0 0; - font-size: 2.4em; - color: #0A507A; - font-weight: 300; } h2 { margin: 1.em 0 0.2em 0; - font-size: 1.5em; - font-weight: 300; padding: 0; - color: #174967; } h3 { margin: 1em 0 -0.3em 0; - font-size: 1.3em; - font-weight: 300; } -div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { +h1 { font-size: 200%; } +h2 { font-size: 160%; } +h3 { font-size: 140%; } +h4 { font-size: 120%; } +h5 { font-size: 110%; } +h6 { font-size: 100%; } + +div a, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { text-decoration: none; } div.body h1 a tt, div.body h2 a tt, div.body h3 a tt, div.body h4 a tt, div.body h5 a tt, div.body h6 a tt { - color: #0A507A !important; + color: #0a507a !important; font-size: inherit !important; } a.headerlink { - color: #0A507A !important; + color: #0a507a !important; font-size: 12px; margin-left: 6px; padding: 0 4px 0 4px; @@ -289,15 +257,6 @@ hr { margin: 2em; } -a tt { - border: 0; - color: #a2881d; -} - -a tt:hover { - color: #e1c13f; -} - pre { font-family: 'Consolas', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; @@ -312,7 +271,7 @@ pre { pre a { color: inherit; - text-decoration: underline; + text-decoration: none; } td.linenos pre { @@ -341,54 +300,39 @@ table td, table th { padding: 0.2em 0.5em 0.2em 0.5em; } -div.admonition, div.warning { - font-size: 0.9em; - margin: 1em 0 1em 0; - border: 1px solid #86989B; - border-radius: 2px; - background-color: #f7f7f7; - padding: 0; +div.note { + background-color: #eee; + border: 1px solid #ccc; } -div.admonition p, div.warning p { - margin: 0.5em 1em 0.5em 1em; - padding: 0; +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; } -div.admonition pre, div.warning pre { - margin: 0.4em 1em 0.4em 1em; -} - -div.admonition p.admonition-title, -div.warning p.admonition-title { - margin-top: 1em; - padding-top: 0.5em; - font-weight: bold; +div.topic { + background-color: #eee; } div.warning { - border: 1px solid #940000; -/* background-color: #FFCCCF;*/ + background-color: #ffe4e4; + border: 1px solid #f66; } -div.warning p.admonition-title { +div.admonition ul li, div.warning ul li { + text-align: left; } -div.admonition ul, div.admonition ol, -div.warning ul, div.warning ol { - margin: 0.1em 0.5em 0.5em 3em; - padding: 0; +div.admonition p.admonition-title + p { + display: inline; } -.viewcode-back { - font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; +p.admonition-title { + display: inline; } -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; +p.admonition-title:after { + content: ":"; } /* ------------------ our styles ----------------*/ @@ -428,17 +372,6 @@ div.feedback a { font-weight: bold; } -img.logo { - width: 150px; -} - -tt, tt.descname { - color: {{ theme_headtextcolor }}; - /*background-color: #ecf0f3;*/ - padding: 0 1px 0 1px; - font-size: 1.4em; -} - div.math p { margin-top: 10px; margin-bottom: 10px; @@ -457,7 +390,6 @@ dl.cfunction > dt:first-child tt.descname { color: #8080B0; } - dl.pyfunction > dt:first-child { margin-bottom: 7px; } From 98e7d4ceec12bebfeb4a1e1f0fbb6173c4d2c691 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Wed, 3 Sep 2014 13:04:24 +0400 Subject: [PATCH 08/72] changed optimal vector width for Intel --- modules/core/src/ocl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index 03889e1b6..d0920ac45 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -4505,8 +4505,8 @@ int predictOptimalVectorWidth(InputArray src1, InputArray src2, InputArray src3, if (vectorWidths[0] == 1) { // it's heuristic - vectorWidths[CV_8U] = vectorWidths[CV_8S] = 16; - vectorWidths[CV_16U] = vectorWidths[CV_16S] = 8; + vectorWidths[CV_8U] = vectorWidths[CV_8S] = 4; + vectorWidths[CV_16U] = vectorWidths[CV_16S] = 2; vectorWidths[CV_32S] = vectorWidths[CV_32F] = vectorWidths[CV_64F] = 1; } From e7b3a73b620d6820110efd814e3b87d0e5522434 Mon Sep 17 00:00:00 2001 From: Dmitriy Anisimov Date: Fri, 5 Sep 2014 21:56:25 +0400 Subject: [PATCH 09/72] fixed all known issues --- doc/_themes/sphinxdoc/static/default.css_t | 60 +++++++++++++--------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/doc/_themes/sphinxdoc/static/default.css_t b/doc/_themes/sphinxdoc/static/default.css_t index 692f14162..16c4b7928 100644 --- a/doc/_themes/sphinxdoc/static/default.css_t +++ b/doc/_themes/sphinxdoc/static/default.css_t @@ -51,15 +51,13 @@ div.related { div.related ul { background-image: url(relbg.png); - height: 1.9em; + text-align: left; border-top: 1px solid #002e50; border-bottom: 1px solid #002e50; } -div.related ul li { - margin: 0 5px 0 0; - padding: 0; - float: left; +div.related li + li { + display: inline; } div.related ul li.right { @@ -122,6 +120,14 @@ div.sphinxsidebar input { font-size: 1em; } +div.sphinxsidebar #searchbox input[type="text"] { + width: 160px; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + width: 40px; +} + div.sphinxsidebar h3 { font-size: 1.5em; border-top: 1px solid #0a507a; @@ -173,11 +179,11 @@ p { } a, a tt { - color: #2878a2; // a2881d + color: #2878a2; } a:hover, a tt:hover { - color: #68b8c2; // #e1c13f; + color: #68b8c2; } a tt { @@ -214,7 +220,8 @@ div a, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { text-decoration: none; } -div.body h1 a tt, div.body h2 a tt, div.body h3 a tt, div.body h4 a tt, div.body h5 a tt, div.body h6 a tt { +div.body h1 a tt, div.body h2 a tt, div.body h3 a tt, +div.body h4 a tt, div.body h5 a tt, div.body h6 a tt { color: #0a507a !important; font-size: inherit !important; } @@ -234,10 +241,12 @@ a.headerlink:hover { } cite, code, tt { - font-family: 'Consolas', 'DejaVu Sans Mono', - 'Bitstream Vera Sans Mono', monospace; + font-family: 'Consolas', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', + monospace; font-size: 14px; letter-spacing: -0.02em; + min-width: 780px; + max-width: 1080px; } tt { @@ -258,8 +267,8 @@ hr { } pre { - font-family: 'Consolas', 'DejaVu Sans Mono', - 'Bitstream Vera Sans Mono', monospace; + font-family: 'Consolas', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', + monospace; font-size: 13px; letter-spacing: 0.015em; line-height: 120%; @@ -278,6 +287,12 @@ td.linenos pre { padding: 0.5em 0; } +td.code pre { + max-width: 740px; + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + div.quotebar { background-color: #f8f8f8; max-width: 250px; @@ -319,7 +334,8 @@ div.warning { border: 1px solid #f66; } -div.admonition ul li, div.warning ul li { +div.admonition ul li, div.warning ul li, +div.admonition ol li, div.warning ol li { text-align: left; } @@ -348,17 +364,12 @@ div.toctree-wrapper li, ul.simple li { margin:0; } -a.toc-backref, a.toc-backref:hover { - font-family: {{ theme_headfont }}; - background-color: {{ theme_headbgcolor }}; - font-weight: normal; - color: {{ theme_headtextcolor }}; - text-decoration: none; -} +/*a.toc-backref { +}*/ div.feedback { - background-color: {{ theme_feedbackbgcolor }}; - color: {{ theme_feedbacktextcolor }}; + /*background-color: #;*/ + /*color: #;*/ padding: 20px 20px 30px 20px; border-top: 1px solid #002e50; } @@ -368,7 +379,7 @@ div.feedback h2 { } div.feedback a { - color: {{ theme_feedbacklinkcolor }}; + /*color: #;*/ font-weight: bold; } @@ -403,7 +414,8 @@ table.field-list { } em.menuselection, em.guilabel { - font-family: {{ theme_guifont }}; + font-family: 'Lucida Sans', 'Lucida Sans Unicode', 'Lucida Grande', Verdana, + Arial, Helvetica, sans-serif; } .enumeratevisibleitemswithsquare ul { From dfaf75f50246159c72a2cdc0e6e63c455894d102 Mon Sep 17 00:00:00 2001 From: Dmitriy Anisimov Date: Sat, 6 Sep 2014 09:29:32 +0400 Subject: [PATCH 10/72] moving algorithm type to param --- modules/ml/include/opencv2/ml.hpp | 7 ++++--- modules/ml/src/knearest.cpp | 14 +++++++------- modules/ml/test/test_emknearestkmeans.cpp | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 0a8f01dd0..2030f69ac 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -230,8 +230,9 @@ public: class CV_EXPORTS_W_MAP Params { public: - Params(int defaultK=10, bool isclassifier_=true, int Emax_=INT_MAX); + Params(int algorithmType_=BRUTE_FORCE, int defaultK=10, bool isclassifier_=true, int Emax_=INT_MAX); + CV_PROP_RW int algorithmType; CV_PROP_RW int defaultK; CV_PROP_RW bool isclassifier; CV_PROP_RW int Emax; // for implementation with KDTree @@ -243,9 +244,9 @@ public: OutputArray neighborResponses=noArray(), OutputArray dist=noArray() ) const = 0; - enum { DEFAULT=1, KDTREE=2 }; + enum { BRUTE_FORCE=1, KDTREE=2 }; - static Ptr create(const Params& params=Params(), int type=DEFAULT); + static Ptr create(const Params& params=Params()); }; /****************************************************************************************\ diff --git a/modules/ml/src/knearest.cpp b/modules/ml/src/knearest.cpp index 14c799be5..ac9e95ca0 100644 --- a/modules/ml/src/knearest.cpp +++ b/modules/ml/src/knearest.cpp @@ -50,14 +50,14 @@ namespace cv { namespace ml { -KNearest::Params::Params(int k, bool isclassifier_, int Emax_) +KNearest::Params::Params(int algorithmType_, int k, bool isclassifier_, int Emax_) : + algorithmType(algorithmType_), + defaultK(k), + isclassifier(isclassifier_), + Emax(Emax_) { - defaultK = k; - isclassifier = isclassifier_; - Emax = Emax_; } - class KNearestImpl : public KNearest { public: @@ -497,9 +497,9 @@ public: Params params; }; -Ptr KNearest::create(const Params& p, int type) +Ptr KNearest::create(const Params& p) { - if (KDTREE==type) + if (KDTREE==p.algorithmType) { return makePtr(p); } diff --git a/modules/ml/test/test_emknearestkmeans.cpp b/modules/ml/test/test_emknearestkmeans.cpp index 8e08170c3..ba0b82b0c 100644 --- a/modules/ml/test/test_emknearestkmeans.cpp +++ b/modules/ml/test/test_emknearestkmeans.cpp @@ -330,7 +330,7 @@ void CV_KNearestTest::run( int /*start_from*/ ) } // KNearest KDTree implementation - Ptr knearestKdt = KNearest::create(ml::KNearest::Params(), ml::KNearest::KDTREE); + Ptr knearestKdt = KNearest::create(ml::KNearest::Params(ml::KNearest::KDTREE)); knearestKdt->train(trainData, ml::ROW_SAMPLE, trainLabels); knearestKdt->findNearest(testData, 4, bestLabels); if( !calcErr( bestLabels, testLabels, sizes, err, true ) ) From ad00e0dd4327613d405eda91af5d73932b0262a2 Mon Sep 17 00:00:00 2001 From: Dmitriy Anisimov Date: Sat, 6 Sep 2014 14:15:04 +0400 Subject: [PATCH 11/72] tt & header background colors changed --- doc/_themes/sphinxdoc/static/default.css_t | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/doc/_themes/sphinxdoc/static/default.css_t b/doc/_themes/sphinxdoc/static/default.css_t index 16c4b7928..ce5ee0635 100644 --- a/doc/_themes/sphinxdoc/static/default.css_t +++ b/doc/_themes/sphinxdoc/static/default.css_t @@ -192,7 +192,7 @@ a tt { h1, h2, h3, h4, h5, h6 { color: #0a507a; - background-color: #f2f8fa; + background-color: #e5f5ff; font-weight: 300; } @@ -244,21 +244,17 @@ cite, code, tt { font-family: 'Consolas', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 14px; - letter-spacing: -0.02em; min-width: 780px; max-width: 1080px; } tt { - background-color: #f2f2f2; - border: 1px solid #ddd; - border-radius: 2px; - color: #333; + color: #003048; padding: 1px; } tt.descname, tt.descclassname, tt.xref { - border: 0; + font-size: 12px; } hr { From aeda3d2d698cd867ed9b311f9ca9c913cbb9b6fc Mon Sep 17 00:00:00 2001 From: Pierrick Koch Date: Tue, 9 Sep 2014 11:04:24 +0200 Subject: [PATCH 12/72] [samples/pyhton] fix common {LINE->CV}_AA --- samples/python2/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/python2/common.py b/samples/python2/common.py index 0ad811ae2..5ba1a71f4 100755 --- a/samples/python2/common.py +++ b/samples/python2/common.py @@ -71,8 +71,8 @@ def mtx2rvec(R): return axis * np.arctan2(s, c) def draw_str(dst, (x, y), s): - cv2.putText(dst, s, (x+1, y+1), cv2.FONT_HERSHEY_PLAIN, 1.0, (0, 0, 0), thickness = 2, lineType=cv2.LINE_AA) - cv2.putText(dst, s, (x, y), cv2.FONT_HERSHEY_PLAIN, 1.0, (255, 255, 255), lineType=cv2.LINE_AA) + cv2.putText(dst, s, (x+1, y+1), cv2.FONT_HERSHEY_PLAIN, 1.0, (0, 0, 0), thickness = 2, lineType=cv2.CV_AA) + cv2.putText(dst, s, (x, y), cv2.FONT_HERSHEY_PLAIN, 1.0, (255, 255, 255), lineType=cv2.CV_AA) class Sketcher: def __init__(self, windowname, dests, colors_func): From 62c704d1e9b8c1ebbdb849dc5276781b23b55c55 Mon Sep 17 00:00:00 2001 From: Philipp Hasper Date: Tue, 9 Sep 2014 12:24:05 +0200 Subject: [PATCH 13/72] Updated PnP parameter documentation --- .../calib3d/doc/camera_calibration_and_3d_reconstruction.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst b/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst index a6027c274..844ff4df0 100644 --- a/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst +++ b/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst @@ -580,7 +580,7 @@ Finds an object pose from 3D-2D point correspondences. :param tvec: Output translation vector. - :param useExtrinsicGuess: Parameter used for ITERATIVE. If true (1), the function uses the provided ``rvec`` and ``tvec`` values as initial approximations of the rotation and translation vectors, respectively, and further optimizes them. + :param useExtrinsicGuess: Parameter used for SOLVEPNP_ITERATIVE. If true (1), the function uses the provided ``rvec`` and ``tvec`` values as initial approximations of the rotation and translation vectors, respectively, and further optimizes them. :param flags: Method for solving a PnP problem: @@ -615,7 +615,7 @@ Finds an object pose from 3D-2D point correspondences using the RANSAC scheme. :param tvec: Output translation vector. - :param useExtrinsicGuess: Parameter used for ITERATIVE. If true (1), the function uses the provided ``rvec`` and ``tvec`` values as initial approximations of the rotation and translation vectors, respectively, and further optimizes them. + :param useExtrinsicGuess: Parameter used for SOLVEPNP_ITERATIVE. If true (1), the function uses the provided ``rvec`` and ``tvec`` values as initial approximations of the rotation and translation vectors, respectively, and further optimizes them. :param iterationsCount: Number of iterations. From 74827c35ff63b34e70db5fc50fbe40a4d5b57d34 Mon Sep 17 00:00:00 2001 From: Igor Kuzmin Date: Tue, 9 Sep 2014 19:22:20 +0400 Subject: [PATCH 14/72] fix for issue 3858 (remove unneeded #include's) also use correct include path on Linux --- modules/videoio/src/cap_ximea.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/videoio/src/cap_ximea.cpp b/modules/videoio/src/cap_ximea.cpp index 891b96115..13a4538d9 100644 --- a/modules/videoio/src/cap_ximea.cpp +++ b/modules/videoio/src/cap_ximea.cpp @@ -1,8 +1,10 @@ #include "precomp.hpp" +#ifdef WIN32 #include "xiApi.h" -#include "xiExt.h" -#include "m3Api.h" +#else +#include +#endif /**********************************************************************************/ @@ -156,7 +158,7 @@ bool CvCaptureCAM_XIMEA::grabFrame() image.size = sizeof(XI_IMG); int mvret = xiGetImage( hmv, timeout, &image); - if(mvret == MM40_ACQUISITION_STOPED) + if(mvret == XI_ACQUISITION_STOPED) { xiStartAcquisition(hmv); mvret = xiGetImage(hmv, timeout, &image); From 4d45a2c43f5b2f0066e9ef5573ebe680e15cdcd5 Mon Sep 17 00:00:00 2001 From: Igor Kuzmin Date: Tue, 9 Sep 2014 19:24:16 +0400 Subject: [PATCH 15/72] XIMEA cam support: use correct library for 64 bit Linux --- modules/videoio/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/videoio/CMakeLists.txt b/modules/videoio/CMakeLists.txt index 94907575d..4ad564af3 100644 --- a/modules/videoio/CMakeLists.txt +++ b/modules/videoio/CMakeLists.txt @@ -94,11 +94,13 @@ endif(HAVE_opencv_androidcamera) if(HAVE_XIMEA) list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_ximea.cpp) - ocv_include_directories(${XIMEA_PATH}) + if(XIMEA_PATH) + ocv_include_directories(${XIMEA_PATH}) + endif() if(XIMEA_LIBRARY_DIR) link_directories("${XIMEA_LIBRARY_DIR}") endif() - if(X86_64) + if(WIN32 AND X86_64) list(APPEND VIDEOIO_LIBRARIES m3apiX64) else() list(APPEND VIDEOIO_LIBRARIES m3api) From ed402c5be6eb4401f03f37ba237846146eedb782 Mon Sep 17 00:00:00 2001 From: Igor Kuzmin Date: Tue, 9 Sep 2014 19:25:14 +0400 Subject: [PATCH 16/72] XIMEA cam support: allow on OS X too --- CMakeLists.txt | 2 +- cmake/OpenCVFindXimea.cmake | 6 ++++++ modules/videoio/CMakeLists.txt | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96b3f8e02..d4afe3ed7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,7 +153,7 @@ OCV_OPTION(WITH_V4L "Include Video 4 Linux support" ON OCV_OPTION(WITH_LIBV4L "Use libv4l for Video 4 Linux support" ON IF (UNIX AND NOT ANDROID) ) OCV_OPTION(WITH_DSHOW "Build VideoIO with DirectShow support" ON IF (WIN32 AND NOT ARM) ) OCV_OPTION(WITH_MSMF "Build VideoIO with Media Foundation support" OFF IF WIN32 ) -OCV_OPTION(WITH_XIMEA "Include XIMEA cameras support" OFF IF (NOT ANDROID AND NOT APPLE) ) +OCV_OPTION(WITH_XIMEA "Include XIMEA cameras support" OFF IF (NOT ANDROID) ) OCV_OPTION(WITH_XINE "Include Xine support (GPL)" OFF IF (UNIX AND NOT APPLE AND NOT ANDROID) ) OCV_OPTION(WITH_CLP "Include Clp support (EPL)" OFF) OCV_OPTION(WITH_OPENCL "Include OpenCL Runtime support" ON IF (NOT IOS) ) diff --git a/cmake/OpenCVFindXimea.cmake b/cmake/OpenCVFindXimea.cmake index 5f85a13dd..2d93292c1 100644 --- a/cmake/OpenCVFindXimea.cmake +++ b/cmake/OpenCVFindXimea.cmake @@ -31,6 +31,12 @@ if(WIN32) else() set(XIMEA_FOUND 0) endif() +elseif(APPLE) + if(EXISTS /Library/Frameworks/m3api.framework) + set(XIMEA_FOUND 1) + else() + set(XIMEA_FOUND 0) + endif() else() if(EXISTS /opt/XIMEA) set(XIMEA_FOUND 1) diff --git a/modules/videoio/CMakeLists.txt b/modules/videoio/CMakeLists.txt index 4ad564af3..3a031a9fe 100644 --- a/modules/videoio/CMakeLists.txt +++ b/modules/videoio/CMakeLists.txt @@ -102,6 +102,8 @@ if(HAVE_XIMEA) endif() if(WIN32 AND X86_64) list(APPEND VIDEOIO_LIBRARIES m3apiX64) + elseif(APPLE) + list(APPEND VIDEOIO_LIBRARIES "-framework m3api") else() list(APPEND VIDEOIO_LIBRARIES m3api) endif() From d3ad26926d717afc54324654024649e1ccbaafce Mon Sep 17 00:00:00 2001 From: Daniel Stonier Date: Tue, 9 Sep 2014 03:20:32 +0900 Subject: [PATCH 17/72] fixed support for parallelised imshows with qt via the gui receiver. --- modules/highgui/src/window_QT.cpp | 105 ++++++++++++++++-------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/modules/highgui/src/window_QT.cpp b/modules/highgui/src/window_QT.cpp index d4dfc989f..f67c2f673 100644 --- a/modules/highgui/src/window_QT.cpp +++ b/modules/highgui/src/window_QT.cpp @@ -76,6 +76,17 @@ static const unsigned int threshold_zoom_img_region = 30; static CvWinProperties* global_control_panel = NULL; //end static and global +// Declaration +Qt::ConnectionType autoBlockingConnection(); + +// Implementation - this allows us to do blocking whilst automatically selecting the right +// behaviour for in-thread and out-of-thread launches of cv windows. Qt strangely doesn't +// cater for this, but does for strictly queued connections. +Qt::ConnectionType autoBlockingConnection() { + return (QThread::currentThread() != QApplication::instance()->thread()) + ? Qt::BlockingQueuedConnection + : Qt::DirectConnection; +} CV_IMPL CvFont cvFontQt(const char* nameFont, int pointSize,CvScalar color,int weight,int style, int spacing) { @@ -104,7 +115,7 @@ CV_IMPL void cvAddText(const CvArr* img, const char* text, CvPoint org, CvFont* QMetaObject::invokeMethod(guiMainThread, "putText", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(void*, (void*) img), Q_ARG(QString,QString(text)), Q_ARG(QPoint, QPoint(org.x,org.y)), @@ -120,8 +131,7 @@ double cvGetRatioWindow_QT(const char* name) double result = -1; QMetaObject::invokeMethod(guiMainThread, "getRatioWindow", - //Qt::DirectConnection, - Qt::AutoConnection, + autoBlockingConnection(), Q_RETURN_ARG(double, result), Q_ARG(QString, QString(name))); @@ -137,7 +147,7 @@ void cvSetRatioWindow_QT(const char* name,double prop_value) QMetaObject::invokeMethod(guiMainThread, "setRatioWindow", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(name)), Q_ARG(double, prop_value)); } @@ -151,8 +161,7 @@ double cvGetPropWindow_QT(const char* name) double result = -1; QMetaObject::invokeMethod(guiMainThread, "getPropWindow", - //Qt::DirectConnection, - Qt::AutoConnection, + autoBlockingConnection(), Q_RETURN_ARG(double, result), Q_ARG(QString, QString(name))); @@ -167,7 +176,7 @@ void cvSetPropWindow_QT(const char* name,double prop_value) QMetaObject::invokeMethod(guiMainThread, "setPropWindow", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(name)), Q_ARG(double, prop_value)); } @@ -180,7 +189,7 @@ void cvSetModeWindow_QT(const char* name, double prop_value) QMetaObject::invokeMethod(guiMainThread, "toggleFullScreen", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(name)), Q_ARG(double, prop_value)); } @@ -195,7 +204,7 @@ double cvGetModeWindow_QT(const char* name) QMetaObject::invokeMethod(guiMainThread, "isFullScreen", - Qt::AutoConnection, + autoBlockingConnection(), Q_RETURN_ARG(double, result), Q_ARG(QString, QString(name))); @@ -210,8 +219,7 @@ CV_IMPL void cvDisplayOverlay(const char* name, const char* text, int delayms) QMetaObject::invokeMethod(guiMainThread, "displayInfo", - Qt::AutoConnection, - //Qt::DirectConnection, + autoBlockingConnection(), Q_ARG(QString, QString(name)), Q_ARG(QString, QString(text)), Q_ARG(int, delayms)); @@ -225,7 +233,7 @@ CV_IMPL void cvSaveWindowParameters(const char* name) QMetaObject::invokeMethod(guiMainThread, "saveWindowParameters", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(name))); } @@ -237,7 +245,7 @@ CV_IMPL void cvLoadWindowParameters(const char* name) QMetaObject::invokeMethod(guiMainThread, "loadWindowParameters", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(name))); } @@ -249,8 +257,7 @@ CV_IMPL void cvDisplayStatusBar(const char* name, const char* text, int delayms) QMetaObject::invokeMethod(guiMainThread, "displayStatusBar", - Qt::AutoConnection, - //Qt::DirectConnection, + autoBlockingConnection(), Q_ARG(QString, QString(name)), Q_ARG(QString, QString(text)), Q_ARG(int, delayms)); @@ -328,7 +335,6 @@ CV_IMPL int cvWaitKey(int delay) guiMainThread->bTimeOut = false; } - return result; } @@ -400,7 +406,6 @@ static CvBar* icvFindBarByName(QBoxLayout* layout, QString name_bar, typeBar typ static CvTrackbar* icvFindTrackBarByName(const char* name_trackbar, const char* name_window, QBoxLayout* layout = NULL) { QString nameQt(name_trackbar); - if ((!name_window || !name_window[0]) && global_control_panel) //window name is null and we have a control panel layout = global_control_panel->myLayout; @@ -470,17 +475,18 @@ CV_IMPL int cvNamedWindow(const char* name, int flags) { if (!guiMainThread) guiMainThread = new GuiReceiver; - - if (multiThreads) + if (QThread::currentThread() != QApplication::instance()->thread()) { + multiThreads = true; QMetaObject::invokeMethod(guiMainThread, "createWindow", - Qt::BlockingQueuedConnection, + Qt::BlockingQueuedConnection, // block so that we can do useful stuff once we confirm it is created Q_ARG(QString, QString(name)), Q_ARG(int, flags)); - else + } else { guiMainThread->createWindow(QString(name), flags); + } - return 1; //Dummy value + return 1; //Dummy value - probably should return the result of the invocation. } @@ -491,8 +497,7 @@ CV_IMPL void cvDestroyWindow(const char* name) QMetaObject::invokeMethod(guiMainThread, "destroyWindow", - //Qt::BlockingQueuedConnection, - Qt::AutoConnection, + Qt::AutoConnection, // if another thread is controlling, let it handle it without blocking ourselves here Q_ARG(QString, QString(name))); } @@ -501,11 +506,10 @@ CV_IMPL void cvDestroyAllWindows() { if (!guiMainThread) return; - QMetaObject::invokeMethod(guiMainThread, "destroyAllWindow", - //Qt::BlockingQueuedConnection, - Qt::AutoConnection); + Qt::AutoConnection // if another thread is controlling, let it handle it without blocking ourselves here + ); } @@ -531,26 +535,21 @@ CV_IMPL void cvMoveWindow(const char* name, int x, int y) { if (!guiMainThread) CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); - QMetaObject::invokeMethod(guiMainThread, "moveWindow", - //Qt::BlockingQueuedConnection, - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(name)), Q_ARG(int, x), Q_ARG(int, y)); } - CV_IMPL void cvResizeWindow(const char* name, int width, int height) { if (!guiMainThread) CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); - QMetaObject::invokeMethod(guiMainThread, "resizeWindow", - //Qt::BlockingQueuedConnection, - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(name)), Q_ARG(int, width), Q_ARG(int, height)); @@ -564,7 +563,7 @@ CV_IMPL int cvCreateTrackbar2(const char* name_bar, const char* window_name, int QMetaObject::invokeMethod(guiMainThread, "addSlider2", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(name_bar)), Q_ARG(QString, QString(window_name)), Q_ARG(void*, (void*)val), @@ -589,7 +588,7 @@ CV_IMPL int cvCreateTrackbar(const char* name_bar, const char* window_name, int* QMetaObject::invokeMethod(guiMainThread, "addSlider", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(name_bar)), Q_ARG(QString, QString(window_name)), Q_ARG(void*, (void*)value), @@ -610,7 +609,7 @@ CV_IMPL int cvCreateButton(const char* button_name, CvButtonCallback on_change, QMetaObject::invokeMethod(guiMainThread, "addButton", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(button_name)), Q_ARG(int, button_type), Q_ARG(int, initial_button_state), @@ -660,13 +659,17 @@ CV_IMPL void cvShowImage(const char* name, const CvArr* arr) { if (!guiMainThread) guiMainThread = new GuiReceiver; - - QMetaObject::invokeMethod(guiMainThread, - "showImage", - //Qt::BlockingQueuedConnection, - Qt::DirectConnection, - Q_ARG(QString, QString(name)), - Q_ARG(void*, (void*)arr)); + if (QThread::currentThread() != QApplication::instance()->thread()) { + multiThreads = true; + QMetaObject::invokeMethod(guiMainThread, + "showImage", + autoBlockingConnection(), + Q_ARG(QString, QString(name)), + Q_ARG(void*, (void*)arr) + ); + } else { + guiMainThread->showImage(QString(name), (void*)arr); + } } @@ -679,7 +682,7 @@ CV_IMPL void cvSetOpenGlDrawCallback(const char* window_name, CvOpenGlDrawCallba QMetaObject::invokeMethod(guiMainThread, "setOpenGlDrawCallback", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(window_name)), Q_ARG(void*, (void*)callback), Q_ARG(void*, userdata)); @@ -693,7 +696,7 @@ CV_IMPL void cvSetOpenGlContext(const char* window_name) QMetaObject::invokeMethod(guiMainThread, "setOpenGlContext", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(window_name))); } @@ -705,7 +708,7 @@ CV_IMPL void cvUpdateWindow(const char* window_name) QMetaObject::invokeMethod(guiMainThread, "updateWindow", - Qt::AutoConnection, + autoBlockingConnection(), Q_ARG(QString, QString(window_name))); } @@ -720,7 +723,7 @@ double cvGetOpenGlProp_QT(const char* name) { QMetaObject::invokeMethod(guiMainThread, "isOpenGl", - Qt::AutoConnection, + autoBlockingConnection(), Q_RETURN_ARG(double, result), Q_ARG(QString, QString(name))); } @@ -741,6 +744,9 @@ GuiReceiver::GuiReceiver() : bTimeOut(false), nb_windows(0) timer = new QTimer(this); QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timeOut())); timer->setSingleShot(true); + if ( doesExternalQAppExist ) { + moveToThread(QApplication::instance()->thread()); + } } @@ -964,6 +970,7 @@ void GuiReceiver::showImage(QString name, void* arr) void GuiReceiver::destroyWindow(QString name) { + QPointer w = icvFindWindowByName(name); if (w) @@ -1525,7 +1532,6 @@ CvWinProperties::~CvWinProperties() CvWindow::CvWindow(QString name, int arg2) { type = type_CvWindow; - moveToThread(qApp->instance()->thread()); param_flags = arg2 & 0x0000000F; param_gui_mode = arg2 & 0x000000F0; @@ -2365,7 +2371,6 @@ void DefaultViewPort::updateImage(const CvArr* arr) //use to compute mouse coordinate, I need to update the ratio here and in resizeEvent ratioX = width() / float(image2Draw_mat->cols); ratioY = height() / float(image2Draw_mat->rows); - updateGeometry(); } From 56091bae1f01992f37329b2de807d9e1dd763443 Mon Sep 17 00:00:00 2001 From: jeremy Date: Tue, 9 Sep 2014 17:03:59 -0500 Subject: [PATCH 18/72] changing many instances of the same grammar error in documentation --- doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.rst | 2 +- doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.rst | 2 +- doc/py_tutorials/py_core/py_optimization/py_optimization.rst | 2 +- .../py_feature2d/py_features_meaning/py_features_meaning.rst | 2 +- doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.rst | 2 +- .../py_gui/py_drawing_functions/py_drawing_functions.rst | 2 +- doc/py_tutorials/py_gui/py_mouse_handling/py_mouse_handling.rst | 2 +- .../py_histograms/py_2d_histogram/py_2d_histogram.rst | 2 +- .../py_histogram_backprojection/py_histogram_backprojection.rst | 2 +- .../py_ml/py_knn/py_knn_understanding/py_knn_understanding.rst | 2 +- .../py_table_of_contents_video/py_table_of_contents_video.rst | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.rst b/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.rst index 24fc28a46..803ac3769 100644 --- a/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.rst +++ b/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.rst @@ -48,7 +48,7 @@ Below code snippet shows a simple procedure to create disparity map. plt.imshow(disparity,'gray') plt.show() -Below image contains the original image (left) and its disparity map (right). As you can see, result is contaminated with high degree of noise. By adjusting the values of numDisparities and blockSize, you can get more better result. +Below image contains the original image (left) and its disparity map (right). As you can see, result is contaminated with high degree of noise. By adjusting the values of numDisparities and blockSize, you can get a better result. .. image:: images/disparity_map.jpg :alt: Disparity Map diff --git a/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.rst b/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.rst index c5916627f..e4bbeff6d 100644 --- a/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.rst +++ b/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.rst @@ -49,7 +49,7 @@ You can modify the pixel values the same way. .. warning:: Numpy is a optimized library for fast array calculations. So simply accessing each and every pixel values and modifying it will be very slow and it is discouraged. -.. note:: Above mentioned method is normally used for selecting a region of array, say first 5 rows and last 3 columns like that. For individual pixel access, Numpy array methods, ``array.item()`` and ``array.itemset()`` is considered to be more better. But it always returns a scalar. So if you want to access all B,G,R values, you need to call ``array.item()`` separately for all. +.. note:: Above mentioned method is normally used for selecting a region of array, say first 5 rows and last 3 columns like that. For individual pixel access, Numpy array methods, ``array.item()`` and ``array.itemset()`` is considered to be better. But it always returns a scalar. So if you want to access all B,G,R values, you need to call ``array.item()`` separately for all. Better pixel accessing and editing method : diff --git a/doc/py_tutorials/py_core/py_optimization/py_optimization.rst b/doc/py_tutorials/py_core/py_optimization/py_optimization.rst index 58d1b78d6..13160fd4d 100644 --- a/doc/py_tutorials/py_core/py_optimization/py_optimization.rst +++ b/doc/py_tutorials/py_core/py_optimization/py_optimization.rst @@ -75,7 +75,7 @@ Measuring Performance in IPython Sometimes you may need to compare the performance of two similar operations. IPython gives you a magic command ``%timeit`` to perform this. It runs the code several times to get more accurate results. Once again, they are suitable to measure single line codes. -For example, do you know which of the following addition operation is more better, ``x = 5; y = x**2``, ``x = 5; y = x*x``, ``x = np.uint8([5]); y = x*x`` or ``y = np.square(x)`` ? We will find it with %timeit in IPython shell. +For example, do you know which of the following addition operation is better, ``x = 5; y = x**2``, ``x = 5; y = x*x``, ``x = np.uint8([5]); y = x*x`` or ``y = np.square(x)`` ? We will find it with %timeit in IPython shell. :: In [10]: x = 5 diff --git a/doc/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.rst b/doc/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.rst index d785cd756..bfd03c030 100644 --- a/doc/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.rst +++ b/doc/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.rst @@ -29,7 +29,7 @@ Image is very simple. At the top of image, six small image patches are given. Qu A and B are flat surfaces, and they are spread in a lot of area. It is difficult to find the exact location of these patches. -C and D are much more simpler. They are edges of the building. You can find an approximate location, but exact location is still difficult. It is because, along the edge, it is same everywhere. Normal to the edge, it is different. So edge is much more better feature compared to flat area, but not good enough (It is good in jigsaw puzzle for comparing continuity of edges). +C and D are much more simpler. They are edges of the building. You can find an approximate location, but exact location is still difficult. It is because, along the edge, it is same everywhere. Normal to the edge, it is different. So edge is a much better feature compared to flat area, but not good enough (It is good in jigsaw puzzle for comparing continuity of edges). Finally, E and F are some corners of the building. And they can be easily found out. Because at corners, wherever you move this patch, it will look different. So they can be considered as a good feature. So now we move into more simpler (and widely used image) for better understanding. diff --git a/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.rst b/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.rst index 6d734dfed..1b8f50d84 100644 --- a/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.rst +++ b/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.rst @@ -110,7 +110,7 @@ Now I want to apply U-SURF, so that it won't find the orientation. >>> plt.imshow(img2),plt.show() -See the results below. All the orientations are shown in same direction. It is more faster than previous. If you are working on cases where orientation is not a problem (like panorama stitching) etc, this is more better. +See the results below. All the orientations are shown in same direction. It is more faster than previous. If you are working on cases where orientation is not a problem (like panorama stitching) etc, this is better. .. image:: images/surf_kp2.jpg :alt: Upright-SURF diff --git a/doc/py_tutorials/py_gui/py_drawing_functions/py_drawing_functions.rst b/doc/py_tutorials/py_gui/py_drawing_functions/py_drawing_functions.rst index 55b1eec91..fe8ae737c 100644 --- a/doc/py_tutorials/py_gui/py_drawing_functions/py_drawing_functions.rst +++ b/doc/py_tutorials/py_gui/py_drawing_functions/py_drawing_functions.rst @@ -69,7 +69,7 @@ To draw a polygon, first you need coordinates of vertices. Make those points int .. Note:: If third argument is ``False``, you will get a polylines joining all the points, not a closed shape. -.. Note:: ``cv2.polylines()`` can be used to draw multiple lines. Just create a list of all the lines you want to draw and pass it to the function. All lines will be drawn individually. It is more better and faster way to draw a group of lines than calling ``cv2.line()`` for each line. +.. Note:: ``cv2.polylines()`` can be used to draw multiple lines. Just create a list of all the lines you want to draw and pass it to the function. All lines will be drawn individually. It is a much better and faster way to draw a group of lines than calling ``cv2.line()`` for each line. Adding Text to Images: ------------------------ diff --git a/doc/py_tutorials/py_gui/py_mouse_handling/py_mouse_handling.rst b/doc/py_tutorials/py_gui/py_mouse_handling/py_mouse_handling.rst index 2aa5c27ee..416241189 100644 --- a/doc/py_tutorials/py_gui/py_mouse_handling/py_mouse_handling.rst +++ b/doc/py_tutorials/py_gui/py_mouse_handling/py_mouse_handling.rst @@ -48,7 +48,7 @@ Creating mouse callback function has a specific format which is same everywhere. More Advanced Demo =================== -Now we go for much more better application. In this, we draw either rectangles or circles (depending on the mode we select) by dragging the mouse like we do in Paint application. So our mouse callback function has two parts, one to draw rectangle and other to draw the circles. This specific example will be really helpful in creating and understanding some interactive applications like object tracking, image segmentation etc. +Now we go for a much better application. In this, we draw either rectangles or circles (depending on the mode we select) by dragging the mouse like we do in Paint application. So our mouse callback function has two parts, one to draw rectangle and other to draw the circles. This specific example will be really helpful in creating and understanding some interactive applications like object tracking, image segmentation etc. :: import cv2 diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.rst b/doc/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.rst index 8ca103991..1beab913b 100644 --- a/doc/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.rst +++ b/doc/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.rst @@ -64,7 +64,7 @@ The result we get is a two dimensional array of size 180x256. So we can show the Method - 2 : Using Matplotlib ------------------------------ -We can use **matplotlib.pyplot.imshow()** function to plot 2D histogram with different color maps. It gives us much more better idea about the different pixel density. But this also, doesn't gives us idea what color is there on a first look, unless you know the Hue values of different colors. Still I prefer this method. It is simple and better. +We can use **matplotlib.pyplot.imshow()** function to plot 2D histogram with different color maps. It gives us a much better idea about the different pixel density. But this also, doesn't gives us idea what color is there on a first look, unless you know the Hue values of different colors. Still I prefer this method. It is simple and better. .. note:: While using this function, remember, interpolation flag should be ``nearest`` for better results. diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.rst b/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.rst index ecf56c3b2..f2fc66437 100644 --- a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.rst +++ b/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.rst @@ -15,7 +15,7 @@ It was proposed by **Michael J. Swain , Dana H. Ballard** in their paper **Index **What is it actually in simple words?** It is used for image segmentation or finding objects of interest in an image. In simple words, it creates an image of the same size (but single channel) as that of our input image, where each pixel corresponds to the probability of that pixel belonging to our object. In more simpler worlds, the output image will have our object of interest in more white compared to remaining part. Well, that is an intuitive explanation. (I can't make it more simpler). Histogram Backprojection is used with camshift algorithm etc. -**How do we do it ?** We create a histogram of an image containing our object of interest (in our case, the ground, leaving player and other things). The object should fill the image as far as possible for better results. And a color histogram is preferred over grayscale histogram, because color of the object is more better way to define the object than its grayscale intensity. We then "back-project" this histogram over our test image where we need to find the object, ie in other words, we calculate the probability of every pixel belonging to the ground and show it. The resulting output on proper thresholding gives us the ground alone. +**How do we do it ?** We create a histogram of an image containing our object of interest (in our case, the ground, leaving player and other things). The object should fill the image as far as possible for better results. And a color histogram is preferred over grayscale histogram, because color of the object is a better way to define the object than its grayscale intensity. We then "back-project" this histogram over our test image where we need to find the object, ie in other words, we calculate the probability of every pixel belonging to the ground and show it. The resulting output on proper thresholding gives us the ground alone. Algorithm in Numpy ==================== diff --git a/doc/py_tutorials/py_ml/py_knn/py_knn_understanding/py_knn_understanding.rst b/doc/py_tutorials/py_ml/py_knn/py_knn_understanding/py_knn_understanding.rst index 182d0039e..22f51539a 100644 --- a/doc/py_tutorials/py_ml/py_knn/py_knn_understanding/py_knn_understanding.rst +++ b/doc/py_tutorials/py_ml/py_knn/py_knn_understanding/py_knn_understanding.rst @@ -37,7 +37,7 @@ Now let's see it in OpenCV. kNN in OpenCV =============== -We will do a simple example here, with two families (classes), just like above. Then in the next chapter, we will do much more better example. +We will do a simple example here, with two families (classes), just like above. Then in the next chapter, we will do an even better example. So here, we label the Red family as **Class-0** (so denoted by 0) and Blue family as **Class-1** (denoted by 1). We create 25 families or 25 training data, and label them either Class-0 or Class-1. We do all these with the help of Random Number Generator in Numpy. diff --git a/doc/py_tutorials/py_video/py_table_of_contents_video/py_table_of_contents_video.rst b/doc/py_tutorials/py_video/py_table_of_contents_video/py_table_of_contents_video.rst index a8c2d3dba..f076cbd70 100644 --- a/doc/py_tutorials/py_video/py_table_of_contents_video/py_table_of_contents_video.rst +++ b/doc/py_tutorials/py_video/py_table_of_contents_video/py_table_of_contents_video.rst @@ -9,7 +9,7 @@ Video Analysis .. cssclass:: toctableopencv =========== ====================================================== - |vdo_1| We have already seen an example of color-based tracking. It is simpler. This time, we see much more better algorithms like "Meanshift", and its upgraded version, "Camshift" to find and track them. + |vdo_1| We have already seen an example of color-based tracking. It is simpler. This time, we see significantly better algorithms like "Meanshift", and its upgraded version, "Camshift" to find and track them. =========== ====================================================== From b5a4159efc6c1b7e73c6f114cbbb35093197b965 Mon Sep 17 00:00:00 2001 From: GregoryMorse Date: Sat, 14 Dec 2013 16:53:30 +0800 Subject: [PATCH 19/72] Add support for WinRT in the MF capture framework by removing the disallowed calls to enumerate devices and create a sample grabber sink and adding framework for the MediaCapture interface and a custom sink which interfaces with the sample grabber callback interface. The change requires discussion for making it completely functional as redundancy is required given that if the source is a video file, the old code pathways must be used. Otherwise all IMFMediaSession, IMFMediaSource, and IMFActivate code must use a MediaCapture code path and all sink code must use the CMediaSink custom sink. Support for the custom sink is extended to non-WinRT not for compatibility as Windows Vista client is a minimum regardless, but because it offers more flexibility, could be faster and is able to be used as an optionally different code path during sink creation based on a future configuration parameter. My discussion and proposal to finish this change: Devices are so easily enumerated through WinRT Windows.Devices namespace that wrapping the calls in a library is quite a chore for little benefit though to get the various modes and formats could still be a worthwhile project. For now conditional compilation to remove videodevices and any offending non-video file related activity in videodevice. In my opinion, this is a different , far less fundamental and important change which can possibly be done as a future project and also much more easily implemented in C++/CX. ImageGrabber has the IMFSampleGrabberSinkCallback replaced with a base class (SharedSampleGrabber) which also be is base class for ImageGrabberRT. This change is necessary as the custom sink does not require a thread to pump events which is done through MediaCapture already. IMFSampleGrabberSinkCallback is the common element between both models and that piece can be shared. Initializing the new ImageGrabberRT is as simple as passing an already initialized MediaCapture object and any video format/encoding parameters. The concurrency event is necessary to wait for completion and is the way the underlying, IAsyncAction wrappers in the task library work as well. Native WIN32 event objects would be an option if HAVE_CONCURRENCY is not defined. I could even imagine doing it with sleep/thread yield and InterlockedCompareExchange yet I am not enthusiastic about that approach either. Since there is a specific compiler HAVE_ for concurrency, I do not like pulling it in though I think for WinRT it is safe to say we will always have it available though should probably conditionally compile with the Interlocked option as WIN32 events would require HAVE_WIN32. It looks like C++/CX cannot be used for the IMediaExtension sink (which should not be a problem) as using COM objects requires WRL and though deriving from IMediaExtension can be done, there is little purpose without COM. Objects from C++/CX can be swapped to interact with objects from native C++ as Inspectable* can reinterpret_cast to the ref object IInspectable^ and vice-versa. A solution to the COM class with C++/CX would be great so we could have dual support. Also without #define for every WRL object in use, the code will get quite muddy given that the */^ would need to be ifdef'd everywhere. Fixed bugs and completed the change. I believe the new classes need to be moved to a header file as the file has become to large and more classes need to be added for handling all the asynchronous problems (one wrapping IAsyncAction in a task and another for making a task out of IAsyncAction). Unfortunately, blocking on the UI thread is not an option in WinRT so a synchronous architecture is considered "illegal" by Microsoft's standards even if implementable (C++/CX ppltasks library throws errors if you try it). Worse, either by design or a bug in the MF MediaCapture class with Custom Sinks causes a crash if stop/start previewing without reinitializing (spPreferredPreviewMediaType is fatally nulled). After decompiling Windows.Media.dll, I worked around this in my own projects by using an activate-able custom sink ID which strangely assigns 1 to this pointer allowing it to be reinitialized in what can only be described as a hack by Microsoft. This would add additional overhead to the project to implement especially for static libraries as it requires IDL/DLL exporting followed by manifest declaration. Better to document that it is not supported. Furthermore, an additional class for IMFAttributes should be implemented to make clean architecture for passing around attributes as opposed to directly calling non-COM interface calls on the objects and making use of SetProperties which would also be a set up for an object that uses the RuntimeClass activation ID. The remaining changes are not difficult and will be complete soon along with debug tracing messages. Update and rename cap_msmf.h to cap_msmf.hpp Successful test - samples are grabbed Library updated and cleaned up with comments, marshaling, exceptions and linker settings Fixed trailing whitespace VS 2013 support and cleanup consistency plus C++/CX new object fixed Conflicts: modules/highgui/src/cap_msmf.cpp modules/highgui/src/cap_msmf.hpp modules/highgui/src/ppltasks_winrt.h Fix merge conflicts VS 2013 Update 2 library bug fix integrated a-wi's changed integrated --- modules/highgui/src/agile_wrl.h | 568 ++ modules/highgui/src/cap_msmf.cpp | 940 +- modules/highgui/src/cap_msmf.hpp | 899 +- modules/highgui/src/ppltasks_winrt.h | 12451 ++++++++++++++++--------- 4 files changed, 9442 insertions(+), 5416 deletions(-) create mode 100644 modules/highgui/src/agile_wrl.h diff --git a/modules/highgui/src/agile_wrl.h b/modules/highgui/src/agile_wrl.h new file mode 100644 index 000000000..99fbf4185 --- /dev/null +++ b/modules/highgui/src/agile_wrl.h @@ -0,0 +1,568 @@ +// +// Copyright (C) Microsoft Corporation +// All rights reserved. +// Modified for native C++ WRL support by Gregory Morse +// +// Code in Details namespace is for internal usage within the library code +// + +#ifndef _PLATFORM_AGILE_H_ +#define _PLATFORM_AGILE_H_ + +#ifdef _MSC_VER +#pragma once +#endif // _MSC_VER + +#include +#include + +template class Agile; + +template +struct UnwrapAgile +{ + static const bool _IsAgile = false; +}; +template +struct UnwrapAgile> +{ + static const bool _IsAgile = true; +}; +template +struct UnwrapAgile> +{ + static const bool _IsAgile = true; +}; + +#define IS_AGILE(T) UnwrapAgile::_IsAgile + +#define __is_winrt_agile(T) (std::is_same::value || std::is_base_of::value || std::is_base_of::value) //derived from Microsoft::WRL::FtmBase or IAgileObject + +#define __is_win_interface(T) (std::is_base_of::value || std::is_base_of::value) //derived from IUnknown or IInspectable + +#define __is_win_class(T) (std::is_same::value || std::is_base_of::value) //derived from Microsoft::WRL::RuntimeClass or HSTRING + + namespace Details + { + IUnknown* __stdcall GetObjectContext(); + HRESULT __stdcall GetProxyImpl(IUnknown*, REFIID, IUnknown*, IUnknown**); + HRESULT __stdcall ReleaseInContextImpl(IUnknown*, IUnknown*); + + template +#if _MSC_VER >= 1800 + __declspec(no_refcount) inline HRESULT GetProxy(T *ObjectIn, IUnknown *ContextCallBack, T **Proxy) +#else + inline HRESULT GetProxy(T *ObjectIn, IUnknown *ContextCallBack, T **Proxy) +#endif + { +#if _MSC_VER >= 1800 + return GetProxyImpl(*reinterpret_cast(&ObjectIn), __uuidof(T*), ContextCallBack, reinterpret_cast(Proxy)); +#else + return GetProxyImpl(*reinterpret_cast(&const_cast(ObjectIn)), __uuidof(T*), ContextCallBack, reinterpret_cast(Proxy)); +#endif + } + + template + inline HRESULT ReleaseInContext(T *ObjectIn, IUnknown *ContextCallBack) + { + return ReleaseInContextImpl(ObjectIn, ContextCallBack); + } + + template + class AgileHelper + { + __abi_IUnknown* _p; + bool _release; + public: + AgileHelper(__abi_IUnknown* p, bool release = true) : _p(p), _release(release) + { + } + AgileHelper(AgileHelper&& other) : _p(other._p), _release(other._release) + { + _other._p = nullptr; + _other._release = true; + } + AgileHelper operator=(AgileHelper&& other) + { + _p = other._p; + _release = other._release; + _other._p = nullptr; + _other._release = true; + return *this; + } + + ~AgileHelper() + { + if (_release && _p) + { + _p->__abi_Release(); + } + } + + __declspec(no_refcount) __declspec(no_release_return) + T* operator->() + { + return reinterpret_cast(_p); + } + + __declspec(no_refcount) __declspec(no_release_return) + operator T * () + { + return reinterpret_cast(_p); + } + private: + AgileHelper(const AgileHelper&); + AgileHelper operator=(const AgileHelper&); + }; + template + struct __remove_hat + { + typedef T type; + }; + template + struct __remove_hat + { + typedef T type; + }; + template + struct AgileTypeHelper + { + typename typedef __remove_hat::type type; + typename typedef __remove_hat::type* agileMemberType; + }; + } // namespace Details + +#pragma warning(push) +#pragma warning(disable: 4451) // Usage of ref class inside this context can lead to invalid marshaling of object across contexts + + template < + typename T, + bool TIsNotAgile = (__is_win_class(typename Details::AgileTypeHelper::type) && !__is_winrt_agile(typename Details::AgileTypeHelper::type)) || + __is_win_interface(typename Details::AgileTypeHelper::type) + > + class Agile + { + static_assert(__is_win_class(typename Details::AgileTypeHelper::type) || __is_win_interface(typename Details::AgileTypeHelper::type), "Agile can only be used with ref class or interface class types"); + typename typedef Details::AgileTypeHelper::agileMemberType TypeT; + TypeT _object; + ::Microsoft::WRL::ComPtr _contextCallback; + ULONG_PTR _contextToken; + +#if _MSC_VER >= 1800 + enum class AgileState + { + NonAgilePointer = 0, + AgilePointer = 1, + Unknown = 2 + }; + AgileState _agileState; +#endif + + void CaptureContext() + { + _contextCallback = Details::GetObjectContext(); + __abi_ThrowIfFailed(CoGetContextToken(&_contextToken)); + } + + void SetObject(TypeT object) + { + // Capture context before setting the pointer + // If context capture fails then nothing to cleanup + Release(); + if (object != nullptr) + { + ::Microsoft::WRL::ComPtr checkIfAgile; + HRESULT hr = reinterpret_cast(object)->QueryInterface(__uuidof(IAgileObject), &checkIfAgile); + // Don't Capture context if object is agile + if (hr != S_OK) + { +#if _MSC_VER >= 1800 + _agileState = AgileState::NonAgilePointer; +#endif + CaptureContext(); + } +#if _MSC_VER >= 1800 + else + { + _agileState = AgileState::AgilePointer; + } +#endif + } + _object = object; + } + + public: + Agile() throw() : _object(nullptr), _contextToken(0) +#if _MSC_VER >= 1800 + , _agileState(AgileState::Unknown) +#endif + { + } + + Agile(nullptr_t) throw() : _object(nullptr), _contextToken(0) +#if _MSC_VER >= 1800 + , _agileState(AgileState::Unknown) +#endif + { + } + + explicit Agile(TypeT object) throw() : _object(nullptr), _contextToken(0) +#if _MSC_VER >= 1800 + , _agileState(AgileState::Unknown) +#endif + { + // Assumes that the source object is from the current context + SetObject(object); + } + + Agile(const Agile& object) throw() : _object(nullptr), _contextToken(0) +#if _MSC_VER >= 1800 + , _agileState(AgileState::Unknown) +#endif + { + // Get returns pointer valid for current context + SetObject(object.Get()); + } + + Agile(Agile&& object) throw() : _object(nullptr), _contextToken(0) +#if _MSC_VER >= 1800 + , _agileState(AgileState::Unknown) +#endif + { + // Assumes that the source object is from the current context + Swap(object); + } + + ~Agile() throw() + { + Release(); + } + + TypeT Get() const + { + // Agile object, no proxy required +#if _MSC_VER >= 1800 + if (_agileState == AgileState::AgilePointer || _object == nullptr) +#else + if (_contextToken == 0 || _contextCallback == nullptr || _object == nullptr) +#endif + { + return _object; + } + + // Do the check for same context + ULONG_PTR currentContextToken; + __abi_ThrowIfFailed(CoGetContextToken(¤tContextToken)); + if (currentContextToken == _contextToken) + { + return _object; + } + +#if _MSC_VER >= 1800 + // Different context and holding on to a non agile object + // Do the costly work of getting a proxy + TypeT localObject; + __abi_ThrowIfFailed(Details::GetProxy(_object, _contextCallback.Get(), &localObject)); + + if (_agileState == AgileState::Unknown) +#else + // Object is agile if it implements IAgileObject + // GetAddressOf captures the context with out knowing the type of object that it will hold + if (_object != nullptr) +#endif + { +#if _MSC_VER >= 1800 + // Object is agile if it implements IAgileObject + // GetAddressOf captures the context with out knowing the type of object that it will hold + ::Microsoft::WRL::ComPtr checkIfAgile; + HRESULT hr = reinterpret_cast(localObject)->QueryInterface(__uuidof(IAgileObject), &checkIfAgile); +#else + ::Microsoft::WRL::ComPtr checkIfAgile; + HRESULT hr = reinterpret_cast(_object)->QueryInterface(__uuidof(IAgileObject), &checkIfAgile); +#endif + if (hr == S_OK) + { + auto pThis = const_cast(this); +#if _MSC_VER >= 1800 + pThis->_agileState = AgileState::AgilePointer; +#endif + pThis->_contextToken = 0; + pThis->_contextCallback = nullptr; + return _object; + } +#if _MSC_VER >= 1800 + else + { + auto pThis = const_cast(this); + pThis->_agileState = AgileState::NonAgilePointer; + } +#endif + } + +#if _MSC_VER < 1800 + // Different context and holding on to a non agile object + // Do the costly work of getting a proxy + TypeT localObject; + __abi_ThrowIfFailed(Details::GetProxy(_object, _contextCallback.Get(), &localObject)); +#endif + return localObject; + } + + TypeT* GetAddressOf() throw() + { + Release(); + CaptureContext(); + return &_object; + } + + TypeT* GetAddressOfForInOut() throw() + { + CaptureContext(); + return &_object; + } + + TypeT operator->() const throw() + { + return Get(); + } + + Agile& operator=(nullptr_t) throw() + { + Release(); + return *this; + } + + Agile& operator=(TypeT object) throw() + { + Agile(object).Swap(*this); + return *this; + } + + Agile& operator=(Agile object) throw() + { + // parameter is by copy which gets pointer valid for current context + object.Swap(*this); + return *this; + } + +#if _MSC_VER < 1800 + Agile& operator=(IUnknown* lp) throw() + { + // bump ref count + ::Microsoft::WRL::ComPtr spObject(lp); + + // put it into Platform Object + Platform::Object object; + *(IUnknown**)(&object) = spObject.Detach(); + + SetObject(object); + return *this; + } +#endif + + void Swap(Agile& object) + { + std::swap(_object, object._object); + std::swap(_contextCallback, object._contextCallback); + std::swap(_contextToken, object._contextToken); +#if _MSC_VER >= 1800 + std::swap(_agileState, object._agileState); +#endif + } + + // Release the interface and set to NULL + void Release() throw() + { + if (_object) + { + // Cast to IInspectable (no QI) + IUnknown* pObject = *(IUnknown**)(&_object); + // Set * to null without release + *(IUnknown**)(&_object) = nullptr; + + ULONG_PTR currentContextToken; + __abi_ThrowIfFailed(CoGetContextToken(¤tContextToken)); + if (_contextToken == 0 || _contextCallback == nullptr || _contextToken == currentContextToken) + { + pObject->Release(); + } + else + { + Details::ReleaseInContext(pObject, _contextCallback.Get()); + } + _contextCallback = nullptr; + _contextToken = 0; +#if _MSC_VER >= 1800 + _agileState = AgileState::Unknown; +#endif + } + } + + bool operator==(nullptr_t) const throw() + { + return _object == nullptr; + } + + bool operator==(const Agile& other) const throw() + { + return _object == other._object && _contextToken == other._contextToken; + } + + bool operator<(const Agile& other) const throw() + { + if (reinterpret_cast(_object) < reinterpret_cast(other._object)) + { + return true; + } + + return _object == other._object && _contextToken < other._contextToken; + } + }; + + template + class Agile + { + static_assert(__is_win_class(typename Details::AgileTypeHelper::type) || __is_win_interface(typename Details::AgileTypeHelper::type), "Agile can only be used with ref class or interface class types"); + typename typedef Details::AgileTypeHelper::agileMemberType TypeT; + TypeT _object; + + public: + Agile() throw() : _object(nullptr) + { + } + + Agile(nullptr_t) throw() : _object(nullptr) + { + } + + explicit Agile(TypeT object) throw() : _object(object) + { + } + + Agile(const Agile& object) throw() : _object(object._object) + { + } + + Agile(Agile&& object) throw() : _object(nullptr) + { + Swap(object); + } + + ~Agile() throw() + { + Release(); + } + + TypeT Get() const + { + return _object; + } + + TypeT* GetAddressOf() throw() + { + Release(); + return &_object; + } + + TypeT* GetAddressOfForInOut() throw() + { + return &_object; + } + + TypeT operator->() const throw() + { + return Get(); + } + + Agile& operator=(nullptr_t) throw() + { + Release(); + return *this; + } + + Agile& operator=(TypeT object) throw() + { + if (_object != object) + { + _object = object; + } + return *this; + } + + Agile& operator=(Agile object) throw() + { + object.Swap(*this); + return *this; + } + +#if _MSC_VER < 1800 + Agile& operator=(IUnknown* lp) throw() + { + Release(); + // bump ref count + ::Microsoft::WRL::ComPtr spObject(lp); + + // put it into Platform Object + Platform::Object object; + *(IUnknown**)(&object) = spObject.Detach(); + + _object = object; + return *this; + } +#endif + + // Release the interface and set to NULL + void Release() throw() + { + _object = nullptr; + } + + void Swap(Agile& object) + { + std::swap(_object, object._object); + } + + bool operator==(nullptr_t) const throw() + { + return _object == nullptr; + } + + bool operator==(const Agile& other) const throw() + { + return _object == other._object; + } + + bool operator<(const Agile& other) const throw() + { + return reinterpret_cast(_object) < reinterpret_cast(other._object); + } + }; + +#pragma warning(pop) + + template + bool operator==(nullptr_t, const Agile& a) throw() + { + return a == nullptr; + } + + template + bool operator!=(const Agile& a, nullptr_t) throw() + { + return !(a == nullptr); + } + + template + bool operator!=(nullptr_t, const Agile& a) throw() + { + return !(a == nullptr); + } + + template + bool operator!=(const Agile& a, const Agile& b) throw() + { + return !(a == b); + } + + +#endif // _PLATFORM_AGILE_H_ diff --git a/modules/highgui/src/cap_msmf.cpp b/modules/highgui/src/cap_msmf.cpp index b1122efbe..2a9ee20a9 100644 --- a/modules/highgui/src/cap_msmf.cpp +++ b/modules/highgui/src/cap_msmf.cpp @@ -47,12 +47,21 @@ Originaly licensed under The Code Project Open License (CPOL) 1.02: http://www.codeproject.com/info/cpol10.aspx */ +//require Windows 8 for some of the formats defined otherwise could baseline on lower version +#if WINVER < _WIN32_WINNT_WIN7 +#undef WINVER +#define WINVER _WIN32_WINNT_WIN7 +#endif +#if defined _MSC_VER && _MSC_VER >= 1600 + #define HAVE_CONCURRENCY +#endif #include #include #include #include #include #include +#include #include #include #include @@ -71,13 +80,11 @@ #pragma comment(lib, "Mfreadwrite") #pragma comment(lib, "MinCore_Downlevel") -// for ComPtr usage -#include -using namespace Microsoft::WRL; - #include #ifdef HAVE_WINRT + // for ComPtr usage +#include #ifdef __cplusplus_winrt #include #include @@ -89,10 +96,169 @@ using namespace Microsoft::WRL; #include #include #include +#ifdef HAVE_CONCURRENCY #include -#include +#ifndef __cplusplus_winrt +__declspec(noreturn) void __stdcall __abi_WinRTraiseException(long); -using namespace Microsoft::WRL::Wrappers; +inline void __abi_ThrowIfFailed(long __hrArg) +{ + if (__hrArg < 0) + { + __abi_WinRTraiseException(__hrArg); + } +} + +struct Guid +{ +public: + Guid(); + Guid(__rcGUID_t); + operator ::__rcGUID_t(); + bool Equals(Guid __guidArg); + bool Equals(__rcGUID_t __guidArg); + Guid(unsigned int __aArg, unsigned short __bArg, unsigned short __cArg, unsigned __int8 __dArg, + unsigned __int8 __eArg, unsigned __int8 __fArg, unsigned __int8 __gArg, unsigned __int8 __hArg, + unsigned __int8 __iArg, unsigned __int8 __jArg, unsigned __int8 __kArg); + Guid(unsigned int __aArg, unsigned short __bArg, unsigned short __cArg, const unsigned __int8* __dArg); +private: + unsigned long __a; + unsigned short __b; + unsigned short __c; + unsigned char __d; + unsigned char __e; + unsigned char __f; + unsigned char __g; + unsigned char __h; + unsigned char __i; + unsigned char __j; + unsigned char __k; +}; + +static_assert(sizeof(Guid) == sizeof(::_GUID), "Incorect size for Guid"); +static_assert(sizeof(__rcGUID_t) == sizeof(::_GUID), "Incorect size for __rcGUID_t"); + +//////////////////////////////////////////////////////////////////////////////// +inline Guid::Guid() : __a(0), __b(0), __c(0), __d(0), __e(0), __f(0), __g(0), __h(0), __i(0), __j(0), __k(0) +{ +} + +inline Guid::Guid(__rcGUID_t __guid) : +__a(reinterpret_cast(__guid).Data1), +__b(reinterpret_cast(__guid).Data2), +__c(reinterpret_cast(__guid).Data3), +__d(reinterpret_cast(__guid).Data4[0]), +__e(reinterpret_cast(__guid).Data4[1]), +__f(reinterpret_cast(__guid).Data4[2]), +__g(reinterpret_cast(__guid).Data4[3]), +__h(reinterpret_cast(__guid).Data4[4]), +__i(reinterpret_cast(__guid).Data4[5]), +__j(reinterpret_cast(__guid).Data4[6]), +__k(reinterpret_cast(__guid).Data4[7]) +{ +} + +inline Guid::operator ::__rcGUID_t() +{ + return reinterpret_cast<__rcGUID_t>(*this); +} + +inline bool Guid::Equals(Guid __guidArg) +{ + return *this == __guidArg; +} + +inline bool Guid::Equals(__rcGUID_t __guidArg) +{ + return *this == static_cast< Guid>(__guidArg); +} + +inline bool operator==(Guid __aArg, Guid __bArg) +{ + auto __a = reinterpret_cast(&__aArg); + auto __b = reinterpret_cast(&__bArg); + + return (__a[0] == __b[0] && __a[1] == __b[1] && __a[2] == __b[2] && __a[3] == __b[3]); +} + +inline bool operator!=(Guid __aArg, Guid __bArg) +{ + return !(__aArg == __bArg); +} + +inline bool operator<(Guid __aArg, Guid __bArg) +{ + auto __a = reinterpret_cast(&__aArg); + auto __b = reinterpret_cast(&__bArg); + + if (__a[0] != __b[0]) + { + return __a[0] < __b[0]; + } + + if (__a[1] != __b[1]) + { + return __a[1] < __b[1]; + } + + if (__a[2] != __b[2]) + { + return __a[2] < __b[2]; + } + + if (__a[3] != __b[3]) + { + return __a[3] < __b[3]; + } + + return false; +} + +inline Guid::Guid(unsigned int __aArg, unsigned short __bArg, unsigned short __cArg, unsigned __int8 __dArg, + unsigned __int8 __eArg, unsigned __int8 __fArg, unsigned __int8 __gArg, unsigned __int8 __hArg, + unsigned __int8 __iArg, unsigned __int8 __jArg, unsigned __int8 __kArg) : + __a(__aArg), __b(__bArg), __c(__cArg), __d(__dArg), __e(__eArg), __f(__fArg), __g(__gArg), __h(__hArg), __i(__iArg), __j(__jArg), __k(__kArg) +{ +} + +inline Guid::Guid(unsigned int __aArg, unsigned short __bArg, unsigned short __cArg, const unsigned __int8 __dArg[8]) : +__a(__aArg), __b(__bArg), __c(__cArg) +{ + __d = __dArg[0]; + __e = __dArg[1]; + __f = __dArg[2]; + __g = __dArg[3]; + __h = __dArg[4]; + __i = __dArg[5]; + __j = __dArg[6]; + __k = __dArg[7]; +} + +__declspec(selectany) Guid __winrt_GUID_NULL(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + +// +//// Don't want to define the real IUnknown from unknown.h here. That would means if the user has +//// any broken code that uses it, compile errors will take the form of e.g.: +//// predefined C++ WinRT types (compiler internal)(41) : see declaration of 'IUnknown::QueryInterface' +//// This is not helpful. If they use IUnknown, we still need to point them to the actual unknown.h so +//// that they can see the original definition. +//// +//// For WinRT, we'll instead have a parallel COM interface hierarchy for basic interfaces starting with _. +//// The type mismatch is not an issue. COM passes types through GUID / void* combos - the original type +//// doesn't come into play unless the user static_casts an implementation type to one of these, but +//// the WinRT implementation types are hidden. +__interface __declspec(uuid("00000000-0000-0000-C000-000000000046")) __abi_IUnknown +{ +public: + virtual long __stdcall __abi_QueryInterface(Guid&, void**) = 0; + virtual unsigned long __stdcall __abi_AddRef() = 0; + virtual unsigned long __stdcall __abi_Release() = 0; +}; +#endif +#include "ppltasks_winrt.h" +#endif +#else +#include #endif struct IMFMediaType; @@ -114,18 +280,23 @@ template void SafeRelease(T **ppT) } } -/// Class for printing info into consol -class DebugPrintOut +#ifdef _DEBUG +/// Class for printing info into console +class DPO { public: - ~DebugPrintOut(void); - static DebugPrintOut& getInstance(); + ~DPO(void); + static DPO& getInstance(); void printOut(const wchar_t *format, ...); void setVerbose(bool state); bool verbose; private: - DebugPrintOut(void); + DPO(void); }; +#define DebugPrintOut(...) DPO::getInstance().printOut(__VA_ARGS__) +#else +#define DebugPrintOut(...) void() +#endif #include "cap_msmf.hpp" @@ -227,7 +398,9 @@ protected: RawImage *ig_RIFirst; RawImage *ig_RISecond; RawImage *ig_RIOut; -}; +private: + ImageGrabberCallback& operator=(const ImageGrabberCallback&); // Declared to fix compilation warning. + }; #ifdef HAVE_WINRT extern const __declspec(selectany) WCHAR RuntimeClass_CV_ImageGrabberWinRT[] = L"cv.ImageGrabberWinRT"; @@ -271,7 +444,7 @@ class ImageGrabber : public ImageGrabberCallback { public: ~ImageGrabber(void); - HRESULT initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat); + HRESULT initImageGrabber(IMFMediaSource *pSource); HRESULT startGrabbing(void); void stopGrabbing(); // IUnknown methods @@ -292,6 +465,8 @@ private: HRESULT AddSourceNode(IMFTopology *pTopology, IMFMediaSource *pSource, IMFPresentationDescriptor *pPD, IMFStreamDescriptor *pSD, IMFTopologyNode **ppNode); HRESULT AddOutputNode(IMFTopology *pTopology, IMFActivate *pActivate, DWORD dwId, IMFTopologyNode **ppNode); + + ImageGrabber& operator=(const ImageGrabber&); // Declared to fix comiplation error. }; /// Class for controlling of thread of the grabbing raw data from video device @@ -373,8 +548,9 @@ public: void waitForDevice() { if (vd_pAction) { - HRESULT hr; - DO_ACTION_SYNCHRONOUSLY(hr, vd_pAction, GET_CURRENT_CONTEXT); +#ifdef HAVE_CONCURRENCY + CREATE_TASK DEFINE_RET_TYPE(void)(vd_pAction).wait(); +#endif vd_pAction = nullptr; } } @@ -385,6 +561,7 @@ public: int getCountFormats(); unsigned int getWidth(); unsigned int getHeight(); + unsigned int getFrameRate() const; MediaType getFormat(unsigned int id); bool setupDevice(unsigned int w, unsigned int h, unsigned int idealFramerate = 0); bool setupDevice(unsigned int id); @@ -406,6 +583,7 @@ private: CamParametrs vd_PrevParametrs; unsigned int vd_Width; unsigned int vd_Height; + unsigned int vd_FrameRate; unsigned int vd_CurrentNumber; bool vd_IsSetuped; std::map vd_CaptureFormats; @@ -413,10 +591,12 @@ private: IMFMediaSource *vd_pSource; #ifdef HAVE_WINRT MAKE_WRL_AGILE_REF(_MediaCapture) vd_pMedCap; - IMedCapFailHandler* vd_pMedCapFail; + EventRegistrationToken vd_cookie; ImageGrabberWinRT *vd_pImGr; MAKE_WRL_REF(_AsyncAction) vd_pAction; +#ifdef HAVE_CONCURRENCY Concurrency::critical_section vd_lock; +#endif #endif emergensyStopEventCallback vd_func; void *vd_userData; @@ -428,7 +608,9 @@ private: 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* pTask, MAKE_WRL_REF(_IDeviceInformation)* ppDevice); +#ifdef HAVE_CONCURRENCY + long checkDevice(_DeviceClass devClass, DEFINE_TASK* pTask, MAKE_WRL_REF(_IDeviceInformation)* ppDevice); +#endif #else long resetDevice(IMFActivate *pActivate); long checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice); @@ -445,8 +627,9 @@ public: long initDevices(_DeviceClass devClass); void waitInit() { if (vds_enumTask) { - HRESULT hr; - DO_ACTION_SYNCHRONOUSLY(hr, vds_enumTask, GET_CURRENT_CONTEXT); +#ifdef HAVE_CONCURRENCY + CREATE_TASK DEFINE_RET_TYPE(void)(vds_enumTask).wait(); +#endif vds_enumTask = nullptr; } } @@ -502,6 +685,8 @@ public: unsigned int getWidth(int deviceID); // Getting height of image, which is getting from videodevice with deviceID unsigned int getHeight(int deviceID); + // Getting frame rate, which is getting from videodevice with deviceID + unsigned int getFrameRate(int deviceID) const; // Getting name of videodevice with deviceID wchar_t *getNameVideoDevice(int deviceID); // Getting interface MediaSource for Media Foundation from videodevice with deviceID @@ -516,8 +701,10 @@ public: bool isDeviceMediaSource(int deviceID); // Checking of using Raw Data of pixels from videodevice with deviceID bool isDeviceRawDataSource(int deviceID); +#ifdef _DEBUG // Setting of the state of outprinting info in console static void setVerbose(bool state); +#endif // Initialization of video device with deviceID by media type with id bool setupDevice(int deviceID, unsigned int id = 0); // Initialization of video device with deviceID by wisth w, height h and fps idealFramerate @@ -536,21 +723,22 @@ private: void updateListOfDevices(); }; -DebugPrintOut::DebugPrintOut(void):verbose(true) +#ifdef _DEBUG +DPO::DPO(void):verbose(true) { } -DebugPrintOut::~DebugPrintOut(void) +DPO::~DPO(void) { } -DebugPrintOut& DebugPrintOut::getInstance() +DPO& DPO::getInstance() { - static DebugPrintOut instance; + static DPO instance; return instance; } -void DebugPrintOut::printOut(const wchar_t *format, ...) +void DPO::printOut(const wchar_t *format, ...) { if(verbose) { @@ -558,23 +746,33 @@ void DebugPrintOut::printOut(const wchar_t *format, ...) wchar_t *p = NULL; va_list args; va_start(args, format); - if(wcscmp(format, L"%i")) + if( ::IsDebuggerPresent() ) { - i = va_arg (args, int); + WCHAR szMsg[512]; + ::StringCchVPrintfW(szMsg, sizeof(szMsg)/sizeof(szMsg[0]), format, args); + ::OutputDebugStringW(szMsg); } - if(wcscmp(format, L"%s")) + else { - p = va_arg (args, wchar_t *); + if(wcscmp(format, L"%i")) + { + i = va_arg (args, int); + } + if(wcscmp(format, L"%s")) + { + p = va_arg (args, wchar_t *); + } + wprintf(format, i,p); } - wprintf(format, i,p); va_end (args); } } -void DebugPrintOut::setVerbose(bool state) +void DPO::setVerbose(bool state) { verbose = state; } +#endif LPCWSTR GetGUIDNameConstNew(const GUID& guid); HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz); @@ -650,7 +848,7 @@ HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, MediaType hr = GetGUIDNameNew(*var.puuid, &pGuidValName); if (SUCCEEDED(hr)) { - out.MF_MT_AM_FORMAT_TYPE = MF_MT_AM_FORMAT_TYPE; + out.MF_MT_AM_FORMAT_TYPE = *var.puuid; out.pMF_MT_AM_FORMAT_TYPEName = pGuidValName; pGuidValName = NULL; } @@ -660,7 +858,7 @@ HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, MediaType hr = GetGUIDNameNew(*var.puuid, &pGuidValName); if (SUCCEEDED(hr)) { - out.MF_MT_MAJOR_TYPE = MF_MT_MAJOR_TYPE; + out.MF_MT_MAJOR_TYPE = *var.puuid; out.pMF_MT_MAJOR_TYPEName = pGuidValName; pGuidValName = NULL; } @@ -670,7 +868,7 @@ HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, MediaType hr = GetGUIDNameNew(*var.puuid, &pGuidValName); if (SUCCEEDED(hr)) { - out.MF_MT_SUBTYPE = MF_MT_SUBTYPE; + out.MF_MT_SUBTYPE = *var.puuid; out.pMF_MT_SUBTYPEName = pGuidValName; pGuidValName = NULL; } @@ -963,9 +1161,8 @@ FormatReader::FormatReader(void) MediaType FormatReader::Read(IMFMediaType *pType) { UINT32 count = 0; - HRESULT hr = S_OK; MediaType out; - hr = pType->LockStore(); + HRESULT hr = pType->LockStore(); if (FAILED(hr)) { return out; @@ -1032,9 +1229,8 @@ ImageGrabber::~ImageGrabber(void) SafeRelease(&ig_pSession); SafeRelease(&ig_pTopology); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Destroying instance of the ImageGrabber class\n", ig_DeviceID); + DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Destroying instance of the ImageGrabber class\n", ig_DeviceID); } #ifdef HAVE_WINRT @@ -1063,9 +1259,7 @@ ImageGrabberWinRT::~ImageGrabberWinRT(void) CloseHandle(ig_hFrameGrabbed); } - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE: Destroying instance of the ImageGrabberWinRT class\n"); + DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE: Destroying instance of the ImageGrabberWinRT class\n"); } HRESULT ImageGrabberWinRT::initImageGrabber(MAKE_WRL_REF(_MediaCapture) pSource, @@ -1082,7 +1276,7 @@ HRESULT ImageGrabberWinRT::initImageGrabber(MAKE_WRL_REF(_MediaCapture) pSource, if (FAILED(hr)) return hr; GET_WRL_OBJ_FROM_OBJ(_VideoEncodingProperties, pVidProps, pMedEncProps, hr); if (FAILED(hr)) return hr; - ComPtr pType = NULL; + _ComPtr pType = NULL; hr = MediaSink::ConvertPropertiesToMediaType(DEREF_AS_NATIVE_WRL_OBJ(ABI::Windows::Media::MediaProperties::IMediaEncodingProperties, pMedEncProps), &pType); if (FAILED(hr)) return hr; MediaType MT = FormatReader::Read(pType.Get()); @@ -1113,13 +1307,17 @@ HRESULT ImageGrabberWinRT::stopGrabbing(MAKE_WRL_REF(_AsyncAction)* action) MAKE_WRL_REF(_AsyncAction) pAction; WRL_METHOD_BASE(imedPrevCap, StopPreviewAsync, pAction, hr) if (SUCCEEDED(hr)) { - SAVE_CURRENT_CONTEXT(context); - *action = reinterpret_cast(BEGIN_CREATE_ASYNC(pAction, context, this) - HRESULT hr; - DO_ACTION_SYNCHRONOUSLY(hr, pAction, context); +#ifdef HAVE_CONCURRENCY + DEFINE_TASK _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction); + *action = reinterpret_cast(BEGIN_CREATE_ASYNC(void, _task, this) + HRESULT hr = S_OK; + _task.wait(); SafeRelease(&ig_pMediaSink); SetEvent(ig_hFinish); END_CREATE_ASYNC(hr)); +#else + *action = nullptr; +#endif } } return hr; @@ -1180,21 +1378,19 @@ HRESULT ImageGrabberWinRT::CreateInstance(ImageGrabberWinRT **ppIG, bool synchro { return E_OUTOFMEMORY; } - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE: Creating instance of ImageGrabberWinRT\n"); + DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE: Creating instance of ImageGrabberWinRT\n"); return S_OK; } #endif -HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat) +HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource) { - ComPtr pSinkActivate = NULL; - ComPtr pType = NULL; - ComPtr pPD = NULL; - ComPtr pSD = NULL; - ComPtr pHandler = NULL; - ComPtr pCurrentType = NULL; - HRESULT hr = S_OK; + _ComPtr pSinkActivate = NULL; + _ComPtr pType = NULL; + _ComPtr pPD = NULL; + _ComPtr pSD = NULL; + _ComPtr pHandler = NULL; + _ComPtr pCurrentType = NULL; MediaType MT; // Clean up. if (ig_pSession) @@ -1204,7 +1400,7 @@ HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat SafeRelease(&ig_pSession); SafeRelease(&ig_pTopology); ig_pSource = pSource; - hr = pSource->CreatePresentationDescriptor(&pPD); + HRESULT hr = pSource->CreatePresentationDescriptor(&pPD); if (FAILED(hr)) { goto err; @@ -1232,25 +1428,16 @@ HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat MT = FormatReader::Read(pCurrentType.Get()); } err: - 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)); + CHECK_HR(hr); + CHECK_HR(hr = RawImage::CreateInstance(&ig_RIFirst, MT.MF_MT_SAMPLE_SIZE)); + CHECK_HR(hr = RawImage::CreateInstance(&ig_RISecond, MT.MF_MT_SAMPLE_SIZE)); ig_RIOut = ig_RISecond; // Configure the media type that the Sample Grabber will receive. // Setting the major and subtype is usually enough for the topology loader // to resolve the topology. CHECK_HR(hr = MFCreateMediaType(pType.GetAddressOf())); - CHECK_HR(hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)); - CHECK_HR(hr = pType->SetGUID(MF_MT_SUBTYPE, VideoFormat)); + CHECK_HR(hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MT.MF_MT_MAJOR_TYPE)); + CHECK_HR(hr = pType->SetGUID(MF_MT_SUBTYPE, MT.MF_MT_SUBTYPE)); // Create the sample grabber sink. CHECK_HR(hr = MFCreateSampleGrabberSinkActivate(pType.Get(), this, pSinkActivate.GetAddressOf())); // To run as fast as possible, set this attribute (requires Windows 7): @@ -1277,19 +1464,16 @@ void ImageGrabber::stopGrabbing() { if(ig_pSession) ig_pSession->Stop(); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Stopping of of grabbing of images\n", ig_DeviceID); + DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Stopping of of grabbing of images\n", ig_DeviceID); } HRESULT ImageGrabber::startGrabbing(void) { - HRESULT hr = S_OK; - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - ComPtr pEvent = NULL; + _ComPtr pEvent = NULL; PROPVARIANT var; PropVariantInit(&var); - hr = ig_pSession->SetTopology(0, ig_pTopology); - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Start Grabbing of the images\n", ig_DeviceID); + HRESULT hr = ig_pSession->SetTopology(0, ig_pTopology); + DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Start Grabbing of the images\n", ig_DeviceID); hr = ig_pSession->Start(&GUID_NULL, &var); for(;;) { @@ -1316,28 +1500,28 @@ HRESULT ImageGrabber::startGrabbing(void) } if (met == MESessionEnded) { - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionEnded \n", ig_DeviceID); + DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionEnded\n", ig_DeviceID); ig_pSession->Stop(); break; } if (met == MESessionStopped) { - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionStopped \n", ig_DeviceID); + DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionStopped \n", ig_DeviceID); break; } if (met == MEVideoCaptureDeviceRemoved) { - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: MEVideoCaptureDeviceRemoved \n", ig_DeviceID); + DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MEVideoCaptureDeviceRemoved \n", ig_DeviceID); break; } if ((met == MEError) || (met == MENonFatalError)) { pEvent->GetStatus(&hrStatus); - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: MEError | MENonFatalError: %u\n", ig_DeviceID, hrStatus); + DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MEError | MENonFatalError: %u\n", ig_DeviceID, hrStatus); break; } } - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID); + DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID); done: SetEvent(ig_hFinish); @@ -1356,11 +1540,11 @@ void ImageGrabberCallback::resumeGrabbing() HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo) { IMFTopology* pTopology = NULL; - ComPtr pPD = NULL; - ComPtr pSD = NULL; - ComPtr pHandler = NULL; - ComPtr pNode1 = NULL; - ComPtr pNode2 = NULL; + _ComPtr pPD = NULL; + _ComPtr pSD = NULL; + _ComPtr pHandler = NULL; + _ComPtr pNode1 = NULL; + _ComPtr pNode2 = NULL; HRESULT hr = S_OK; DWORD cStreams = 0; CHECK_HR(hr = MFCreateTopology(&pTopology)); @@ -1400,7 +1584,7 @@ HRESULT ImageGrabber::AddSourceNode( IMFStreamDescriptor *pSD, // Stream descriptor. IMFTopologyNode **ppNode) // Receives the node pointer. { - ComPtr pNode = NULL; + _ComPtr pNode = NULL; HRESULT hr = S_OK; CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, pNode.GetAddressOf())); CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource)); @@ -1421,7 +1605,7 @@ HRESULT ImageGrabber::AddOutputNode( DWORD dwId, // Identifier of the stream sink. IMFTopologyNode **ppNode) // Receives the node pointer. { - ComPtr pNode = NULL; + _ComPtr pNode = NULL; HRESULT hr = S_OK; CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, pNode.GetAddressOf())); CHECK_HR(hr = pNode->SetObject(pActivate)); @@ -1443,8 +1627,7 @@ HRESULT ImageGrabber::CreateInstance(ImageGrabber **ppIG, unsigned int deviceID, { return E_OUTOFMEMORY; } - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"IMAGEGRABBER VIDEODEVICE %i: Creating instance of ImageGrabber\n", deviceID); + DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Creating instance of ImageGrabber\n", deviceID); return S_OK; } @@ -1537,7 +1720,7 @@ STDMETHODIMP ImageGrabberCallback::OnProcessSample(REFGUID guidMajorMediaType, D DWORD status = WaitForMultipleObjects(2, tmp, FALSE, INFINITE); if (status == WAIT_OBJECT_0) { - printf("OnProcessFrame called after ig_hFinish event\n"); + DebugPrintOut(L"OnProcessFrame called after ig_hFinish event\n"); return S_OK; } @@ -1584,15 +1767,14 @@ DWORD WINAPI MainThreadFunction( LPVOID lpParam ) HRESULT ImageGrabberThread::CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID, bool synchronious) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); *ppIGT = new (std::nothrow) ImageGrabberThread(pSource, deviceID, synchronious); if (ppIGT == NULL) { - DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Memory cannot be allocated\n", deviceID); + DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Memory cannot be allocated\n", deviceID); return E_OUTOFMEMORY; } else - DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Creating of the instance of ImageGrabberThread\n", deviceID); + DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Creating of the instance of ImageGrabberThread\n", deviceID); return S_OK; } @@ -1601,24 +1783,23 @@ ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int dev igt_Handle(NULL), igt_stop(false) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); HRESULT hr = ImageGrabber::CreateInstance(&igt_pImageGrabber, deviceID, synchronious); igt_DeviceID = deviceID; if(SUCCEEDED(hr)) { - hr = igt_pImageGrabber->initImageGrabber(pSource, MFVideoFormat_RGB24); + hr = igt_pImageGrabber->initImageGrabber(pSource); if(!SUCCEEDED(hr)) { - DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with initialization of the instance of the ImageGrabber class\n", deviceID); + DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with initialization of the instance of the ImageGrabber class\n", deviceID); } else { - DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Initialization of instance of the ImageGrabber class\n", deviceID); + DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Initialization of instance of the ImageGrabber class\n", deviceID); } } else { - DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with creation of the instance of the ImageGrabber class\n", deviceID); + DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with creation of the instance of the ImageGrabber class\n", deviceID); } } @@ -1633,8 +1814,7 @@ void ImageGrabberThread::setEmergencyStopEvent(void *userData, void(*func)(int, ImageGrabberThread::~ImageGrabberThread(void) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Destroing ImageGrabberThread\n", igt_DeviceID); + DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Destroing ImageGrabberThread\n", igt_DeviceID); if (igt_Handle) WaitForSingleObject(igt_Handle, INFINITE); delete igt_pImageGrabber; @@ -1662,30 +1842,29 @@ void ImageGrabberThread::start() void ImageGrabberThread::run() { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if(igt_pImageGrabber) { - DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Thread for grabbing images is started\n", igt_DeviceID); + DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Thread for grabbing images is started\n", igt_DeviceID); HRESULT hr = igt_pImageGrabber->startGrabbing(); if(!SUCCEEDED(hr)) { - DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with starting the process of grabbing\n", igt_DeviceID); + DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with starting the process of grabbing\n", igt_DeviceID); } } else { - DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i The thread is finished without execution of grabbing\n", igt_DeviceID); + DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i The thread is finished without execution of grabbing\n", igt_DeviceID); } if(!igt_stop) { - DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Emergency Stop thread\n", igt_DeviceID); + DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Emergency Stop thread\n", igt_DeviceID); if(igt_func) { igt_func(igt_DeviceID, igt_userData); } } else - DPO->printOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Finish thread\n", igt_DeviceID); + DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Finish thread\n", igt_DeviceID); } ImageGrabber *ImageGrabberThread::getImageGrabber() @@ -1698,8 +1877,7 @@ Media_Foundation::Media_Foundation(void) HRESULT hr = MFStartup(MF_VERSION); if(!SUCCEEDED(hr)) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MEDIA FOUNDATION: It cannot be created!!!\n"); + DebugPrintOut(L"MEDIA FOUNDATION: It cannot be created!!!\n"); } } @@ -1708,8 +1886,7 @@ Media_Foundation::~Media_Foundation(void) HRESULT hr = MFShutdown(); if(!SUCCEEDED(hr)) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MEDIA FOUNDATION: Resources cannot be released\n"); + DebugPrintOut(L"MEDIA FOUNDATION: Resources cannot be released\n"); } } @@ -1720,7 +1897,7 @@ bool Media_Foundation::buildListOfDevices() videoDevices *vDs = &videoDevices::getInstance(); hr = vDs->initDevices(WRL_ENUM_GET(_DeviceClass, DeviceClass, VideoCapture)); #else - ComPtr pAttributes = NULL; + _ComPtr pAttributes = NULL; CoInitialize(NULL); hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1); if (SUCCEEDED(hr)) @@ -1738,8 +1915,7 @@ bool Media_Foundation::buildListOfDevices() #endif if (FAILED(hr)) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MEDIA FOUNDATION: The access to the video cameras denied\n"); + DebugPrintOut(L"MEDIA FOUNDATION: The access to the video cameras denied\n"); } return (SUCCEEDED(hr)); @@ -1803,11 +1979,11 @@ 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_pImGrTh(NULL), vd_func(NULL), vd_userData(NULL) + vd_Width(0), vd_Height(0), vd_FrameRate(0), vd_pSource(NULL), vd_pImGrTh(NULL), vd_func(NULL), vd_userData(NULL) { #ifdef HAVE_WINRT vd_pMedCap = nullptr; - vd_pMedCapFail = NULL; + vd_cookie.value = 0; vd_pImGr = NULL; vd_pAction = nullptr; #endif @@ -1899,7 +2075,7 @@ long videoDevice::resetDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice) long videoDevice::resetDevice(IMFActivate *pActivate) #endif { - HRESULT hr = -1; + HRESULT hr = E_FAIL; vd_CurrentFormats.clear(); if(vd_pFriendlyName) CoTaskMemFree(vd_pFriendlyName); @@ -1926,25 +2102,28 @@ long videoDevice::resetDevice(IMFActivate *pActivate) if (FAILED(hr)) return hr; MAKE_WRL_REF(_AsyncAction) pAction; WRL_METHOD(DEREF_WRL_OBJ(pIMedCap), _InitializeWithSettingsAsync, pAction, hr, DEREF_WRL_OBJ(pCapInitSet)) +#ifdef HAVE_CONCURRENCY + DEFINE_TASK _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction); if (FAILED(hr)) return hr; MAKE_WRL_AGILE_REF(_MediaCapture) pAgileMedCap; pAgileMedCap = PREPARE_TRANSFER_WRL_OBJ(pIMedCap); Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; SAVE_CURRENT_CONTEXT(context); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(pAction, pOldAction, context, &pAgileMedCap, this) - HRESULT hr; - if (pOldAction) DO_ACTION_SYNCHRONOUSLY(hr, pOldAction, GET_CURRENT_CONTEXT); - DO_ACTION_SYNCHRONOUSLY(hr, pAction, context); + vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, _task, pOldAction, context, &pAgileMedCap, this) + HRESULT hr = S_OK; + if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); + _task.wait(); if (SUCCEEDED(hr)) { //all camera capture calls only in original context BEGIN_CALL_IN_CONTEXT(hr, context, pAgileMedCap, this) enumerateCaptureFormats(DEREF_AGILE_WRL_OBJ(pAgileMedCap)); - END_CALL_IN_CONTEXT(S_OK) + END_CALL_IN_CONTEXT_BASE } buildLibraryofTypes(); RELEASE_AGILE_WRL(pAgileMedCap) END_CREATE_ASYNC(hr)); +#endif } #else if(pActivate) @@ -1965,8 +2144,7 @@ long videoDevice::resetDevice(IMFActivate *pActivate) if(FAILED(hr)) { vd_pFriendlyName = NULL; - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"VIDEODEVICE %i: IMFMediaSource interface cannot be created \n", vd_CurrentNumber); + DebugPrintOut(L"VIDEODEVICE %i: IMFMediaSource interface cannot be created \n", vd_CurrentNumber); } } #endif @@ -1984,15 +2162,14 @@ long videoDevice::readInfoOfDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice, un #else long videoDevice::readInfoOfDevice(IMFActivate *pActivate, unsigned int Num) { - HRESULT hr = -1; vd_CurrentNumber = Num; - hr = resetDevice(pActivate); - return hr; + return resetDevice(pActivate); } #endif #ifdef HAVE_WINRT -long videoDevice::checkDevice(_DeviceClass devClass, DEFINE_TASK* pTask, MAKE_WRL_REF(_IDeviceInformation)* ppDevice) +#ifdef HAVE_CONCURRENCY +long videoDevice::checkDevice(_DeviceClass devClass, DEFINE_TASK* pTask, MAKE_WRL_REF(_IDeviceInformation)* ppDevice) { HRESULT hr = S_OK; ACTIVATE_STATIC_OBJ(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation, MAKE_WRL_OBJ(_DeviceInformationStatics), pDevStat, hr) @@ -2000,10 +2177,10 @@ long videoDevice::checkDevice(_DeviceClass devClass, DEFINE_TASK* pTask MAKE_WRL_REF(_AsyncOperation) pAction; WRL_METHOD(pDevStat, _FindAllAsyncDeviceClass, pAction, hr, devClass) if (SUCCEEDED(hr)) { - *pTask = CREATE_TASK([pAction, &ppDevice, this]() -> HRESULT { - HRESULT hr; - MAKE_WRL_OBJ(_VectorView) pVector; - DO_OPERATION_SYNCHRONOUSLY_VECTOR(hr, pAction, GET_CURRENT_CONTEXT, pVector, _VectorView, _DeviceInformation, _DeviceInformationCollection); + *pTask = CREATE_TASK DEFINE_RET_TYPE(void)([pAction, &ppDevice, this]() -> DEFINE_RET_FORMAL(void) { + HRESULT hr = S_OK; + MAKE_WRL_OBJ(_VectorView) pVector = + CREATE_TASK DEFINE_RET_TYPE(MAKE_WRL_REF(_VectorView))(pAction).get(); UINT32 count = 0; if (SUCCEEDED(hr)) WRL_PROP_GET(pVector, Size, count, hr) if (SUCCEEDED(hr) && count > 0) { @@ -2021,20 +2198,19 @@ long videoDevice::checkDevice(_DeviceClass devClass, DEFINE_TASK* pTask } } } - return hr; + RET_VAL_BASE; }); } return hr; } +#endif #else long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice) { - HRESULT hr = S_OK; IMFActivate **ppDevices = NULL; - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); UINT32 count; wchar_t *newFriendlyName = NULL; - hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count); + HRESULT hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count); if (SUCCEEDED(hr)) { if(count > 0) @@ -2050,8 +2226,8 @@ long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice) { if(wcscmp(newFriendlyName, vd_pFriendlyName) != 0) { - DPO->printOut(L"VIDEODEVICE %i: Chosen device cannot be found \n", vd_CurrentNumber); - hr = -1; + DebugPrintOut(L"VIDEODEVICE %i: Chosen device cannot be found \n", vd_CurrentNumber); + hr = E_INVALIDARG; pDevice = NULL; } else @@ -2062,13 +2238,13 @@ long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice) } else { - DPO->printOut(L"VIDEODEVICE %i: Name of device cannot be gotten \n", vd_CurrentNumber); + DebugPrintOut(L"VIDEODEVICE %i: Name of device cannot be gotten \n", vd_CurrentNumber); } } else { - DPO->printOut(L"VIDEODEVICE %i: Number of devices more than corrent number of the device \n", vd_CurrentNumber); - hr = -1; + DebugPrintOut(L"VIDEODEVICE %i: Number of devices more than corrent number of the device \n", vd_CurrentNumber); + hr = E_INVALIDARG; } for(UINT32 i = 0; i < count; i++) { @@ -2077,11 +2253,11 @@ long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice) SafeRelease(ppDevices); } else - hr = -1; + hr = E_FAIL; } else { - DPO->printOut(L"VIDEODEVICE %i: List of DeviceSources cannot be enumerated \n", vd_CurrentNumber); + DebugPrintOut(L"VIDEODEVICE %i: List of DeviceSources cannot be enumerated \n", vd_CurrentNumber); } return hr; } @@ -2092,19 +2268,20 @@ long videoDevice::initDevice() HRESULT hr = S_OK; CoInitialize(NULL); #ifdef HAVE_WINRT +#ifdef HAVE_CONCURRENCY Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; SAVE_CURRENT_CONTEXT(context); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(pOldAction, context, this) + vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, pOldAction, context, this) HRESULT hr; - if (pOldAction) DO_ACTION_SYNCHRONOUSLY(hr, pOldAction, GET_CURRENT_CONTEXT); - DEFINE_TASK pTask; + if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); + DEFINE_TASK pTask; MAKE_WRL_OBJ(_IDeviceInformation) pDevInfo; hr = checkDevice(WRL_ENUM_GET(_DeviceClass, DeviceClass, VideoCapture), &pTask, REF_WRL_OBJ(pDevInfo)); - if (SUCCEEDED(hr)) hr = pTask.get(); + if (SUCCEEDED(hr)) pTask.wait(); if (SUCCEEDED(hr)) { - MAKE_WRL_REF(_AsyncAction) pAction; - BEGIN_CALL_IN_CONTEXT(hr, context, pDevInfo, &pAction, context, this) + DEFINE_TASK _task; + BEGIN_CALL_IN_CONTEXT(hr, context, pDevInfo, &_task, context, this) HRESULT hr; ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCapture, _MediaCapture, pIMedCap, hr) if (SUCCEEDED(hr)) { @@ -2120,24 +2297,24 @@ long videoDevice::initDevice() } if (SUCCEEDED(hr)) WRL_PROP_PUT(pCapInitSet, StreamingCaptureMode, WRL_ENUM_GET(_StreamingCaptureMode, StreamingCaptureMode, Video), hr) - if (SUCCEEDED(hr)) { - vd_pMedCapFail = create_medcapfailedhandler([this, context](){ + if (SUCCEEDED(hr)) reinterpret_cast(DEREF_AGILE_WRL_OBJ(vd_pMedCap))->add_Failed(Microsoft::WRL::Callback([this, context](ABI::Windows::Media::Capture::IMediaCapture*, ABI::Windows::Media::Capture::IMediaCaptureFailedEventArgs*) -> HRESULT { HRESULT hr; BEGIN_CALL_IN_CONTEXT(hr, context, this) closeDevice(); - END_CALL_IN_CONTEXT(S_OK) - }); - } - if (SUCCEEDED(hr)) hr = vd_pMedCapFail->AddHandler(reinterpret_cast(DEREF_AGILE_WRL_OBJ(vd_pMedCap))); - if (SUCCEEDED(hr)) WRL_METHOD(vd_pMedCap, _InitializeWithSettingsAsync, pAction, hr, DEREF_WRL_OBJ(pCapInitSet)) + END_CALL_IN_CONTEXT_BASE + return hr; + }).Get(), &vd_cookie); + MAKE_WRL_OBJ(_AsyncAction) pAction; + if (SUCCEEDED(hr)) WRL_METHOD(vd_pMedCap, _InitializeWithSettingsAsync, *REF_WRL_OBJ(pAction), hr, DEREF_WRL_OBJ(pCapInitSet)) + if (SUCCEEDED(hr)) _task = CREATE_TASK DEFINE_RET_TYPE(void)(DEREF_WRL_OBJ(pAction)); } END_CALL_IN_CONTEXT(hr) - DO_ACTION_SYNCHRONOUSLY(hr, pAction, context); + _task.wait(); } END_CREATE_ASYNC(hr)); +#endif #else - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - ComPtr pAttributes = NULL; + _ComPtr pAttributes = NULL; IMFActivate *vd_pActivate = NULL; hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1); if (SUCCEEDED(hr)) @@ -2164,12 +2341,12 @@ long videoDevice::initDevice() } else { - DPO->printOut(L"VIDEODEVICE %i: Device there is not \n", vd_CurrentNumber); + DebugPrintOut(L"VIDEODEVICE %i: Device there is not \n", vd_CurrentNumber); } } else { - DPO->printOut(L"VIDEODEVICE %i: The attribute of video cameras cannot be getting \n", vd_CurrentNumber); + DebugPrintOut(L"VIDEODEVICE %i: The attribute of video cameras cannot be getting \n", vd_CurrentNumber); } #endif return hr; @@ -2199,17 +2376,18 @@ void videoDevice::closeDevice() vd_IsSetuped = false; #ifdef HAVE_WINRT +#ifdef HAVE_CONCURRENCY if (DEREF_AGILE_WRL_OBJ(vd_pMedCap)) { MAKE_WRL_REF(_AsyncAction) action; Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; vd_pImGr->stopGrabbing(&action); - vd_pMedCapFail->RemoveHandler(reinterpret_cast(DEREF_AGILE_WRL_OBJ(vd_pMedCap))); - SafeRelease(&vd_pMedCapFail); - vd_pAction = reinterpret_cast(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); + reinterpret_cast(DEREF_AGILE_WRL_OBJ(vd_pMedCap))->remove_Failed(vd_cookie); + vd_cookie.value = 0; + vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, action, pOldAction, this) + HRESULT hr = S_OK; + if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); + CREATE_TASK DEFINE_RET_TYPE(void)(action).wait(); RELEASE_WRL(vd_pMedCap) if(vd_LockOut == RawDataLock) { delete vd_pImGr; @@ -2219,9 +2397,10 @@ void videoDevice::closeDevice() END_CREATE_ASYNC(hr)); return; } +#endif #endif - vd_pSource->Stop(); + vd_pSource->Shutdown(); SafeRelease(&vd_pSource); if(vd_LockOut == RawDataLock) { @@ -2231,8 +2410,7 @@ void videoDevice::closeDevice() } vd_pImGrTh = NULL; vd_LockOut = OpenLock; - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"VIDEODEVICE %i: Device is stopped \n", vd_CurrentNumber); + DebugPrintOut(L"VIDEODEVICE %i: Device is stopped \n", vd_CurrentNumber); } } unsigned int videoDevice::getWidth() @@ -2249,6 +2427,15 @@ unsigned int videoDevice::getHeight() else return 0; } + +unsigned int videoDevice::getFrameRate() const +{ + if(vd_IsSetuped) + return vd_FrameRate; + else + return 0; +} + IMFMediaSource *videoDevice::getMediaSource() { IMFMediaSource *out = NULL; @@ -2261,17 +2448,26 @@ IMFMediaSource *videoDevice::getMediaSource() } int videoDevice::findType(unsigned int size, unsigned int frameRate) { - if(vd_CaptureFormats.size() == 0) - return 0; - FrameRateMap FRM = vd_CaptureFormats[size]; - if(FRM.size() == 0) - return 0; + // For required frame size look for the suitable video format. + // If not found, get the format for the largest available frame size. + FrameRateMap FRM; + std::map::const_iterator fmt; + fmt = vd_CaptureFormats.find(size); + if( fmt != vd_CaptureFormats.end() ) + FRM = fmt->second; + else + FRM = vd_CaptureFormats.rbegin()->second; + + if( FRM.empty() ) + return -1; + UINT64 frameRateMax = 0; SUBTYPEMap STMMax; if(frameRate == 0) { std::map::iterator f = FRM.begin(); for(; f != FRM.end(); f++) { + // Looking for highest possible frame rate. if((*f).first >= frameRateMax) { frameRateMax = (*f).first; @@ -2284,22 +2480,26 @@ int videoDevice::findType(unsigned int size, unsigned int frameRate) std::map::iterator f = FRM.begin(); for(; f != FRM.end(); f++) { - if((*f).first >= frameRateMax) - { - if(frameRate > (*f).first) - { - frameRateMax = (*f).first; - STMMax = (*f).second; - } - } + // Looking for frame rate higher that recently found but not higher then demanded. + if( (*f).first >= frameRateMax && (*f).first <= frameRate ) + { + frameRateMax = (*f).first; + STMMax = (*f).second; + } } } - if(STMMax.size() == 0) - return 0; - std::map::iterator S = STMMax.begin(); - vectorNum VN = (*S).second; - if(VN.size() == 0) - return 0; + // Get first (default) item from the list if no suitable frame rate found. + if( STMMax.empty() ) + STMMax = FRM.begin()->second; + + // Check if there are any format types on the list. + if( STMMax.empty() ) + return -1; + + vectorNum VN = STMMax.begin()->second; + if( VN.empty() ) + return -1; + return VN[0]; } @@ -2311,16 +2511,20 @@ void videoDevice::buildLibraryofTypes() int count = 0; for(; i != vd_CurrentFormats.end(); i++) { - size = (*i).MF_MT_FRAME_SIZE; - framerate = (*i).MF_MT_FRAME_RATE_NUMERATOR; - FrameRateMap FRM = vd_CaptureFormats[size]; - SUBTYPEMap STM = FRM[framerate]; - String subType((*i).pMF_MT_SUBTYPEName); - vectorNum VN = STM[subType]; - VN.push_back(count); - STM[subType] = VN; - FRM[framerate] = STM; - vd_CaptureFormats[size] = FRM; + // Count only supported video formats. + if( (*i).MF_MT_SUBTYPE == MFVideoFormat_RGB24 ) + { + size = (*i).MF_MT_FRAME_SIZE; + framerate = (*i).MF_MT_FRAME_RATE_NUMERATOR / (*i).MF_MT_FRAME_RATE_DENOMINATOR; + FrameRateMap FRM = vd_CaptureFormats[size]; + SUBTYPEMap STM = FRM[framerate]; + String subType((*i).pMF_MT_SUBTYPEName); + vectorNum VN = STM[subType]; + VN.push_back(count); + STM[subType] = VN; + FRM[framerate] = STM; + vd_CaptureFormats[size] = FRM; + } count++; } } @@ -2347,10 +2551,10 @@ long videoDevice::setDeviceFormat(MAKE_WRL_REF(_MediaCapture) pSource, unsigned long videoDevice::setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex) { - ComPtr pPD = NULL; - ComPtr pSD = NULL; - ComPtr pHandler = NULL; - ComPtr pType = NULL; + _ComPtr pPD = NULL; + _ComPtr pSD = NULL; + _ComPtr pHandler = NULL; + _ComPtr pType = NULL; HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf()); if (FAILED(hr)) { @@ -2393,8 +2597,7 @@ RawImage * videoDevice::getRawImageOut() return vd_pImGrTh->getImageGrabber()->getRawImage(); else { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"VIDEODEVICE %i: The instance of ImageGrabberThread class does not exist \n", vd_CurrentNumber); + DebugPrintOut(L"VIDEODEVICE %i: The instance of ImageGrabberThread class does not exist \n", vd_CurrentNumber); } return NULL; } @@ -2417,22 +2620,23 @@ bool videoDevice::isFrameNew() delete vd_pImGr; return false; } +#ifdef HAVE_CONCURRENCY Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; - SAVE_CURRENT_CONTEXT(context); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(action, pOldAction, context, this) - HRESULT hr; - if (pOldAction) DO_ACTION_SYNCHRONOUSLY(hr, pOldAction, GET_CURRENT_CONTEXT); - DO_ACTION_SYNCHRONOUSLY(hr, action, context); + DEFINE_TASK _task = CREATE_TASK DEFINE_RET_TYPE(void)(action); + vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, _task, pOldAction, this) + HRESULT hr = S_OK; + if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); + _task.wait(); END_CREATE_ASYNC(hr)); +#endif return true; } #endif HRESULT hr = ImageGrabberThread::CreateInstance(&vd_pImGrTh, vd_pSource, vd_CurrentNumber); if(FAILED(hr)) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"VIDEODEVICE %i: The instance of ImageGrabberThread class cannot be created.\n", vd_CurrentNumber); + DebugPrintOut(L"VIDEODEVICE %i: The instance of ImageGrabberThread class cannot be created.\n", vd_CurrentNumber); return false; } vd_pImGrTh->setEmergencyStopEvent(vd_userData, vd_func); @@ -2463,38 +2667,47 @@ bool videoDevice::isDeviceRawDataSource() bool videoDevice::setupDevice(unsigned int id) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if(!vd_IsSetuped) { - HRESULT hr = -1; - hr = initDevice(); + HRESULT hr = initDevice(); if(SUCCEEDED(hr)) { #ifdef HAVE_WINRT +#ifdef HAVE_CONCURRENCY Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; SAVE_CURRENT_CONTEXT(context); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(pOldAction, context, id, DPO, this) + vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, pOldAction, context, id, this) HRESULT hr; - if (pOldAction) DO_ACTION_SYNCHRONOUSLY(hr, pOldAction, GET_CURRENT_CONTEXT); + if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); +#endif #endif vd_Width = vd_CurrentFormats[id].width; vd_Height = vd_CurrentFormats[id].height; + vd_FrameRate = vd_CurrentFormats[id].MF_MT_FRAME_RATE_NUMERATOR / + vd_CurrentFormats[id].MF_MT_FRAME_RATE_DENOMINATOR; #ifdef HAVE_WINRT +#ifdef HAVE_CONCURRENCY 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); + DEFINE_TASK _task; + BEGIN_CALL_IN_CONTEXT(hr, context, id, &_task, this) + MAKE_WRL_REF(_AsyncAction) pAction; + HRESULT hr = setDeviceFormat(DEREF_AGILE_WRL_OBJ(vd_pMedCap), (DWORD) id, &pAction); + if (SUCCEEDED(hr)) _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction); + END_CALL_IN_CONTEXT(hr) + if (SUCCEEDED(hr)) _task.wait(); } else +#endif #endif hr = setDeviceFormat(vd_pSource, (DWORD) id); vd_IsSetuped = (SUCCEEDED(hr)); if(vd_IsSetuped) - DPO->printOut(L"\n\nVIDEODEVICE %i: Device is setuped \n", vd_CurrentNumber); + DebugPrintOut(L"\n\nVIDEODEVICE %i: Device is setuped \n", vd_CurrentNumber); vd_PrevParametrs = getParametrs(); #ifdef HAVE_WINRT +#ifdef HAVE_CONCURRENCY END_CREATE_ASYNC(hr)); +#endif return true; #else return vd_IsSetuped; @@ -2502,13 +2715,13 @@ bool videoDevice::setupDevice(unsigned int id) } else { - DPO->printOut(L"VIDEODEVICE %i: Interface IMFMediaSource cannot be got \n", vd_CurrentNumber); + DebugPrintOut(L"VIDEODEVICE %i: Interface IMFMediaSource cannot be got \n", vd_CurrentNumber); return false; } } else { - DPO->printOut(L"VIDEODEVICE %i: Device is setuped already \n", vd_CurrentNumber); + DebugPrintOut(L"VIDEODEVICE %i: Device is setuped already \n", vd_CurrentNumber); return false; } } @@ -2516,6 +2729,9 @@ bool videoDevice::setupDevice(unsigned int id) bool videoDevice::setupDevice(unsigned int w, unsigned int h, unsigned int idealFramerate) { unsigned int id = findType(w * h, idealFramerate); + if( id < 0 ) + return false; + return setupDevice(id); } @@ -2554,7 +2770,7 @@ HRESULT videoDevice::enumerateCaptureFormats(MAKE_WRL_REF(_MediaCapture) pSource MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps; WRL_METHOD(pVector, GetAt, pMedEncProps, hr, i) if (FAILED(hr)) return hr; - ComPtr pType = NULL; + _ComPtr pType = NULL; hr = MediaSink::ConvertPropertiesToMediaType(DEREF_AS_NATIVE_WRL_OBJ(ABI::Windows::Media::MediaProperties::IMediaEncodingProperties, pMedEncProps), &pType); if (FAILED(hr)) return hr; MediaType MT = FormatReader::Read(pType.Get()); @@ -2566,10 +2782,10 @@ HRESULT videoDevice::enumerateCaptureFormats(MAKE_WRL_REF(_MediaCapture) pSource HRESULT videoDevice::enumerateCaptureFormats(IMFMediaSource *pSource) { - ComPtr pPD = NULL; - ComPtr pSD = NULL; - ComPtr pHandler = NULL; - ComPtr pType = NULL; + _ComPtr pPD = NULL; + _ComPtr pSD = NULL; + _ComPtr pHandler = NULL; + _ComPtr pType = NULL; HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf()); if (FAILED(hr)) { @@ -2649,11 +2865,12 @@ long videoDevices::initDevices(_DeviceClass devClass) MAKE_WRL_REF(_AsyncOperation) pAction; WRL_METHOD(pDevStat, _FindAllAsyncDeviceClass, pAction, hr, devClass) if (SUCCEEDED(hr)) { +#ifdef HAVE_CONCURRENCY SAVE_CURRENT_CONTEXT(context); - vds_enumTask = reinterpret_cast(BEGIN_CREATE_ASYNC(pAction, context, this) - HRESULT hr; - MAKE_WRL_OBJ(_VectorView) pVector; - DO_OPERATION_SYNCHRONOUSLY_VECTOR(hr, pAction, GET_CURRENT_CONTEXT, pVector, _VectorView, _DeviceInformation, _DeviceInformationCollection); + vds_enumTask = reinterpret_cast(BEGIN_CREATE_ASYNC(void, pAction, context, this) + HRESULT hr = S_OK; + MAKE_WRL_OBJ(_VectorView) pVector = + CREATE_TASK DEFINE_RET_TYPE(MAKE_WRL_REF(_VectorView))(pAction).get(); if (SUCCEEDED(hr)) WRL_PROP_GET(pVector, Size, count, hr) if (SUCCEEDED(hr) && count > 0) { for (UINT32 i = 0; i < count; i++) { @@ -2663,22 +2880,22 @@ long videoDevices::initDevices(_DeviceClass devClass) 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) + END_CALL_IN_CONTEXT_BASE vds_Devices.push_back(vd); } } } END_CREATE_ASYNC(hr)); +#endif } return hr; } #else long videoDevices::initDevices(IMFAttributes *pAttributes) { - HRESULT hr = S_OK; clearDevices(); IMFActivate **ppDevices = NULL; - hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count); + HRESULT hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count); if (SUCCEEDED(hr)) { if(count > 0) @@ -2693,12 +2910,11 @@ long videoDevices::initDevices(IMFAttributes *pAttributes) SafeRelease(ppDevices); } else - hr = -1; + hr = E_INVALIDARG; } else { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"VIDEODEVICES: The instances of the videoDevice class cannot be created\n"); + DebugPrintOut(L"VIDEODEVICES: The instances of the videoDevice class cannot be created\n"); } return hr; } @@ -2768,56 +2984,50 @@ void MediaType::Clear() videoInput::videoInput(void): accessToDevices(false) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"\n***** VIDEOINPUT LIBRARY - 2013 (Author: Evgeny Pereguda) *****\n\n"); + DebugPrintOut(L"\n***** VIDEOINPUT LIBRARY - 2013 (Author: Evgeny Pereguda) *****\n\n"); updateListOfDevices(); if(!accessToDevices) - DPO->printOut(L"INITIALIZATION: There is not any suitable video device\n"); + DebugPrintOut(L"INITIALIZATION: There is not any suitable video device\n"); } void videoInput::updateListOfDevices() { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); Media_Foundation *MF = &Media_Foundation::getInstance(); accessToDevices = MF->buildListOfDevices(); if(!accessToDevices) - DPO->printOut(L"UPDATING: There is not any suitable video device\n"); + DebugPrintOut(L"UPDATING: There is not any suitable video device\n"); } videoInput::~videoInput(void) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"\n***** CLOSE VIDEOINPUT LIBRARY - 2013 *****\n\n"); + DebugPrintOut(L"\n***** CLOSE VIDEOINPUT LIBRARY - 2013 *****\n\n"); } IMFMediaSource *videoInput::getMediaSource(int deviceID) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if(accessToDevices) { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); + videoDevice * VD = videoDevices::getInstance().getDevice(deviceID); if(VD) { IMFMediaSource *out = VD->getMediaSource(); if(!out) - DPO->printOut(L"VideoDevice %i: There is not any suitable IMFMediaSource interface\n", deviceID); + DebugPrintOut(L"VideoDevice %i: There is not any suitable IMFMediaSource interface\n", deviceID); return out; } } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return NULL; } bool videoInput::setupDevice(int deviceID, unsigned int id) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0 ) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return false; } if(accessToDevices) @@ -2828,23 +3038,22 @@ bool videoInput::setupDevice(int deviceID, unsigned int id) { bool out = VD->setupDevice(id); if(!out) - DPO->printOut(L"VIDEODEVICE %i: This device cannot be started\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: This device cannot be started\n", deviceID); return out; } } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return false; } bool videoInput::setupDevice(int deviceID, unsigned int w, unsigned int h, unsigned int idealFramerate) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0 ) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return false; } if(accessToDevices) @@ -2855,23 +3064,22 @@ bool videoInput::setupDevice(int deviceID, unsigned int w, unsigned int h, unsig { bool out = VD->setupDevice(w, h, idealFramerate); if(!out) - DPO->printOut(L"VIDEODEVICE %i: this device cannot be started\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: this device cannot be started\n", deviceID); return out; } } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n", deviceID); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n", deviceID); } return false; } MediaType videoInput::getFormat(int deviceID, unsigned int id) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return MediaType(); } if(accessToDevices) @@ -2883,17 +3091,16 @@ MediaType videoInput::getFormat(int deviceID, unsigned int id) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return MediaType(); } bool videoInput::isDeviceSetup(int deviceID) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return false; } if(accessToDevices) @@ -2905,17 +3112,16 @@ bool videoInput::isDeviceSetup(int deviceID) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return false; } bool videoInput::isDeviceMediaSource(int deviceID) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return false; } if(accessToDevices) @@ -2927,17 +3133,16 @@ bool videoInput::isDeviceMediaSource(int deviceID) } else { - DPO->printOut(L"Device(s): There is not any suitable video device\n"); + DebugPrintOut(L"Device(s): There is not any suitable video device\n"); } return false; } bool videoInput::isDeviceRawDataSource(int deviceID) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return false; } if(accessToDevices) @@ -2952,17 +3157,16 @@ bool videoInput::isDeviceRawDataSource(int deviceID) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return false; } bool videoInput::isFrameNew(int deviceID) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return false; } if(accessToDevices) @@ -2981,7 +3185,7 @@ bool videoInput::isFrameNew(int deviceID) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return false; } @@ -2989,10 +3193,9 @@ bool videoInput::isFrameNew(int deviceID) #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); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return; } if(accessToDevices) @@ -3011,7 +3214,7 @@ void videoInput::waitForDevice(int deviceID) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return; } @@ -3019,10 +3222,9 @@ void videoInput::waitForDevice(int deviceID) unsigned int videoInput::getCountFormats(int deviceID) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return 0; } if(accessToDevices) @@ -3034,7 +3236,7 @@ unsigned int videoInput::getCountFormats(int deviceID) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return 0; } @@ -3048,10 +3250,9 @@ void videoInput::closeAllDevices() void videoInput::setParametrs(int deviceID, CamParametrs parametrs) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return; } if(accessToDevices) @@ -3063,17 +3264,16 @@ void videoInput::setParametrs(int deviceID, CamParametrs parametrs) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } } CamParametrs videoInput::getParametrs(int deviceID) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); CamParametrs out; if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return out; } if(accessToDevices) @@ -3085,17 +3285,16 @@ CamParametrs videoInput::getParametrs(int deviceID) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return out; } void videoInput::closeDevice(int deviceID) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return; } if(accessToDevices) @@ -3107,16 +3306,15 @@ void videoInput::closeDevice(int deviceID) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } } unsigned int videoInput::getWidth(int deviceID) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return 0; } if(accessToDevices) @@ -3128,17 +3326,16 @@ unsigned int videoInput::getWidth(int deviceID) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return 0; } unsigned int videoInput::getHeight(int deviceID) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return 0; } if(accessToDevices) @@ -3150,17 +3347,36 @@ unsigned int videoInput::getHeight(int deviceID) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + } + return 0; +} + +unsigned int videoInput::getFrameRate(int deviceID) const +{ + if (deviceID < 0) + { + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + return 0; + } + if(accessToDevices) + { + videoDevice * VD = videoDevices::getInstance().getDevice(deviceID); + if(VD) + return VD->getFrameRate(); + } + else + { + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return 0; } wchar_t *videoInput::getNameVideoDevice(int deviceID) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return NULL; } if(accessToDevices) @@ -3172,14 +3388,13 @@ wchar_t *videoInput::getNameVideoDevice(int deviceID) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return L"Empty"; } unsigned int videoInput::listDevices(bool silent) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); int out = 0; if(accessToDevices) { @@ -3188,18 +3403,17 @@ unsigned int videoInput::listDevices(bool silent) VDS->waitInit(); #endif out = VDS->getCount(); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - if(!silent)DPO->printOut(L"\nVIDEOINPUT SPY MODE!\n\n"); - if(!silent)DPO->printOut(L"SETUP: Looking For Capture Devices\n"); + if(!silent) DebugPrintOut(L"\nVIDEOINPUT SPY MODE!\n\n"); + if(!silent) DebugPrintOut(L"SETUP: Looking For Capture Devices\n"); for(int i = 0; i < out; i++) { - if(!silent)DPO->printOut(L"SETUP: %i) %s \n",i, getNameVideoDevice(i)); + if(!silent) DebugPrintOut(L"SETUP: %i) %s \n",i, getNameVideoDevice(i)); } - if(!silent)DPO->printOut(L"SETUP: %i Device(s) found\n\n", out); + if(!silent) DebugPrintOut(L"SETUP: %i Device(s) found\n\n", out); } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return out; } @@ -3215,18 +3429,19 @@ bool videoInput::isDevicesAcceable() return accessToDevices; } +#ifdef _DEBUG void videoInput::setVerbose(bool state) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->setVerbose(state); + DPO *dpo = &DPO::getInstance(); + dpo->setVerbose(state); } +#endif void videoInput::setEmergencyStopEvent(int deviceID, void *userData, void(*func)(int, void *)) { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return; } if(accessToDevices) @@ -3241,18 +3456,16 @@ void videoInput::setEmergencyStopEvent(int deviceID, void *userData, void(*func) } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } } bool videoInput::getPixels(int deviceID, unsigned char * dstBuffer, bool flipRedAndBlue, bool flipImage) { bool success = false; - unsigned int bytes = 3; - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); if (deviceID < 0) { - DPO->printOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); + DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); return success; } if(accessToDevices) @@ -3260,14 +3473,14 @@ bool videoInput::getPixels(int deviceID, unsigned char * dstBuffer, bool flipRed bool isRaw = isDeviceRawDataSource(deviceID); if(isRaw) { - videoDevices *VDS = &videoDevices::getInstance(); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - RawImage *RIOut = VDS->getDevice(deviceID)->getRawImageOut(); + videoDevice *VD = videoDevices::getInstance().getDevice(deviceID); + RawImage *RIOut = VD->getRawImageOut(); if(RIOut) { - unsigned int height = VDS->getDevice(deviceID)->getHeight(); - unsigned int width = VDS->getDevice(deviceID)->getWidth(); - unsigned int size = bytes * width * height; + const unsigned int bytes = 3; + const unsigned int height = VD->getHeight(); + const unsigned int width = VD->getWidth(); + const unsigned int size = bytes * width * height; if(size == RIOut->getSize()) { processPixels(RIOut->getpPixels(), dstBuffer, width, height, bytes, flipRedAndBlue, flipImage); @@ -3275,22 +3488,22 @@ bool videoInput::getPixels(int deviceID, unsigned char * dstBuffer, bool flipRed } else { - DPO->printOut(L"ERROR: GetPixels() - bufferSizes do not match!\n"); + DebugPrintOut(L"ERROR: GetPixels() - bufferSizes do not match!\n"); } } else { - DPO->printOut(L"ERROR: GetPixels() - Unable to grab frame for device %i\n", deviceID); + DebugPrintOut(L"ERROR: GetPixels() - Unable to grab frame for device %i\n", deviceID); } } else { - DPO->printOut(L"ERROR: GetPixels() - Not raw data source device %i\n", deviceID); + DebugPrintOut(L"ERROR: GetPixels() - Not raw data source device %i\n", deviceID); } } else { - DPO->printOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); + DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); } return success; } @@ -3377,17 +3590,21 @@ protected: IplImage* frame; videoInput VI; #ifdef HAVE_WINRT +#ifdef HAVE_CONCURRENCY DEFINE_TASK openTask; Concurrency::critical_section lock; #endif +#endif }; +#ifdef _DEBUG struct SuppressVideoInputMessages { SuppressVideoInputMessages() { videoInput::setVerbose(true); } }; static SuppressVideoInputMessages do_it; +#endif CvCaptureCAM_MSMF::CvCaptureCAM_MSMF(): index(-1), @@ -3421,8 +3638,10 @@ void CvCaptureCAM_MSMF::close() bool CvCaptureCAM_MSMF::open( int _index ) { #ifdef HAVE_WINRT +#ifdef HAVE_CONCURRENCY SAVE_CURRENT_CONTEXT(context); - auto func = [_index, context, this]() -> bool { + auto func = [_index, context, this](DEFINE_RET_VAL(bool)) -> DEFINE_RET_FORMAL(bool) { +#endif #endif int try_index = _index; int devices = 0; @@ -3433,14 +3652,18 @@ bool CvCaptureCAM_MSMF::open( int _index ) try_index = try_index < 0 ? 0 : (try_index > devices-1 ? devices-1 : try_index); #ifdef HAVE_WINRT HRESULT hr; +#ifdef HAVE_CONCURRENCY BEGIN_CALL_IN_CONTEXT(hr, context, this, try_index) #endif - VI.setupDevice(try_index); +#endif + VI.setupDevice(try_index, 0, 0, 0); // With maximum frame size. #ifdef HAVE_WINRT - END_CALL_IN_CONTEXT(S_OK) +#ifdef HAVE_CONCURRENCY + END_CALL_IN_CONTEXT_BASE VI.waitForDevice(try_index); BEGIN_CALL_IN_CONTEXT(hr, context, this, try_index) HRESULT hr = S_OK; +#endif #endif if( !VI.isFrameNew(try_index) ) #ifdef HAVE_WINRT @@ -3450,11 +3673,13 @@ bool CvCaptureCAM_MSMF::open( int _index ) #endif index = try_index; #ifdef HAVE_WINRT - END_CALL_IN_CONTEXT(hr); - return true; +#ifdef HAVE_CONCURRENCY + END_CALL_IN_CONTEXT_BASE + RET_VAL(true) }; Concurrency::critical_section::scoped_lock _LockHolder(lock); CREATE_OR_CONTINUE_TASK(openTask, bool, func) +#endif #endif return true; } @@ -3468,11 +3693,12 @@ bool CvCaptureCAM_MSMF::grabFrame() IplImage* CvCaptureCAM_MSMF::retrieveFrame(int) { - if( !frame || (int)VI.getWidth(index) != frame->width || (int)VI.getHeight(index) != frame->height ) + const int w = (int)VI.getWidth(index); + const int h = (int)VI.getHeight(index); + if( !frame || w != frame->width || h != frame->height ) { if (frame) cvReleaseImage( &frame ); - unsigned int w = VI.getWidth(index), h = VI.getHeight(index); frame = cvCreateImage( cvSize(w,h), 8, 3 ); } VI.getPixels( index, (uchar*)frame->imageData, false, true ); @@ -3488,33 +3714,47 @@ double CvCaptureCAM_MSMF::getProperty( int property_id ) return VI.getWidth(index); case CV_CAP_PROP_FRAME_HEIGHT: return VI.getHeight(index); + case CV_CAP_PROP_FPS: + return VI.getFrameRate(index); + default: + break; } - return -1; + return 0; } bool CvCaptureCAM_MSMF::setProperty( int property_id, double value ) { // image capture properties + unsigned int fps = 0; bool handled = false; switch( property_id ) { case CV_CAP_PROP_FRAME_WIDTH: width = cvRound(value); + fps = VI.getFrameRate(index); handled = true; break; case CV_CAP_PROP_FRAME_HEIGHT: height = cvRound(value); + fps = VI.getFrameRate(index); handled = true; break; + case CV_CAP_PROP_FPS: + width = (int)VI.getHeight(index); + height = (int)VI.getWidth(index); + fps = cvRound(value); + break; } if ( handled ) { if( width > 0 && height > 0 ) { - if( width != (int)VI.getWidth(index) || height != (int)VI.getHeight(index) && VI.isDeviceSetup(index))//|| fourcc != VI.getFourcc(index) ) + if( (width != (int)VI.getWidth(index) || height != (int)VI.getHeight(index) || fps != VI.getFrameRate(index)) + && VI.isDeviceSetup(index))//|| fourcc != VI.getFourcc(index) ) { VI.closeDevice(index); - VI.setupDevice(index, width, height); + VI.setupDevice(index, width, height, fps); } + width = height = -1; return VI.isDeviceSetup(index); } return true; @@ -3573,14 +3813,12 @@ bool CvCaptureFile_MSMF::open(const char* filename) wchar_t* unicodeFileName = new wchar_t[strlen(filename)+1]; MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, (int)strlen(filename)+1); - HRESULT hr = S_OK; - MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID; - ComPtr pSourceResolver = NULL; + _ComPtr pSourceResolver = NULL; IUnknown* pUnkSource = NULL; - hr = MFCreateSourceResolver(pSourceResolver.GetAddressOf()); + HRESULT hr = MFCreateSourceResolver(pSourceResolver.GetAddressOf()); if (SUCCEEDED(hr)) { @@ -3714,10 +3952,10 @@ IplImage* CvCaptureFile_MSMF::retrieveFrame(int) HRESULT CvCaptureFile_MSMF::enumerateCaptureFormats(IMFMediaSource *pSource) { - ComPtr pPD = NULL; - ComPtr pSD = NULL; - ComPtr pHandler = NULL; - ComPtr pType = NULL; + _ComPtr pPD = NULL; + _ComPtr pSD = NULL; + _ComPtr pHandler = NULL; + _ComPtr pType = NULL; HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf()); if (FAILED(hr)) { @@ -3834,7 +4072,7 @@ private: GUID inputFormat; DWORD streamIndex; - ComPtr sinkWriter; + _ComPtr sinkWriter; bool initiated; @@ -3874,8 +4112,10 @@ const GUID CvVideoWriter_MSMF::FourCC2GUID(int fourcc) return MFVideoFormat_DVSD; break; case CV_FOURCC_MACRO('d', 'v', 's', 'l'): return MFVideoFormat_DVSL; break; - case CV_FOURCC_MACRO('H', '2', '6', '3'): +#if (WINVER >= _WIN32_WINNT_WIN8) + case CV_FOURCC_MACRO('H', '2', '6', '3'): // Available only for Win 8 target. return MFVideoFormat_H263; break; +#endif case CV_FOURCC_MACRO('H', '2', '6', '4'): return MFVideoFormat_H264; break; case CV_FOURCC_MACRO('M', '4', 'S', '2'): @@ -3985,10 +4225,10 @@ bool CvVideoWriter_MSMF::writeFrame(const IplImage* img) HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename) { - ComPtr spAttr; - ComPtr mediaTypeOut; - ComPtr mediaTypeIn; - ComPtr spByteStream; + _ComPtr spAttr; + _ComPtr mediaTypeOut; + _ComPtr mediaTypeIn; + _ComPtr spByteStream; MFCreateAttributes(&spAttr, 10); spAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true); @@ -4085,8 +4325,8 @@ HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename) HRESULT CvVideoWriter_MSMF::WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& Start, const LONGLONG& Duration) { - ComPtr sample; - ComPtr buffer; + _ComPtr sample; + _ComPtr buffer; const LONG cbWidth = 4 * videoWidth; const DWORD cbBuffer = cbWidth * videoHeight; diff --git a/modules/highgui/src/cap_msmf.hpp b/modules/highgui/src/cap_msmf.hpp index c212ca910..bf3741b7d 100644 --- a/modules/highgui/src/cap_msmf.hpp +++ b/modules/highgui/src/cap_msmf.hpp @@ -1,6 +1,206 @@ #ifdef HAVE_WINRT #define ICustomStreamSink StreamSink -#include "ppltasks_winrt.h" +#ifndef __cplusplus_winrt + +#define __is_winrt_array(type) (type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt8Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_Int16Array ||\ + type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt16Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_Int32Array ||\ + type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt32Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_Int64Array ||\ + type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt64Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_SingleArray ||\ + type == ABI::Windows::Foundation::PropertyType::PropertyType_DoubleArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_Char16Array ||\ + type == ABI::Windows::Foundation::PropertyType::PropertyType_BooleanArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_StringArray ||\ + type == ABI::Windows::Foundation::PropertyType::PropertyType_InspectableArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_DateTimeArray ||\ + type == ABI::Windows::Foundation::PropertyType::PropertyType_TimeSpanArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_GuidArray ||\ + type == ABI::Windows::Foundation::PropertyType::PropertyType_PointArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_SizeArray ||\ + type == ABI::Windows::Foundation::PropertyType::PropertyType_RectArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_OtherTypeArray) + +template::value> +struct winrt_type +{ +}; +template +struct winrt_type<_Type, true> +{ + static IUnknown* create(_Type* _ObjInCtx) { + return reinterpret_cast(_ObjInCtx); + } + static IID getuuid() { return __uuidof(_Type); } + static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_OtherType; +}; +template +struct winrt_type<_Type, false> +{ + static IUnknown* create(_Type* _ObjInCtx) { + Microsoft::WRL::ComPtr _PObj; + Microsoft::WRL::ComPtr 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 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(_PObj.Detach()); + } + return nullptr; + } + static IID getuuid() { return __uuidof(ABI::Windows::Foundation::IPropertyValue); } + static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_OtherType; +}; + +template<> +struct winrt_type +{ + static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, void* _ObjInCtx, IInspectable** ppInsp) { + (void)_ObjInCtx; + return spPropVal->CreateEmpty(ppInsp); + } + static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty; +}; +#define MAKE_TYPE(Type, Name) template<>\ +struct winrt_type\ +{\ + static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, Type* _ObjInCtx, IInspectable** ppInsp) {\ + return spPropVal->Create##Name(*_ObjInCtx, ppInsp);\ +}\ + static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_##Name;\ +}; + +template +struct winrt_array_type +{ + static IUnknown* create(_Type* _ObjInCtx, size_t N) { + Microsoft::WRL::ComPtr _PObj; + Microsoft::WRL::ComPtr 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 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(_PObj.Detach()); + } + return nullptr; + } + static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_OtherTypeArray; +}; +template +struct winrt_prop_type {}; + +template <> +struct winrt_prop_type { + typedef void _Type; +}; + +template <> +struct winrt_prop_type { + typedef void _Type; +}; + +template <> +struct winrt_prop_type { + typedef void _Type; +}; + +#define MAKE_PROP(Prop, Type) template <>\ +struct winrt_prop_type {\ + typedef Type _Type;\ +}; + +#define MAKE_ARRAY_TYPE(Type, Name) MAKE_PROP(Name, Type)\ + MAKE_PROP(Name##Array, Type*)\ + MAKE_TYPE(Type, Name)\ + template<>\ +struct winrt_array_type\ +{\ + static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, Type** _ObjInCtx, IInspectable** ppInsp) {\ + return spPropVal->Create##Name##Array(__valueSize, *_ObjInCtx, ppInsp);\ +}\ + static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_##Name##Array;\ + static std::vector PropertyValueToVector(ABI::Windows::Foundation::IPropertyValue* propValue)\ +{\ + UINT32 uLen = 0;\ + Type* pArray = nullptr;\ + propValue->Get##Name##Array(&uLen, &pArray);\ + return std::vector(pArray, pArray + uLen);\ +}\ +}; +MAKE_ARRAY_TYPE(BYTE, UInt8) +MAKE_ARRAY_TYPE(INT16, Int16) +MAKE_ARRAY_TYPE(UINT16, UInt16) +MAKE_ARRAY_TYPE(INT32, Int32) +MAKE_ARRAY_TYPE(UINT32, UInt32) +MAKE_ARRAY_TYPE(INT64, Int64) +MAKE_ARRAY_TYPE(UINT64, UInt64) +MAKE_ARRAY_TYPE(FLOAT, Single) +MAKE_ARRAY_TYPE(DOUBLE, Double) +MAKE_ARRAY_TYPE(WCHAR, Char16) +//MAKE_ARRAY_TYPE(boolean, Boolean) //conflict with identical type in C++ of BYTE/UInt8 +MAKE_ARRAY_TYPE(HSTRING, String) +MAKE_ARRAY_TYPE(IInspectable*, Inspectable) +MAKE_ARRAY_TYPE(GUID, Guid) +MAKE_ARRAY_TYPE(ABI::Windows::Foundation::DateTime, DateTime) +MAKE_ARRAY_TYPE(ABI::Windows::Foundation::TimeSpan, TimeSpan) +MAKE_ARRAY_TYPE(ABI::Windows::Foundation::Point, Point) +MAKE_ARRAY_TYPE(ABI::Windows::Foundation::Size, Size) +MAKE_ARRAY_TYPE(ABI::Windows::Foundation::Rect, Rect) + +template < typename T > +struct DerefHelper +{ + typedef T DerefType; +}; + +template < typename T > +struct DerefHelper +{ + typedef T DerefType; +}; + +#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_base_of::value || \ + std::is_base_of::DerefType>::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) +#endif #else EXTERN_C const IID IID_ICustomStreamSink; @@ -178,12 +378,33 @@ MAKE_MAP(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypeMap(StreamSinkMarkerTypeP #ifdef HAVE_WINRT +#ifdef __cplusplus_winrt +#define _ContextCallback Concurrency::details::_ContextCallback +#define BEGIN_CALL_IN_CONTEXT(hr, var, ...) hr = S_OK;\ + var._CallInContext([__VA_ARGS__]() { +#define END_CALL_IN_CONTEXT(hr) if (FAILED(hr)) throw Platform::Exception::CreateException(hr);\ +}); +#define END_CALL_IN_CONTEXT_BASE }); +#else +#define _ContextCallback Concurrency_winrt::details::_ContextCallback +#define BEGIN_CALL_IN_CONTEXT(hr, var, ...) hr = var._CallInContext([__VA_ARGS__]() -> HRESULT { +#define END_CALL_IN_CONTEXT(hr) return hr;\ +}); +#define END_CALL_IN_CONTEXT_BASE return S_OK;\ +}); +#endif +#define GET_CURRENT_CONTEXT _ContextCallback::_CaptureCurrent() +#define SAVE_CURRENT_CONTEXT(var) _ContextCallback var = GET_CURRENT_CONTEXT + +#define COMMA , + #ifdef __cplusplus_winrt #define _Object Platform::Object^ #define _ObjectObj Platform::Object^ #define _String Platform::String^ #define _StringObj Platform::String^ #define _StringReference ref new Platform::String +#define _StringReferenceObj Platform::String^ #define _DeviceInformationCollection Windows::Devices::Enumeration::DeviceInformationCollection #define _MediaCapture Windows::Media::Capture::MediaCapture #define _MediaCaptureVideoPreview Windows::Media::Capture::MediaCapture @@ -193,6 +414,7 @@ MAKE_MAP(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypeMap(StreamSinkMarkerTypeP #define _MediaEncodingProperties Windows::Media::MediaProperties::IMediaEncodingProperties #define _VideoEncodingProperties Windows::Media::MediaProperties::VideoEncodingProperties #define _MediaStreamType Windows::Media::Capture::MediaStreamType +#define _AsyncInfo Windows::Foundation::IAsyncInfo #define _AsyncAction Windows::Foundation::IAsyncAction #define _AsyncOperation Windows::Foundation::IAsyncOperation #define _DeviceClass Windows::Devices::Enumeration::DeviceClass @@ -209,29 +431,37 @@ MAKE_MAP(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypeMap(StreamSinkMarkerTypeP #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(action), ctxt) -#define DO_OPERATION_SYNCHRONOUSLY_VECTOR(hr, action, ctxt, pResult, vectortype, elementtype, _type) hr = S_OK;\ -pResult = CCompletionHandler::PerformSynchronously<_type^>(reinterpret_cast^>(action), ctxt) -#define BEGIN_CREATE_ASYNC(...) reinterpret_cast(Concurrency::create_async([__VA_ARGS__]() { +#define BEGIN_CREATE_ASYNC(type, ...) (Concurrency::create_async([__VA_ARGS__]() { #define END_CREATE_ASYNC(hr) if (FAILED(hr)) throw Platform::Exception::CreateException(hr);\ })) #define DEFINE_TASK Concurrency::task #define CREATE_TASK Concurrency::create_task #define CREATE_OR_CONTINUE_TASK(_task, rettype, func) _task = (_task == Concurrency::task()) ? Concurrency::create_task(func) : _task.then([func](rettype) -> rettype { return func(); }); +#define DEFINE_RET_VAL(x) +#define DEFINE_RET_TYPE(x) +#define DEFINE_RET_FORMAL(x) x +#define RET_VAL(x) return x; +#define RET_VAL_BASE +#define MAKE_STRING(str) str +#define GET_STL_STRING(str) std::wstring(str->Data()) +#define GET_STL_STRING_RAW(str) std::wstring(str->Data()) #define MAKE_WRL_OBJ(x) x^ #define MAKE_WRL_REF(x) x^ +#define MAKE_OBJ_REF(x) x^ #define MAKE_WRL_AGILE_REF(x) Platform::Agile +#define MAKE_PROPERTY_BACKING(Type, PropName) property Type PropName; +#define MAKE_PROPERTY(Type, PropName, PropValue) +#define MAKE_PROPERTY_STRING(Type, PropName, PropValue) +#define MAKE_READONLY_PROPERTY(Type, PropName, PropValue) property Type PropName\ +{\ + Type get() { return PropValue; }\ +} +#define THROW_INVALID_ARG throw ref new Platform::InvalidArgumentException(); #define RELEASE_AGILE_WRL(x) x = nullptr; #define RELEASE_WRL(x) x = nullptr; #define GET_WRL_OBJ_FROM_REF(objtype, obj, orig, hr) objtype^ obj = orig;\ hr = S_OK; -#define GET_WRL_OBJ_FROM_OBJ(objtype, obj, orig, hr) objtype^ obj = orig;\ +#define GET_WRL_OBJ_FROM_OBJ(objtype, obj, orig, hr) objtype^ obj = safe_cast(orig);\ hr = S_OK; #define WRL_ENUM_GET(obj, prefix, prop) obj::##prop #define WRL_PROP_GET(obj, prop, arg, hr) arg = obj->##prop;\ @@ -242,11 +472,18 @@ hr = S_OK; hr = S_OK; #define WRL_METHOD(obj, method, ret, hr, ...) ret = obj->##method(__VA_ARGS__);\ hr = S_OK; +#define WRL_METHOD_NORET_BASE(obj, method, hr) obj->##method();\ + hr = S_OK; +#define WRL_METHOD_NORET(obj, method, hr, ...) obj->##method(__VA_ARGS__);\ + hr = S_OK; #define REF_WRL_OBJ(obj) &obj #define DEREF_WRL_OBJ(obj) obj #define DEREF_AGILE_WRL_OBJ(obj) obj.Get() #define DEREF_AS_NATIVE_WRL_OBJ(type, obj) reinterpret_cast(obj) #define PREPARE_TRANSFER_WRL_OBJ(obj) obj +#define ACTIVATE_LOCAL_OBJ_BASE(objtype) ref new objtype() +#define ACTIVATE_LOCAL_OBJ(objtype, ...) ref new objtype(__VA_ARGS__) +#define ACTIVATE_EVENT_HANDLER(objtype, ...) ref new objtype(__VA_ARGS__) #define ACTIVATE_OBJ(rtclass, objtype, obj, hr) MAKE_WRL_OBJ(objtype) obj = ref new objtype();\ hr = S_OK; #define ACTIVATE_STATIC_OBJ(rtclass, objtype, obj, hr) objtype obj;\ @@ -257,6 +494,7 @@ hr = S_OK; #define _String HSTRING #define _StringObj Microsoft::WRL::Wrappers::HString #define _StringReference Microsoft::WRL::Wrappers::HStringReference +#define _StringReferenceObj Microsoft::WRL::Wrappers::HStringReference #define _DeviceInformationCollection ABI::Windows::Devices::Enumeration::DeviceInformationCollection #define _MediaCapture ABI::Windows::Media::Capture::IMediaCapture #define _MediaCaptureVideoPreview ABI::Windows::Media::Capture::IMediaCaptureVideoPreview @@ -266,6 +504,7 @@ hr = S_OK; #define _MediaEncodingProperties ABI::Windows::Media::MediaProperties::IMediaEncodingProperties #define _VideoEncodingProperties ABI::Windows::Media::MediaProperties::IVideoEncodingProperties #define _MediaStreamType ABI::Windows::Media::Capture::MediaStreamType +#define _AsyncInfo ABI::Windows::Foundation::IAsyncInfo #define _AsyncAction ABI::Windows::Foundation::IAsyncAction #define _AsyncOperation ABI::Windows::Foundation::IAsyncOperation #define _DeviceClass ABI::Windows::Devices::Enumeration::DeviceClass @@ -282,21 +521,32 @@ hr = S_OK; #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::PerformActionSynchronously(action, ctxt) -#define DO_OPERATION_SYNCHRONOUSLY_VECTOR(hr, action, ctxt, pResult, vectortype, elementtype, _type) hr = CCompletionHandler, ABI::Windows::Foundation::IAsyncOperation<_type*>>::PerformSynchronously*>(action, ctxt, pResult.GetAddressOf()) -#define BEGIN_CREATE_ASYNC(...) Concurrency_winrt::create_async([__VA_ARGS__]() -> HRESULT { +#define BEGIN_CREATE_ASYNC(type, ...) Concurrency_winrt::create_async([__VA_ARGS__]() -> HRESULT { #define END_CREATE_ASYNC(hr) return hr;\ }) #define DEFINE_TASK Concurrency_winrt::task #define CREATE_TASK Concurrency_winrt::create_task -#define CREATE_OR_CONTINUE_TASK(_task, rettype, func) _task = (_task == Concurrency_winrt::task()) ? Concurrency_winrt::create_task(func) : _task.then([func](rettype) -> rettype { return func(); }); +#define CREATE_OR_CONTINUE_TASK(_task, rettype, func) _task = (_task == Concurrency_winrt::task()) ? Concurrency_winrt::create_task(func) : _task.then([func](rettype, rettype* retVal) -> HRESULT { return func(retVal); }); +#define DEFINE_RET_VAL(x) x* retVal +#define DEFINE_RET_TYPE(x) +#define DEFINE_RET_FORMAL(x) HRESULT +#define RET_VAL(x) *retVal = x;\ +return S_OK; +#define RET_VAL_BASE return S_OK; +#define MAKE_STRING(str) Microsoft::WRL::Wrappers::HStringReference(L##str) +#define GET_STL_STRING(str) std::wstring(str.GetRawBuffer(NULL)) +#define GET_STL_STRING_RAW(str) WindowsGetStringRawBuffer(str, NULL) #define MAKE_WRL_OBJ(x) Microsoft::WRL::ComPtr #define MAKE_WRL_REF(x) x* +#define MAKE_OBJ_REF(x) x #define MAKE_WRL_AGILE_REF(x) x* +#define MAKE_PROPERTY_BACKING(Type, PropName) Type PropName; +#define MAKE_PROPERTY(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { *pVal = PropValue; } else { return E_INVALIDARG; } return S_OK; }\ + STDMETHODIMP put_##PropName(Type Val) { PropValue = Val; return S_OK; } +#define MAKE_PROPERTY_STRING(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { return ::WindowsDuplicateString(PropValue.Get(), pVal); } else { return E_INVALIDARG; } }\ + STDMETHODIMP put_##PropName(Type Val) { return PropValue.Set(Val); } +#define MAKE_READONLY_PROPERTY(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { *pVal = PropValue; } else { return E_INVALIDARG; } return S_OK; } +#define THROW_INVALID_ARG RoOriginateError(E_INVALIDARG, nullptr); #define RELEASE_AGILE_WRL(x) if (x) { (x)->Release(); x = nullptr; } #define RELEASE_WRL(x) if (x) { (x)->Release(); x = nullptr; } #define GET_WRL_OBJ_FROM_REF(objtype, obj, orig, hr) Microsoft::WRL::ComPtr obj;\ @@ -308,11 +558,15 @@ hr = orig.As(&obj); #define WRL_PROP_PUT(obj, prop, arg, hr) hr = obj->put_##prop(arg); #define WRL_METHOD_BASE(obj, method, ret, hr) hr = obj->##method(&ret); #define WRL_METHOD(obj, method, ret, hr, ...) hr = obj->##method(__VA_ARGS__, &ret); +#define WRL_METHOD_NORET_BASE(obj, method, hr) hr = obj->##method(); #define REF_WRL_OBJ(obj) obj.GetAddressOf() #define DEREF_WRL_OBJ(obj) obj.Get() #define DEREF_AGILE_WRL_OBJ(obj) obj #define DEREF_AS_NATIVE_WRL_OBJ(type, obj) obj.Get() #define PREPARE_TRANSFER_WRL_OBJ(obj) obj.Detach() +#define ACTIVATE_LOCAL_OBJ_BASE(objtype) Microsoft::WRL::Make() +#define ACTIVATE_LOCAL_OBJ(objtype, ...) Microsoft::WRL::Make(__VA_ARGS__) +#define ACTIVATE_EVENT_HANDLER(objtype, ...) Microsoft::WRL::Callback(__VA_ARGS__).Get() #define ACTIVATE_OBJ(rtclass, objtype, obj, hr) MAKE_WRL_OBJ(objtype) obj;\ {\ Microsoft::WRL::ComPtr objFactory;\ @@ -333,272 +587,96 @@ hr = orig.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 +#define _ComPtr Microsoft::WRL::ComPtr #else -template -class CCompletionHandler - : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::ClassicCom>, - TCompletionHandler, IAgileObject, FtmBase> -#endif + +template +class ComPtr : public ATL::CComPtr { - MixInHelper() -#ifndef __cplusplus_winrt public: - CCompletionHandler() {} - - STDMETHODIMP Invoke(TAction* /*asyncInfo*/, AsyncStatus /*asyncStatus*/) + ComPtr() throw() { - m_Event.set(); - return S_OK; } - void wait() { m_Event.wait(); } -#endif -#ifdef __cplusplus_winrt -internal: - template - static TResult PerformSynchronously(Windows::Foundation::IAsyncOperation^ asyncOp, _ContextCallback context) + ComPtr(int nNull) throw() : + CComPtr((T*)nNull) { - TResult pResult; - context._CallInContext([asyncOp, &pResult]() { Concurrency::task asyncTask = Concurrency::task(asyncOp); pResult = asyncTask.get(); }); - return pResult; -#else - template - static HRESULT PerformSynchronously(TAction* asyncOp, _ContextCallback context, TResult* pResult) + } + ComPtr(T* lp) throw() : + CComPtr(lp) + { - HRESULT hr; - ComPtr> completeHandler = Microsoft::WRL::Make>(); - 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 + } + ComPtr(_In_ const CComPtr& lp) throw() : + CComPtr(lp.p) + { + } + virtual ~ComPtr() {} + + T* const* GetAddressOf() const throw() + { + return &p; } -#ifdef __cplusplus_winrt - static void PerformActionSynchronously(Windows::Foundation::IAsyncAction^ asyncOp, _ContextCallback context) + T** GetAddressOf() throw() { - context._CallInContext([asyncOp](){ Concurrency::task(asyncOp).get(); }); -#else - static HRESULT PerformActionSynchronously(TAction* asyncOp, _ContextCallback context) - { - HRESULT hr; - ComPtr> completeHandler = Microsoft::WRL::Make>(); - 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 + return &p; + } + + T** ReleaseAndGetAddressOf() throw() + { + InternalRelease(); + return &p; + } + + T* Get() const throw() + { + return p; + } + ComPtr& operator=(decltype(__nullptr)) throw() + { + InternalRelease(); + return *this; + } + ComPtr& operator=(_In_ const int nNull) throw() + { + ASSERT(nNull == 0); + (void)nNull; + InternalRelease(); + return *this; + } + unsigned long Reset() + { + return InternalRelease(); + } + // query for U interface + template + HRESULT As(_Inout_ U** lp) const throw() + { + return p->QueryInterface(__uuidof(U), (void**)lp); + } + // query for U interface + template + HRESULT As(_Out_ ComPtr* lp) const throw() + { + return p->QueryInterface(__uuidof(U), reinterpret_cast(lp->ReleaseAndGetAddressOf())); } -#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 -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 -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 -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 -static auto _IsValidCreateAsync(_Ty _Param, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType(), cancellation_token::none()), std::true_type()); - -// All else is invalid -template -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 -class CAsyncAction - : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRt>, - Microsoft::WRL::Implements, Microsoft::WRL::AsyncBase> -{ - 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) + unsigned long InternalRelease() throw() { - if (!(std::is_same>::_AsyncKind, Concurrency_winrt::details::_TypeSelectorAsyncTask>::value)) + unsigned long ref = 0; + T* temp = p; + + if (temp != nullptr) { - // 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); + p = nullptr; + ref = temp->Release(); } - } - 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(_M_func, _M_cts.get_token()); - AddRef(); - _M_task.then([this](Concurrency_winrt::task _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; - }); + return ref; } -private: - - _Function _M_func; - Concurrency_winrt::task _M_task; - Concurrency::cancellation_token_source _M_cts; - _ContextCallback _M_completeDelegateContext; }; -template -__declspec(noinline) -CAsyncAction<_Function>* create_async(const _Function& _Func) -{ - static_assert(std::is_same::value, - "argument to create_async must be a callable object taking zero, one or two arguments"); - CAsyncAction<_Function>* action = Microsoft::WRL::Make>(_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 -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 -__declspec(noinline) -MediaCaptureFailedHandler<_Function>* create_medcapfailedhandler(const _Function& _Func) -{ - return Microsoft::WRL::Make>(_Func).Detach(); -} - +#define _ComPtr ComPtr #endif template @@ -946,7 +1024,7 @@ done: } protected: - ComPtr _spAttributes; + _ComPtr _spAttributes; }; class StreamSink : @@ -1005,11 +1083,11 @@ public: #ifdef HAVE_WINRT STDMETHOD(RuntimeClassInitialize)() { return S_OK; } #else - ULONG AddRef() + ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&m_cRef); } - ULONG Release() + ULONG STDMETHODCALLTYPE Release() { ULONG cRef = InterlockedDecrement(&m_cRef); if (cRef == 0) @@ -1025,7 +1103,7 @@ public: if (m_spFTM == nullptr) { EnterCriticalSection(&m_critSec); if (m_spFTM == nullptr) { - hr = CoCreateFreeThreadedMarshaler(static_cast(this), &m_spFTM); + hr = CoCreateFreeThreadedMarshaler((IMFStreamSink*)this, &m_spFTM); } LeaveCriticalSection(&m_critSec); } @@ -1061,14 +1139,12 @@ public: InitializeCriticalSectionEx(&m_critSec, 3000, 0); ZeroMemory(&m_guiCurrentSubtype, sizeof(m_guiCurrentSubtype)); CBaseAttributes::Initialize(0U); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::StreamSink\n"); + DebugPrintOut(L"StreamSink::StreamSink\n"); } virtual ~StreamSink() { DeleteCriticalSection(&m_critSec); assert(m_IsShutdown); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::~StreamSink\n"); + DebugPrintOut(L"StreamSink::~StreamSink\n"); } HRESULT Initialize() @@ -1078,7 +1154,7 @@ public: hr = MFCreateEventQueue(&m_spEventQueue); if (SUCCEEDED(hr)) { - ComPtr pMedSink; + _ComPtr pMedSink; hr = CBaseAttributes<>::GetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, __uuidof(IMFMediaSink), (LPVOID*)pMedSink.GetAddressOf()); assert(pMedSink.Get() != NULL); if (SUCCEEDED(hr)) { @@ -1102,10 +1178,8 @@ public: // Called when the presentation clock starts. HRESULT Start(MFTIME start) { - EnterCriticalSection(&m_critSec); - HRESULT hr = S_OK; - + EnterCriticalSection(&m_critSec); if (m_state != State_TypeNotSet) { if (start != PRESENTATION_CURRENT_POSITION) { @@ -1184,7 +1258,7 @@ public: // Shuts down the stream sink. HRESULT Shutdown() { - ComPtr pSampleCallback; + _ComPtr pSampleCallback; HRESULT hr = S_OK; assert(!m_IsShutdown); hr = m_pParent->GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); @@ -1217,7 +1291,7 @@ public: if (SUCCEEDED(hr)) { - ComPtr pMedSink; + _ComPtr pMedSink; hr = CBaseAttributes<>::GetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, __uuidof(IMFMediaSink), (LPVOID*)pMedSink.GetAddressOf()); if (SUCCEEDED(hr)) { *ppMediaSink = pMedSink.Detach(); @@ -1225,8 +1299,7 @@ public: } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::GetMediaSink: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::GetMediaSink: HRESULT=%i\n", hr); return hr; } @@ -1247,8 +1320,7 @@ public: } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::GetIdentifier: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::GetIdentifier: HRESULT=%i\n", hr); return hr; } @@ -1270,14 +1342,13 @@ public: } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::GetMediaTypeHandler: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::GetMediaTypeHandler: HRESULT=%i\n", hr); return hr; } HRESULT STDMETHODCALLTYPE ProcessSample(IMFSample *pSample) { - ComPtr pInput; - ComPtr pSampleCallback; + _ComPtr pInput; + _ComPtr pSampleCallback; BYTE *pSrc = NULL; // Source buffer. // Stride if the buffer does not support IMF2DBuffer LONGLONG hnsTime = 0; @@ -1334,6 +1405,7 @@ public: /* [in] */ MFSTREAMSINK_MARKER_TYPE eMarkerType, /* [in] */ __RPC__in const PROPVARIANT * /*pvarMarkerValue*/, /* [in] */ __RPC__in const PROPVARIANT * /*pvarContextValue*/) { + eMarkerType; EnterCriticalSection(&m_critSec); HRESULT hr = S_OK; @@ -1345,12 +1417,12 @@ public: if (SUCCEEDED(hr)) { + //at shutdown will receive MFSTREAMSINK_MARKER_ENDOFSEGMENT 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()); + DebugPrintOut(L"StreamSink::PlaceMarker: HRESULT=%i %s\n", hr, StreamSinkMarkerTypeMap.at(eMarkerType).c_str()); return hr; } @@ -1364,8 +1436,7 @@ public: } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::Flush: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::Flush: HRESULT=%i\n", hr); return hr; } @@ -1378,7 +1449,7 @@ public: HRESULT hr = S_OK; - ComPtr pQueue; + _ComPtr pQueue; { EnterCriticalSection(&m_critSec); @@ -1403,13 +1474,12 @@ public: 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()); + DebugPrintOut(L"StreamSink::GetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str()); else - DPO->printOut(L"StreamSink::GetEvent: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::GetEvent: HRESULT=%i\n", hr); return hr; } @@ -1426,8 +1496,7 @@ public: hr = m_spEventQueue->BeginGetEvent(pCallback, punkState); } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::BeginGetEvent: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::BeginGetEvent: HRESULT=%i\n", hr); return hr; } @@ -1449,14 +1518,13 @@ public: } 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()); + DebugPrintOut(L"StreamSink::EndGetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str()); else - DPO->printOut(L"StreamSink::EndGetEvent: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::EndGetEvent: HRESULT=%i\n", hr); return hr; } @@ -1475,9 +1543,8 @@ public: } 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); + DebugPrintOut(L"StreamSink::QueueEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(met).c_str()); + DebugPrintOut(L"StreamSink::QueueEvent: HRESULT=%i\n", hr); return hr; } @@ -1522,13 +1589,14 @@ public: hr = MF_E_INVALIDTYPE; } } + // We don't return any "close match" types. if (ppMediaType) { *ppMediaType = nullptr; } if (ppMediaType && SUCCEEDED(hr)) { - ComPtr pType; + _ComPtr pType; hr = MFCreateMediaType(ppMediaType); if (SUCCEEDED(hr)) { hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType); @@ -1558,8 +1626,7 @@ public: } } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::IsMediaTypeSupported: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::IsMediaTypeSupported: HRESULT=%i\n", hr); return hr; } @@ -1583,8 +1650,7 @@ public: } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::GetMediaTypeCount: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::GetMediaTypeCount: HRESULT=%i\n", hr); return hr; } @@ -1609,7 +1675,7 @@ public: //return preferred type based on media capture library 6 elements preferred preview type //hr = m_spCurrentType.CopyTo(ppType); if (SUCCEEDED(hr)) { - ComPtr pType; + _ComPtr pType; hr = MFCreateMediaType(ppType); if (SUCCEEDED(hr)) { hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType); @@ -1641,8 +1707,7 @@ public: } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::GetMediaTypeByIndex: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::GetMediaTypeByIndex: HRESULT=%i\n", hr); return hr; } @@ -1674,9 +1739,6 @@ public: if (SUCCEEDED(hr)) { - GUID guiMajorType; - pMediaType->GetMajorType(&guiMajorType); - hr = MFCreateMediaType(m_spCurrentType.ReleaseAndGetAddressOf()); if (SUCCEEDED(hr)) { @@ -1686,7 +1748,11 @@ public: { hr = m_spCurrentType->GetGUID(MF_MT_SUBTYPE, &m_guiCurrentSubtype); } + GUID guid; if (SUCCEEDED(hr)) { + hr = m_spCurrentType->GetMajorType(&guid); + } + if (SUCCEEDED(hr) && guid == MFMediaType_Video) { hr = MFGetAttributeSize(m_spCurrentType.Get(), MF_MT_FRAME_SIZE, &m_imageWidthInPixels, &m_imageHeightInPixels); } if (SUCCEEDED(hr)) @@ -1696,8 +1762,7 @@ public: } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::SetCurrentMediaType: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::SetCurrentMediaType: HRESULT=%i\n", hr); return hr; } @@ -1723,8 +1788,7 @@ public: } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"StreamSink::GetCurrentMediaType: HRESULT=%i\n", hr); + DebugPrintOut(L"StreamSink::GetCurrentMediaType: HRESULT=%i\n", hr); return hr; } @@ -1737,13 +1801,12 @@ public: return E_INVALIDARG; } - ComPtr pType; + _ComPtr 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); + DebugPrintOut(L"StreamSink::GetMajorType: HRESULT=%i\n", hr); return hr; } private: @@ -1759,10 +1822,10 @@ private: long m_cRef; #endif IMFAttributes* m_pParent; - ComPtr m_spCurrentType; - ComPtr m_spEventQueue; // Event queue + _ComPtr m_spCurrentType; + _ComPtr m_spEventQueue; // Event queue - ComPtr m_spFTM; + _ComPtr m_spFTM; State m_state; bool m_fGetStartTimeFromSample; bool m_fWaitingForFirstSample; @@ -2296,7 +2359,7 @@ class MediaSink : Microsoft::WRL::Implements, IMFMediaSink, IMFClockStateSink, - FtmBase, + Microsoft::WRL::FtmBase, CBaseAttributes<>> #else public IMFMediaSink, public IMFClockStateSink, public CBaseAttributes<> @@ -2307,11 +2370,11 @@ class MediaSink : public: #else public: - ULONG AddRef() + ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&m_cRef); } - ULONG Release() + ULONG STDMETHODCALLTYPE Release() { ULONG cRef = InterlockedDecrement(&m_cRef); if (cRef == 0) @@ -2347,13 +2410,11 @@ public: 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"); + DebugPrintOut(L"MediaSink::MediaSink\n"); } virtual ~MediaSink() { - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::~MediaSink\n"); + DebugPrintOut(L"MediaSink::~MediaSink\n"); DeleteCriticalSection(&m_critSec); assert(m_IsShutdown); } @@ -2376,7 +2437,7 @@ public: Microsoft::WRL::ComPtr spInsp; Microsoft::WRL::ComPtr> spSetting; Microsoft::WRL::ComPtr spPropVal; - ComPtr pMedEncProps; + Microsoft::WRL::ComPtr pMedEncProps; UINT32 uiType = ABI::Windows::Media::Capture::MediaStreamType_VideoPreview; hr = pConfiguration->QueryInterface(IID_PPV_ARGS(&spSetting)); @@ -2385,7 +2446,7 @@ public: } if (SUCCEEDED(hr)) { - hr = spSetting->Lookup(HStringReference(MF_PROP_SAMPLEGRABBERCALLBACK).Get(), spInsp.ReleaseAndGetAddressOf()); + hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_SAMPLEGRABBERCALLBACK).Get(), spInsp.ReleaseAndGetAddressOf()); if (FAILED(hr)) { hr = E_INVALIDARG; } @@ -2394,7 +2455,7 @@ public: } } if (SUCCEEDED(hr)) { - hr = spSetting->Lookup(HStringReference(MF_PROP_VIDTYPE).Get(), spInsp.ReleaseAndGetAddressOf()); + hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_VIDTYPE).Get(), spInsp.ReleaseAndGetAddressOf()); if (FAILED(hr)) { hr = E_INVALIDARG; } @@ -2405,7 +2466,7 @@ public: } } if (SUCCEEDED(hr)) { - hr = spSetting->Lookup(HStringReference(MF_PROP_VIDENCPROPS).Get(), spInsp.ReleaseAndGetAddressOf()); + hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_VIDENCPROPS).Get(), spInsp.ReleaseAndGetAddressOf()); if (FAILED(hr)) { hr = E_INVALIDARG; } @@ -2480,14 +2541,13 @@ public: case ABI::Windows::Foundation::PropertyType_String: { - HSTRING value; - hr = pValue->GetString(&value); + Microsoft::WRL::Wrappers::HString value; + hr = pValue->GetString(value.GetAddressOf()); if (SUCCEEDED(hr)) { UINT32 len = 0; - LPCWSTR szValue = WindowsGetStringRawBuffer(value, &len); + LPCWSTR szValue = WindowsGetStringRawBuffer(value.Get(), &len); hr = pAttr->SetString(guidKey, szValue); - WindowsDeleteString(value); } } break; @@ -2516,7 +2576,7 @@ public: case ABI::Windows::Foundation::PropertyType_Inspectable: { - ComPtr value; + Microsoft::WRL::ComPtr value; hr = TYPE_E_TYPEMISMATCH; if (SUCCEEDED(hr)) { @@ -2534,10 +2594,10 @@ public: static HRESULT ConvertPropertiesToMediaType(_In_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties *pMEP, _Outptr_ IMFMediaType **ppMT) { HRESULT hr = S_OK; - ComPtr spMT; - ComPtr> spMap; - ComPtr*>> spIterable; - ComPtr*>> spIterator; + _ComPtr spMT; + Microsoft::WRL::ComPtr> spMap; + Microsoft::WRL::ComPtr*>> spIterable; + Microsoft::WRL::ComPtr*>> spIterator; if (pMEP == nullptr || ppMT == nullptr) { @@ -2545,7 +2605,7 @@ public: } *ppMT = nullptr; - hr = pMEP->get_Properties(&spMap); + hr = pMEP->get_Properties(spMap.GetAddressOf()); if (SUCCEEDED(hr)) { @@ -2568,9 +2628,9 @@ public: while (hasCurrent) { - ComPtr > spKeyValuePair; - ComPtr spValue; - ComPtr spPropValue; + Microsoft::WRL::ComPtr > spKeyValuePair; + Microsoft::WRL::ComPtr spValue; + Microsoft::WRL::ComPtr spPropValue; GUID guidKey; hr = spIterator->get_Current(&spKeyValuePair); @@ -2609,8 +2669,8 @@ public: if (SUCCEEDED(hr)) { - ComPtr spValue; - ComPtr spPropValue; + Microsoft::WRL::ComPtr spValue; + Microsoft::WRL::ComPtr spPropValue; GUID guiMajorType; hr = spMap->Lookup(MF_MT_MAJOR_TYPE, spValue.GetAddressOf()); @@ -2639,12 +2699,12 @@ public: return hr; } - HRESULT SetMediaStreamProperties( - ABI::Windows::Media::Capture::MediaStreamType MediaStreamType, + //this should be passed through SetProperties! + HRESULT SetMediaStreamProperties(ABI::Windows::Media::Capture::MediaStreamType MediaStreamType, _In_opt_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties *mediaEncodingProperties) { HRESULT hr = S_OK; - ComPtr spMediaType; + _ComPtr spMediaType; if (MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_VideoPreview && MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_VideoRecord && @@ -2657,7 +2717,7 @@ public: if (mediaEncodingProperties != nullptr) { - ComPtr spStreamSink; + _ComPtr spStreamSink; hr = ConvertPropertiesToMediaType(mediaEncodingProperties, &spMediaType); if (SUCCEEDED(hr)) { @@ -2678,18 +2738,18 @@ public: if (pdwCharacteristics == NULL) return E_INVALIDARG; EnterCriticalSection(&m_critSec); if (SUCCEEDED(hr = CheckShutdown())) { - *pdwCharacteristics = MEDIASINK_FIXED_STREAMS; + //if had an activation object for the sink, shut down would be managed and MF_STREAM_SINK_SUPPORTS_ROTATION appears to be setable to TRUE + *pdwCharacteristics = MEDIASINK_FIXED_STREAMS;// | MEDIASINK_REQUIRE_REFERENCE_MEDIATYPE; } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::GetCharacteristics: HRESULT=%i\n", hr); - return S_OK; + DebugPrintOut(L"MediaSink::GetCharacteristics: HRESULT=%i\n", hr); + return hr; } HRESULT STDMETHODCALLTYPE AddStreamSink( DWORD dwStreamSinkIdentifier, IMFMediaType * /*pMediaType*/, IMFStreamSink **ppStreamSink) { - ComPtr spMFStream; - ComPtr pStream; + _ComPtr spMFStream; + _ComPtr pStream; EnterCriticalSection(&m_critSec); HRESULT hr = CheckShutdown(); @@ -2729,7 +2789,7 @@ public: } // Initialize the stream. - ComPtr pAttr; + _ComPtr pAttr; if (SUCCEEDED(hr)) { hr = pStream.As(&pAttr); } @@ -2752,7 +2812,7 @@ public: for (; pos != posEnd; pos = m_streams.Next(pos)) { DWORD dwCurrId; - ComPtr spCurr; + _ComPtr spCurr; hr = m_streams.GetItemPos(pos, &spCurr); if (FAILED(hr)) { @@ -2781,8 +2841,7 @@ public: *ppStreamSink = spMFStream.Detach(); } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::AddStreamSink: HRESULT=%i\n", hr); + DebugPrintOut(L"MediaSink::AddStreamSink: HRESULT=%i\n", hr); return hr; } @@ -2791,7 +2850,7 @@ public: HRESULT hr = CheckShutdown(); ComPtrList::POSITION pos = m_streams.FrontPosition(); ComPtrList::POSITION endPos = m_streams.EndPosition(); - ComPtr spStream; + _ComPtr spStream; if (SUCCEEDED(hr)) { @@ -2821,11 +2880,18 @@ public: if (SUCCEEDED(hr)) { hr = m_streams.Remove(pos, nullptr); - static_cast(spStream.Get())->Shutdown(); + _ComPtr spCustomSink; +#ifdef HAVE_WINRT + spCustomSink = static_cast(spStream.Get()); + hr = S_OK; +#else + hr = spStream.As(&spCustomSink); +#endif + if (SUCCEEDED(hr)) + hr = spCustomSink->Shutdown(); } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::RemoveStreamSink: HRESULT=%i\n", hr); + DebugPrintOut(L"MediaSink::RemoveStreamSink: HRESULT=%i\n", hr); return hr; } @@ -2845,8 +2911,7 @@ public: } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::GetStreamSinkCount: HRESULT=%i\n", hr); + DebugPrintOut(L"MediaSink::GetStreamSinkCount: HRESULT=%i\n", hr); return hr; } @@ -2857,7 +2922,7 @@ public: return E_INVALIDARG; } - ComPtr spStream; + _ComPtr spStream; EnterCriticalSection(&m_critSec); DWORD cStreams = m_streams.GetCount(); @@ -2894,8 +2959,7 @@ public: *ppStreamSink = spStream.Detach(); } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::GetStreamSinkByIndex: HRESULT=%i\n", hr); + DebugPrintOut(L"MediaSink::GetStreamSinkByIndex: HRESULT=%i\n", hr); return hr; } @@ -2908,7 +2972,7 @@ public: EnterCriticalSection(&m_critSec); HRESULT hr = CheckShutdown(); - ComPtr spResult; + _ComPtr spResult; if (SUCCEEDED(hr)) { @@ -2917,7 +2981,7 @@ public: for (; pos != endPos; pos = m_streams.Next(pos)) { - ComPtr spStream; + _ComPtr spStream; hr = m_streams.GetItemPos(pos, &spStream); DWORD dwId; @@ -2950,8 +3014,7 @@ public: *ppStreamSink = spResult.Detach(); } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::GetStreamSinkById: HRESULT=%i\n", hr); + DebugPrintOut(L"MediaSink::GetStreamSinkById: HRESULT=%i\n", hr); return hr; } @@ -2976,7 +3039,7 @@ public: } } - ComPtr pSampleCallback; + _ComPtr pSampleCallback; if (SUCCEEDED(hr)) { // Release the pointer to the old clock. // Store the pointer to the new clock. @@ -2986,8 +3049,7 @@ public: LeaveCriticalSection(&m_critSec); if (SUCCEEDED(hr)) hr = pSampleCallback->OnSetPresentationClock(pPresentationClock); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::SetPresentationClock: HRESULT=%i\n", hr); + DebugPrintOut(L"MediaSink::SetPresentationClock: HRESULT=%i\n", hr); return hr; } @@ -3010,8 +3072,7 @@ public: } } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::GetPresentationClock: HRESULT=%i\n", hr); + DebugPrintOut(L"MediaSink::GetPresentationClock: HRESULT=%i\n", hr); return hr; } @@ -3025,13 +3086,16 @@ public: m_streams.Clear(); m_spClock.ReleaseAndGetAddressOf(); + _ComPtr pType; + hr = CBaseAttributes<>::GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)pType.GetAddressOf()); + if (SUCCEEDED(hr)) { hr = DeleteItem(MF_MEDIASINK_PREFERREDTYPE); + } m_IsShutdown = true; } LeaveCriticalSection(&m_critSec); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::Shutdown: HRESULT=%i\n", hr); + DebugPrintOut(L"MediaSink::Shutdown: HRESULT=%i\n", hr); return hr; } class ShutdownFunc @@ -3039,8 +3103,16 @@ public: public: HRESULT operator()(IMFStreamSink *pStream) const { - static_cast(pStream)->Shutdown(); - return S_OK; + _ComPtr spCustomSink; + HRESULT hr; +#ifdef HAVE_WINRT + spCustomSink = static_cast(pStream); +#else + hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); + if (FAILED(hr)) return hr; +#endif + hr = spCustomSink->Shutdown(); + return hr; } }; @@ -3054,7 +3126,16 @@ public: HRESULT operator()(IMFStreamSink *pStream) const { - return static_cast(pStream)->Start(_llStartTime); + _ComPtr spCustomSink; + HRESULT hr; +#ifdef HAVE_WINRT + spCustomSink = static_cast(pStream); +#else + hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); + if (FAILED(hr)) return hr; +#endif + hr = spCustomSink->Start(_llStartTime); + return hr; } LONGLONG _llStartTime; @@ -3065,7 +3146,16 @@ public: public: HRESULT operator()(IMFStreamSink *pStream) const { - return static_cast(pStream)->Stop(); + _ComPtr spCustomSink; + HRESULT hr; +#ifdef HAVE_WINRT + spCustomSink = static_cast(pStream); +#else + hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); + if (FAILED(hr)) return hr; +#endif + hr = spCustomSink->Stop(); + return hr; } }; @@ -3078,7 +3168,7 @@ public: for (; pos != endPos; pos = col.Next(pos)) { - ComPtr spStream; + _ComPtr spStream; hr = col.GetItemPos(pos, &spStream); if (FAILED(hr)) @@ -3104,14 +3194,13 @@ public: m_llStartTime = llClockStartOffset; hr = ForEach(m_streams, StartFunc(llClockStartOffset)); } - ComPtr pSampleCallback; + _ComPtr pSampleCallback; if (SUCCEEDED(hr)) hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); LeaveCriticalSection(&m_critSec); if (SUCCEEDED(hr)) hr = pSampleCallback->OnClockStart(hnsSystemTime, llClockStartOffset); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::OnClockStart: HRESULT=%i\n", hr); + DebugPrintOut(L"MediaSink::OnClockStart: HRESULT=%i\n", hr); return hr; } @@ -3125,38 +3214,35 @@ public: // Stop each stream hr = ForEach(m_streams, StopFunc()); } - ComPtr pSampleCallback; + _ComPtr pSampleCallback; if (SUCCEEDED(hr)) hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); LeaveCriticalSection(&m_critSec); if (SUCCEEDED(hr)) hr = pSampleCallback->OnClockStop(hnsSystemTime); - DebugPrintOut *DPO = &DebugPrintOut::getInstance(); - DPO->printOut(L"MediaSink::OnClockStop: HRESULT=%i\n", hr); + DebugPrintOut(L"MediaSink::OnClockStop: HRESULT=%i\n", hr); return hr; } HRESULT STDMETHODCALLTYPE OnClockPause( MFTIME hnsSystemTime) { HRESULT hr; - ComPtr pSampleCallback; + _ComPtr 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); + DebugPrintOut(L"MediaSink::OnClockPause: HRESULT=%i\n", hr); return hr; } HRESULT STDMETHODCALLTYPE OnClockRestart( MFTIME hnsSystemTime) { HRESULT hr; - ComPtr pSampleCallback; + _ComPtr 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); + DebugPrintOut(L"MediaSink::OnClockRestart: HRESULT=%i\n", hr); return hr; } @@ -3164,12 +3250,11 @@ public: MFTIME hnsSystemTime, float flRate) { HRESULT hr; - ComPtr pSampleCallback; + _ComPtr 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); + DebugPrintOut(L"MediaSink::OnClockSetRate: HRESULT=%i\n", hr); return hr; } private: @@ -3179,7 +3264,7 @@ private: CRITICAL_SECTION m_critSec; bool m_IsShutdown; ComPtrList m_streams; - ComPtr m_spClock; + _ComPtr m_spClock; LONGLONG m_llStartTime; }; diff --git a/modules/highgui/src/ppltasks_winrt.h b/modules/highgui/src/ppltasks_winrt.h index 29dccbd70..1243baea9 100644 --- a/modules/highgui/src/ppltasks_winrt.h +++ b/modules/highgui/src/ppltasks_winrt.h @@ -17,24 +17,44 @@ #pragma once +#ifndef _PPLTASKS_WINRT_H +#define _PPLTASKS_WINRT_H + #include #include +#if _MSC_VER >= 1800 +#include + +// Cannot build using a compiler that is older than dev10 SP1 +#ifdef _MSC_VER +#if _MSC_FULL_VER < 160040219 /*IFSTRIP=IGN*/ +#error ERROR: Visual Studio 2010 SP1 or later is required to build ppltasks +#endif /*IFSTRIP=IGN*/ +#endif +#else #include +#endif #include #include #include #include +#if _MSC_VER >= 1800 +#include +#endif #ifndef __cplusplus_winrt #include #include +#if _MSC_VER >= 1800 +#include "agile_wrl.h" +#endif #include #include #ifndef _UITHREADCTXT_SUPPORT -#ifdef WINAPI_FAMILY +#ifdef WINAPI_FAMILY /*IFSTRIP=IGN*/ // It is safe to include winapifamily as WINAPI_FAMILY was defined by the user #include @@ -45,72 +65,72 @@ #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 +#else /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */ #define _UITHREADCTXT_SUPPORT 1 -#endif +#endif /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */ -#else +#else /* WINAPI_FAMILY */ // Not supported without a WINAPI_FAMILY setting. #define _UITHREADCTXT_SUPPORT 0 -#endif // #ifdef WINAPI_FAMILY +#endif /* WINAPI_FAMILY */ -#endif // #ifndef _UITHREADCTXT_SUPPORT +#endif /* _UITHREADCTXT_SUPPORT */ #if _UITHREADCTXT_SUPPORT #include -#endif // _UITHREADCTXT_SUPPORT +#endif /* _UITHREADCTXT_SUPPORT */ #pragma detect_mismatch("_PPLTASKS_WITH_WINRT", "0") + +#ifdef _DEBUG +#define _DBG_ONLY(X) X +#else +#define _DBG_ONLY(X) +#endif // #ifdef _DEBUG + +// std::copy_exception changed to std::make_exception_ptr from VS 2010 to VS 11. +#ifdef _MSC_VER +#if _MSC_VER < 1700 /*IFSTRIP=IGN*/ +namespace std +{ + template exception_ptr make_exception_ptr(_E _Except) + { + return copy_exception(_Except); + } +} +#endif +#ifndef _PPLTASK_ASYNC_LOGGING +#if _MSC_VER >= 1800 && defined(__cplusplus_winrt) +#define _PPLTASK_ASYNC_LOGGING 1 // Only enable async logging under dev12 winrt +#else +#define _PPLTASK_ASYNC_LOGGING 0 +#endif +#endif +#endif + #pragma pack(push,_CRT_PACKING) #pragma warning(push) #pragma warning(disable: 28197) #pragma warning(disable: 4100) // Unreferenced formal parameter - needed for document generation +#if _MSC_VER >= 1800 +#pragma warning(disable: 4127) // constant express in if condition - we use it for meta programming +#else #pragma warning(disable: 4702) // Unreachable code - it is caused by user lambda throw exceptions +#endif // 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) +// stuff ported from Dev11 CRT +// NOTE: this doesn't actually match std::declval. it behaves differently for void! +// so don't blindly change it to std::declval. +namespace stdx +{ + template + _T&& declval(); +} /// /// The Concurrency_winrt namespace provides classes and functions that give you access to the Concurrency Runtime, @@ -119,7 +139,38 @@ /**/ namespace Concurrency_winrt { + // In debug builds, default to 10 frames, unless this is overridden prior to #includ'ing ppltasks.h. In retail builds, default to only one frame. +#ifndef PPL_TASK_SAVE_FRAME_COUNT +#ifdef _DEBUG +#define PPL_TASK_SAVE_FRAME_COUNT 10 +#else +#define PPL_TASK_SAVE_FRAME_COUNT 1 +#endif +#endif + + /// + /// Helper macro to determine how many stack frames need to be saved. When any number less or equal to 1 is specified, + /// only one frame is captured and no stackwalk will be involved. Otherwise, the number of callstack frames will be captured. + /// + /// + /// This needs to be defined as a macro rather than a function so that if we're only gathering one frame, _ReturnAddress() + /// will evaluate to client code, rather than a helper function inside of _TaskCreationCallstack, itself. + /// +#ifdef _CAPTURE_CALLSTACK +#undef _CAPTURE_CALLSTACK +#endif +#if PPL_TASK_SAVE_FRAME_COUNT > 1 +#if !defined(_DEBUG) +#pragma message ("WARNING: Redefinning PPL_TASK_SAVE_FRAME_COUNT under Release build for non-desktop applications is not supported; only one frame will be captured!") +#define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress()) +#else +#define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureMultiFramesCallstack(PPL_TASK_SAVE_FRAME_COUNT) +#endif +#else +#define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress()) +#endif /// + /// A type that represents the terminal state of a task. Valid values are completed and canceled. /// /// @@ -151,7 +202,18 @@ template <> class task; /// /// /**/ -_CRTIMP2 bool __cdecl is_task_cancellation_requested(); +#if _MSC_VER >= 1800 +inline bool __cdecl is_task_cancellation_requested() +{ + return ::Concurrency::details::_TaskCollection_t::_Is_cancellation_requested(); +} +#else +inline bool __cdecl is_task_cancellation_requested() +{ + // ConcRT scheduler under the hood is using TaskCollection, which is same as task_group + return ::Concurrency::is_current_task_group_canceling(); +} +#endif /// /// Cancels the currently executing task. This function can be called from within the body of a task to abort the @@ -164,10 +226,56 @@ _CRTIMP2 bool __cdecl is_task_cancellation_requested(); /// /// /**/ -_CRTIMP2 __declspec(noreturn) void __cdecl cancel_current_task(); +//#if _MSC_VER >= 1800 +inline __declspec(noreturn) void __cdecl cancel_current_task() +{ + throw Concurrency::task_canceled(); +} +//#else +//_CRTIMP2 __declspec(noreturn) void __cdecl cancel_current_task(); +//#endif namespace details { +#if _MSC_VER >= 1800 + /// + /// Callstack container, which is used to capture and preserve callstacks in ppltasks. + /// Members of this class is examined by vc debugger, thus there will be no public access methods. + /// Please note that names of this class should be kept stable for debugger examining. + /// + class _TaskCreationCallstack + { + private: + // If _M_SingleFrame != nullptr, there will be only one frame of callstacks, which is stored in _M_SingleFrame; + // otherwise, _M_Frame will store all the callstack frames. + void* _M_SingleFrame; + std::vector _M_frames; + public: + _TaskCreationCallstack() + { + _M_SingleFrame = nullptr; + } + + // Store one frame of callstack. This function works for both Debug / Release CRT. + static _TaskCreationCallstack _CaptureSingleFrameCallstack(void *_SingleFrame) + { + _TaskCreationCallstack _csc; + _csc._M_SingleFrame = _SingleFrame; + return _csc; + } + + // Capture _CaptureFrames number of callstack frames. This function only work properly for Desktop or Debug CRT. + __declspec(noinline) + static _TaskCreationCallstack _CaptureMultiFramesCallstack(size_t _CaptureFrames) + { + _TaskCreationCallstack _csc; + _csc._M_frames.resize(_CaptureFrames); + // skip 2 frames to make sure callstack starts from user code + _csc._M_frames.resize(::Concurrency::details::platform::CaptureCallstack(&_csc._M_frames[0], 2, _CaptureFrames)); + return _csc; + } + }; +#endif typedef UINT32 _Unit_type; struct _TypeSelectorNoAsync {}; @@ -231,12 +339,12 @@ namespace details typedef _Type _Value; }; - struct _NonUserType { public: int _Dummy; }; + //struct _NonUserType { public: int _Dummy; }; template struct _ValueTypeOrRefType { - typedef _NonUserType _Value; + typedef _Unit_type _Value; }; template @@ -245,6 +353,18 @@ namespace details typedef _Type _Value; }; + template + _Ty _UnwrapAsyncActionWithProgressSelector(ABI::Windows::Foundation::IAsyncActionWithProgress_impl<_Ty>*); + + template + _Ty _UnwrapAsyncActionWithProgressSelector(...); + + template + _Progress _UnwrapAsyncOperationWithProgressProgressSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress_impl<_Ty, _Progress>*); + + template + _Progress _UnwrapAsyncOperationWithProgressProgressSelector(...); + template _T2 _ProgressTypeSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*); @@ -254,42 +374,7 @@ namespace details template struct _GetProgressType { - typedef decltype(_ProgressTypeSelector(std::declval<_Type>())) _Value; - }; - - template