Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 #include "precomp.hpp"
     42 #if (defined WIN32 || defined _WIN32) && defined HAVE_MSMF
     43 /*
     44    Media Foundation-based Video Capturing module is based on
     45    videoInput library by Evgeny Pereguda:
     46    http://www.codeproject.com/Articles/559437/Capturing-of-video-from-web-camera-on-Windows-7-an
     47    Originaly licensed under The Code Project Open License (CPOL) 1.02:
     48    http://www.codeproject.com/info/cpol10.aspx
     49 */
     50 //require Windows 8 for some of the formats defined otherwise could baseline on lower version
     51 #if WINVER < _WIN32_WINNT_WIN7
     52 #undef WINVER
     53 #define WINVER _WIN32_WINNT_WIN7
     54 #endif
     55 #if defined _MSC_VER && _MSC_VER >= 1600
     56     #define HAVE_CONCURRENCY
     57 #endif
     58 #include <windows.h>
     59 #include <guiddef.h>
     60 #include <mfidl.h>
     61 #include <Mfapi.h>
     62 #include <mfplay.h>
     63 #include <mfobjects.h>
     64 #include <tchar.h>
     65 #include <strsafe.h>
     66 #include <Mfreadwrite.h>
     67 #include <new>
     68 #include <map>
     69 #include <vector>
     70 #include <string>
     71 #include <stdio.h>
     72 #include <stdarg.h>
     73 #include <string.h>
     74 
     75 #ifdef _MSC_VER
     76 #pragma warning(disable:4503)
     77 #pragma comment(lib, "mfplat")
     78 #pragma comment(lib, "mf")
     79 #pragma comment(lib, "mfuuid")
     80 #pragma comment(lib, "Strmiids")
     81 #pragma comment(lib, "Mfreadwrite")
     82 #if (WINVER >= 0x0602) // Available since Win 8
     83 #pragma comment(lib, "MinCore_Downlevel")
     84 #endif
     85 #endif
     86 
     87 #include <mferror.h>
     88 
     89 #ifdef WINRT
     90     // for ComPtr usage
     91 #include <wrl/client.h>
     92 #ifdef __cplusplus_winrt
     93 #include <agile.h>
     94 #include <vccorlib.h>
     95 #endif
     96 
     97 #include <wrl\async.h>
     98 #include <wrl\implements.h>
     99 #include <wrl\module.h>
    100 #include <wrl\wrappers\corewrappers.h>
    101 #include <windows.media.capture.h>
    102 #include <windows.devices.enumeration.h>
    103 #ifdef HAVE_CONCURRENCY
    104 #include <concrt.h>
    105 #ifndef __cplusplus_winrt
    106 __declspec(noreturn) void __stdcall __abi_WinRTraiseException(long);
    107 
    108 inline void __abi_ThrowIfFailed(long __hrArg)
    109 {
    110     if (__hrArg < 0)
    111     {
    112         __abi_WinRTraiseException(__hrArg);
    113     }
    114 }
    115 
    116 struct Guid
    117 {
    118 public:
    119     Guid();
    120     Guid(__rcGUID_t);
    121     operator ::__rcGUID_t();
    122     bool Equals(Guid __guidArg);
    123     bool Equals(__rcGUID_t __guidArg);
    124     Guid(unsigned int __aArg, unsigned short __bArg, unsigned short __cArg, unsigned __int8 __dArg,
    125         unsigned __int8 __eArg, unsigned __int8 __fArg, unsigned __int8 __gArg, unsigned __int8 __hArg,
    126         unsigned __int8 __iArg, unsigned __int8 __jArg, unsigned __int8 __kArg);
    127     Guid(unsigned int __aArg, unsigned short __bArg, unsigned short __cArg, const unsigned __int8* __dArg);
    128 private:
    129     unsigned long  __a;
    130     unsigned short __b;
    131     unsigned short __c;
    132     unsigned char __d;
    133     unsigned char __e;
    134     unsigned char __f;
    135     unsigned char __g;
    136     unsigned char __h;
    137     unsigned char __i;
    138     unsigned char __j;
    139     unsigned char __k;
    140 };
    141 
    142 static_assert(sizeof(Guid) == sizeof(::_GUID), "Incorect size for Guid");
    143 static_assert(sizeof(__rcGUID_t) == sizeof(::_GUID), "Incorect size for __rcGUID_t");
    144 
    145 ////////////////////////////////////////////////////////////////////////////////
    146 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)
    147 {
    148 }
    149 
    150 inline Guid::Guid(__rcGUID_t __guid) :
    151 __a(reinterpret_cast<const __s_GUID&>(__guid).Data1),
    152 __b(reinterpret_cast<const __s_GUID&>(__guid).Data2),
    153 __c(reinterpret_cast<const __s_GUID&>(__guid).Data3),
    154 __d(reinterpret_cast<const __s_GUID&>(__guid).Data4[0]),
    155 __e(reinterpret_cast<const __s_GUID&>(__guid).Data4[1]),
    156 __f(reinterpret_cast<const __s_GUID&>(__guid).Data4[2]),
    157 __g(reinterpret_cast<const __s_GUID&>(__guid).Data4[3]),
    158 __h(reinterpret_cast<const __s_GUID&>(__guid).Data4[4]),
    159 __i(reinterpret_cast<const __s_GUID&>(__guid).Data4[5]),
    160 __j(reinterpret_cast<const __s_GUID&>(__guid).Data4[6]),
    161 __k(reinterpret_cast<const __s_GUID&>(__guid).Data4[7])
    162 {
    163 }
    164 
    165 inline Guid::operator ::__rcGUID_t()
    166 {
    167     return reinterpret_cast<__rcGUID_t>(*this);
    168 }
    169 
    170 inline bool Guid::Equals(Guid __guidArg)
    171 {
    172     return *this == __guidArg;
    173 }
    174 
    175 inline bool Guid::Equals(__rcGUID_t __guidArg)
    176 {
    177     return *this == static_cast< Guid>(__guidArg);
    178 }
    179 
    180 inline bool operator==(Guid __aArg, Guid __bArg)
    181 {
    182     auto __a = reinterpret_cast<unsigned long*>(&__aArg);
    183     auto __b = reinterpret_cast<unsigned long*>(&__bArg);
    184 
    185     return (__a[0] == __b[0] && __a[1] == __b[1] && __a[2] == __b[2] && __a[3] == __b[3]);
    186 }
    187 
    188 inline bool operator!=(Guid __aArg, Guid __bArg)
    189 {
    190     return !(__aArg == __bArg);
    191 }
    192 
    193 inline bool operator<(Guid __aArg, Guid __bArg)
    194 {
    195     auto __a = reinterpret_cast<unsigned long*>(&__aArg);
    196     auto __b = reinterpret_cast<unsigned long*>(&__bArg);
    197 
    198     if (__a[0] != __b[0])
    199     {
    200         return __a[0] < __b[0];
    201     }
    202 
    203     if (__a[1] != __b[1])
    204     {
    205         return __a[1] < __b[1];
    206     }
    207 
    208     if (__a[2] != __b[2])
    209     {
    210         return __a[2] < __b[2];
    211     }
    212 
    213     if (__a[3] != __b[3])
    214     {
    215         return __a[3] < __b[3];
    216     }
    217 
    218     return false;
    219 }
    220 
    221 inline Guid::Guid(unsigned int __aArg, unsigned short __bArg, unsigned short __cArg, unsigned __int8 __dArg,
    222     unsigned __int8 __eArg, unsigned __int8 __fArg, unsigned __int8 __gArg, unsigned __int8 __hArg,
    223     unsigned __int8 __iArg, unsigned __int8 __jArg, unsigned __int8 __kArg) :
    224     __a(__aArg), __b(__bArg), __c(__cArg), __d(__dArg), __e(__eArg), __f(__fArg), __g(__gArg), __h(__hArg), __i(__iArg), __j(__jArg), __k(__kArg)
    225 {
    226 }
    227 
    228 inline Guid::Guid(unsigned int __aArg, unsigned short __bArg, unsigned short __cArg, const unsigned __int8 __dArg[8]) :
    229 __a(__aArg), __b(__bArg), __c(__cArg)
    230 {
    231     __d = __dArg[0];
    232     __e = __dArg[1];
    233     __f = __dArg[2];
    234     __g = __dArg[3];
    235     __h = __dArg[4];
    236     __i = __dArg[5];
    237     __j = __dArg[6];
    238     __k = __dArg[7];
    239 }
    240 
    241 __declspec(selectany) Guid __winrt_GUID_NULL(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
    242 
    243 //
    244 //// Don't want to define the real IUnknown from unknown.h here. That would means if the user has
    245 //// any broken code that uses it, compile errors will take the form of e.g.:
    246 ////     predefined C++ WinRT types (compiler internal)(41) : see declaration of 'IUnknown::QueryInterface'
    247 //// This is not helpful. If they use IUnknown, we still need to point them to the actual unknown.h so
    248 //// that they can see the original definition.
    249 ////
    250 //// For WinRT, we'll instead have a parallel COM interface hierarchy for basic interfaces starting with _.
    251 //// The type mismatch is not an issue. COM passes types through GUID / void* combos - the original type
    252 //// doesn't come into play unless the user static_casts an implementation type to one of these, but
    253 //// the WinRT implementation types are hidden.
    254 __interface __declspec(uuid("00000000-0000-0000-C000-000000000046")) __abi_IUnknown
    255 {
    256 public:
    257     virtual long __stdcall __abi_QueryInterface(Guid&, void**) = 0;
    258     virtual unsigned long __stdcall __abi_AddRef() = 0;
    259     virtual unsigned long __stdcall __abi_Release() = 0;
    260 };
    261 #endif
    262 #include "ppltasks_winrt.h"
    263 #endif
    264 #else
    265 #include <comdef.h>
    266 #endif
    267 
    268 struct IMFMediaType;
    269 #ifndef WINRT
    270 struct IMFActivate;
    271 struct IMFMediaSource;
    272 #endif
    273 struct IMFAttributes;
    274 
    275 namespace
    276 {
    277 
    278 template <class T> void SafeRelease(T **ppT)
    279 {
    280     if (*ppT)
    281     {
    282         (*ppT)->Release();
    283         *ppT = NULL;
    284     }
    285 }
    286 
    287 #ifdef _DEBUG
    288 /// Class for printing info into console
    289 class DPO
    290 {
    291 public:
    292     ~DPO(void);
    293     static DPO& getInstance();
    294     void printOut(const wchar_t *format, ...);
    295     void setVerbose(bool state);
    296     bool verbose;
    297 private:
    298     DPO(void);
    299 };
    300 #define DebugPrintOut(...) DPO::getInstance().printOut(__VA_ARGS__)
    301 #else
    302 #define DebugPrintOut(...) void()
    303 #endif
    304 
    305 #include "cap_msmf.hpp"
    306 
    307 // Structure for collecting info about types of video, which are supported by current video device
    308 struct MediaType
    309 {
    310     unsigned int MF_MT_FRAME_SIZE;
    311     unsigned int height;
    312     unsigned int width;
    313     unsigned int MF_MT_YUV_MATRIX;
    314     unsigned int MF_MT_VIDEO_LIGHTING;
    315     int MF_MT_DEFAULT_STRIDE; // stride is negative if image is bottom-up
    316     unsigned int MF_MT_VIDEO_CHROMA_SITING;
    317     GUID MF_MT_AM_FORMAT_TYPE;
    318     wchar_t *pMF_MT_AM_FORMAT_TYPEName;
    319     unsigned int MF_MT_FIXED_SIZE_SAMPLES;
    320     unsigned int MF_MT_VIDEO_NOMINAL_RANGE;
    321     unsigned int MF_MT_FRAME_RATE_NUMERATOR;
    322     unsigned int MF_MT_FRAME_RATE_DENOMINATOR;
    323     unsigned int MF_MT_PIXEL_ASPECT_RATIO;
    324     unsigned int MF_MT_PIXEL_ASPECT_RATIO_low;
    325     unsigned int MF_MT_ALL_SAMPLES_INDEPENDENT;
    326     unsigned int MF_MT_FRAME_RATE_RANGE_MIN;
    327     unsigned int MF_MT_FRAME_RATE_RANGE_MIN_low;
    328     unsigned int MF_MT_SAMPLE_SIZE;
    329     unsigned int MF_MT_VIDEO_PRIMARIES;
    330     unsigned int MF_MT_INTERLACE_MODE;
    331     unsigned int MF_MT_FRAME_RATE_RANGE_MAX;
    332     unsigned int MF_MT_FRAME_RATE_RANGE_MAX_low;
    333     GUID MF_MT_MAJOR_TYPE;
    334     GUID MF_MT_SUBTYPE;
    335     wchar_t *pMF_MT_MAJOR_TYPEName;
    336     wchar_t *pMF_MT_SUBTYPEName;
    337     MediaType();
    338     ~MediaType();
    339     void Clear();
    340 };
    341 
    342 /// Class for parsing info from IMFMediaType into the local MediaType
    343 class FormatReader
    344 {
    345 public:
    346     static MediaType Read(IMFMediaType *pType);
    347     ~FormatReader(void);
    348 private:
    349     FormatReader(void);
    350 };
    351 
    352 DWORD WINAPI MainThreadFunction( LPVOID lpParam );
    353 typedef void(*emergensyStopEventCallback)(int, void *);
    354 
    355 class RawImage
    356 {
    357 public:
    358     ~RawImage(void);
    359     // Function of creation of the instance of the class
    360     static long CreateInstance(RawImage **ppRImage,unsigned int size);
    361     void setCopy(const BYTE * pSampleBuffer);
    362     void fastCopy(const BYTE * pSampleBuffer);
    363     unsigned char * getpPixels();
    364     bool isNew();
    365     unsigned int getSize();
    366 private:
    367     bool ri_new;
    368     unsigned int ri_size;
    369     unsigned char *ri_pixels;
    370     RawImage(unsigned int size);
    371 };
    372 
    373 class ImageGrabberCallback : public IMFSampleGrabberSinkCallback
    374 {
    375 public:
    376     void pauseGrabbing();
    377     void resumeGrabbing();
    378     RawImage *getRawImage();
    379     // IMFClockStateSink methods
    380     STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset);
    381     STDMETHODIMP OnClockStop(MFTIME hnsSystemTime);
    382     STDMETHODIMP OnClockPause(MFTIME hnsSystemTime);
    383     STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime);
    384     STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate);
    385     // IMFSampleGrabberSinkCallback methods
    386     STDMETHODIMP OnSetPresentationClock(IMFPresentationClock* pClock);
    387     STDMETHODIMP OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags,
    388         LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer,
    389         DWORD dwSampleSize);
    390     STDMETHODIMP OnShutdown();
    391 
    392     const HANDLE ig_hFrameReady;
    393     const HANDLE ig_hFrameGrabbed;
    394     const HANDLE ig_hFinish;
    395 protected:
    396     ImageGrabberCallback(bool synchronous);
    397     bool ig_RIE;
    398     bool ig_Close;
    399     bool ig_Synchronous;
    400     long m_cRef;
    401 
    402     RawImage *ig_RIFirst;
    403     RawImage *ig_RISecond;
    404     RawImage *ig_RIOut;
    405 private:
    406     ImageGrabberCallback& operator=(const ImageGrabberCallback&);   // Declared to fix compilation warning.
    407  };
    408 
    409 #ifdef WINRT
    410 extern const __declspec(selectany) WCHAR RuntimeClass_CV_ImageGrabberWinRT[] = L"cv.ImageGrabberWinRT";
    411 
    412 class ImageGrabberWinRT :
    413     public Microsoft::WRL::RuntimeClass<
    414     Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>,
    415     IMFSampleGrabberSinkCallback>, public ImageGrabberCallback
    416 {
    417     InspectableClass(RuntimeClass_CV_ImageGrabberWinRT, BaseTrust)
    418 public:
    419     ImageGrabberWinRT(bool synchronous);
    420     ~ImageGrabberWinRT(void);
    421 
    422     HRESULT initImageGrabber(MAKE_WRL_REF(_MediaCapture) pSource,
    423         GUID VideoFormat);
    424     HRESULT startGrabbing(MAKE_WRL_REF(_AsyncAction)* action);
    425     HRESULT stopGrabbing(MAKE_WRL_REF(_AsyncAction)* action);
    426     // IMFClockStateSink methods
    427     STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) { return ImageGrabberCallback::OnClockStart(hnsSystemTime, llClockStartOffset); }
    428     STDMETHODIMP OnClockStop(MFTIME hnsSystemTime) { return ImageGrabberCallback::OnClockStop(hnsSystemTime); }
    429     STDMETHODIMP OnClockPause(MFTIME hnsSystemTime) { return ImageGrabberCallback::OnClockPause(hnsSystemTime); }
    430     STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime) { return ImageGrabberCallback::OnClockRestart(hnsSystemTime); }
    431     STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate) { return ImageGrabberCallback::OnClockSetRate(hnsSystemTime, flRate); }
    432     // IMFSampleGrabberSinkCallback methods
    433     STDMETHODIMP OnSetPresentationClock(IMFPresentationClock* pClock) { return ImageGrabberCallback::OnSetPresentationClock(pClock); }
    434     STDMETHODIMP OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags,
    435         LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer,
    436         DWORD dwSampleSize) { return ImageGrabberCallback::OnProcessSample(guidMajorMediaType, dwSampleFlags, llSampleTime, llSampleDuration, pSampleBuffer, dwSampleSize); }
    437     STDMETHODIMP OnShutdown() { return ImageGrabberCallback::OnShutdown(); }
    438     // Function of creation of the instance of the class
    439     static HRESULT CreateInstance(ImageGrabberWinRT **ppIG, bool synchronous = false);
    440 private:
    441     MAKE_WRL_AGILE_REF(_MediaCapture) ig_pMedCapSource;
    442     MediaSink* ig_pMediaSink;
    443 };
    444 #endif
    445 
    446 // Class for grabbing image from video stream
    447 class ImageGrabber : public ImageGrabberCallback
    448 {
    449 public:
    450     ~ImageGrabber(void);
    451     HRESULT initImageGrabber(IMFMediaSource *pSource);
    452     HRESULT startGrabbing(void);
    453     void stopGrabbing();
    454     // IUnknown methods
    455     STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
    456     STDMETHODIMP_(ULONG) AddRef();
    457     STDMETHODIMP_(ULONG) Release();
    458     // Function of creation of the instance of the class
    459     static HRESULT CreateInstance(ImageGrabber **ppIG, unsigned int deviceID, bool synchronous = false);
    460 
    461 private:
    462     unsigned int ig_DeviceID;
    463 
    464     IMFMediaSource *ig_pSource;
    465     IMFMediaSession *ig_pSession;
    466     IMFTopology *ig_pTopology;
    467     ImageGrabber(unsigned int deviceID, bool synchronous);
    468     HRESULT CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo);
    469     HRESULT AddSourceNode(IMFTopology *pTopology, IMFMediaSource *pSource,
    470         IMFPresentationDescriptor *pPD, IMFStreamDescriptor *pSD, IMFTopologyNode **ppNode);
    471     HRESULT AddOutputNode(IMFTopology *pTopology, IMFActivate *pActivate, DWORD dwId, IMFTopologyNode **ppNode);
    472 
    473     ImageGrabber& operator=(const ImageGrabber&);   // Declared to fix comiplation error.
    474 };
    475 
    476 /// Class for controlling of thread of the grabbing raw data from video device
    477 class ImageGrabberThread
    478 {
    479     friend DWORD WINAPI MainThreadFunction( LPVOID lpParam );
    480 public:
    481     ~ImageGrabberThread(void);
    482     static HRESULT CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID, bool synchronious = false);
    483     void start();
    484     void stop();
    485     void setEmergencyStopEvent(void *userData, void(*func)(int, void *));
    486     ImageGrabber *getImageGrabber();
    487 protected:
    488     virtual void run();
    489 private:
    490     ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID, bool synchronious);
    491     HANDLE igt_Handle;
    492     DWORD   igt_ThreadIdArray;
    493     ImageGrabber *igt_pImageGrabber;
    494     emergensyStopEventCallback igt_func;
    495     void *igt_userData;
    496     bool igt_stop;
    497     unsigned int igt_DeviceID;
    498 };
    499 
    500 // Structure for collecting info about one parametr of current video device
    501 struct Parametr
    502 {
    503     long CurrentValue;
    504     long Min;
    505     long Max;
    506     long Step;
    507     long Default;
    508     long Flag;
    509     Parametr();
    510 };
    511 
    512 // Structure for collecting info about 17 parametrs of current video device
    513 struct CamParametrs
    514 {
    515         Parametr Brightness;
    516         Parametr Contrast;
    517         Parametr Hue;
    518         Parametr Saturation;
    519         Parametr Sharpness;
    520         Parametr Gamma;
    521         Parametr ColorEnable;
    522         Parametr WhiteBalance;
    523         Parametr BacklightCompensation;
    524         Parametr Gain;
    525         Parametr Pan;
    526         Parametr Tilt;
    527         Parametr Roll;
    528         Parametr Zoom;
    529         Parametr Exposure;
    530         Parametr Iris;
    531         Parametr Focus;
    532 };
    533 
    534 typedef std::wstring String;
    535 typedef std::vector<int> vectorNum;
    536 typedef std::map<String, vectorNum> SUBTYPEMap;
    537 typedef std::map<UINT64, SUBTYPEMap> FrameRateMap;
    538 typedef void(*emergensyStopEventCallback)(int, void *);
    539 
    540 /// Class for controlling of video device
    541 class videoDevice
    542 {
    543 public:
    544     videoDevice(void);
    545     ~videoDevice(void);
    546     void closeDevice();
    547     CamParametrs getParametrs();
    548     void setParametrs(CamParametrs parametrs);
    549     void setEmergencyStopEvent(void *userData, void(*func)(int, void *));
    550 #ifdef WINRT
    551     long readInfoOfDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice, unsigned int Num);
    552     void waitForDevice()
    553     {
    554         if (vd_pAction) {
    555 #ifdef HAVE_CONCURRENCY
    556             CREATE_TASK DEFINE_RET_TYPE(void)(vd_pAction).wait();
    557 #endif
    558             vd_pAction = nullptr;
    559         }
    560     }
    561 #else
    562     long readInfoOfDevice(IMFActivate *pActivate, unsigned int Num);
    563 #endif
    564     wchar_t *getName();
    565     int getCountFormats();
    566     unsigned int getWidth();
    567     unsigned int getHeight();
    568     unsigned int getFrameRate() const;
    569     MediaType getFormat(unsigned int id);
    570     bool setupDevice(unsigned int w, unsigned int h, unsigned int idealFramerate = 0);
    571     bool setupDevice(unsigned int id);
    572     bool isDeviceSetup();
    573     bool isDeviceMediaSource();
    574     bool isDeviceRawDataSource();
    575     bool isFrameNew();
    576     IMFMediaSource *getMediaSource();
    577     RawImage *getRawImageOut();
    578 private:
    579     enum typeLock
    580     {
    581         MediaSourceLock,
    582         RawDataLock,
    583         OpenLock
    584     } vd_LockOut;
    585     wchar_t *vd_pFriendlyName;
    586     ImageGrabberThread *vd_pImGrTh;
    587     CamParametrs vd_PrevParametrs;
    588     unsigned int vd_Width;
    589     unsigned int vd_Height;
    590     unsigned int vd_FrameRate;
    591     unsigned int vd_CurrentNumber;
    592     bool vd_IsSetuped;
    593     std::map<UINT64, FrameRateMap> vd_CaptureFormats;
    594     std::vector<MediaType> vd_CurrentFormats;
    595     IMFMediaSource *vd_pSource;
    596 #ifdef WINRT
    597     MAKE_WRL_AGILE_REF(_MediaCapture) vd_pMedCap;
    598     EventRegistrationToken vd_cookie;
    599     ImageGrabberWinRT *vd_pImGr;
    600     MAKE_WRL_REF(_AsyncAction) vd_pAction;
    601 #ifdef HAVE_CONCURRENCY
    602     Concurrency::critical_section vd_lock;
    603 #endif
    604 #endif
    605     emergensyStopEventCallback vd_func;
    606     void *vd_userData;
    607     HRESULT enumerateCaptureFormats(IMFMediaSource *pSource);
    608     long setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex);
    609     void buildLibraryofTypes();
    610     int findType(unsigned int size, unsigned int frameRate = 0);
    611 #ifdef WINRT
    612     HRESULT enumerateCaptureFormats(MAKE_WRL_REF(_MediaCapture) pSource);
    613     long setDeviceFormat(MAKE_WRL_REF(_MediaCapture) pSource, unsigned long dwFormatIndex, MAKE_WRL_REF(_AsyncAction)* pAction);
    614     long resetDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice);
    615 #ifdef HAVE_CONCURRENCY
    616     long checkDevice(_DeviceClass devClass, DEFINE_TASK<void>* pTask, MAKE_WRL_REF(_IDeviceInformation)* ppDevice);
    617 #endif
    618 #else
    619     long resetDevice(IMFActivate *pActivate);
    620     long checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice);
    621 #endif
    622     long initDevice();
    623 };
    624 
    625 /// Class for managing of list of video devices
    626 class videoDevices
    627 {
    628 public:
    629     ~videoDevices(void);
    630 #ifdef WINRT
    631     long initDevices(_DeviceClass devClass);
    632     void waitInit() {
    633         if (vds_enumTask) {
    634 #ifdef HAVE_CONCURRENCY
    635             CREATE_TASK DEFINE_RET_TYPE(void)(vds_enumTask).wait();
    636 #endif
    637             vds_enumTask = nullptr;
    638         }
    639     }
    640 #else
    641     long initDevices(IMFAttributes *pAttributes);
    642 #endif
    643     static videoDevices& getInstance();
    644     videoDevice *getDevice(unsigned int i);
    645     unsigned int getCount();
    646     void clearDevices();
    647 private:
    648     UINT32 count;
    649 #ifdef WINRT
    650     MAKE_WRL_REF(_AsyncAction) vds_enumTask;
    651 #endif
    652     std::vector<videoDevice *> vds_Devices;
    653     videoDevices(void);
    654 };
    655 
    656 // Class for creating of Media Foundation context
    657 class Media_Foundation
    658 {
    659 public:
    660     virtual ~Media_Foundation(void);
    661     static Media_Foundation& getInstance();
    662     bool buildListOfDevices();
    663 private:
    664     Media_Foundation(void);
    665 };
    666 
    667 /// The only visiable class for controlling of video devices in format singelton
    668 class videoInput
    669 {
    670 public:
    671     virtual ~videoInput(void);
    672     // Getting of static instance of videoInput class
    673     static videoInput& getInstance();
    674     // Closing video device with deviceID
    675     void closeDevice(int deviceID);
    676     // Setting callback function for emergency events(for example: removing video device with deviceID) with userData
    677     void setEmergencyStopEvent(int deviceID, void *userData, void(*func)(int, void *));
    678     // Closing all devices
    679     void closeAllDevices();
    680     // Getting of parametrs of video device with deviceID
    681     CamParametrs getParametrs(int deviceID);
    682     // Setting of parametrs of video device with deviceID
    683     void setParametrs(int deviceID, CamParametrs parametrs);
    684     // Getting numbers of existence videodevices with listing in consol
    685     unsigned int listDevices(bool silent = false);
    686     // Getting numbers of formats, which are supported by videodevice with deviceID
    687     unsigned int getCountFormats(int deviceID) const;
    688     // Getting width of image, which is getting from videodevice with deviceID
    689     unsigned int getWidth(int deviceID) const;
    690     // Getting height of image, which is getting from videodevice with deviceID
    691     unsigned int getHeight(int deviceID) const;
    692     // Getting frame rate, which is getting from videodevice with deviceID
    693     unsigned int getFrameRate(int deviceID) const;
    694     // Getting name of videodevice with deviceID
    695     wchar_t *getNameVideoDevice(int deviceID);
    696     // Getting interface MediaSource for Media Foundation from videodevice with deviceID
    697     IMFMediaSource *getMediaSource(int deviceID);
    698     // Getting format with id, which is supported by videodevice with deviceID
    699     MediaType getFormat(int deviceID, int unsigned id);
    700     // Checking of existence of the suitable video devices
    701     bool isDevicesAcceable();
    702     // Checking of using the videodevice with deviceID
    703     bool isDeviceSetup(int deviceID);
    704     // Checking of using MediaSource from videodevice with deviceID
    705     bool isDeviceMediaSource(int deviceID);
    706     // Checking of using Raw Data of pixels from videodevice with deviceID
    707     bool isDeviceRawDataSource(int deviceID);
    708 #ifdef _DEBUG
    709     // Setting of the state of outprinting info in console
    710     static void setVerbose(bool state);
    711 #endif
    712     // Initialization of video device with deviceID by media type with id
    713     bool setupDevice(int deviceID, unsigned int id = 0);
    714     // Initialization of video device with deviceID by wisth w, height h and fps idealFramerate
    715     bool setupDevice(int deviceID, unsigned int w, unsigned int h, unsigned int idealFramerate = 30);
    716     // Checking of recivig of new frame from video device with deviceID
    717     bool isFrameNew(int deviceID);
    718 #ifdef WINRT
    719     void waitForDevice(int deviceID);
    720 #endif
    721     // Writing of Raw Data pixels from video device with deviceID with correction of RedAndBlue flipping flipRedAndBlue and vertical flipping flipImage
    722     bool getPixels(int deviceID, unsigned char * pixels, bool flipRedAndBlue = false, bool flipImage = false);
    723     static void processPixels(unsigned char * src, unsigned char * dst, unsigned int width, unsigned int height, unsigned int bpp, bool bRGB, bool bFlip);
    724 private:
    725     bool accessToDevices;
    726     videoInput(void);
    727     void updateListOfDevices();
    728 };
    729 
    730 #ifdef _DEBUG
    731 DPO::DPO(void):verbose(true)
    732 {
    733 }
    734 
    735 DPO::~DPO(void)
    736 {
    737 }
    738 
    739 DPO& DPO::getInstance()
    740 {
    741     static DPO instance;
    742     return instance;
    743 }
    744 
    745 void DPO::printOut(const wchar_t *format, ...)
    746 {
    747     if(verbose)
    748     {
    749         int i = 0;
    750         wchar_t *p = NULL;
    751         va_list args;
    752         va_start(args, format);
    753         if( ::IsDebuggerPresent() )
    754         {
    755             WCHAR szMsg[512];
    756             ::StringCchVPrintfW(szMsg, sizeof(szMsg)/sizeof(szMsg[0]), format, args);
    757             ::OutputDebugStringW(szMsg);
    758         }
    759         else
    760         {
    761             if(wcscmp(format, L"%i"))
    762             {
    763                 i = va_arg (args, int);
    764             }
    765             if(wcscmp(format, L"%s"))
    766             {
    767                 p = va_arg (args, wchar_t *);
    768             }
    769             wprintf(format, i,p);
    770         }
    771         va_end (args);
    772     }
    773 }
    774 
    775 void DPO::setVerbose(bool state)
    776 {
    777     verbose = state;
    778 }
    779 #endif
    780 
    781 LPCWSTR GetGUIDNameConstNew(const GUID& guid);
    782 HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz);
    783 HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index);
    784 HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, MediaType &out);
    785 
    786 unsigned int *GetParametr(GUID guid, MediaType &out)
    787 {
    788     if(guid == MF_MT_YUV_MATRIX)
    789         return &(out.MF_MT_YUV_MATRIX);
    790     if(guid == MF_MT_VIDEO_LIGHTING)
    791         return &(out.MF_MT_VIDEO_LIGHTING);
    792     if(guid == MF_MT_DEFAULT_STRIDE)
    793         return (unsigned int*)&(out.MF_MT_DEFAULT_STRIDE);
    794     if(guid == MF_MT_VIDEO_CHROMA_SITING)
    795         return &(out.MF_MT_VIDEO_CHROMA_SITING);
    796     if(guid == MF_MT_VIDEO_NOMINAL_RANGE)
    797         return &(out.MF_MT_VIDEO_NOMINAL_RANGE);
    798     if(guid == MF_MT_ALL_SAMPLES_INDEPENDENT)
    799         return &(out.MF_MT_ALL_SAMPLES_INDEPENDENT);
    800     if(guid == MF_MT_FIXED_SIZE_SAMPLES)
    801         return &(out.MF_MT_FIXED_SIZE_SAMPLES);
    802     if(guid == MF_MT_SAMPLE_SIZE)
    803         return &(out.MF_MT_SAMPLE_SIZE);
    804     if(guid == MF_MT_VIDEO_PRIMARIES)
    805         return &(out.MF_MT_VIDEO_PRIMARIES);
    806     if(guid == MF_MT_INTERLACE_MODE)
    807         return &(out.MF_MT_INTERLACE_MODE);
    808     return NULL;
    809 }
    810 
    811 HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, MediaType &out)
    812 {
    813     WCHAR *pGuidName = NULL;
    814     WCHAR *pGuidValName = NULL;
    815     GUID guid = { 0 };
    816     PROPVARIANT var;
    817     PropVariantInit(&var);
    818     HRESULT hr = pAttr->GetItemByIndex(index, &guid, &var);
    819     if (FAILED(hr))
    820     {
    821         goto done;
    822     }
    823     hr = GetGUIDNameNew(guid, &pGuidName);
    824     if (FAILED(hr))
    825     {
    826         goto done;
    827     }
    828     hr = SpecialCaseAttributeValueNew(guid, var, out);
    829     unsigned int *p;
    830     if (FAILED(hr))
    831     {
    832         goto done;
    833     }
    834     if (hr == S_FALSE)
    835     {
    836         switch (var.vt)
    837         {
    838         case VT_UI4:
    839             p = GetParametr(guid, out);
    840             if(p)
    841             {
    842                 *p = var.ulVal;
    843             }
    844             break;
    845         case VT_UI8:
    846             break;
    847         case VT_R8:
    848             break;
    849         case VT_CLSID:
    850             if(guid == MF_MT_AM_FORMAT_TYPE)
    851             {
    852                 hr = GetGUIDNameNew(*var.puuid, &pGuidValName);
    853                 if (SUCCEEDED(hr))
    854                 {
    855                     out.MF_MT_AM_FORMAT_TYPE = *var.puuid;
    856                     out.pMF_MT_AM_FORMAT_TYPEName = pGuidValName;
    857                     pGuidValName = NULL;
    858                 }
    859             }
    860             if(guid == MF_MT_MAJOR_TYPE)
    861             {
    862                 hr = GetGUIDNameNew(*var.puuid, &pGuidValName);
    863                 if (SUCCEEDED(hr))
    864                 {
    865                     out.MF_MT_MAJOR_TYPE = *var.puuid;
    866                     out.pMF_MT_MAJOR_TYPEName = pGuidValName;
    867                     pGuidValName = NULL;
    868                 }
    869             }
    870             if(guid == MF_MT_SUBTYPE)
    871             {
    872                 hr = GetGUIDNameNew(*var.puuid, &pGuidValName);
    873                 if (SUCCEEDED(hr))
    874                 {
    875                     out.MF_MT_SUBTYPE = *var.puuid;
    876                     out.pMF_MT_SUBTYPEName = pGuidValName;
    877                     pGuidValName = NULL;
    878                 }
    879             }
    880             break;
    881         case VT_LPWSTR:
    882             break;
    883         case VT_VECTOR | VT_UI1:
    884             break;
    885         case VT_UNKNOWN:
    886             break;
    887         default:
    888             break;
    889         }
    890     }
    891 done:
    892     CoTaskMemFree(pGuidName);
    893     CoTaskMemFree(pGuidValName);
    894     PropVariantClear(&var);
    895     return hr;
    896 }
    897 
    898 HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz)
    899 {
    900     HRESULT hr = S_OK;
    901     WCHAR *pName = NULL;
    902     LPCWSTR pcwsz = GetGUIDNameConstNew(guid);
    903     if (pcwsz)
    904     {
    905         size_t cchLength = 0;
    906         hr = StringCchLengthW(pcwsz, STRSAFE_MAX_CCH, &cchLength);
    907         if (FAILED(hr))
    908         {
    909             goto done;
    910         }
    911         pName = (WCHAR*)CoTaskMemAlloc((cchLength + 1) * sizeof(WCHAR));
    912         if (pName == NULL)
    913         {
    914             hr = E_OUTOFMEMORY;
    915             goto done;
    916         }
    917         hr = StringCchCopyW(pName, cchLength + 1, pcwsz);
    918         if (FAILED(hr))
    919         {
    920             goto done;
    921         }
    922     }
    923     else
    924     {
    925         hr = StringFromCLSID(guid, &pName);
    926     }
    927 done:
    928     if (FAILED(hr))
    929     {
    930         *ppwsz = NULL;
    931         CoTaskMemFree(pName);
    932     }
    933     else
    934     {
    935         *ppwsz = pName;
    936     }
    937     return hr;
    938 }
    939 
    940 void LogUINT32AsUINT64New(const PROPVARIANT& var, UINT32 &uHigh, UINT32 &uLow)
    941 {
    942     Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &uHigh, &uLow);
    943 }
    944 
    945 float OffsetToFloatNew(const MFOffset& offset)
    946 {
    947     return offset.value + (static_cast<float>(offset.fract) / 65536.0f);
    948 }
    949 
    950 HRESULT LogVideoAreaNew(const PROPVARIANT& var)
    951 {
    952     if (var.caub.cElems < sizeof(MFVideoArea))
    953     {
    954         return S_OK;
    955     }
    956     return S_OK;
    957 }
    958 
    959 HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, MediaType &out)
    960 {
    961     if (guid == MF_MT_DEFAULT_STRIDE)
    962     {
    963         out.MF_MT_DEFAULT_STRIDE = var.intVal;
    964     } else
    965     if (guid == MF_MT_FRAME_SIZE)
    966     {
    967         UINT32 uHigh = 0, uLow = 0;
    968         LogUINT32AsUINT64New(var, uHigh, uLow);
    969         out.width = uHigh;
    970         out.height = uLow;
    971         out.MF_MT_FRAME_SIZE = out.width * out.height;
    972     }
    973     else
    974     if (guid == MF_MT_FRAME_RATE)
    975     {
    976         UINT32 uHigh = 0, uLow = 0;
    977         LogUINT32AsUINT64New(var, uHigh, uLow);
    978         out.MF_MT_FRAME_RATE_NUMERATOR = uHigh;
    979         out.MF_MT_FRAME_RATE_DENOMINATOR = uLow;
    980     }
    981     else
    982     if (guid == MF_MT_FRAME_RATE_RANGE_MAX)
    983     {
    984         UINT32 uHigh = 0, uLow = 0;
    985         LogUINT32AsUINT64New(var, uHigh, uLow);
    986         out.MF_MT_FRAME_RATE_RANGE_MAX = uHigh;
    987         out.MF_MT_FRAME_RATE_RANGE_MAX_low = uLow;
    988     }
    989     else
    990     if (guid == MF_MT_FRAME_RATE_RANGE_MIN)
    991     {
    992         UINT32 uHigh = 0, uLow = 0;
    993         LogUINT32AsUINT64New(var, uHigh, uLow);
    994         out.MF_MT_FRAME_RATE_RANGE_MIN = uHigh;
    995         out.MF_MT_FRAME_RATE_RANGE_MIN_low = uLow;
    996     }
    997     else
    998     if (guid == MF_MT_PIXEL_ASPECT_RATIO)
    999     {
   1000         UINT32 uHigh = 0, uLow = 0;
   1001         LogUINT32AsUINT64New(var, uHigh, uLow);
   1002         out.MF_MT_PIXEL_ASPECT_RATIO = uHigh;
   1003         out.MF_MT_PIXEL_ASPECT_RATIO_low = uLow;
   1004     }
   1005     else
   1006     {
   1007         return S_FALSE;
   1008     }
   1009     return S_OK;
   1010 }
   1011 
   1012 #ifndef IF_EQUAL_RETURN
   1013 #define IF_EQUAL_RETURN(param, val) if(val == param) return L#val
   1014 #endif
   1015 
   1016 LPCWSTR GetGUIDNameConstNew(const GUID& guid)
   1017 {
   1018     IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE);
   1019     IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE);
   1020     IF_EQUAL_RETURN(guid, MF_MT_SUBTYPE);
   1021     IF_EQUAL_RETURN(guid, MF_MT_ALL_SAMPLES_INDEPENDENT);
   1022     IF_EQUAL_RETURN(guid, MF_MT_FIXED_SIZE_SAMPLES);
   1023     IF_EQUAL_RETURN(guid, MF_MT_COMPRESSED);
   1024     IF_EQUAL_RETURN(guid, MF_MT_SAMPLE_SIZE);
   1025     IF_EQUAL_RETURN(guid, MF_MT_WRAPPED_TYPE);
   1026     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_NUM_CHANNELS);
   1027     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_SECOND);
   1028     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND);
   1029     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_AVG_BYTES_PER_SECOND);
   1030     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BLOCK_ALIGNMENT);
   1031     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BITS_PER_SAMPLE);
   1032     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_VALID_BITS_PER_SAMPLE);
   1033     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_BLOCK);
   1034     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_CHANNEL_MASK);
   1035     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FOLDDOWN_MATRIX);
   1036     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKREF);
   1037     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKTARGET);
   1038     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGREF);
   1039     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGTARGET);
   1040     IF_EQUAL_RETURN(guid, MF_MT_AUDIO_PREFER_WAVEFORMATEX);
   1041     IF_EQUAL_RETURN(guid, MF_MT_AAC_PAYLOAD_TYPE);
   1042     IF_EQUAL_RETURN(guid, MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION);
   1043     IF_EQUAL_RETURN(guid, MF_MT_FRAME_SIZE);
   1044     IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE);
   1045     IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MAX);
   1046     IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MIN);
   1047     IF_EQUAL_RETURN(guid, MF_MT_PIXEL_ASPECT_RATIO);
   1048     IF_EQUAL_RETURN(guid, MF_MT_DRM_FLAGS);
   1049     IF_EQUAL_RETURN(guid, MF_MT_PAD_CONTROL_FLAGS);
   1050     IF_EQUAL_RETURN(guid, MF_MT_SOURCE_CONTENT_HINT);
   1051     IF_EQUAL_RETURN(guid, MF_MT_VIDEO_CHROMA_SITING);
   1052     IF_EQUAL_RETURN(guid, MF_MT_INTERLACE_MODE);
   1053     IF_EQUAL_RETURN(guid, MF_MT_TRANSFER_FUNCTION);
   1054     IF_EQUAL_RETURN(guid, MF_MT_VIDEO_PRIMARIES);
   1055     IF_EQUAL_RETURN(guid, MF_MT_CUSTOM_VIDEO_PRIMARIES);
   1056     IF_EQUAL_RETURN(guid, MF_MT_YUV_MATRIX);
   1057     IF_EQUAL_RETURN(guid, MF_MT_VIDEO_LIGHTING);
   1058     IF_EQUAL_RETURN(guid, MF_MT_VIDEO_NOMINAL_RANGE);
   1059     IF_EQUAL_RETURN(guid, MF_MT_GEOMETRIC_APERTURE);
   1060     IF_EQUAL_RETURN(guid, MF_MT_MINIMUM_DISPLAY_APERTURE);
   1061     IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_APERTURE);
   1062     IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_ENABLED);
   1063     IF_EQUAL_RETURN(guid, MF_MT_AVG_BITRATE);
   1064     IF_EQUAL_RETURN(guid, MF_MT_AVG_BIT_ERROR_RATE);
   1065     IF_EQUAL_RETURN(guid, MF_MT_MAX_KEYFRAME_SPACING);
   1066     IF_EQUAL_RETURN(guid, MF_MT_DEFAULT_STRIDE);
   1067     IF_EQUAL_RETURN(guid, MF_MT_PALETTE);
   1068     IF_EQUAL_RETURN(guid, MF_MT_USER_DATA);
   1069     IF_EQUAL_RETURN(guid, MF_MT_AM_FORMAT_TYPE);
   1070     IF_EQUAL_RETURN(guid, MF_MT_MPEG_START_TIME_CODE);
   1071     IF_EQUAL_RETURN(guid, MF_MT_MPEG2_PROFILE);
   1072     IF_EQUAL_RETURN(guid, MF_MT_MPEG2_LEVEL);
   1073     IF_EQUAL_RETURN(guid, MF_MT_MPEG2_FLAGS);
   1074     IF_EQUAL_RETURN(guid, MF_MT_MPEG_SEQUENCE_HEADER);
   1075     IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_0);
   1076     IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_0);
   1077     IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_1);
   1078     IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_1);
   1079     IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_SRC_PACK);
   1080     IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_CTRL_PACK);
   1081     IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_HEADER);
   1082     IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_FORMAT);
   1083     IF_EQUAL_RETURN(guid, MF_MT_IMAGE_LOSS_TOLERANT);
   1084     IF_EQUAL_RETURN(guid, MF_MT_MPEG4_SAMPLE_DESCRIPTION);
   1085     IF_EQUAL_RETURN(guid, MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY);
   1086     IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_4CC);
   1087     IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_WAVE_FORMAT_TAG);
   1088     // Media types
   1089     IF_EQUAL_RETURN(guid, MFMediaType_Audio);
   1090     IF_EQUAL_RETURN(guid, MFMediaType_Video);
   1091     IF_EQUAL_RETURN(guid, MFMediaType_Protected);
   1092     IF_EQUAL_RETURN(guid, MFMediaType_SAMI);
   1093     IF_EQUAL_RETURN(guid, MFMediaType_Script);
   1094     IF_EQUAL_RETURN(guid, MFMediaType_Image);
   1095     IF_EQUAL_RETURN(guid, MFMediaType_HTML);
   1096     IF_EQUAL_RETURN(guid, MFMediaType_Binary);
   1097     IF_EQUAL_RETURN(guid, MFMediaType_FileTransfer);
   1098     IF_EQUAL_RETURN(guid, MFVideoFormat_AI44); //     FCC('AI44')
   1099     IF_EQUAL_RETURN(guid, MFVideoFormat_ARGB32); //   D3DFMT_A8R8G8B8
   1100     IF_EQUAL_RETURN(guid, MFVideoFormat_AYUV); //     FCC('AYUV')
   1101     IF_EQUAL_RETURN(guid, MFVideoFormat_DV25); //     FCC('dv25')
   1102     IF_EQUAL_RETURN(guid, MFVideoFormat_DV50); //     FCC('dv50')
   1103     IF_EQUAL_RETURN(guid, MFVideoFormat_DVH1); //     FCC('dvh1')
   1104     IF_EQUAL_RETURN(guid, MFVideoFormat_DVSD); //     FCC('dvsd')
   1105     IF_EQUAL_RETURN(guid, MFVideoFormat_DVSL); //     FCC('dvsl')
   1106     IF_EQUAL_RETURN(guid, MFVideoFormat_H264); //     FCC('H264')
   1107     IF_EQUAL_RETURN(guid, MFVideoFormat_I420); //     FCC('I420')
   1108     IF_EQUAL_RETURN(guid, MFVideoFormat_IYUV); //     FCC('IYUV')
   1109     IF_EQUAL_RETURN(guid, MFVideoFormat_M4S2); //     FCC('M4S2')
   1110     IF_EQUAL_RETURN(guid, MFVideoFormat_MJPG);
   1111     IF_EQUAL_RETURN(guid, MFVideoFormat_MP43); //     FCC('MP43')
   1112     IF_EQUAL_RETURN(guid, MFVideoFormat_MP4S); //     FCC('MP4S')
   1113     IF_EQUAL_RETURN(guid, MFVideoFormat_MP4V); //     FCC('MP4V')
   1114     IF_EQUAL_RETURN(guid, MFVideoFormat_MPG1); //     FCC('MPG1')
   1115     IF_EQUAL_RETURN(guid, MFVideoFormat_MSS1); //     FCC('MSS1')
   1116     IF_EQUAL_RETURN(guid, MFVideoFormat_MSS2); //     FCC('MSS2')
   1117     IF_EQUAL_RETURN(guid, MFVideoFormat_NV11); //     FCC('NV11')
   1118     IF_EQUAL_RETURN(guid, MFVideoFormat_NV12); //     FCC('NV12')
   1119     IF_EQUAL_RETURN(guid, MFVideoFormat_P010); //     FCC('P010')
   1120     IF_EQUAL_RETURN(guid, MFVideoFormat_P016); //     FCC('P016')
   1121     IF_EQUAL_RETURN(guid, MFVideoFormat_P210); //     FCC('P210')
   1122     IF_EQUAL_RETURN(guid, MFVideoFormat_P216); //     FCC('P216')
   1123     IF_EQUAL_RETURN(guid, MFVideoFormat_RGB24); //    D3DFMT_R8G8B8
   1124     IF_EQUAL_RETURN(guid, MFVideoFormat_RGB32); //    D3DFMT_X8R8G8B8
   1125     IF_EQUAL_RETURN(guid, MFVideoFormat_RGB555); //   D3DFMT_X1R5G5B5
   1126     IF_EQUAL_RETURN(guid, MFVideoFormat_RGB565); //   D3DFMT_R5G6B5
   1127     IF_EQUAL_RETURN(guid, MFVideoFormat_RGB8);
   1128     IF_EQUAL_RETURN(guid, MFVideoFormat_UYVY); //     FCC('UYVY')
   1129     IF_EQUAL_RETURN(guid, MFVideoFormat_v210); //     FCC('v210')
   1130     IF_EQUAL_RETURN(guid, MFVideoFormat_v410); //     FCC('v410')
   1131     IF_EQUAL_RETURN(guid, MFVideoFormat_WMV1); //     FCC('WMV1')
   1132     IF_EQUAL_RETURN(guid, MFVideoFormat_WMV2); //     FCC('WMV2')
   1133     IF_EQUAL_RETURN(guid, MFVideoFormat_WMV3); //     FCC('WMV3')
   1134     IF_EQUAL_RETURN(guid, MFVideoFormat_WVC1); //     FCC('WVC1')
   1135     IF_EQUAL_RETURN(guid, MFVideoFormat_Y210); //     FCC('Y210')
   1136     IF_EQUAL_RETURN(guid, MFVideoFormat_Y216); //     FCC('Y216')
   1137     IF_EQUAL_RETURN(guid, MFVideoFormat_Y410); //     FCC('Y410')
   1138     IF_EQUAL_RETURN(guid, MFVideoFormat_Y416); //     FCC('Y416')
   1139     IF_EQUAL_RETURN(guid, MFVideoFormat_Y41P);
   1140     IF_EQUAL_RETURN(guid, MFVideoFormat_Y41T);
   1141     IF_EQUAL_RETURN(guid, MFVideoFormat_YUY2); //     FCC('YUY2')
   1142     IF_EQUAL_RETURN(guid, MFVideoFormat_YV12); //     FCC('YV12')
   1143     IF_EQUAL_RETURN(guid, MFVideoFormat_YVYU);
   1144     IF_EQUAL_RETURN(guid, MFAudioFormat_PCM); //              WAVE_FORMAT_PCM
   1145     IF_EQUAL_RETURN(guid, MFAudioFormat_Float); //            WAVE_FORMAT_IEEE_FLOAT
   1146     IF_EQUAL_RETURN(guid, MFAudioFormat_DTS); //              WAVE_FORMAT_DTS
   1147     IF_EQUAL_RETURN(guid, MFAudioFormat_Dolby_AC3_SPDIF); //  WAVE_FORMAT_DOLBY_AC3_SPDIF
   1148     IF_EQUAL_RETURN(guid, MFAudioFormat_DRM); //              WAVE_FORMAT_DRM
   1149     IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV8); //        WAVE_FORMAT_WMAUDIO2
   1150     IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV9); //        WAVE_FORMAT_WMAUDIO3
   1151     IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudio_Lossless); // WAVE_FORMAT_WMAUDIO_LOSSLESS
   1152     IF_EQUAL_RETURN(guid, MFAudioFormat_WMASPDIF); //         WAVE_FORMAT_WMASPDIF
   1153     IF_EQUAL_RETURN(guid, MFAudioFormat_MSP1); //             WAVE_FORMAT_WMAVOICE9
   1154     IF_EQUAL_RETURN(guid, MFAudioFormat_MP3); //              WAVE_FORMAT_MPEGLAYER3
   1155     IF_EQUAL_RETURN(guid, MFAudioFormat_MPEG); //             WAVE_FORMAT_MPEG
   1156     IF_EQUAL_RETURN(guid, MFAudioFormat_AAC); //              WAVE_FORMAT_MPEG_HEAAC
   1157     IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS); //             WAVE_FORMAT_MPEG_ADTS_AAC
   1158     return NULL;
   1159 }
   1160 
   1161 FormatReader::FormatReader(void)
   1162 {
   1163 }
   1164 
   1165 MediaType FormatReader::Read(IMFMediaType *pType)
   1166 {
   1167     UINT32 count = 0;
   1168     MediaType out;
   1169     HRESULT hr = pType->LockStore();
   1170     if (FAILED(hr))
   1171     {
   1172         return out;
   1173     }
   1174     hr = pType->GetCount(&count);
   1175     if (FAILED(hr))
   1176     {
   1177         return out;
   1178     }
   1179     for (UINT32 i = 0; i < count; i++)
   1180     {
   1181         hr = LogAttributeValueByIndexNew(pType, i, out);
   1182         if (FAILED(hr))
   1183         {
   1184             break;
   1185         }
   1186     }
   1187     hr = pType->UnlockStore();
   1188     if (FAILED(hr))
   1189     {
   1190         return out;
   1191     }
   1192     return out;
   1193 }
   1194 
   1195 FormatReader::~FormatReader(void)
   1196 {
   1197 }
   1198 
   1199 #define CHECK_HR(x) if (FAILED(x)) { goto done; }
   1200 
   1201 ImageGrabberCallback::ImageGrabberCallback(bool synchronous):
   1202     m_cRef(1),
   1203     ig_RIE(true),
   1204     ig_Close(false),
   1205     ig_Synchronous(synchronous),
   1206     ig_hFrameReady(synchronous ? CreateEvent(NULL, FALSE, FALSE, NULL): 0),
   1207     ig_hFrameGrabbed(synchronous ? CreateEvent(NULL, FALSE, TRUE, NULL): 0),
   1208     ig_hFinish(CreateEvent(NULL, TRUE, FALSE, NULL))
   1209 {}
   1210 
   1211 ImageGrabber::ImageGrabber(unsigned int deviceID, bool synchronous):
   1212     ImageGrabberCallback(synchronous),
   1213     ig_DeviceID(deviceID),
   1214     ig_pSource(NULL),
   1215     ig_pSession(NULL),
   1216     ig_pTopology(NULL)
   1217 {}
   1218 
   1219 ImageGrabber::~ImageGrabber(void)
   1220 {
   1221     if (ig_pSession)
   1222     {
   1223         ig_pSession->Shutdown();
   1224     }
   1225 
   1226     CloseHandle(ig_hFinish);
   1227 
   1228     if (ig_Synchronous)
   1229     {
   1230         CloseHandle(ig_hFrameReady);
   1231         CloseHandle(ig_hFrameGrabbed);
   1232     }
   1233 
   1234     SafeRelease(&ig_pSession);
   1235     SafeRelease(&ig_pTopology);
   1236 
   1237     DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Destroying instance of the ImageGrabber class\n", ig_DeviceID);
   1238 }
   1239 
   1240 #ifdef WINRT
   1241 
   1242 ImageGrabberWinRT::ImageGrabberWinRT(bool synchronous):
   1243     ImageGrabberCallback(synchronous),
   1244     ig_pMediaSink(NULL)
   1245 {
   1246     ig_pMedCapSource = nullptr;
   1247 }
   1248 
   1249 ImageGrabberWinRT::~ImageGrabberWinRT(void)
   1250 {
   1251     //stop must already be performed and complete by object owner
   1252     if (ig_pMediaSink != NULL) {
   1253         ((IMFMediaSink*)ig_pMediaSink)->Shutdown();
   1254     }
   1255     SafeRelease(&ig_pMediaSink);
   1256     RELEASE_AGILE_WRL(ig_pMedCapSource)
   1257 
   1258     CloseHandle(ig_hFinish);
   1259 
   1260     if (ig_Synchronous)
   1261     {
   1262         CloseHandle(ig_hFrameReady);
   1263         CloseHandle(ig_hFrameGrabbed);
   1264     }
   1265 
   1266     DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE: Destroying instance of the ImageGrabberWinRT class\n");
   1267 }
   1268 
   1269 HRESULT ImageGrabberWinRT::initImageGrabber(MAKE_WRL_REF(_MediaCapture) pSource,
   1270     GUID VideoFormat)
   1271 {
   1272     HRESULT hr;
   1273     MAKE_WRL_OBJ(_VideoDeviceController) pDevCont;
   1274     WRL_PROP_GET(pSource, VideoDeviceController, pDevCont, hr)
   1275     if (FAILED(hr)) return hr;
   1276     GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr)
   1277     if (FAILED(hr)) return hr;
   1278     MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps;
   1279     WRL_METHOD(pMedDevCont, GetMediaStreamProperties, pMedEncProps, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview))
   1280     if (FAILED(hr)) return hr;
   1281     GET_WRL_OBJ_FROM_OBJ(_VideoEncodingProperties, pVidProps, pMedEncProps, hr);
   1282     if (FAILED(hr)) return hr;
   1283     _ComPtr<IMFMediaType> pType = NULL;
   1284     hr = MediaSink::ConvertPropertiesToMediaType(DEREF_AS_NATIVE_WRL_OBJ(ABI::Windows::Media::MediaProperties::IMediaEncodingProperties, pMedEncProps), &pType);
   1285     if (FAILED(hr)) return hr;
   1286     MediaType MT = FormatReader::Read(pType.Get());
   1287     unsigned int sizeRawImage = 0;
   1288     if(VideoFormat == MFVideoFormat_RGB24)
   1289     {
   1290         sizeRawImage = MT.MF_MT_FRAME_SIZE * 3;
   1291     }
   1292     else if(VideoFormat == MFVideoFormat_RGB32)
   1293     {
   1294         sizeRawImage = MT.MF_MT_FRAME_SIZE * 4;
   1295     }
   1296     sizeRawImage = MT.MF_MT_SAMPLE_SIZE;
   1297     CHECK_HR(hr = RawImage::CreateInstance(&ig_RIFirst, sizeRawImage));
   1298     CHECK_HR(hr = RawImage::CreateInstance(&ig_RISecond, sizeRawImage));
   1299     ig_RIOut = ig_RISecond;
   1300     ig_pMedCapSource = pSource;
   1301 done:
   1302     return hr;
   1303 }
   1304 
   1305 HRESULT ImageGrabberWinRT::stopGrabbing(MAKE_WRL_REF(_AsyncAction)* action)
   1306 {
   1307     HRESULT hr = S_OK;
   1308     if (ig_pMedCapSource != nullptr) {
   1309         GET_WRL_OBJ_FROM_REF(_MediaCaptureVideoPreview, imedPrevCap, DEREF_AGILE_WRL_OBJ(ig_pMedCapSource), hr)
   1310         if (FAILED(hr)) return hr;
   1311         MAKE_WRL_REF(_AsyncAction) pAction;
   1312         WRL_METHOD_BASE(imedPrevCap, StopPreviewAsync, pAction, hr)
   1313         if (SUCCEEDED(hr)) {
   1314 #ifdef HAVE_CONCURRENCY
   1315             DEFINE_TASK<void> _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction);
   1316             *action = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(void, _task, this)
   1317                 HRESULT hr = S_OK;
   1318                 _task.wait();
   1319                 SafeRelease(&ig_pMediaSink);
   1320                 SetEvent(ig_hFinish);
   1321             END_CREATE_ASYNC(hr));
   1322 #else
   1323             *action = nullptr;
   1324 #endif
   1325         }
   1326     }
   1327     return hr;
   1328 }
   1329 
   1330 HRESULT ImageGrabberWinRT::startGrabbing(MAKE_WRL_REF(_AsyncAction)* action)
   1331 {
   1332     HRESULT hr = S_OK;
   1333     GET_WRL_OBJ_FROM_REF(_MediaCaptureVideoPreview, imedPrevCap, DEREF_AGILE_WRL_OBJ(ig_pMedCapSource), hr)
   1334     if (FAILED(hr)) return hr;
   1335     ACTIVATE_OBJ(RuntimeClass_Windows_Foundation_Collections_PropertySet, _PropertySet, pSet, hr)
   1336     if (FAILED(hr)) return hr;
   1337     GET_WRL_OBJ_FROM_OBJ(_Map, spSetting, pSet, hr)
   1338     if (FAILED(hr)) return hr;
   1339     ACTIVATE_STATIC_OBJ(RuntimeClass_Windows_Foundation_PropertyValue, MAKE_WRL_OBJ(_PropertyValueStatics), spPropVal, hr)
   1340     if (FAILED(hr)) return hr;
   1341     _ObjectObj pVal;
   1342     boolean bReplaced;
   1343     WRL_METHOD(spPropVal, CreateUInt32, pVal, hr, (unsigned int)WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview))
   1344     if (FAILED(hr)) return hr;
   1345     WRL_METHOD(spSetting, Insert, bReplaced, hr, DEREF_WRL_OBJ(_StringReference(MF_PROP_VIDTYPE)), DEREF_WRL_OBJ(pVal))
   1346     if (FAILED(hr)) return hr;
   1347     WRL_METHOD(spSetting, Insert, bReplaced, hr, DEREF_WRL_OBJ(_StringReference(MF_PROP_SAMPLEGRABBERCALLBACK)), reinterpret_cast<_Object>(this))
   1348     if (FAILED(hr)) return hr;
   1349     MAKE_WRL_OBJ(_VideoDeviceController) pDevCont;
   1350     WRL_PROP_GET(ig_pMedCapSource, VideoDeviceController, pDevCont, hr)
   1351     if (FAILED(hr)) return hr;
   1352     GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr)
   1353     if (FAILED(hr)) return hr;
   1354     MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps;
   1355     WRL_METHOD(pMedDevCont, GetMediaStreamProperties, pMedEncProps, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview))
   1356     if (FAILED(hr)) return hr;
   1357     GET_WRL_OBJ_FROM_OBJ(_VideoEncodingProperties, pVidProps, pMedEncProps, hr);
   1358     if (FAILED(hr)) return hr;
   1359     ACTIVATE_OBJ(RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile, _MediaEncodingProfile, pEncProps, hr)
   1360     if (FAILED(hr)) return hr;
   1361     WRL_PROP_PUT(pEncProps, Video, DEREF_WRL_OBJ(pVidProps), hr)
   1362     if (FAILED(hr)) return hr;
   1363     WRL_METHOD(spSetting, Insert, bReplaced, hr, DEREF_WRL_OBJ(_StringReference(MF_PROP_VIDENCPROPS)), DEREF_WRL_OBJ(pVidProps))
   1364     if (SUCCEEDED(hr)) {
   1365         //can start/stop multiple times with same MediaCapture object if using activatable class
   1366         WRL_METHOD(imedPrevCap, _StartPreviewToCustomSinkIdAsync, *action, hr, DEREF_WRL_OBJ(pEncProps), DEREF_WRL_OBJ(_StringReference(RuntimeClass_CV_MediaSink)), DEREF_WRL_OBJ(pSet))
   1367         if (FAILED(hr) && hr == REGDB_E_CLASSNOTREG) {
   1368             hr = Microsoft::WRL::Make<MediaSink>().CopyTo(&ig_pMediaSink);
   1369             if (FAILED(hr)) return hr;
   1370             hr = ((ABI::Windows::Media::IMediaExtension*)ig_pMediaSink)->SetProperties(DEREF_AS_NATIVE_WRL_OBJ(ABI::Windows::Foundation::Collections::IPropertySet, pSet));
   1371             if (FAILED(hr)) return hr;
   1372             WRL_METHOD(imedPrevCap, StartPreviewToCustomSinkAsync, *action, hr, DEREF_WRL_OBJ(pEncProps), reinterpret_cast<MAKE_WRL_REF(_MediaExtension)>(ig_pMediaSink))
   1373         }
   1374     }
   1375     return hr;
   1376 }
   1377 
   1378 HRESULT ImageGrabberWinRT::CreateInstance(ImageGrabberWinRT **ppIG, bool synchronous)
   1379 {
   1380     *ppIG = Microsoft::WRL::Make<ImageGrabberWinRT>(synchronous).Detach();
   1381     if (ppIG == NULL)
   1382     {
   1383         return E_OUTOFMEMORY;
   1384     }
   1385     DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE: Creating instance of ImageGrabberWinRT\n");
   1386     return S_OK;
   1387 }
   1388 #endif
   1389 
   1390 HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource)
   1391 {
   1392     _ComPtr<IMFActivate> pSinkActivate = NULL;
   1393     _ComPtr<IMFMediaType> pType = NULL;
   1394     _ComPtr<IMFPresentationDescriptor> pPD = NULL;
   1395     _ComPtr<IMFStreamDescriptor> pSD = NULL;
   1396     _ComPtr<IMFMediaTypeHandler> pHandler = NULL;
   1397     _ComPtr<IMFMediaType> pCurrentType = NULL;
   1398     MediaType MT;
   1399      // Clean up.
   1400     if (ig_pSession)
   1401     {
   1402         ig_pSession->Shutdown();
   1403     }
   1404     SafeRelease(&ig_pSession);
   1405     SafeRelease(&ig_pTopology);
   1406     ig_pSource = pSource;
   1407     HRESULT hr = pSource->CreatePresentationDescriptor(&pPD);
   1408     if (FAILED(hr))
   1409     {
   1410         goto err;
   1411     }
   1412     BOOL fSelected;
   1413     hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD);
   1414     if (FAILED(hr)) {
   1415         goto err;
   1416     }
   1417     hr = pSD->GetMediaTypeHandler(&pHandler);
   1418     if (FAILED(hr)) {
   1419         goto err;
   1420     }
   1421     DWORD cTypes = 0;
   1422     hr = pHandler->GetMediaTypeCount(&cTypes);
   1423     if (FAILED(hr)) {
   1424         goto err;
   1425     }
   1426     if(cTypes > 0)
   1427     {
   1428         hr = pHandler->GetCurrentMediaType(&pCurrentType);
   1429         if (FAILED(hr)) {
   1430             goto err;
   1431         }
   1432         MT = FormatReader::Read(pCurrentType.Get());
   1433     }
   1434 err:
   1435     CHECK_HR(hr);
   1436     CHECK_HR(hr = RawImage::CreateInstance(&ig_RIFirst, MT.MF_MT_SAMPLE_SIZE));
   1437     CHECK_HR(hr = RawImage::CreateInstance(&ig_RISecond, MT.MF_MT_SAMPLE_SIZE));
   1438     ig_RIOut = ig_RISecond;
   1439     // Configure the media type that the Sample Grabber will receive.
   1440     // Setting the major and subtype is usually enough for the topology loader
   1441     // to resolve the topology.
   1442     CHECK_HR(hr = MFCreateMediaType(pType.GetAddressOf()));
   1443     CHECK_HR(hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MT.MF_MT_MAJOR_TYPE));
   1444     CHECK_HR(hr = pType->SetGUID(MF_MT_SUBTYPE, MT.MF_MT_SUBTYPE));
   1445     // Create the sample grabber sink.
   1446     CHECK_HR(hr = MFCreateSampleGrabberSinkActivate(pType.Get(), this, pSinkActivate.GetAddressOf()));
   1447     // To run as fast as possible, set this attribute (requires Windows 7):
   1448     CHECK_HR(hr = pSinkActivate->SetUINT32(MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, TRUE));
   1449     // Create the Media Session.
   1450     CHECK_HR(hr = MFCreateMediaSession(NULL, &ig_pSession));
   1451     // Create the topology.
   1452     CHECK_HR(hr = CreateTopology(pSource, pSinkActivate.Get(), &ig_pTopology));
   1453 done:
   1454     // Clean up.
   1455     if (FAILED(hr))
   1456     {
   1457         if (ig_pSession)
   1458         {
   1459             ig_pSession->Shutdown();
   1460         }
   1461         SafeRelease(&ig_pSession);
   1462         SafeRelease(&ig_pTopology);
   1463     }
   1464     return hr;
   1465 }
   1466 
   1467 void ImageGrabber::stopGrabbing()
   1468 {
   1469     if(ig_pSession)
   1470         ig_pSession->Stop();
   1471     DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Stopping of of grabbing of images\n", ig_DeviceID);
   1472 }
   1473 
   1474 HRESULT ImageGrabber::startGrabbing(void)
   1475 {
   1476     PROPVARIANT var;
   1477     PropVariantInit(&var);
   1478     HRESULT hr = ig_pSession->SetTopology(0, ig_pTopology);
   1479     DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Start Grabbing of the images\n", ig_DeviceID);
   1480     hr = ig_pSession->Start(&GUID_NULL, &var);
   1481     for(;;)
   1482     {
   1483         _ComPtr<IMFMediaEvent> pEvent = NULL;
   1484         HRESULT hrStatus = S_OK;
   1485         MediaEventType met;
   1486         if(!ig_pSession) break;
   1487         hr = ig_pSession->GetEvent(0, &pEvent);
   1488         if(!SUCCEEDED(hr))
   1489         {
   1490             hr = S_OK;
   1491             goto done;
   1492         }
   1493         hr = pEvent->GetStatus(&hrStatus);
   1494         if(!SUCCEEDED(hr))
   1495         {
   1496             hr = S_OK;
   1497             goto done;
   1498         }
   1499         hr = pEvent->GetType(&met);
   1500         if(!SUCCEEDED(hr))
   1501         {
   1502             hr = S_OK;
   1503             goto done;
   1504         }
   1505         if (met == MESessionEnded)
   1506         {
   1507             DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionEnded\n", ig_DeviceID);
   1508             ig_pSession->Stop();
   1509             break;
   1510         }
   1511         if (met == MESessionStopped)
   1512         {
   1513             DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionStopped \n", ig_DeviceID);
   1514             break;
   1515         }
   1516 #if (WINVER >= 0x0602) // Available since Win 8
   1517         if (met == MEVideoCaptureDeviceRemoved)
   1518         {
   1519             DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MEVideoCaptureDeviceRemoved \n", ig_DeviceID);
   1520             break;
   1521         }
   1522 #endif
   1523         if ((met == MEError) || (met == MENonFatalError))
   1524         {
   1525             pEvent->GetStatus(&hrStatus);
   1526             DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MEError | MENonFatalError: %u\n", ig_DeviceID, hrStatus);
   1527             break;
   1528         }
   1529     }
   1530     DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID);
   1531 
   1532 done:
   1533     SetEvent(ig_hFinish);
   1534 
   1535     return hr;
   1536 }
   1537 
   1538 void ImageGrabberCallback::pauseGrabbing()
   1539 {
   1540 }
   1541 
   1542 void ImageGrabberCallback::resumeGrabbing()
   1543 {
   1544 }
   1545 
   1546 HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo)
   1547 {
   1548     IMFTopology* pTopology = NULL;
   1549     _ComPtr<IMFPresentationDescriptor> pPD = NULL;
   1550     _ComPtr<IMFStreamDescriptor> pSD = NULL;
   1551     _ComPtr<IMFMediaTypeHandler> pHandler = NULL;
   1552     _ComPtr<IMFTopologyNode> pNode1 = NULL;
   1553     _ComPtr<IMFTopologyNode> pNode2 = NULL;
   1554     HRESULT hr = S_OK;
   1555     DWORD cStreams = 0;
   1556     CHECK_HR(hr = MFCreateTopology(&pTopology));
   1557     CHECK_HR(hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf()));
   1558     CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams));
   1559     for (DWORD i = 0; i < cStreams; i++)
   1560     {
   1561         // In this example, we look for audio streams and connect them to the sink.
   1562         BOOL fSelected = FALSE;
   1563         GUID majorType;
   1564         CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(i, &fSelected, &pSD));
   1565         CHECK_HR(hr = pSD->GetMediaTypeHandler(&pHandler));
   1566         CHECK_HR(hr = pHandler->GetMajorType(&majorType));
   1567         if (majorType == MFMediaType_Video && fSelected)
   1568         {
   1569             CHECK_HR(hr = AddSourceNode(pTopology, pSource, pPD.Get(), pSD.Get(), pNode1.GetAddressOf()));
   1570             CHECK_HR(hr = AddOutputNode(pTopology, pSinkActivate, 0, pNode2.GetAddressOf()));
   1571             CHECK_HR(hr = pNode1->ConnectOutput(0, pNode2.Get(), 0));
   1572             break;
   1573         }
   1574         else
   1575         {
   1576             CHECK_HR(hr = pPD->DeselectStream(i));
   1577         }
   1578     }
   1579     *ppTopo = pTopology;
   1580     (*ppTopo)->AddRef();
   1581 
   1582 done:
   1583     return hr;
   1584 }
   1585 
   1586 HRESULT ImageGrabber::AddSourceNode(
   1587     IMFTopology *pTopology,           // Topology.
   1588     IMFMediaSource *pSource,          // Media source.
   1589     IMFPresentationDescriptor *pPD,   // Presentation descriptor.
   1590     IMFStreamDescriptor *pSD,         // Stream descriptor.
   1591     IMFTopologyNode **ppNode)         // Receives the node pointer.
   1592 {
   1593     _ComPtr<IMFTopologyNode> pNode = NULL;
   1594     HRESULT hr = S_OK;
   1595     CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, pNode.GetAddressOf()));
   1596     CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource));
   1597     CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD));
   1598     CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD));
   1599     CHECK_HR(hr = pTopology->AddNode(pNode.Get()));
   1600     // Return the pointer to the caller.
   1601     *ppNode = pNode.Get();
   1602     (*ppNode)->AddRef();
   1603 
   1604 done:
   1605     return hr;
   1606 }
   1607 
   1608 HRESULT ImageGrabber::AddOutputNode(
   1609     IMFTopology *pTopology,     // Topology.
   1610     IMFActivate *pActivate,     // Media sink activation object.
   1611     DWORD dwId,                 // Identifier of the stream sink.
   1612     IMFTopologyNode **ppNode)   // Receives the node pointer.
   1613 {
   1614     _ComPtr<IMFTopologyNode> pNode = NULL;
   1615     HRESULT hr = S_OK;
   1616     CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, pNode.GetAddressOf()));
   1617     CHECK_HR(hr = pNode->SetObject(pActivate));
   1618     CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId));
   1619     CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE));
   1620     CHECK_HR(hr = pTopology->AddNode(pNode.Get()));
   1621     // Return the pointer to the caller.
   1622     *ppNode = pNode.Get();
   1623     (*ppNode)->AddRef();
   1624 
   1625 done:
   1626     return hr;
   1627 }
   1628 
   1629 HRESULT ImageGrabber::CreateInstance(ImageGrabber **ppIG, unsigned int deviceID, bool synchronious)
   1630 {
   1631     *ppIG = new (std::nothrow) ImageGrabber(deviceID, synchronious);
   1632     if (ppIG == NULL)
   1633     {
   1634         return E_OUTOFMEMORY;
   1635     }
   1636     DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Creating instance of ImageGrabber\n", deviceID);
   1637     return S_OK;
   1638 }
   1639 
   1640 STDMETHODIMP ImageGrabber::QueryInterface(REFIID riid, void** ppv)
   1641 {
   1642     HRESULT hr = E_NOINTERFACE;
   1643     *ppv = NULL;
   1644     if(riid == IID_IUnknown || riid == IID_IMFSampleGrabberSinkCallback)
   1645     {
   1646         *ppv = static_cast<IMFSampleGrabberSinkCallback *>(this);
   1647         hr = S_OK;
   1648     }
   1649     if(riid == IID_IMFClockStateSink)
   1650     {
   1651         *ppv = static_cast<IMFClockStateSink *>(this);
   1652         hr = S_OK;
   1653     }
   1654     if(SUCCEEDED(hr))
   1655     {
   1656         reinterpret_cast<IUnknown *>(*ppv)->AddRef();
   1657     }
   1658     return hr;
   1659 }
   1660 
   1661 STDMETHODIMP_(ULONG) ImageGrabber::AddRef()
   1662 {
   1663     return InterlockedIncrement(&m_cRef);
   1664 }
   1665 
   1666 STDMETHODIMP_(ULONG) ImageGrabber::Release()
   1667 {
   1668     ULONG cRef = InterlockedDecrement(&m_cRef);
   1669     if (cRef == 0)
   1670     {
   1671         delete this;
   1672     }
   1673     return cRef;
   1674 }
   1675 
   1676 STDMETHODIMP ImageGrabberCallback::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset)
   1677 {
   1678     (void)hnsSystemTime;
   1679     (void)llClockStartOffset;
   1680     return S_OK;
   1681 }
   1682 
   1683 STDMETHODIMP ImageGrabberCallback::OnClockStop(MFTIME hnsSystemTime)
   1684 {
   1685     (void)hnsSystemTime;
   1686     return S_OK;
   1687 }
   1688 
   1689 STDMETHODIMP ImageGrabberCallback::OnClockPause(MFTIME hnsSystemTime)
   1690 {
   1691     (void)hnsSystemTime;
   1692     return S_OK;
   1693 }
   1694 
   1695 STDMETHODIMP ImageGrabberCallback::OnClockRestart(MFTIME hnsSystemTime)
   1696 {
   1697     (void)hnsSystemTime;
   1698     return S_OK;
   1699 }
   1700 
   1701 STDMETHODIMP ImageGrabberCallback::OnClockSetRate(MFTIME hnsSystemTime, float flRate)
   1702 {
   1703     (void)flRate;
   1704     (void)hnsSystemTime;
   1705     return S_OK;
   1706 }
   1707 
   1708 STDMETHODIMP ImageGrabberCallback::OnSetPresentationClock(IMFPresentationClock* pClock)
   1709 {
   1710     (void)pClock;
   1711     return S_OK;
   1712 }
   1713 
   1714 STDMETHODIMP ImageGrabberCallback::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags,
   1715     LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer,
   1716     DWORD dwSampleSize)
   1717 {
   1718     (void)guidMajorMediaType;
   1719     (void)llSampleTime;
   1720     (void)dwSampleFlags;
   1721     (void)llSampleDuration;
   1722     (void)dwSampleSize;
   1723 
   1724     HANDLE tmp[] = {ig_hFinish, ig_hFrameGrabbed, NULL};
   1725 
   1726     DWORD status = WaitForMultipleObjects(2, tmp, FALSE, INFINITE);
   1727     if (status == WAIT_OBJECT_0)
   1728     {
   1729         DebugPrintOut(L"OnProcessFrame called after ig_hFinish event\n");
   1730         return S_OK;
   1731     }
   1732 
   1733     if(ig_RIE)
   1734     {
   1735         ig_RIFirst->fastCopy(pSampleBuffer);
   1736         ig_RIOut = ig_RIFirst;
   1737     }
   1738     else
   1739     {
   1740         ig_RISecond->fastCopy(pSampleBuffer);
   1741         ig_RIOut = ig_RISecond;
   1742     }
   1743 
   1744     if (ig_Synchronous)
   1745     {
   1746         SetEvent(ig_hFrameReady);
   1747     }
   1748     else
   1749     {
   1750         ig_RIE = !ig_RIE;
   1751     }
   1752 
   1753     return S_OK;
   1754 }
   1755 
   1756 STDMETHODIMP ImageGrabberCallback::OnShutdown()
   1757 {
   1758     SetEvent(ig_hFinish);
   1759     return S_OK;
   1760 }
   1761 
   1762 RawImage *ImageGrabberCallback::getRawImage()
   1763 {
   1764     return ig_RIOut;
   1765 }
   1766 
   1767 DWORD WINAPI MainThreadFunction( LPVOID lpParam )
   1768 {
   1769     ImageGrabberThread *pIGT = (ImageGrabberThread *)lpParam;
   1770     pIGT->run();
   1771     return 0;
   1772 }
   1773 
   1774 HRESULT ImageGrabberThread::CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID, bool synchronious)
   1775 {
   1776     *ppIGT = new (std::nothrow) ImageGrabberThread(pSource, deviceID, synchronious);
   1777     if (ppIGT == NULL)
   1778     {
   1779         DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Memory cannot be allocated\n", deviceID);
   1780         return E_OUTOFMEMORY;
   1781     }
   1782     else
   1783         DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Creating of the instance of ImageGrabberThread\n", deviceID);
   1784     return S_OK;
   1785 }
   1786 
   1787 ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID, bool synchronious) :
   1788     igt_func(NULL),
   1789     igt_Handle(NULL),
   1790     igt_stop(false)
   1791 {
   1792     HRESULT hr = ImageGrabber::CreateInstance(&igt_pImageGrabber, deviceID, synchronious);
   1793     igt_DeviceID = deviceID;
   1794     if(SUCCEEDED(hr))
   1795     {
   1796         hr = igt_pImageGrabber->initImageGrabber(pSource);
   1797         if(!SUCCEEDED(hr))
   1798         {
   1799             DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with initialization of the instance of the ImageGrabber class\n", deviceID);
   1800         }
   1801         else
   1802         {
   1803             DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Initialization of instance of the ImageGrabber class\n", deviceID);
   1804         }
   1805     }
   1806     else
   1807     {
   1808         DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with creation of the instance of the ImageGrabber class\n", deviceID);
   1809     }
   1810 }
   1811 
   1812 void ImageGrabberThread::setEmergencyStopEvent(void *userData, void(*func)(int, void *))
   1813 {
   1814     if(func)
   1815     {
   1816         igt_func = func;
   1817         igt_userData = userData;
   1818     }
   1819 }
   1820 
   1821 ImageGrabberThread::~ImageGrabberThread(void)
   1822 {
   1823     DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Destroing ImageGrabberThread\n", igt_DeviceID);
   1824     if (igt_Handle)
   1825         WaitForSingleObject(igt_Handle, INFINITE);
   1826     delete igt_pImageGrabber;
   1827 }
   1828 
   1829 void ImageGrabberThread::stop()
   1830 {
   1831     igt_stop = true;
   1832     if(igt_pImageGrabber)
   1833     {
   1834         igt_pImageGrabber->stopGrabbing();
   1835     }
   1836 }
   1837 
   1838 void ImageGrabberThread::start()
   1839 {
   1840     igt_Handle = CreateThread(
   1841             NULL,                  // default security attributes
   1842             0,                     // use default stack size
   1843             MainThreadFunction,    // thread function name
   1844             this,                  // argument to thread function
   1845             0,                     // use default creation flags
   1846             &igt_ThreadIdArray);   // returns the thread identifier
   1847 }
   1848 
   1849 void ImageGrabberThread::run()
   1850 {
   1851     if(igt_pImageGrabber)
   1852     {
   1853         DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Thread for grabbing images is started\n", igt_DeviceID);
   1854         HRESULT hr = igt_pImageGrabber->startGrabbing();
   1855         if(!SUCCEEDED(hr))
   1856         {
   1857             DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with starting the process of grabbing\n", igt_DeviceID);
   1858         }
   1859     }
   1860     else
   1861     {
   1862         DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i The thread is finished without execution of grabbing\n", igt_DeviceID);
   1863     }
   1864     if(!igt_stop)
   1865     {
   1866         DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Emergency Stop thread\n", igt_DeviceID);
   1867         if(igt_func)
   1868         {
   1869             igt_func(igt_DeviceID, igt_userData);
   1870         }
   1871     }
   1872     else
   1873         DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Finish thread\n", igt_DeviceID);
   1874 }
   1875 
   1876 ImageGrabber *ImageGrabberThread::getImageGrabber()
   1877 {
   1878     return igt_pImageGrabber;
   1879 }
   1880 
   1881 Media_Foundation::Media_Foundation(void)
   1882 {
   1883     HRESULT hr = MFStartup(MF_VERSION);
   1884     if(!SUCCEEDED(hr))
   1885     {
   1886         DebugPrintOut(L"MEDIA FOUNDATION: It cannot be created!!!\n");
   1887     }
   1888 }
   1889 
   1890 Media_Foundation::~Media_Foundation(void)
   1891 {
   1892     HRESULT hr = MFShutdown();
   1893     if(!SUCCEEDED(hr))
   1894     {
   1895         DebugPrintOut(L"MEDIA FOUNDATION: Resources cannot be released\n");
   1896     }
   1897 }
   1898 
   1899 bool Media_Foundation::buildListOfDevices()
   1900 {
   1901     HRESULT hr = S_OK;
   1902 #ifdef WINRT
   1903     videoDevices *vDs = &videoDevices::getInstance();
   1904     hr = vDs->initDevices(WRL_ENUM_GET(_DeviceClass, DeviceClass, VideoCapture));
   1905 #else
   1906     _ComPtr<IMFAttributes> pAttributes = NULL;
   1907     CoInitialize(NULL);
   1908     hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1);
   1909     if (SUCCEEDED(hr))
   1910     {
   1911         hr = pAttributes->SetGUID(
   1912             MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
   1913             MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
   1914             );
   1915     }
   1916     if (SUCCEEDED(hr))
   1917     {
   1918         videoDevices *vDs = &videoDevices::getInstance();
   1919         hr = vDs->initDevices(pAttributes.Get());
   1920     }
   1921 #endif
   1922     if (FAILED(hr))
   1923     {
   1924        DebugPrintOut(L"MEDIA FOUNDATION: The access to the video cameras denied\n");
   1925     }
   1926 
   1927     return (SUCCEEDED(hr));
   1928 }
   1929 
   1930 Media_Foundation& Media_Foundation::getInstance()
   1931 {
   1932     static Media_Foundation instance;
   1933     return instance;
   1934 }
   1935 
   1936 RawImage::RawImage(unsigned int size): ri_new(false), ri_pixels(NULL)
   1937 {
   1938     ri_size = size;
   1939     ri_pixels = new unsigned char[size];
   1940     memset((void *)ri_pixels,0,ri_size);
   1941 }
   1942 
   1943 bool RawImage::isNew()
   1944 {
   1945     return ri_new;
   1946 }
   1947 
   1948 unsigned int RawImage::getSize()
   1949 {
   1950     return ri_size;
   1951 }
   1952 
   1953 RawImage::~RawImage(void)
   1954 {
   1955     delete []ri_pixels;
   1956     ri_pixels = NULL;
   1957 }
   1958 
   1959 long RawImage::CreateInstance(RawImage **ppRImage,unsigned int size)
   1960 {
   1961     *ppRImage = new (std::nothrow) RawImage(size);
   1962     if (ppRImage == NULL)
   1963     {
   1964         return E_OUTOFMEMORY;
   1965     }
   1966     return S_OK;
   1967 }
   1968 
   1969 void RawImage::setCopy(const BYTE * pSampleBuffer)
   1970 {
   1971     memcpy(ri_pixels, pSampleBuffer, ri_size);
   1972     ri_new = true;
   1973 }
   1974 
   1975 void RawImage::fastCopy(const BYTE * pSampleBuffer)
   1976 {
   1977     memcpy(ri_pixels, pSampleBuffer, ri_size);
   1978     ri_new = true;
   1979 }
   1980 
   1981 unsigned char * RawImage::getpPixels()
   1982 {
   1983     ri_new = false;
   1984     return ri_pixels;
   1985 }
   1986 
   1987 videoDevice::videoDevice(void): vd_IsSetuped(false), vd_LockOut(OpenLock), vd_pFriendlyName(NULL),
   1988     vd_Width(0), vd_Height(0), vd_FrameRate(0), vd_pSource(NULL), vd_pImGrTh(NULL), vd_func(NULL), vd_userData(NULL)
   1989 {
   1990 #ifdef WINRT
   1991     vd_pMedCap = nullptr;
   1992     vd_cookie.value = 0;
   1993     vd_pImGr = NULL;
   1994     vd_pAction = nullptr;
   1995 #endif
   1996 }
   1997 
   1998 void videoDevice::setParametrs(CamParametrs parametrs)
   1999 {
   2000     if(vd_IsSetuped)
   2001     {
   2002         if(vd_pSource)
   2003         {
   2004             Parametr *pParametr = (Parametr *)(&parametrs);
   2005             Parametr *pPrevParametr = (Parametr *)(&vd_PrevParametrs);
   2006             IAMVideoProcAmp *pProcAmp = NULL;
   2007             HRESULT hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcAmp));
   2008             if (SUCCEEDED(hr))
   2009             {
   2010                 for(unsigned int i = 0; i < 10; i++)
   2011                 {
   2012                     if(pPrevParametr[i].CurrentValue != pParametr[i].CurrentValue || pPrevParametr[i].Flag != pParametr[i].Flag)
   2013                         hr = pProcAmp->Set(VideoProcAmp_Brightness + i, pParametr[i].CurrentValue, pParametr[i].Flag);
   2014                 }
   2015                 pProcAmp->Release();
   2016             }
   2017             IAMCameraControl *pProcControl = NULL;
   2018             hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcControl));
   2019             if (SUCCEEDED(hr))
   2020             {
   2021                 for(unsigned int i = 0; i < 7; i++)
   2022                 {
   2023                     if(pPrevParametr[10 + i].CurrentValue != pParametr[10 + i].CurrentValue || pPrevParametr[10 + i].Flag != pParametr[10 + i].Flag)
   2024                     hr = pProcControl->Set(CameraControl_Pan+i, pParametr[10 + i].CurrentValue, pParametr[10 + i].Flag);
   2025                 }
   2026                 pProcControl->Release();
   2027             }
   2028             vd_PrevParametrs = parametrs;
   2029         }
   2030     }
   2031 }
   2032 
   2033 CamParametrs videoDevice::getParametrs()
   2034 {
   2035     CamParametrs out;
   2036     if(vd_IsSetuped)
   2037     {
   2038         if(vd_pSource)
   2039         {
   2040             Parametr *pParametr = (Parametr *)(&out);
   2041             IAMVideoProcAmp *pProcAmp = NULL;
   2042             HRESULT hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcAmp));
   2043             if (SUCCEEDED(hr))
   2044             {
   2045                 for(unsigned int i = 0; i < 10; i++)
   2046                 {
   2047                     Parametr temp;
   2048                     hr = pProcAmp->GetRange(VideoProcAmp_Brightness+i, &temp.Min, &temp.Max, &temp.Step, &temp.Default, &temp.Flag);
   2049                     if (SUCCEEDED(hr))
   2050                     {
   2051                         temp.CurrentValue = temp.Default;
   2052                         pParametr[i] = temp;
   2053                     }
   2054                 }
   2055                 pProcAmp->Release();
   2056             }
   2057             IAMCameraControl *pProcControl = NULL;
   2058             hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcControl));
   2059             if (SUCCEEDED(hr))
   2060             {
   2061                 for(unsigned int i = 0; i < 7; i++)
   2062                 {
   2063                     Parametr temp;
   2064                     hr = pProcControl->GetRange(CameraControl_Pan+i, &temp.Min, &temp.Max, &temp.Step, &temp.Default, &temp.Flag);
   2065                     if (SUCCEEDED(hr))
   2066                     {
   2067                         temp.CurrentValue = temp.Default;
   2068                         pParametr[10 + i] = temp;
   2069                     }
   2070                 }
   2071                 pProcControl->Release();
   2072             }
   2073         }
   2074     }
   2075     return out;
   2076 }
   2077 
   2078 #ifdef WINRT
   2079 long videoDevice::resetDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice)
   2080 #else
   2081 long videoDevice::resetDevice(IMFActivate *pActivate)
   2082 #endif
   2083 {
   2084     HRESULT hr = E_FAIL;
   2085     vd_CurrentFormats.clear();
   2086     if(vd_pFriendlyName)
   2087         CoTaskMemFree(vd_pFriendlyName);
   2088     vd_pFriendlyName = NULL;
   2089 #ifdef WINRT
   2090     if (pDevice)
   2091     {
   2092         ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCapture, _MediaCapture, pIMedCap, hr)
   2093         if (FAILED(hr)) return hr;
   2094         ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings, _MediaCaptureInitializationSettings, pCapInitSet, hr)
   2095         if (FAILED(hr)) return hr;
   2096         _StringObj str;
   2097         WRL_PROP_GET(pDevice, Name, *REF_WRL_OBJ(str), hr)
   2098         if (FAILED(hr)) return hr;
   2099         unsigned int length = 0;
   2100         PCWSTR wstr = WindowsGetStringRawBuffer(reinterpret_cast<HSTRING>(DEREF_WRL_OBJ(str)), &length);
   2101         vd_pFriendlyName = (wchar_t*)CoTaskMemAlloc((length + 1) * sizeof(wchar_t));
   2102         wcscpy(vd_pFriendlyName, wstr);
   2103         WRL_PROP_GET(pDevice, Id, *REF_WRL_OBJ(str), hr)
   2104         if (FAILED(hr)) return hr;
   2105         WRL_PROP_PUT(pCapInitSet, VideoDeviceId, DEREF_WRL_OBJ(str), hr)
   2106         if (FAILED(hr)) return hr;
   2107         WRL_PROP_PUT(pCapInitSet, StreamingCaptureMode, WRL_ENUM_GET(_StreamingCaptureMode, StreamingCaptureMode, Video), hr)
   2108         if (FAILED(hr)) return hr;
   2109         MAKE_WRL_REF(_AsyncAction) pAction;
   2110         WRL_METHOD(DEREF_WRL_OBJ(pIMedCap), _InitializeWithSettingsAsync, pAction, hr, DEREF_WRL_OBJ(pCapInitSet))
   2111 #ifdef HAVE_CONCURRENCY
   2112         DEFINE_TASK<void> _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction);
   2113         if (FAILED(hr)) return hr;
   2114         MAKE_WRL_AGILE_REF(_MediaCapture) pAgileMedCap;
   2115         pAgileMedCap = PREPARE_TRANSFER_WRL_OBJ(pIMedCap);
   2116         Concurrency::critical_section::scoped_lock _LockHolder(vd_lock);
   2117         MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction;
   2118         SAVE_CURRENT_CONTEXT(context);
   2119         vd_pAction = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(void, _task, pOldAction, context, &pAgileMedCap, this)
   2120            HRESULT hr = S_OK;
   2121            if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait();
   2122            _task.wait();
   2123            if (SUCCEEDED(hr)) {
   2124                 //all camera capture calls only in original context
   2125                 BEGIN_CALL_IN_CONTEXT(hr, context, pAgileMedCap, this)
   2126                     enumerateCaptureFormats(DEREF_AGILE_WRL_OBJ(pAgileMedCap));
   2127                 END_CALL_IN_CONTEXT_BASE
   2128            }
   2129            buildLibraryofTypes();
   2130            RELEASE_AGILE_WRL(pAgileMedCap)
   2131         END_CREATE_ASYNC(hr));
   2132 #endif
   2133     }
   2134 #else
   2135     if(pActivate)
   2136     {
   2137         IMFMediaSource *pSource = NULL;
   2138         hr = pActivate->GetAllocatedString(
   2139                 MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
   2140                 &vd_pFriendlyName,
   2141                 NULL
   2142                 );
   2143         hr = pActivate->ActivateObject(
   2144             __uuidof(IMFMediaSource),
   2145             (void**)&pSource
   2146             );
   2147         enumerateCaptureFormats(pSource);
   2148         buildLibraryofTypes();
   2149         SafeRelease(&pSource);
   2150         if(FAILED(hr))
   2151         {
   2152             vd_pFriendlyName = NULL;
   2153             DebugPrintOut(L"VIDEODEVICE %i: IMFMediaSource interface cannot be created \n", vd_CurrentNumber);
   2154         }
   2155     }
   2156 #endif
   2157     return hr;
   2158 }
   2159 
   2160 #ifdef WINRT
   2161 long videoDevice::readInfoOfDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice, unsigned int Num)
   2162 {
   2163     HRESULT hr = -1;
   2164     vd_CurrentNumber = Num;
   2165     hr = resetDevice(pDevice);
   2166     return hr;
   2167 }
   2168 #else
   2169 long videoDevice::readInfoOfDevice(IMFActivate *pActivate, unsigned int Num)
   2170 {
   2171     vd_CurrentNumber = Num;
   2172     return resetDevice(pActivate);
   2173 }
   2174 #endif
   2175 
   2176 #ifdef WINRT
   2177 #ifdef HAVE_CONCURRENCY
   2178 long videoDevice::checkDevice(_DeviceClass devClass, DEFINE_TASK<void>* pTask, MAKE_WRL_REF(_IDeviceInformation)* ppDevice)
   2179 {
   2180     HRESULT hr = S_OK;
   2181     ACTIVATE_STATIC_OBJ(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation, MAKE_WRL_OBJ(_DeviceInformationStatics), pDevStat, hr)
   2182     if (FAILED(hr)) return hr;
   2183     MAKE_WRL_REF(_AsyncOperation<MAKE_WRL_REF(_DeviceInformationCollection)>) pAction;
   2184     WRL_METHOD(pDevStat, _FindAllAsyncDeviceClass, pAction, hr, devClass)
   2185     if (SUCCEEDED(hr)) {
   2186         *pTask = CREATE_TASK DEFINE_RET_TYPE(void)([pAction, &ppDevice, this]() -> DEFINE_RET_FORMAL(void) {
   2187             HRESULT hr = S_OK;
   2188             MAKE_WRL_OBJ(_VectorView<MAKE_WRL_REF(_DeviceInformation)>) pVector =
   2189                 CREATE_TASK DEFINE_RET_TYPE(MAKE_WRL_REF(_VectorView<MAKE_WRL_REF(_DeviceInformation)>))(pAction).get();
   2190             UINT32 count = 0;
   2191             if (SUCCEEDED(hr)) WRL_PROP_GET(pVector, Size, count, hr)
   2192             if (SUCCEEDED(hr) && count > 0) {
   2193                 for (UINT32 i = 0; i < count; i++) {
   2194                     MAKE_WRL_OBJ(_IDeviceInformation) pDevice;
   2195                     WRL_METHOD(pVector, GetAt, pDevice, hr, i)
   2196                     if (SUCCEEDED(hr)) {
   2197                         _StringObj str;
   2198                         unsigned int length = 0;
   2199                         WRL_PROP_GET(pDevice, Name, *REF_WRL_OBJ(str), hr)
   2200                         PCWSTR wstr = WindowsGetStringRawBuffer(reinterpret_cast<HSTRING>(DEREF_WRL_OBJ(str)), &length);
   2201                         if (wcscmp(wstr, vd_pFriendlyName) == 0) {
   2202                             *ppDevice = PREPARE_TRANSFER_WRL_OBJ(pDevice);
   2203                         }
   2204                     }
   2205                 }
   2206             }
   2207             RET_VAL_BASE;
   2208         });
   2209     }
   2210     return hr;
   2211 }
   2212 #endif
   2213 #else
   2214 long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice)
   2215 {
   2216     IMFActivate **ppDevices = NULL;
   2217     UINT32 count;
   2218     wchar_t *newFriendlyName = NULL;
   2219     HRESULT hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
   2220     if (SUCCEEDED(hr))
   2221     {
   2222         if(count > 0)
   2223         {
   2224             if(count > vd_CurrentNumber)
   2225             {
   2226                 hr = ppDevices[vd_CurrentNumber]->GetAllocatedString(
   2227                 MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
   2228                 &newFriendlyName,
   2229                 NULL
   2230                 );
   2231                 if (SUCCEEDED(hr))
   2232                 {
   2233                     if(wcscmp(newFriendlyName, vd_pFriendlyName) != 0)
   2234                     {
   2235                         DebugPrintOut(L"VIDEODEVICE %i: Chosen device cannot be found \n", vd_CurrentNumber);
   2236                         hr = E_INVALIDARG;
   2237                         pDevice = NULL;
   2238                     }
   2239                     else
   2240                     {
   2241                         *pDevice = ppDevices[vd_CurrentNumber];
   2242                         (*pDevice)->AddRef();
   2243                     }
   2244                 }
   2245                 else
   2246                 {
   2247                     DebugPrintOut(L"VIDEODEVICE %i: Name of device cannot be gotten \n", vd_CurrentNumber);
   2248                 }
   2249             }
   2250             else
   2251             {
   2252                 DebugPrintOut(L"VIDEODEVICE %i: Number of devices more than corrent number of the device \n", vd_CurrentNumber);
   2253                 hr = E_INVALIDARG;
   2254             }
   2255             for(UINT32 i = 0; i < count; i++)
   2256             {
   2257                 SafeRelease(&ppDevices[i]);
   2258             }
   2259             SafeRelease(ppDevices);
   2260         }
   2261         else
   2262             hr = E_FAIL;
   2263     }
   2264     else
   2265     {
   2266         DebugPrintOut(L"VIDEODEVICE %i: List of DeviceSources cannot be enumerated \n", vd_CurrentNumber);
   2267     }
   2268     return hr;
   2269 }
   2270 #endif
   2271 
   2272 long videoDevice::initDevice()
   2273 {
   2274     HRESULT hr = S_OK;
   2275     CoInitialize(NULL);
   2276 #ifdef WINRT
   2277 #ifdef HAVE_CONCURRENCY
   2278     Concurrency::critical_section::scoped_lock _LockHolder(vd_lock);
   2279     MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction;
   2280     SAVE_CURRENT_CONTEXT(context);
   2281     vd_pAction = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(void, pOldAction, context, this)
   2282         HRESULT hr;
   2283         if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait();
   2284         DEFINE_TASK<void> pTask;
   2285         MAKE_WRL_OBJ(_IDeviceInformation) pDevInfo;
   2286         hr = checkDevice(WRL_ENUM_GET(_DeviceClass, DeviceClass, VideoCapture), &pTask, REF_WRL_OBJ(pDevInfo));
   2287         if (SUCCEEDED(hr)) pTask.wait();
   2288         if (SUCCEEDED(hr)) {
   2289             DEFINE_TASK<void> _task;
   2290             BEGIN_CALL_IN_CONTEXT(hr, context, pDevInfo, &_task, context, this)
   2291                 HRESULT hr;
   2292                 ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCapture, _MediaCapture, pIMedCap, hr)
   2293                 if (SUCCEEDED(hr)) {
   2294                     RELEASE_WRL(vd_pMedCap);
   2295                     vd_pMedCap = PREPARE_TRANSFER_WRL_OBJ(pIMedCap);
   2296                     ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings, _MediaCaptureInitializationSettings, pCapInitSet, hr)
   2297                     _StringObj str;
   2298                     if (SUCCEEDED(hr)) {
   2299                         WRL_PROP_GET(pDevInfo, Id, *REF_WRL_OBJ(str), hr)
   2300                         if (SUCCEEDED(hr)) {
   2301                             WRL_PROP_PUT(pCapInitSet, VideoDeviceId, DEREF_WRL_OBJ(str), hr)
   2302                         }
   2303                     }
   2304                     if (SUCCEEDED(hr))
   2305                         WRL_PROP_PUT(pCapInitSet, StreamingCaptureMode, WRL_ENUM_GET(_StreamingCaptureMode, StreamingCaptureMode, Video), hr)
   2306                     if (SUCCEEDED(hr)) reinterpret_cast<ABI::Windows::Media::Capture::IMediaCapture*>(DEREF_AGILE_WRL_OBJ(vd_pMedCap))->add_Failed(Microsoft::WRL::Callback<ABI::Windows::Media::Capture::IMediaCaptureFailedEventHandler>([this, context](ABI::Windows::Media::Capture::IMediaCapture*, ABI::Windows::Media::Capture::IMediaCaptureFailedEventArgs*) -> HRESULT {
   2307                             HRESULT hr;
   2308                             BEGIN_CALL_IN_CONTEXT(hr, context, this)
   2309                                 closeDevice();
   2310                             END_CALL_IN_CONTEXT_BASE
   2311                             return hr;
   2312                         }).Get(), &vd_cookie);
   2313                     MAKE_WRL_OBJ(_AsyncAction) pAction;
   2314                     if (SUCCEEDED(hr)) WRL_METHOD(vd_pMedCap, _InitializeWithSettingsAsync, *REF_WRL_OBJ(pAction), hr, DEREF_WRL_OBJ(pCapInitSet))
   2315                     if (SUCCEEDED(hr)) _task = CREATE_TASK DEFINE_RET_TYPE(void)(DEREF_WRL_OBJ(pAction));
   2316                 }
   2317             END_CALL_IN_CONTEXT(hr)
   2318             _task.wait();
   2319         }
   2320     END_CREATE_ASYNC(hr));
   2321 #endif
   2322 #else
   2323     _ComPtr<IMFAttributes> pAttributes = NULL;
   2324     IMFActivate *vd_pActivate = NULL;
   2325     hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1);
   2326     if (SUCCEEDED(hr))
   2327     {
   2328         hr = pAttributes->SetGUID(
   2329             MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
   2330             MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
   2331             );
   2332     }
   2333     if (SUCCEEDED(hr))
   2334     {
   2335         hr = checkDevice(pAttributes.Get(), &vd_pActivate);
   2336         if (SUCCEEDED(hr) && vd_pActivate)
   2337         {
   2338             SafeRelease(&vd_pSource);
   2339             hr = vd_pActivate->ActivateObject(
   2340                 __uuidof(IMFMediaSource),
   2341                 (void**)&vd_pSource
   2342                 );
   2343             if (SUCCEEDED(hr))
   2344             {
   2345             }
   2346             SafeRelease(&vd_pActivate);
   2347         }
   2348         else
   2349         {
   2350             DebugPrintOut(L"VIDEODEVICE %i: Device there is not \n", vd_CurrentNumber);
   2351         }
   2352     }
   2353     else
   2354     {
   2355         DebugPrintOut(L"VIDEODEVICE %i: The attribute of video cameras cannot be getting \n", vd_CurrentNumber);
   2356     }
   2357 #endif
   2358     return hr;
   2359 }
   2360 
   2361 MediaType videoDevice::getFormat(unsigned int id)
   2362 {
   2363     if(id < vd_CurrentFormats.size())
   2364     {
   2365         return vd_CurrentFormats[id];
   2366     }
   2367     else return MediaType();
   2368 }
   2369 int videoDevice::getCountFormats()
   2370 {
   2371     return (int)vd_CurrentFormats.size();
   2372 }
   2373 void videoDevice::setEmergencyStopEvent(void *userData, void(*func)(int, void *))
   2374 {
   2375     vd_func = func;
   2376     vd_userData = userData;
   2377 }
   2378 void videoDevice::closeDevice()
   2379 {
   2380     if(vd_IsSetuped)
   2381     {
   2382         vd_IsSetuped = false;
   2383 
   2384 #ifdef WINRT
   2385 #ifdef HAVE_CONCURRENCY
   2386         if (DEREF_AGILE_WRL_OBJ(vd_pMedCap)) {
   2387             MAKE_WRL_REF(_AsyncAction) action;
   2388             Concurrency::critical_section::scoped_lock _LockHolder(vd_lock);
   2389             MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction;
   2390             vd_pImGr->stopGrabbing(&action);
   2391             reinterpret_cast<ABI::Windows::Media::Capture::IMediaCapture*>(DEREF_AGILE_WRL_OBJ(vd_pMedCap))->remove_Failed(vd_cookie);
   2392             vd_cookie.value = 0;
   2393             vd_pAction = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(void, action, pOldAction, this)
   2394                 HRESULT hr = S_OK;
   2395                 if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait();
   2396                 CREATE_TASK DEFINE_RET_TYPE(void)(action).wait();
   2397                 RELEASE_WRL(vd_pMedCap)
   2398                 if(vd_LockOut == RawDataLock) {
   2399                     delete vd_pImGr;
   2400                 }
   2401                 vd_pImGr = NULL;
   2402                 vd_LockOut = OpenLock;
   2403             END_CREATE_ASYNC(hr));
   2404             return;
   2405         }
   2406 #endif
   2407 #endif
   2408 
   2409         vd_pSource->Shutdown();
   2410         SafeRelease(&vd_pSource);
   2411         if(vd_LockOut == RawDataLock)
   2412         {
   2413             vd_pImGrTh->stop();
   2414             Sleep(500);
   2415             delete vd_pImGrTh;
   2416         }
   2417         vd_pImGrTh = NULL;
   2418         vd_LockOut = OpenLock;
   2419         DebugPrintOut(L"VIDEODEVICE %i: Device is stopped \n", vd_CurrentNumber);
   2420     }
   2421 }
   2422 unsigned int videoDevice::getWidth()
   2423 {
   2424     if(vd_IsSetuped)
   2425         return vd_Width;
   2426     else
   2427         return 0;
   2428 }
   2429 unsigned int videoDevice::getHeight()
   2430 {
   2431     if(vd_IsSetuped)
   2432         return vd_Height;
   2433     else
   2434         return 0;
   2435 }
   2436 
   2437 unsigned int videoDevice::getFrameRate() const
   2438 {
   2439     if(vd_IsSetuped)
   2440         return vd_FrameRate;
   2441     else
   2442         return 0;
   2443 }
   2444 
   2445 IMFMediaSource *videoDevice::getMediaSource()
   2446 {
   2447     IMFMediaSource *out = NULL;
   2448     if(vd_LockOut == OpenLock)
   2449     {
   2450         vd_LockOut = MediaSourceLock;
   2451         out = vd_pSource;
   2452     }
   2453     return out;
   2454 }
   2455 int videoDevice::findType(unsigned int size, unsigned int frameRate)
   2456 {
   2457     // For required frame size look for the suitable video format.
   2458     // If not found, get the format for the largest available frame size.
   2459     FrameRateMap FRM;
   2460     std::map<UINT64, FrameRateMap>::const_iterator fmt;
   2461     fmt = vd_CaptureFormats.find(size);
   2462     if( fmt != vd_CaptureFormats.end() )
   2463         FRM = fmt->second;
   2464     else if( !vd_CaptureFormats.empty() )
   2465         FRM = vd_CaptureFormats.rbegin()->second;
   2466 
   2467     if( FRM.empty() )
   2468         return -1;
   2469 
   2470     UINT64 frameRateMax = 0;  SUBTYPEMap STMMax;
   2471     if(frameRate == 0)
   2472     {
   2473         std::map<UINT64, SUBTYPEMap>::iterator f = FRM.begin();
   2474         for(; f != FRM.end(); f++)
   2475         {
   2476             // Looking for highest possible frame rate.
   2477              if((*f).first >= frameRateMax)
   2478              {
   2479                  frameRateMax = (*f).first;
   2480                  STMMax = (*f).second;
   2481              }
   2482         }
   2483     }
   2484     else
   2485     {
   2486         std::map<UINT64, SUBTYPEMap>::iterator f = FRM.begin();
   2487         for(; f != FRM.end(); f++)
   2488         {
   2489             // Looking for frame rate higher that recently found but not higher then demanded.
   2490             if( (*f).first >= frameRateMax && (*f).first <= frameRate )
   2491             {
   2492                 frameRateMax = (*f).first;
   2493                 STMMax = (*f).second;
   2494             }
   2495         }
   2496     }
   2497     // Get first (default) item from the list if no suitable frame rate found.
   2498     if( STMMax.empty() )
   2499         STMMax = FRM.begin()->second;
   2500 
   2501     // Check if there are any format types on the list.
   2502     if( STMMax.empty() )
   2503         return -1;
   2504 
   2505     vectorNum VN = STMMax.begin()->second;
   2506     if( VN.empty() )
   2507         return -1;
   2508 
   2509     return VN[0];
   2510 }
   2511 
   2512 void videoDevice::buildLibraryofTypes()
   2513 {
   2514     unsigned int size;
   2515     unsigned int framerate;
   2516     std::vector<MediaType>::iterator i = vd_CurrentFormats.begin();
   2517     int count = 0;
   2518     for(; i != vd_CurrentFormats.end(); i++)
   2519     {
   2520         // Count only supported video formats.
   2521         if( (*i).MF_MT_SUBTYPE == MFVideoFormat_RGB24 )
   2522         {
   2523             size = (*i).MF_MT_FRAME_SIZE;
   2524             framerate = (*i).MF_MT_FRAME_RATE_NUMERATOR / (*i).MF_MT_FRAME_RATE_DENOMINATOR;
   2525             FrameRateMap FRM = vd_CaptureFormats[size];
   2526             SUBTYPEMap STM = FRM[framerate];
   2527             String subType((*i).pMF_MT_SUBTYPEName);
   2528             vectorNum VN = STM[subType];
   2529             VN.push_back(count);
   2530             STM[subType] = VN;
   2531             FRM[framerate] = STM;
   2532             vd_CaptureFormats[size] = FRM;
   2533         }
   2534         count++;
   2535     }
   2536 }
   2537 
   2538 #ifdef WINRT
   2539 long videoDevice::setDeviceFormat(MAKE_WRL_REF(_MediaCapture) pSource, unsigned long  dwFormatIndex, MAKE_WRL_REF(_AsyncAction)* pAction)
   2540 {
   2541     HRESULT hr;
   2542     MAKE_WRL_OBJ(_VideoDeviceController) pDevCont;
   2543     WRL_PROP_GET(pSource, VideoDeviceController, pDevCont, hr)
   2544     if (FAILED(hr)) return hr;
   2545     GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr)
   2546     if (FAILED(hr)) return hr;
   2547     MAKE_WRL_OBJ(_VectorView<MAKE_WRL_REF(_MediaEncodingProperties)>) pVector;
   2548     WRL_METHOD(pMedDevCont, GetAvailableMediaStreamProperties, pVector, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview))
   2549     if (FAILED(hr)) return hr;
   2550     MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps;
   2551     WRL_METHOD(pVector, GetAt, pMedEncProps, hr, dwFormatIndex)
   2552     if (FAILED(hr)) return hr;
   2553     WRL_METHOD(pMedDevCont, SetMediaStreamPropertiesAsync, *pAction, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview), DEREF_WRL_OBJ(pMedEncProps))
   2554     return hr;
   2555 }
   2556 #endif
   2557 
   2558 long videoDevice::setDeviceFormat(IMFMediaSource *pSource, unsigned long  dwFormatIndex)
   2559 {
   2560     _ComPtr<IMFPresentationDescriptor> pPD = NULL;
   2561     _ComPtr<IMFStreamDescriptor> pSD = NULL;
   2562     _ComPtr<IMFMediaTypeHandler> pHandler = NULL;
   2563     _ComPtr<IMFMediaType> pType = NULL;
   2564     HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf());
   2565     if (FAILED(hr))
   2566     {
   2567         goto done;
   2568     }
   2569     BOOL fSelected;
   2570     hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, pSD.GetAddressOf());
   2571     if (FAILED(hr))
   2572     {
   2573         goto done;
   2574     }
   2575     hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf());
   2576     if (FAILED(hr))
   2577     {
   2578         goto done;
   2579     }
   2580     hr = pHandler->GetMediaTypeByIndex((DWORD)dwFormatIndex, pType.GetAddressOf());
   2581     if (FAILED(hr))
   2582     {
   2583         goto done;
   2584     }
   2585     hr = pHandler->SetCurrentMediaType(pType.Get());
   2586 
   2587 done:
   2588     return hr;
   2589 }
   2590 
   2591 bool videoDevice::isDeviceSetup()
   2592 {
   2593     return vd_IsSetuped;
   2594 }
   2595 
   2596 RawImage * videoDevice::getRawImageOut()
   2597 {
   2598     if(!vd_IsSetuped) return NULL;
   2599 #ifdef WINRT
   2600     if(vd_pImGr) return vd_pImGr->getRawImage();
   2601 #endif
   2602     if(vd_pImGrTh)
   2603             return vd_pImGrTh->getImageGrabber()->getRawImage();
   2604     else
   2605     {
   2606         DebugPrintOut(L"VIDEODEVICE %i: The instance of ImageGrabberThread class does not exist  \n", vd_CurrentNumber);
   2607     }
   2608     return NULL;
   2609 }
   2610 
   2611 bool videoDevice::isFrameNew()
   2612 {
   2613     if(!vd_IsSetuped) return false;
   2614     if(vd_LockOut == RawDataLock || vd_LockOut == OpenLock)
   2615     {
   2616         if(vd_LockOut == OpenLock)
   2617         {
   2618             vd_LockOut = RawDataLock;
   2619 
   2620             //must already be closed
   2621 #ifdef WINRT
   2622             if (DEREF_AGILE_WRL_OBJ(vd_pMedCap)) {
   2623                 MAKE_WRL_REF(_AsyncAction) action;
   2624                 if (FAILED(ImageGrabberWinRT::CreateInstance(&vd_pImGr))) return false;
   2625                 if (FAILED(vd_pImGr->initImageGrabber(DEREF_AGILE_WRL_OBJ(vd_pMedCap), MFVideoFormat_RGB24)) || FAILED(vd_pImGr->startGrabbing(&action))) {
   2626                     delete vd_pImGr;
   2627                     return false;
   2628                 }
   2629 #ifdef HAVE_CONCURRENCY
   2630                 Concurrency::critical_section::scoped_lock _LockHolder(vd_lock);
   2631                 MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction;
   2632                 DEFINE_TASK<void> _task = CREATE_TASK DEFINE_RET_TYPE(void)(action);
   2633                 vd_pAction = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(void, _task, pOldAction, this)
   2634                     HRESULT hr = S_OK;
   2635                     if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait();
   2636                     _task.wait();
   2637                 END_CREATE_ASYNC(hr));
   2638 #endif
   2639                 return true;
   2640             }
   2641 #endif
   2642             HRESULT hr = ImageGrabberThread::CreateInstance(&vd_pImGrTh, vd_pSource, vd_CurrentNumber);
   2643             if(FAILED(hr))
   2644             {
   2645                 DebugPrintOut(L"VIDEODEVICE %i: The instance of ImageGrabberThread class cannot be created.\n", vd_CurrentNumber);
   2646                 return false;
   2647             }
   2648             vd_pImGrTh->setEmergencyStopEvent(vd_userData, vd_func);
   2649             vd_pImGrTh->start();
   2650             return true;
   2651         }
   2652 #ifdef WINRT
   2653         if(vd_pImGr)
   2654             return vd_pImGr->getRawImage()->isNew();
   2655 #endif
   2656         if(vd_pImGrTh)
   2657             return vd_pImGrTh->getImageGrabber()->getRawImage()->isNew();
   2658     }
   2659     return false;
   2660 }
   2661 
   2662 bool videoDevice::isDeviceMediaSource()
   2663 {
   2664     if(vd_LockOut == MediaSourceLock) return true;
   2665     return false;
   2666 }
   2667 
   2668 bool videoDevice::isDeviceRawDataSource()
   2669 {
   2670     if(vd_LockOut == RawDataLock) return true;
   2671     return false;
   2672 }
   2673 
   2674 bool videoDevice::setupDevice(unsigned int id)
   2675 {
   2676     if(!vd_IsSetuped)
   2677     {
   2678         HRESULT hr = initDevice();
   2679         if(SUCCEEDED(hr))
   2680         {
   2681 #ifdef WINRT
   2682 #ifdef HAVE_CONCURRENCY
   2683             Concurrency::critical_section::scoped_lock _LockHolder(vd_lock);
   2684             MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction;
   2685             SAVE_CURRENT_CONTEXT(context);
   2686             vd_pAction = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(void, pOldAction, context, id, this)
   2687                 HRESULT hr;
   2688                 if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait();
   2689 #endif
   2690 #endif
   2691             vd_Width = vd_CurrentFormats[id].width;
   2692             vd_Height = vd_CurrentFormats[id].height;
   2693             vd_FrameRate = vd_CurrentFormats[id].MF_MT_FRAME_RATE_NUMERATOR /
   2694                            vd_CurrentFormats[id].MF_MT_FRAME_RATE_DENOMINATOR;
   2695 #ifdef WINRT
   2696 #ifdef HAVE_CONCURRENCY
   2697             if (DEREF_AGILE_WRL_OBJ(vd_pMedCap)) {
   2698                 DEFINE_TASK<void> _task;
   2699                 BEGIN_CALL_IN_CONTEXT(hr, context, id, &_task, this)
   2700                     MAKE_WRL_REF(_AsyncAction) pAction;
   2701                     HRESULT hr = setDeviceFormat(DEREF_AGILE_WRL_OBJ(vd_pMedCap), (DWORD) id, &pAction);
   2702                     if (SUCCEEDED(hr)) _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction);
   2703                 END_CALL_IN_CONTEXT(hr)
   2704                 if (SUCCEEDED(hr)) _task.wait();
   2705             } else
   2706 #endif
   2707 #endif
   2708             hr = setDeviceFormat(vd_pSource, (DWORD) id);
   2709             vd_IsSetuped = (SUCCEEDED(hr));
   2710             if(vd_IsSetuped)
   2711                 DebugPrintOut(L"\n\nVIDEODEVICE %i: Device is setuped \n", vd_CurrentNumber);
   2712             vd_PrevParametrs = getParametrs();
   2713 #ifdef WINRT
   2714 #ifdef HAVE_CONCURRENCY
   2715             END_CREATE_ASYNC(hr));
   2716 #endif
   2717             return true;
   2718 #else
   2719             return vd_IsSetuped;
   2720 #endif
   2721         }
   2722         else
   2723         {
   2724             DebugPrintOut(L"VIDEODEVICE %i: Interface IMFMediaSource cannot be got \n", vd_CurrentNumber);
   2725             return false;
   2726         }
   2727     }
   2728     else
   2729     {
   2730         DebugPrintOut(L"VIDEODEVICE %i: Device is setuped already \n", vd_CurrentNumber);
   2731         return false;
   2732     }
   2733 }
   2734 
   2735 bool videoDevice::setupDevice(unsigned int w, unsigned int h, unsigned int idealFramerate)
   2736 {
   2737     unsigned int id = findType(w * h, idealFramerate);
   2738     if( id < 0 )
   2739         return false;
   2740 
   2741     return setupDevice(id);
   2742 }
   2743 
   2744 wchar_t *videoDevice::getName()
   2745 {
   2746     return vd_pFriendlyName;
   2747 }
   2748 
   2749 videoDevice::~videoDevice(void)
   2750 {
   2751     closeDevice();
   2752 #ifdef WINRT
   2753     RELEASE_WRL(vd_pMedCap)
   2754 #endif
   2755     SafeRelease(&vd_pSource);
   2756     if(vd_pFriendlyName)
   2757         CoTaskMemFree(vd_pFriendlyName);
   2758 }
   2759 
   2760 #ifdef WINRT
   2761 HRESULT videoDevice::enumerateCaptureFormats(MAKE_WRL_REF(_MediaCapture) pSource)
   2762 {
   2763     HRESULT hr;
   2764     MAKE_WRL_OBJ(_VideoDeviceController) pDevCont;
   2765     WRL_PROP_GET(pSource, VideoDeviceController, pDevCont, hr)
   2766     if (FAILED(hr)) return hr;
   2767     GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr)
   2768     if (FAILED(hr)) return hr;
   2769     MAKE_WRL_OBJ(_VectorView<MAKE_WRL_REF(_MediaEncodingProperties)>) pVector;
   2770     WRL_METHOD(pMedDevCont, GetAvailableMediaStreamProperties, pVector, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview))
   2771     if (FAILED(hr)) return hr;
   2772     UINT32 count;
   2773     WRL_PROP_GET(pVector, Size, count, hr)
   2774     if (FAILED(hr)) return hr;
   2775     for (UINT32 i = 0; i < count; i++) {
   2776         MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps;
   2777         WRL_METHOD(pVector, GetAt, pMedEncProps, hr, i)
   2778         if (FAILED(hr)) return hr;
   2779         _ComPtr<IMFMediaType> pType = NULL;
   2780         hr = MediaSink::ConvertPropertiesToMediaType(DEREF_AS_NATIVE_WRL_OBJ(ABI::Windows::Media::MediaProperties::IMediaEncodingProperties, pMedEncProps), &pType);
   2781         if (FAILED(hr)) return hr;
   2782         MediaType MT = FormatReader::Read(pType.Get());
   2783         vd_CurrentFormats.push_back(MT);
   2784     }
   2785     return hr;
   2786 }
   2787 #endif
   2788 
   2789 HRESULT videoDevice::enumerateCaptureFormats(IMFMediaSource *pSource)
   2790 {
   2791     _ComPtr<IMFPresentationDescriptor> pPD = NULL;
   2792     _ComPtr<IMFStreamDescriptor> pSD = NULL;
   2793     _ComPtr<IMFMediaTypeHandler> pHandler = NULL;
   2794     _ComPtr<IMFMediaType> pType = NULL;
   2795     HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf());
   2796     if (FAILED(hr))
   2797     {
   2798         goto done;
   2799     }
   2800     BOOL fSelected;
   2801     hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, pSD.GetAddressOf());
   2802     if (FAILED(hr))
   2803     {
   2804         goto done;
   2805     }
   2806     hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf());
   2807     if (FAILED(hr))
   2808     {
   2809         goto done;
   2810     }
   2811     DWORD cTypes = 0;
   2812     hr = pHandler->GetMediaTypeCount(&cTypes);
   2813     if (FAILED(hr))
   2814     {
   2815         goto done;
   2816     }
   2817     for (DWORD i = 0; i < cTypes; i++)
   2818     {
   2819         hr = pHandler->GetMediaTypeByIndex(i, pType.GetAddressOf());
   2820         if (FAILED(hr))
   2821         {
   2822             goto done;
   2823         }
   2824         MediaType MT = FormatReader::Read(pType.Get());
   2825         vd_CurrentFormats.push_back(MT);
   2826     }
   2827 
   2828 done:
   2829     return hr;
   2830 }
   2831 
   2832 videoDevices::videoDevices(void): count(0)
   2833 {
   2834 #ifdef WINRT
   2835     vds_enumTask = nullptr;
   2836 #endif
   2837 }
   2838 
   2839 void videoDevices::clearDevices()
   2840 {
   2841     std::vector<videoDevice *>::iterator i = vds_Devices.begin();
   2842     for(; i != vds_Devices.end(); ++i)
   2843         delete (*i);
   2844     vds_Devices.clear();
   2845 }
   2846 
   2847 videoDevices::~videoDevices(void)
   2848 {
   2849     clearDevices();
   2850 }
   2851 
   2852 videoDevice * videoDevices::getDevice(unsigned int i)
   2853 {
   2854     if(i >= vds_Devices.size())
   2855     {
   2856         return NULL;
   2857     }
   2858     if(i < 0)
   2859     {
   2860         return NULL;
   2861     }
   2862     return vds_Devices[i];
   2863 }
   2864 
   2865 #ifdef WINRT
   2866 long videoDevices::initDevices(_DeviceClass devClass)
   2867 {
   2868     HRESULT hr = S_OK;
   2869     ACTIVATE_STATIC_OBJ(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation, MAKE_WRL_OBJ(_DeviceInformationStatics), pDevStat, hr)
   2870     if (FAILED(hr)) return hr;
   2871     MAKE_WRL_REF(_AsyncOperation<MAKE_WRL_REF(_DeviceInformationCollection)>) pAction;
   2872     WRL_METHOD(pDevStat, _FindAllAsyncDeviceClass, pAction, hr, devClass)
   2873     if (SUCCEEDED(hr)) {
   2874 #ifdef HAVE_CONCURRENCY
   2875            SAVE_CURRENT_CONTEXT(context);
   2876            vds_enumTask = reinterpret_cast<MAKE_WRL_REF(_AsyncAction)>(BEGIN_CREATE_ASYNC(void, pAction, context, this)
   2877             HRESULT hr = S_OK;
   2878             MAKE_WRL_OBJ(_VectorView<MAKE_WRL_REF(_DeviceInformation)>) pVector =
   2879                 CREATE_TASK DEFINE_RET_TYPE(MAKE_WRL_REF(_VectorView<MAKE_WRL_REF(_DeviceInformation)>))(pAction).get();
   2880             if (SUCCEEDED(hr)) WRL_PROP_GET(pVector, Size, count, hr)
   2881             if (SUCCEEDED(hr) && count > 0) {
   2882                 for (UINT32 i = 0; i < count; i++) {
   2883                     videoDevice *vd = new videoDevice;
   2884                     MAKE_WRL_OBJ(_IDeviceInformation) pDevice;
   2885                     WRL_METHOD(pVector, GetAt, pDevice, hr, i)
   2886                     if (SUCCEEDED(hr)) {
   2887                         BEGIN_CALL_IN_CONTEXT(hr, context, vd, pDevice, i)
   2888                             vd->readInfoOfDevice(DEREF_WRL_OBJ(pDevice), i);
   2889                         END_CALL_IN_CONTEXT_BASE
   2890                         vds_Devices.push_back(vd);
   2891                     }
   2892                 }
   2893             }
   2894         END_CREATE_ASYNC(hr));
   2895 #endif
   2896     }
   2897     return hr;
   2898 }
   2899 #else
   2900 long videoDevices::initDevices(IMFAttributes *pAttributes)
   2901 {
   2902     clearDevices();
   2903     IMFActivate **ppDevices = NULL;
   2904     HRESULT hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
   2905     if (SUCCEEDED(hr))
   2906     {
   2907         if(count > 0)
   2908         {
   2909             for(UINT32 i = 0; i < count; i++)
   2910             {
   2911                 videoDevice *vd = new videoDevice;
   2912                 vd->readInfoOfDevice(ppDevices[i], i);
   2913                 vds_Devices.push_back(vd);
   2914                 SafeRelease(&ppDevices[i]);
   2915             }
   2916             SafeRelease(ppDevices);
   2917         }
   2918         else
   2919             hr = E_INVALIDARG;
   2920     }
   2921     else
   2922     {
   2923         DebugPrintOut(L"VIDEODEVICES: The instances of the videoDevice class cannot be created\n");
   2924     }
   2925     return hr;
   2926 }
   2927 #endif
   2928 
   2929 unsigned int videoDevices::getCount()
   2930 {
   2931     return (unsigned int)vds_Devices.size();
   2932 }
   2933 
   2934 videoDevices& videoDevices::getInstance()
   2935 {
   2936     static videoDevices instance;
   2937     return instance;
   2938 }
   2939 
   2940 Parametr::Parametr()
   2941 {
   2942     CurrentValue = 0;
   2943     Min = 0;
   2944     Max = 0;
   2945     Step = 0;
   2946     Default = 0;
   2947     Flag = 0;
   2948 }
   2949 
   2950 MediaType::MediaType()
   2951 {
   2952     pMF_MT_AM_FORMAT_TYPEName = NULL;
   2953     pMF_MT_MAJOR_TYPEName = NULL;
   2954     pMF_MT_SUBTYPEName = NULL;
   2955     Clear();
   2956 }
   2957 
   2958 MediaType::~MediaType()
   2959 {
   2960     Clear();
   2961 }
   2962 
   2963 void MediaType::Clear()
   2964 {
   2965     MF_MT_FRAME_SIZE = 0;
   2966     height = 0;
   2967     width = 0;
   2968     MF_MT_YUV_MATRIX = 0;
   2969     MF_MT_VIDEO_LIGHTING = 0;
   2970     MF_MT_DEFAULT_STRIDE = 0;
   2971     MF_MT_VIDEO_CHROMA_SITING = 0;
   2972     MF_MT_FIXED_SIZE_SAMPLES = 0;
   2973     MF_MT_VIDEO_NOMINAL_RANGE = 0;
   2974     MF_MT_FRAME_RATE_NUMERATOR = 0;
   2975     MF_MT_FRAME_RATE_DENOMINATOR = 0;
   2976     MF_MT_PIXEL_ASPECT_RATIO = 0;
   2977     MF_MT_PIXEL_ASPECT_RATIO_low = 0;
   2978     MF_MT_ALL_SAMPLES_INDEPENDENT = 0;
   2979     MF_MT_FRAME_RATE_RANGE_MIN = 0;
   2980     MF_MT_FRAME_RATE_RANGE_MIN_low = 0;
   2981     MF_MT_SAMPLE_SIZE = 0;
   2982     MF_MT_VIDEO_PRIMARIES = 0;
   2983     MF_MT_INTERLACE_MODE = 0;
   2984     MF_MT_FRAME_RATE_RANGE_MAX = 0;
   2985     MF_MT_FRAME_RATE_RANGE_MAX_low = 0;
   2986     memset(&MF_MT_MAJOR_TYPE, 0, sizeof(GUID));
   2987     memset(&MF_MT_AM_FORMAT_TYPE, 0, sizeof(GUID));
   2988     memset(&MF_MT_SUBTYPE, 0, sizeof(GUID));
   2989 }
   2990 
   2991 videoInput::videoInput(void): accessToDevices(false)
   2992 {
   2993     DebugPrintOut(L"\n***** VIDEOINPUT LIBRARY - 2013 (Author: Evgeny Pereguda) *****\n\n");
   2994     updateListOfDevices();
   2995     if(!accessToDevices)
   2996         DebugPrintOut(L"INITIALIZATION: There is not any suitable video device\n");
   2997 }
   2998 
   2999 void videoInput::updateListOfDevices()
   3000 {
   3001     Media_Foundation *MF = &Media_Foundation::getInstance();
   3002     accessToDevices = MF->buildListOfDevices();
   3003     if(!accessToDevices)
   3004         DebugPrintOut(L"UPDATING: There is not any suitable video device\n");
   3005 }
   3006 
   3007 videoInput::~videoInput(void)
   3008 {
   3009     DebugPrintOut(L"\n***** CLOSE VIDEOINPUT LIBRARY - 2013 *****\n\n");
   3010 }
   3011 
   3012 IMFMediaSource *videoInput::getMediaSource(int deviceID)
   3013 {
   3014     if(accessToDevices)
   3015     {
   3016         videoDevice * VD = videoDevices::getInstance().getDevice(deviceID);
   3017         if(VD)
   3018         {
   3019             IMFMediaSource *out = VD->getMediaSource();
   3020             if(!out)
   3021                 DebugPrintOut(L"VideoDevice %i: There is not any suitable IMFMediaSource interface\n", deviceID);
   3022             return out;
   3023         }
   3024     }
   3025     else
   3026     {
   3027         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3028     }
   3029     return NULL;
   3030 }
   3031 
   3032 bool videoInput::setupDevice(int deviceID, unsigned int id)
   3033 {
   3034     if (deviceID < 0 )
   3035     {
   3036         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3037         return false;
   3038     }
   3039     if(accessToDevices)
   3040     {
   3041         videoDevices *VDS = &videoDevices::getInstance();
   3042         videoDevice * VD = VDS->getDevice(deviceID);
   3043         if(VD)
   3044         {
   3045             bool out = VD->setupDevice(id);
   3046             if(!out)
   3047                 DebugPrintOut(L"VIDEODEVICE %i: This device cannot be started\n", deviceID);
   3048             return out;
   3049         }
   3050     }
   3051     else
   3052     {
   3053         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3054     }
   3055     return false;
   3056 }
   3057 
   3058 bool videoInput::setupDevice(int deviceID, unsigned int w, unsigned int h, unsigned int idealFramerate)
   3059 {
   3060     if (deviceID < 0 )
   3061     {
   3062         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3063         return false;
   3064     }
   3065     if(accessToDevices)
   3066     {
   3067         videoDevices *VDS = &videoDevices::getInstance();
   3068         videoDevice * VD = VDS->getDevice(deviceID);
   3069         if(VD)
   3070         {
   3071             bool out = VD->setupDevice(w, h, idealFramerate);
   3072             if(!out)
   3073                 DebugPrintOut(L"VIDEODEVICE %i: this device cannot be started\n", deviceID);
   3074             return out;
   3075         }
   3076     }
   3077     else
   3078     {
   3079         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n", deviceID);
   3080     }
   3081     return false;
   3082 }
   3083 
   3084 MediaType videoInput::getFormat(int deviceID, unsigned int id)
   3085 {
   3086     if (deviceID < 0)
   3087     {
   3088         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3089         return MediaType();
   3090     }
   3091     if(accessToDevices)
   3092     {
   3093         videoDevices *VDS = &videoDevices::getInstance();
   3094         videoDevice * VD = VDS->getDevice(deviceID);
   3095         if(VD)
   3096             return VD->getFormat(id);
   3097     }
   3098     else
   3099     {
   3100         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3101     }
   3102     return MediaType();
   3103 }
   3104 
   3105 bool videoInput::isDeviceSetup(int deviceID)
   3106 {
   3107     if (deviceID < 0)
   3108     {
   3109         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3110         return false;
   3111     }
   3112     if(accessToDevices)
   3113     {
   3114         videoDevices *VDS = &videoDevices::getInstance();
   3115         videoDevice * VD = VDS->getDevice(deviceID);
   3116         if(VD)
   3117             return VD->isDeviceSetup();
   3118     }
   3119     else
   3120     {
   3121         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3122     }
   3123     return false;
   3124 }
   3125 
   3126 bool videoInput::isDeviceMediaSource(int deviceID)
   3127 {
   3128     if (deviceID < 0)
   3129     {
   3130         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3131         return false;
   3132     }
   3133     if(accessToDevices)
   3134     {
   3135         videoDevices *VDS = &videoDevices::getInstance();
   3136         videoDevice * VD = VDS->getDevice(deviceID);
   3137         if(VD)
   3138             return VD->isDeviceMediaSource();
   3139     }
   3140     else
   3141     {
   3142         DebugPrintOut(L"Device(s): There is not any suitable video device\n");
   3143     }
   3144     return false;
   3145 }
   3146 
   3147 bool videoInput::isDeviceRawDataSource(int deviceID)
   3148 {
   3149     if (deviceID < 0)
   3150     {
   3151         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3152         return false;
   3153     }
   3154     if(accessToDevices)
   3155     {
   3156         videoDevices *VDS = &videoDevices::getInstance();
   3157         videoDevice * VD = VDS->getDevice(deviceID);
   3158         if(VD)
   3159         {
   3160             bool isRaw = VD->isDeviceRawDataSource();
   3161             return isRaw;
   3162         }
   3163     }
   3164     else
   3165     {
   3166         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3167     }
   3168     return false;
   3169 }
   3170 
   3171 bool videoInput::isFrameNew(int deviceID)
   3172 {
   3173     if (deviceID < 0)
   3174     {
   3175         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3176         return false;
   3177     }
   3178     if(accessToDevices)
   3179     {
   3180         if(!isDeviceSetup(deviceID))
   3181         {
   3182             if(isDeviceMediaSource(deviceID))
   3183                 return false;
   3184         }
   3185         videoDevices *VDS = &videoDevices::getInstance();
   3186         videoDevice * VD = VDS->getDevice(deviceID);
   3187         if(VD)
   3188         {
   3189             return VD->isFrameNew();
   3190         }
   3191     }
   3192     else
   3193     {
   3194         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3195     }
   3196     return false;
   3197 }
   3198 
   3199 #ifdef WINRT
   3200 void videoInput::waitForDevice(int deviceID)
   3201 {
   3202     if (deviceID < 0)
   3203     {
   3204         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3205         return;
   3206     }
   3207     if(accessToDevices)
   3208     {
   3209         if(!isDeviceSetup(deviceID))
   3210         {
   3211             if(isDeviceMediaSource(deviceID))
   3212                 return;
   3213         }
   3214         videoDevices *VDS = &videoDevices::getInstance();
   3215         videoDevice * VD = VDS->getDevice(deviceID);
   3216         if(VD)
   3217         {
   3218             VD->waitForDevice();
   3219         }
   3220     }
   3221     else
   3222     {
   3223         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3224     }
   3225     return;
   3226 }
   3227 #endif
   3228 
   3229 unsigned int videoInput::getCountFormats(int deviceID) const
   3230 {
   3231     if (deviceID < 0)
   3232     {
   3233         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3234         return 0;
   3235     }
   3236     if(accessToDevices)
   3237     {
   3238         videoDevices *VDS = &videoDevices::getInstance();
   3239         videoDevice * VD = VDS->getDevice(deviceID);
   3240         if(VD)
   3241             return VD->getCountFormats();
   3242     }
   3243     else
   3244     {
   3245         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3246     }
   3247     return 0;
   3248 }
   3249 
   3250 void videoInput::closeAllDevices()
   3251 {
   3252     videoDevices *VDS = &videoDevices::getInstance();
   3253     for(unsigned int i = 0; i < VDS->getCount(); i++)
   3254         closeDevice(i);
   3255 }
   3256 
   3257 void videoInput::setParametrs(int deviceID, CamParametrs parametrs)
   3258 {
   3259     if (deviceID < 0)
   3260     {
   3261         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3262         return;
   3263     }
   3264     if(accessToDevices)
   3265     {
   3266         videoDevices *VDS = &videoDevices::getInstance();
   3267         videoDevice *VD = VDS->getDevice(deviceID);
   3268         if(VD)
   3269             VD->setParametrs(parametrs);
   3270     }
   3271     else
   3272     {
   3273         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3274     }
   3275 }
   3276 
   3277 CamParametrs videoInput::getParametrs(int deviceID)
   3278 {
   3279     CamParametrs out;
   3280     if (deviceID < 0)
   3281     {
   3282         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3283         return out;
   3284     }
   3285     if(accessToDevices)
   3286     {
   3287         videoDevices *VDS = &videoDevices::getInstance();
   3288         videoDevice *VD = VDS->getDevice(deviceID);
   3289         if(VD)
   3290             out = VD->getParametrs();
   3291     }
   3292     else
   3293     {
   3294         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3295     }
   3296     return out;
   3297 }
   3298 
   3299 void videoInput::closeDevice(int deviceID)
   3300 {
   3301     if (deviceID < 0)
   3302     {
   3303         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3304         return;
   3305     }
   3306     if(accessToDevices)
   3307     {
   3308         videoDevices *VDS = &videoDevices::getInstance();
   3309         videoDevice *VD = VDS->getDevice(deviceID);
   3310         if(VD)
   3311             VD->closeDevice();
   3312     }
   3313     else
   3314     {
   3315         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3316     }
   3317 }
   3318 
   3319 unsigned int videoInput::getWidth(int deviceID) const
   3320 {
   3321     if (deviceID < 0)
   3322     {
   3323         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3324         return 0;
   3325     }
   3326     if(accessToDevices)
   3327     {
   3328         videoDevices *VDS = &videoDevices::getInstance();
   3329         videoDevice * VD = VDS->getDevice(deviceID);
   3330         if(VD)
   3331             return VD->getWidth();
   3332     }
   3333     else
   3334     {
   3335         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3336     }
   3337     return 0;
   3338 }
   3339 
   3340 unsigned int videoInput::getHeight(int deviceID) const
   3341 {
   3342     if (deviceID < 0)
   3343     {
   3344         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3345         return 0;
   3346     }
   3347     if(accessToDevices)
   3348     {
   3349         videoDevices *VDS = &videoDevices::getInstance();
   3350         videoDevice * VD = VDS->getDevice(deviceID);
   3351         if(VD)
   3352             return VD->getHeight();
   3353     }
   3354     else
   3355     {
   3356         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3357     }
   3358     return 0;
   3359 }
   3360 
   3361 unsigned int videoInput::getFrameRate(int deviceID) const
   3362 {
   3363     if (deviceID < 0)
   3364     {
   3365         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3366         return 0;
   3367     }
   3368     if(accessToDevices)
   3369     {
   3370         videoDevice * VD = videoDevices::getInstance().getDevice(deviceID);
   3371         if(VD)
   3372             return VD->getFrameRate();
   3373     }
   3374     else
   3375     {
   3376         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3377     }
   3378     return 0;
   3379 }
   3380 
   3381 wchar_t *videoInput::getNameVideoDevice(int deviceID)
   3382 {
   3383     if (deviceID < 0)
   3384     {
   3385         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3386         return NULL;
   3387     }
   3388     if(accessToDevices)
   3389     {
   3390         videoDevices *VDS = &videoDevices::getInstance();
   3391         videoDevice * VD = VDS->getDevice(deviceID);
   3392         if(VD)
   3393             return VD->getName();
   3394     }
   3395     else
   3396     {
   3397         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3398     }
   3399     return L"Empty";
   3400 }
   3401 
   3402 unsigned int videoInput::listDevices(bool silent)
   3403 {
   3404     int out = 0;
   3405     if(accessToDevices)
   3406     {
   3407         videoDevices *VDS = &videoDevices::getInstance();
   3408 #ifdef WINRT
   3409         VDS->waitInit();
   3410 #endif
   3411         out = VDS->getCount();
   3412         if(!silent) DebugPrintOut(L"\nVIDEOINPUT SPY MODE!\n\n");
   3413         if(!silent) DebugPrintOut(L"SETUP: Looking For Capture Devices\n");
   3414         for(int i = 0; i < out; i++)
   3415         {
   3416             if(!silent) DebugPrintOut(L"SETUP: %i) %s \n",i, getNameVideoDevice(i));
   3417         }
   3418         if(!silent) DebugPrintOut(L"SETUP: %i Device(s) found\n\n", out);
   3419     }
   3420     else
   3421     {
   3422         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3423     }
   3424     return out;
   3425 }
   3426 
   3427 videoInput& videoInput::getInstance()
   3428 {
   3429     static videoInput instance;
   3430     return instance;
   3431 }
   3432 
   3433 bool videoInput::isDevicesAcceable()
   3434 {
   3435     return accessToDevices;
   3436 }
   3437 
   3438 #ifdef _DEBUG
   3439 void videoInput::setVerbose(bool state)
   3440 {
   3441     DPO *dpo = &DPO::getInstance();
   3442     dpo->setVerbose(state);
   3443 }
   3444 #endif
   3445 
   3446 void videoInput::setEmergencyStopEvent(int deviceID, void *userData, void(*func)(int, void *))
   3447 {
   3448     if (deviceID < 0)
   3449     {
   3450         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3451         return;
   3452     }
   3453     if(accessToDevices)
   3454     {
   3455         if(func)
   3456         {
   3457             videoDevices *VDS = &videoDevices::getInstance();
   3458             videoDevice * VD = VDS->getDevice(deviceID);
   3459             if(VD)
   3460                 VD->setEmergencyStopEvent(userData, func);
   3461         }
   3462     }
   3463     else
   3464     {
   3465         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3466     }
   3467 }
   3468 
   3469 bool videoInput::getPixels(int deviceID, unsigned char * dstBuffer, bool flipRedAndBlue, bool flipImage)
   3470 {
   3471     bool success = false;
   3472     if (deviceID < 0)
   3473     {
   3474         DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID);
   3475         return success;
   3476     }
   3477     if(accessToDevices)
   3478     {
   3479         bool isRaw = isDeviceRawDataSource(deviceID);
   3480         if(isRaw)
   3481         {
   3482             videoDevice *VD = videoDevices::getInstance().getDevice(deviceID);
   3483             RawImage *RIOut = VD->getRawImageOut();
   3484             if(RIOut)
   3485             {
   3486                 const unsigned int bytes = 3;
   3487                 const unsigned int height = VD->getHeight();
   3488                 const unsigned int width  = VD->getWidth();
   3489                 const unsigned int size = bytes * width * height;
   3490                 if(size == RIOut->getSize())
   3491                 {
   3492                     processPixels(RIOut->getpPixels(), dstBuffer, width, height, bytes, flipRedAndBlue, flipImage);
   3493                     success = true;
   3494                 }
   3495                 else
   3496                 {
   3497                     DebugPrintOut(L"ERROR: GetPixels() - bufferSizes do not match!\n");
   3498                 }
   3499             }
   3500             else
   3501             {
   3502                 DebugPrintOut(L"ERROR: GetPixels() - Unable to grab frame for device %i\n", deviceID);
   3503             }
   3504         }
   3505         else
   3506         {
   3507             DebugPrintOut(L"ERROR: GetPixels() - Not raw data source device %i\n", deviceID);
   3508         }
   3509     }
   3510     else
   3511     {
   3512         DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n");
   3513     }
   3514     return success;
   3515 }
   3516 
   3517 void videoInput::processPixels(unsigned char * src, unsigned char * dst, unsigned int width,
   3518                                 unsigned int height, unsigned int bpp, bool bRGB, bool bFlip)
   3519 {
   3520     unsigned int widthInBytes = width * bpp;
   3521     unsigned int numBytes = widthInBytes * height;
   3522     int *dstInt, *srcInt;
   3523     if(!bRGB)
   3524     {
   3525         if(bFlip)
   3526         {
   3527             for(unsigned int y = 0; y < height; y++)
   3528             {
   3529                 dstInt = (int *)(dst + (y * widthInBytes));
   3530                 srcInt = (int *)(src + ( (height -y -1) * widthInBytes));
   3531                 memcpy(dstInt, srcInt, widthInBytes);
   3532             }
   3533         }
   3534         else
   3535         {
   3536             memcpy(dst, src, numBytes);
   3537         }
   3538     }
   3539     else
   3540     {
   3541         if(bFlip)
   3542         {
   3543             unsigned int x = 0;
   3544             unsigned int y = (height - 1) * widthInBytes;
   3545             src += y;
   3546             for(unsigned int i = 0; i < numBytes; i+=3)
   3547             {
   3548                 if(x >= width)
   3549                 {
   3550                     x = 0;
   3551                     src -= widthInBytes*2;
   3552                 }
   3553                 *dst = *(src+2);
   3554                 dst++;
   3555                 *dst = *(src+1);
   3556                 dst++;
   3557                 *dst = *src;
   3558                 dst++;
   3559                 src+=3;
   3560                 x++;
   3561             }
   3562         }
   3563         else
   3564         {
   3565             for(unsigned int i = 0; i < numBytes; i+=3)
   3566             {
   3567                 *dst = *(src+2);
   3568                 dst++;
   3569                 *dst = *(src+1);
   3570                 dst++;
   3571                 *dst = *src;
   3572                 dst++;
   3573                 src+=3;
   3574             }
   3575         }
   3576     }
   3577 }
   3578 }
   3579 
   3580 /******* Capturing video from camera via Microsoft Media Foundation **********/
   3581 class CvCaptureCAM_MSMF : public CvCapture
   3582 {
   3583 public:
   3584     CvCaptureCAM_MSMF();
   3585     virtual ~CvCaptureCAM_MSMF();
   3586     virtual bool open( int index );
   3587     virtual void close();
   3588     virtual double getProperty(int) const;
   3589     virtual bool setProperty(int, double);
   3590     virtual bool grabFrame();
   3591     virtual IplImage* retrieveFrame(int);
   3592     virtual int getCaptureDomain() { return CV_CAP_MSMF; } // Return the type of the capture object: CV_CAP_VFW, etc...
   3593 protected:
   3594     void init();
   3595     int index, width, height, fourcc;
   3596     IplImage* frame;
   3597     videoInput VI;
   3598 #ifdef WINRT
   3599 #ifdef HAVE_CONCURRENCY
   3600     DEFINE_TASK<bool> openTask;
   3601     Concurrency::critical_section lock;
   3602 #endif
   3603 #endif
   3604 };
   3605 
   3606 #ifdef _DEBUG
   3607 struct SuppressVideoInputMessages
   3608 {
   3609     SuppressVideoInputMessages() { videoInput::setVerbose(true); }
   3610 };
   3611 
   3612 static SuppressVideoInputMessages do_it;
   3613 #endif
   3614 
   3615 CvCaptureCAM_MSMF::CvCaptureCAM_MSMF():
   3616     index(-1),
   3617     width(-1),
   3618     height(-1),
   3619     fourcc(-1),
   3620     frame(NULL),
   3621     VI(videoInput::getInstance())
   3622 {
   3623     CoInitialize(0);
   3624 }
   3625 
   3626 CvCaptureCAM_MSMF::~CvCaptureCAM_MSMF()
   3627 {
   3628     close();
   3629     CoUninitialize();
   3630 }
   3631 
   3632 void CvCaptureCAM_MSMF::close()
   3633 {
   3634     if( index >= 0 )
   3635     {
   3636         VI.closeDevice(index);
   3637         index = -1;
   3638         cvReleaseImage(&frame);
   3639     }
   3640     width = height = -1;
   3641 }
   3642 
   3643 // Initialize camera input
   3644 bool CvCaptureCAM_MSMF::open( int _index )
   3645 {
   3646 #ifdef WINRT
   3647 #ifdef HAVE_CONCURRENCY
   3648     SAVE_CURRENT_CONTEXT(context);
   3649     auto func = [_index, context, this](DEFINE_RET_VAL(bool)) -> DEFINE_RET_FORMAL(bool) {
   3650 #endif
   3651 #endif
   3652     int try_index = _index;
   3653     int devices = 0;
   3654     close();
   3655     devices = VI.listDevices(true);
   3656     if (devices == 0)
   3657         return false;
   3658     try_index = try_index < 0 ? 0 : (try_index > devices-1 ? devices-1 : try_index);
   3659 #ifdef WINRT
   3660     HRESULT hr;
   3661 #ifdef HAVE_CONCURRENCY
   3662     BEGIN_CALL_IN_CONTEXT(hr, context, this, try_index)
   3663 #endif
   3664 #endif
   3665     VI.setupDevice(try_index, 0, 0, 0); // With maximum frame size.
   3666 #ifdef WINRT
   3667 #ifdef HAVE_CONCURRENCY
   3668     END_CALL_IN_CONTEXT_BASE
   3669     VI.waitForDevice(try_index);
   3670     BEGIN_CALL_IN_CONTEXT(hr, context, this, try_index)
   3671     HRESULT hr = S_OK;
   3672 #endif
   3673 #endif
   3674     if( !VI.isFrameNew(try_index) )
   3675 #ifdef WINRT
   3676         hr = E_FAIL;
   3677 #else
   3678         return false;
   3679 #endif
   3680     index = try_index;
   3681 #ifdef WINRT
   3682 #ifdef HAVE_CONCURRENCY
   3683     END_CALL_IN_CONTEXT_BASE
   3684     RET_VAL(true)
   3685     };
   3686     Concurrency::critical_section::scoped_lock _LockHolder(lock);
   3687     CREATE_OR_CONTINUE_TASK(openTask, bool, func)
   3688 #endif
   3689 #endif
   3690     return true;
   3691 }
   3692 
   3693 bool CvCaptureCAM_MSMF::grabFrame()
   3694 {
   3695     while (VI.isDeviceSetup(index) && !VI.isFrameNew(index))
   3696         Sleep(1);
   3697     return VI.isDeviceSetup(index);
   3698 }
   3699 
   3700 IplImage* CvCaptureCAM_MSMF::retrieveFrame(int)
   3701 {
   3702     const int w = (int)VI.getWidth(index);
   3703     const int h = (int)VI.getHeight(index);
   3704     if( !frame || w != frame->width || h != frame->height )
   3705     {
   3706         if (frame)
   3707             cvReleaseImage( &frame );
   3708         frame = cvCreateImage( cvSize(w,h), 8, 3 );
   3709     }
   3710     VI.getPixels( index, (uchar*)frame->imageData, false, true );
   3711     return frame;
   3712 }
   3713 
   3714 double CvCaptureCAM_MSMF::getProperty( int property_id ) const
   3715 {
   3716     // image format proprrties
   3717     switch( property_id )
   3718     {
   3719     case CV_CAP_PROP_FRAME_WIDTH:
   3720         return VI.getWidth(index);
   3721     case CV_CAP_PROP_FRAME_HEIGHT:
   3722         return VI.getHeight(index);
   3723     case CV_CAP_PROP_FPS:
   3724         return VI.getFrameRate(index);
   3725     default:
   3726         break;
   3727     }
   3728     return 0;
   3729 }
   3730 bool CvCaptureCAM_MSMF::setProperty( int property_id, double value )
   3731 {
   3732     // image capture properties
   3733     unsigned int fps = 0;
   3734     bool handled = false;
   3735     switch( property_id )
   3736     {
   3737     case CV_CAP_PROP_FRAME_WIDTH:
   3738         width = cvRound(value);
   3739         fps = VI.getFrameRate(index);
   3740         handled = true;
   3741         break;
   3742     case CV_CAP_PROP_FRAME_HEIGHT:
   3743         height = cvRound(value);
   3744         fps = VI.getFrameRate(index);
   3745         handled = true;
   3746         break;
   3747     case CV_CAP_PROP_FPS:
   3748         width = (int)VI.getHeight(index);
   3749         height = (int)VI.getWidth(index);
   3750         fps = cvRound(value);
   3751         break;
   3752     }
   3753 
   3754     if ( handled ) {
   3755         if( width > 0 && height > 0 )
   3756         {
   3757             if( (width != (int)VI.getWidth(index) || height != (int)VI.getHeight(index) || fps != VI.getFrameRate(index))
   3758                 && VI.isDeviceSetup(index))//|| fourcc != VI.getFourcc(index) )
   3759             {
   3760                 VI.closeDevice(index);
   3761                 VI.setupDevice(index, width, height, fps);
   3762             }
   3763             width = height = -1;
   3764             return VI.isDeviceSetup(index);
   3765         }
   3766         return true;
   3767     }
   3768 
   3769     return false;
   3770 }
   3771 
   3772 class CvCaptureFile_MSMF : public CvCapture
   3773 {
   3774 public:
   3775     CvCaptureFile_MSMF();
   3776     virtual ~CvCaptureFile_MSMF();
   3777 
   3778     virtual bool open( const char* filename );
   3779     virtual void close();
   3780 
   3781     virtual double getProperty(int) const;
   3782     virtual bool setProperty(int, double);
   3783     virtual bool grabFrame();
   3784     virtual IplImage* retrieveFrame(int);
   3785     virtual int getCaptureDomain() { return CV_CAP_MSMF; }
   3786 protected:
   3787     ImageGrabberThread* grabberThread;
   3788     IMFMediaSource* videoFileSource;
   3789     std::vector<MediaType> captureFormats;
   3790     int captureFormatIndex;
   3791     IplImage* frame;
   3792     bool isOpened;
   3793 
   3794     HRESULT enumerateCaptureFormats(IMFMediaSource *pSource);
   3795     HRESULT getSourceDuration(IMFMediaSource *pSource, MFTIME *pDuration) const;
   3796 };
   3797 
   3798 CvCaptureFile_MSMF::CvCaptureFile_MSMF():
   3799     grabberThread(NULL),
   3800     videoFileSource(NULL),
   3801     captureFormatIndex(0),
   3802     frame(NULL),
   3803     isOpened(false)
   3804 {
   3805     MFStartup(MF_VERSION);
   3806 }
   3807 
   3808 CvCaptureFile_MSMF::~CvCaptureFile_MSMF()
   3809 {
   3810     close();
   3811     MFShutdown();
   3812 }
   3813 
   3814 bool CvCaptureFile_MSMF::open(const char* filename)
   3815 {
   3816     if (!filename)
   3817         return false;
   3818 
   3819     wchar_t* unicodeFileName = new wchar_t[strlen(filename)+1];
   3820     MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, (int)strlen(filename)+1);
   3821 
   3822     MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
   3823 
   3824     _ComPtr<IMFSourceResolver> pSourceResolver = NULL;
   3825     IUnknown* pUnkSource = NULL;
   3826 
   3827     HRESULT hr = MFCreateSourceResolver(pSourceResolver.GetAddressOf());
   3828 
   3829     if (SUCCEEDED(hr))
   3830     {
   3831         hr = pSourceResolver->CreateObjectFromURL(
   3832             unicodeFileName,
   3833             MF_RESOLUTION_MEDIASOURCE,
   3834             NULL, // Optional property store.
   3835             &ObjectType,
   3836             &pUnkSource
   3837             );
   3838     }
   3839 
   3840     // Get the IMFMediaSource from the IUnknown pointer.
   3841     if (SUCCEEDED(hr))
   3842     {
   3843         hr = pUnkSource->QueryInterface(IID_PPV_ARGS(&videoFileSource));
   3844     }
   3845 
   3846     SafeRelease(&pUnkSource);
   3847 
   3848     if (SUCCEEDED(hr))
   3849     {
   3850         hr = enumerateCaptureFormats(videoFileSource);
   3851     }
   3852 
   3853     if( captureFormats.empty() )
   3854     {
   3855         isOpened = false;
   3856     }
   3857     else
   3858     {
   3859         if (SUCCEEDED(hr))
   3860         {
   3861             hr = ImageGrabberThread::CreateInstance(&grabberThread, videoFileSource, (unsigned int)-2, true);
   3862         }
   3863 
   3864         isOpened = SUCCEEDED(hr);
   3865     }
   3866 
   3867     if (isOpened)
   3868     {
   3869         grabberThread->start();
   3870     }
   3871 
   3872     return isOpened;
   3873 }
   3874 
   3875 void CvCaptureFile_MSMF::close()
   3876 {
   3877     if (grabberThread)
   3878     {
   3879         isOpened = false;
   3880         SetEvent(grabberThread->getImageGrabber()->ig_hFinish);
   3881         grabberThread->stop();
   3882         delete grabberThread;
   3883     }
   3884 
   3885     if (videoFileSource)
   3886     {
   3887         videoFileSource->Shutdown();
   3888     }
   3889 }
   3890 
   3891 bool CvCaptureFile_MSMF::setProperty(int property_id, double value)
   3892 {
   3893     // image capture properties
   3894     // FIXME: implement method in VideoInput back end
   3895     (void) property_id;
   3896     (void) value;
   3897     return false;
   3898 }
   3899 
   3900 double CvCaptureFile_MSMF::getProperty(int property_id) const
   3901 {
   3902     // image format proprrties
   3903     switch( property_id )
   3904     {
   3905     case CV_CAP_PROP_FRAME_WIDTH:
   3906         return captureFormats[captureFormatIndex].width;
   3907     case CV_CAP_PROP_FRAME_HEIGHT:
   3908         return captureFormats[captureFormatIndex].height;
   3909     case CV_CAP_PROP_FRAME_COUNT:
   3910         {
   3911             MFTIME duration;
   3912             getSourceDuration(this->videoFileSource, &duration);
   3913             double fps = ((double)captureFormats[captureFormatIndex].MF_MT_FRAME_RATE_NUMERATOR) /
   3914             ((double)captureFormats[captureFormatIndex].MF_MT_FRAME_RATE_DENOMINATOR);
   3915             return (double)floor(((double)duration/1e7)*fps+0.5);
   3916         }
   3917     case CV_CAP_PROP_FOURCC:
   3918         return captureFormats[captureFormatIndex].MF_MT_SUBTYPE.Data1;
   3919     case CV_CAP_PROP_FPS:
   3920         return ((double)captureFormats[captureFormatIndex].MF_MT_FRAME_RATE_NUMERATOR) /
   3921             ((double)captureFormats[captureFormatIndex].MF_MT_FRAME_RATE_DENOMINATOR);
   3922     }
   3923 
   3924     return -1;
   3925 }
   3926 
   3927 bool CvCaptureFile_MSMF::grabFrame()
   3928 {
   3929     DWORD waitResult = (DWORD)-1;
   3930     if (isOpened)
   3931     {
   3932         SetEvent(grabberThread->getImageGrabber()->ig_hFrameGrabbed);
   3933         HANDLE tmp[] = {grabberThread->getImageGrabber()->ig_hFrameReady, grabberThread->getImageGrabber()->ig_hFinish, 0};
   3934         waitResult = WaitForMultipleObjects(2, tmp, FALSE, INFINITE);
   3935     }
   3936 
   3937     return isOpened && grabberThread->getImageGrabber()->getRawImage()->isNew() && (waitResult == WAIT_OBJECT_0);
   3938 }
   3939 
   3940 IplImage* CvCaptureFile_MSMF::retrieveFrame(int)
   3941 {
   3942     unsigned int width = captureFormats[captureFormatIndex].width;
   3943     unsigned int height = captureFormats[captureFormatIndex].height;
   3944     unsigned int bytes = 3;
   3945     if( !frame || (int)width != frame->width || (int)height != frame->height )
   3946     {
   3947         if (frame)
   3948             cvReleaseImage( &frame );
   3949         frame = cvCreateImage( cvSize(width,height), 8, 3 );
   3950     }
   3951 
   3952     RawImage *RIOut = grabberThread->getImageGrabber()->getRawImage();
   3953     unsigned int size = bytes * width * height;
   3954 
   3955     bool verticalFlip = captureFormats[captureFormatIndex].MF_MT_DEFAULT_STRIDE < 0;
   3956 
   3957     if(RIOut && size == RIOut->getSize())
   3958     {
   3959          videoInput::processPixels(RIOut->getpPixels(), (unsigned char*)frame->imageData, width,
   3960              height, bytes, false, verticalFlip);
   3961     }
   3962 
   3963     return frame;
   3964 }
   3965 
   3966 HRESULT CvCaptureFile_MSMF::enumerateCaptureFormats(IMFMediaSource *pSource)
   3967 {
   3968     _ComPtr<IMFPresentationDescriptor> pPD = NULL;
   3969     _ComPtr<IMFStreamDescriptor> pSD = NULL;
   3970     _ComPtr<IMFMediaTypeHandler> pHandler = NULL;
   3971     _ComPtr<IMFMediaType> pType = NULL;
   3972     HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf());
   3973     if (FAILED(hr))
   3974     {
   3975         goto done;
   3976     }
   3977 
   3978     BOOL fSelected;
   3979     hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, pSD.GetAddressOf());
   3980     if (FAILED(hr))
   3981     {
   3982         goto done;
   3983     }
   3984     hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf());
   3985     if (FAILED(hr))
   3986     {
   3987         goto done;
   3988     }
   3989     DWORD cTypes = 0;
   3990     hr = pHandler->GetMediaTypeCount(&cTypes);
   3991     if (FAILED(hr))
   3992     {
   3993         goto done;
   3994     }
   3995     for (DWORD i = 0; i < cTypes; i++)
   3996     {
   3997         hr = pHandler->GetMediaTypeByIndex(i, pType.GetAddressOf());
   3998         if (FAILED(hr))
   3999         {
   4000             goto done;
   4001         }
   4002         MediaType MT = FormatReader::Read(pType.Get());
   4003         // We can capture only RGB video.
   4004         if( MT.MF_MT_SUBTYPE == MFVideoFormat_RGB24 )
   4005             captureFormats.push_back(MT);
   4006     }
   4007 
   4008 done:
   4009     return hr;
   4010 }
   4011 
   4012 HRESULT CvCaptureFile_MSMF::getSourceDuration(IMFMediaSource *pSource, MFTIME *pDuration) const
   4013 {
   4014     *pDuration = 0;
   4015 
   4016     IMFPresentationDescriptor *pPD = NULL;
   4017 
   4018     HRESULT hr = pSource->CreatePresentationDescriptor(&pPD);
   4019     if (SUCCEEDED(hr))
   4020     {
   4021         hr = pPD->GetUINT64(MF_PD_DURATION, (UINT64*)pDuration);
   4022         pPD->Release();
   4023     }
   4024     return hr;
   4025 }
   4026 
   4027 CvCapture* cvCreateCameraCapture_MSMF( int index )
   4028 {
   4029     CvCaptureCAM_MSMF* capture = new CvCaptureCAM_MSMF;
   4030     try
   4031     {
   4032         if( capture->open( index ))
   4033             return capture;
   4034     }
   4035     catch(...)
   4036     {
   4037         delete capture;
   4038         throw;
   4039     }
   4040     delete capture;
   4041     return 0;
   4042 }
   4043 
   4044 CvCapture* cvCreateFileCapture_MSMF (const char* filename)
   4045 {
   4046     CvCaptureFile_MSMF* capture = new CvCaptureFile_MSMF;
   4047     try
   4048     {
   4049         if( capture->open(filename) )
   4050             return capture;
   4051         else
   4052         {
   4053             delete capture;
   4054             return NULL;
   4055         }
   4056     }
   4057     catch(...)
   4058     {
   4059         delete capture;
   4060         throw;
   4061     }
   4062 }
   4063 
   4064 //
   4065 //
   4066 // Media Foundation-based Video Writer
   4067 //
   4068 //
   4069 
   4070 class CvVideoWriter_MSMF : public CvVideoWriter
   4071 {
   4072 public:
   4073     CvVideoWriter_MSMF();
   4074     virtual ~CvVideoWriter_MSMF();
   4075     virtual bool open(const char* filename, int fourcc,
   4076                        double fps, CvSize frameSize, bool isColor);
   4077     virtual void close();
   4078     virtual bool writeFrame(const IplImage* img);
   4079 
   4080 private:
   4081     UINT32 videoWidth;
   4082     UINT32 videoHeight;
   4083     double fps;
   4084     UINT32 bitRate;
   4085     UINT32 frameSize;
   4086     GUID   encodingFormat;
   4087     GUID   inputFormat;
   4088 
   4089     DWORD  streamIndex;
   4090     _ComPtr<IMFSinkWriter> sinkWriter;
   4091 
   4092     bool   initiated;
   4093 
   4094     LONGLONG rtStart;
   4095     UINT64 rtDuration;
   4096 
   4097     HRESULT InitializeSinkWriter(const char* filename);
   4098     static const GUID FourCC2GUID(int fourcc);
   4099     HRESULT WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& rtStart, const LONGLONG& rtDuration);
   4100 };
   4101 
   4102 CvVideoWriter_MSMF::CvVideoWriter_MSMF():
   4103     initiated(false)
   4104 {
   4105 }
   4106 
   4107 CvVideoWriter_MSMF::~CvVideoWriter_MSMF()
   4108 {
   4109     close();
   4110 }
   4111 
   4112 const GUID CvVideoWriter_MSMF::FourCC2GUID(int fourcc)
   4113 {
   4114     switch(fourcc)
   4115     {
   4116         case CV_FOURCC_MACRO('d', 'v', '2', '5'):
   4117             return MFVideoFormat_DV25; break;
   4118         case CV_FOURCC_MACRO('d', 'v', '5', '0'):
   4119             return MFVideoFormat_DV50; break;
   4120         case CV_FOURCC_MACRO('d', 'v', 'c', ' '):
   4121             return MFVideoFormat_DVC; break;
   4122         case CV_FOURCC_MACRO('d', 'v', 'h', '1'):
   4123             return MFVideoFormat_DVH1; break;
   4124         case CV_FOURCC_MACRO('d', 'v', 'h', 'd'):
   4125             return MFVideoFormat_DVHD; break;
   4126         case CV_FOURCC_MACRO('d', 'v', 's', 'd'):
   4127             return MFVideoFormat_DVSD; break;
   4128         case CV_FOURCC_MACRO('d', 'v', 's', 'l'):
   4129                 return MFVideoFormat_DVSL; break;
   4130 #if (WINVER >= 0x0602)
   4131         case CV_FOURCC_MACRO('H', '2', '6', '3'):   // Available only for Win 8 target.
   4132                 return MFVideoFormat_H263; break;
   4133 #endif
   4134         case CV_FOURCC_MACRO('H', '2', '6', '4'):
   4135                 return MFVideoFormat_H264; break;
   4136         case CV_FOURCC_MACRO('M', '4', 'S', '2'):
   4137                 return MFVideoFormat_M4S2; break;
   4138         case CV_FOURCC_MACRO('M', 'J', 'P', 'G'):
   4139                 return MFVideoFormat_MJPG; break;
   4140         case CV_FOURCC_MACRO('M', 'P', '4', '3'):
   4141                 return MFVideoFormat_MP43; break;
   4142         case CV_FOURCC_MACRO('M', 'P', '4', 'S'):
   4143                 return MFVideoFormat_MP4S; break;
   4144         case CV_FOURCC_MACRO('M', 'P', '4', 'V'):
   4145                 return MFVideoFormat_MP4V; break;
   4146         case CV_FOURCC_MACRO('M', 'P', 'G', '1'):
   4147                 return MFVideoFormat_MPG1; break;
   4148         case CV_FOURCC_MACRO('M', 'S', 'S', '1'):
   4149                 return MFVideoFormat_MSS1; break;
   4150         case CV_FOURCC_MACRO('M', 'S', 'S', '2'):
   4151                 return MFVideoFormat_MSS2; break;
   4152         case CV_FOURCC_MACRO('W', 'M', 'V', '1'):
   4153                 return MFVideoFormat_WMV1; break;
   4154         case CV_FOURCC_MACRO('W', 'M', 'V', '2'):
   4155                 return MFVideoFormat_WMV2; break;
   4156         case CV_FOURCC_MACRO('W', 'M', 'V', '3'):
   4157                 return MFVideoFormat_WMV3; break;
   4158         case CV_FOURCC_MACRO('W', 'V', 'C', '1'):
   4159                 return MFVideoFormat_WVC1; break;
   4160         default:
   4161             return MFVideoFormat_H264;
   4162     }
   4163 }
   4164 
   4165 bool CvVideoWriter_MSMF::open( const char* filename, int fourcc,
   4166                        double _fps, CvSize frameSize, bool /*isColor*/ )
   4167 {
   4168     videoWidth = frameSize.width;
   4169     videoHeight = frameSize.height;
   4170     fps = _fps;
   4171     bitRate = (UINT32)fps*videoWidth*videoHeight; // 1-bit per pixel
   4172     encodingFormat = FourCC2GUID(fourcc);
   4173     inputFormat = MFVideoFormat_RGB32;
   4174 
   4175     HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
   4176     if (SUCCEEDED(hr))
   4177     {
   4178         hr = MFStartup(MF_VERSION);
   4179         if (SUCCEEDED(hr))
   4180         {
   4181             hr = InitializeSinkWriter(filename);
   4182             if (SUCCEEDED(hr))
   4183             {
   4184                 initiated = true;
   4185                 rtStart = 0;
   4186                 MFFrameRateToAverageTimePerFrame((UINT32)fps, 1, &rtDuration);
   4187             }
   4188         }
   4189     }
   4190 
   4191     return SUCCEEDED(hr);
   4192 }
   4193 
   4194 void CvVideoWriter_MSMF::close()
   4195 {
   4196     if (!initiated)
   4197     {
   4198         return;
   4199     }
   4200 
   4201     initiated = false;
   4202     sinkWriter->Finalize();
   4203     MFShutdown();
   4204 }
   4205 
   4206 bool CvVideoWriter_MSMF::writeFrame(const IplImage* img)
   4207 {
   4208     if (!img)
   4209         return false;
   4210 
   4211     int length = img->width * img->height * 4;
   4212     DWORD* target = new DWORD[length];
   4213 
   4214     for (int rowIdx = 0; rowIdx < img->height; rowIdx++)
   4215     {
   4216         char* rowStart = img->imageData + rowIdx*img->widthStep;
   4217         for (int colIdx = 0; colIdx < img->width; colIdx++)
   4218         {
   4219             BYTE b = rowStart[colIdx * img->nChannels + 0];
   4220             BYTE g = rowStart[colIdx * img->nChannels + 1];
   4221             BYTE r = rowStart[colIdx * img->nChannels + 2];
   4222 
   4223             target[rowIdx*img->width+colIdx] = (r << 16) + (g << 8) + b;
   4224         }
   4225     }
   4226 
   4227     // Send frame to the sink writer.
   4228     HRESULT hr = WriteFrame(target, rtStart, rtDuration);
   4229     if (FAILED(hr))
   4230     {
   4231         delete[] target;
   4232         return false;
   4233     }
   4234     rtStart += rtDuration;
   4235 
   4236     delete[] target;
   4237 
   4238     return true;
   4239 }
   4240 
   4241 HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename)
   4242 {
   4243     _ComPtr<IMFAttributes> spAttr;
   4244     _ComPtr<IMFMediaType>  mediaTypeOut;
   4245     _ComPtr<IMFMediaType>  mediaTypeIn;
   4246     _ComPtr<IMFByteStream> spByteStream;
   4247 
   4248     MFCreateAttributes(&spAttr, 10);
   4249     spAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true);
   4250 
   4251     wchar_t* unicodeFileName = new wchar_t[strlen(filename)+1];
   4252     MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, (int)strlen(filename)+1);
   4253 
   4254     HRESULT hr = MFCreateSinkWriterFromURL(unicodeFileName, NULL, spAttr.Get(), &sinkWriter);
   4255 
   4256     delete[] unicodeFileName;
   4257 
   4258     // Set the output media type.
   4259     if (SUCCEEDED(hr))
   4260     {
   4261         hr = MFCreateMediaType(&mediaTypeOut);
   4262     }
   4263     if (SUCCEEDED(hr))
   4264     {
   4265         hr = mediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
   4266     }
   4267     if (SUCCEEDED(hr))
   4268     {
   4269         hr = mediaTypeOut->SetGUID(MF_MT_SUBTYPE, encodingFormat);
   4270     }
   4271     if (SUCCEEDED(hr))
   4272     {
   4273         hr = mediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, bitRate);
   4274     }
   4275     if (SUCCEEDED(hr))
   4276     {
   4277         hr = mediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
   4278     }
   4279     if (SUCCEEDED(hr))
   4280     {
   4281         hr = MFSetAttributeSize(mediaTypeOut.Get(), MF_MT_FRAME_SIZE, videoWidth, videoHeight);
   4282     }
   4283     if (SUCCEEDED(hr))
   4284     {
   4285         hr = MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_FRAME_RATE, (UINT32)fps, 1);
   4286     }
   4287     if (SUCCEEDED(hr))
   4288     {
   4289         hr = MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
   4290     }
   4291 
   4292     if (SUCCEEDED(hr))
   4293     {
   4294         hr = sinkWriter->AddStream(mediaTypeOut.Get(), &streamIndex);
   4295     }
   4296 
   4297     // Set the input media type.
   4298     if (SUCCEEDED(hr))
   4299     {
   4300         hr = MFCreateMediaType(&mediaTypeIn);
   4301     }
   4302     if (SUCCEEDED(hr))
   4303     {
   4304         hr = mediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
   4305     }
   4306     if (SUCCEEDED(hr))
   4307     {
   4308         hr = mediaTypeIn->SetGUID(MF_MT_SUBTYPE, inputFormat);
   4309     }
   4310     if (SUCCEEDED(hr))
   4311     {
   4312         hr = mediaTypeIn->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
   4313     }
   4314     if (SUCCEEDED(hr))
   4315     {
   4316         hr = MFSetAttributeSize(mediaTypeIn.Get(), MF_MT_FRAME_SIZE, videoWidth, videoHeight);
   4317     }
   4318     if (SUCCEEDED(hr))
   4319     {
   4320         hr = MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_FRAME_RATE, (UINT32)fps, 1);
   4321     }
   4322     if (SUCCEEDED(hr))
   4323     {
   4324         hr = MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
   4325     }
   4326 
   4327     if (SUCCEEDED(hr))
   4328     {
   4329         hr = sinkWriter->SetInputMediaType(streamIndex, mediaTypeIn.Get(), NULL);
   4330     }
   4331 
   4332     // Tell the sink writer to start accepting data.
   4333     if (SUCCEEDED(hr))
   4334     {
   4335         hr = sinkWriter->BeginWriting();
   4336     }
   4337 
   4338     return hr;
   4339 }
   4340 
   4341 HRESULT CvVideoWriter_MSMF::WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& Start, const LONGLONG& Duration)
   4342 {
   4343     _ComPtr<IMFSample> sample;
   4344     _ComPtr<IMFMediaBuffer> buffer;
   4345 
   4346     const LONG cbWidth = 4 * videoWidth;
   4347     const DWORD cbBuffer = cbWidth * videoHeight;
   4348 
   4349     BYTE *pData = NULL;
   4350 
   4351     // Create a new memory buffer.
   4352     HRESULT hr = MFCreateMemoryBuffer(cbBuffer, &buffer);
   4353 
   4354     // Lock the buffer and copy the video frame to the buffer.
   4355     if (SUCCEEDED(hr))
   4356     {
   4357         hr = buffer->Lock(&pData, NULL, NULL);
   4358     }
   4359 
   4360     if (SUCCEEDED(hr))
   4361     {
   4362 #if defined(_M_ARM)
   4363         hr = MFCopyImage(
   4364             pData,                      // Destination buffer.
   4365             -cbWidth,                   // Destination stride.
   4366             (BYTE*)videoFrameBuffer,    // First row in source image.
   4367             cbWidth,                    // Source stride.
   4368             cbWidth,                    // Image width in bytes.
   4369             videoHeight                 // Image height in pixels.
   4370             );
   4371 #else
   4372         hr = MFCopyImage(
   4373             pData,                      // Destination buffer.
   4374             cbWidth,                    // Destination stride.
   4375             (BYTE*)videoFrameBuffer,    // First row in source image.
   4376             cbWidth,                    // Source stride.
   4377             cbWidth,                    // Image width in bytes.
   4378             videoHeight                 // Image height in pixels.
   4379             );
   4380 #endif
   4381     }
   4382 
   4383     if (buffer)
   4384     {
   4385         buffer->Unlock();
   4386     }
   4387 
   4388     // Set the data length of the buffer.
   4389     if (SUCCEEDED(hr))
   4390     {
   4391         hr = buffer->SetCurrentLength(cbBuffer);
   4392     }
   4393 
   4394     // Create a media sample and add the buffer to the sample.
   4395     if (SUCCEEDED(hr))
   4396     {
   4397         hr = MFCreateSample(&sample);
   4398     }
   4399     if (SUCCEEDED(hr))
   4400     {
   4401         hr = sample->AddBuffer(buffer.Get());
   4402     }
   4403 
   4404     // Set the time stamp and the duration.
   4405     if (SUCCEEDED(hr))
   4406     {
   4407         hr = sample->SetSampleTime(Start);
   4408     }
   4409     if (SUCCEEDED(hr))
   4410     {
   4411         hr = sample->SetSampleDuration(Duration);
   4412     }
   4413 
   4414     // Send the sample to the Sink Writer.
   4415     if (SUCCEEDED(hr))
   4416     {
   4417         hr = sinkWriter->WriteSample(streamIndex, sample.Get());
   4418     }
   4419 
   4420     return hr;
   4421 }
   4422 
   4423 CvVideoWriter* cvCreateVideoWriter_MSMF( const char* filename, int fourcc,
   4424                                         double fps, CvSize frameSize, int isColor )
   4425 {
   4426     CvVideoWriter_MSMF* writer = new CvVideoWriter_MSMF;
   4427     if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 ))
   4428         return writer;
   4429     delete writer;
   4430     return NULL;
   4431 }
   4432 
   4433 #endif
   4434