diff --git a/cmake/OpenCVFindLibsVideo.cmake b/cmake/OpenCVFindLibsVideo.cmake index f7b427bf45..9ed9ceb823 100644 --- a/cmake/OpenCVFindLibsVideo.cmake +++ b/cmake/OpenCVFindLibsVideo.cmake @@ -261,6 +261,13 @@ endif(WITH_DSHOW) ocv_clear_vars(HAVE_MSMF) if(WITH_MSMF) check_include_file(Mfapi.h HAVE_MSMF) + check_include_file(D3D11.h D3D11_found) + check_include_file(D3d11_4.h D3D11_4_found) + if(D3D11_found AND D3D11_4_found) + set(HAVE_DXVA YES) + else() + set(HAVE_DXVA NO) + endif() endif(WITH_MSMF) # --- Extra HighGUI and VideoIO libs on Windows --- diff --git a/modules/videoio/CMakeLists.txt b/modules/videoio/CMakeLists.txt index 3562bfe05f..02d2bd830f 100644 --- a/modules/videoio/CMakeLists.txt +++ b/modules/videoio/CMakeLists.txt @@ -86,6 +86,9 @@ endif() if (WIN32 AND HAVE_MSMF) list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_msmf.hpp) list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_msmf.cpp) + if (HAVE_DXVA) + add_definitions(-DHAVE_DXVA) + endif() endif() if (WIN32 AND HAVE_VFW) diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp index d4582d6f5e..fa0c54793d 100644 --- a/modules/videoio/src/cap_msmf.cpp +++ b/modules/videoio/src/cap_msmf.cpp @@ -52,9 +52,6 @@ #undef WINVER #define WINVER _WIN32_WINNT_WIN8 #endif -#if defined _MSC_VER && _MSC_VER >= 1600 - #define HAVE_CONCURRENCY -#endif #include #include #include @@ -64,10 +61,15 @@ #include #include #include +#ifdef HAVE_DXVA +#include +#include +#endif #include #include #include #include +#include #include #include #include @@ -79,6 +81,9 @@ #pragma comment(lib, "mfuuid") #pragma comment(lib, "Strmiids") #pragma comment(lib, "Mfreadwrite") +#ifdef HAVE_DXVA +#pragma comment(lib, "d3d11") +#endif #if (WINVER >= 0x0602) // Available since Win 8 #pragma comment(lib, "MinCore_Downlevel") #endif @@ -86,3833 +91,1696 @@ #include -#ifdef WINRT - // for ComPtr usage -#include -#ifdef __cplusplus_winrt -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#ifdef HAVE_CONCURRENCY -#include -#ifndef __cplusplus_winrt -#include "wrl.h" -#endif -#include "ppltasks_winrt.hpp" -#endif -#else #include -#endif struct IMFMediaType; -#ifndef WINRT struct IMFActivate; struct IMFMediaSource; -#endif struct IMFAttributes; namespace { -template void SafeRelease(T **ppT) +#ifdef _DEBUG +void DPOprintOut(const wchar_t *format, ...) { - if (*ppT) + int i = 0; + wchar_t *p = NULL; + va_list args; + va_start(args, format); + if (::IsDebuggerPresent()) + { + WCHAR szMsg[512]; + ::StringCchVPrintfW(szMsg, sizeof(szMsg) / sizeof(szMsg[0]), format, args); + ::OutputDebugStringW(szMsg); + } + else { - (*ppT)->Release(); - *ppT = NULL; + if (wcscmp(format, L"%i")) + { + i = va_arg(args, int); + } + if (wcscmp(format, L"%s")) + { + p = va_arg(args, wchar_t *); + } + wprintf(format, i, p); } + va_end(args); } +#define DebugPrintOut(...) DPOprintOut(__VA_ARGS__) +#else +#define DebugPrintOut(...) void() +#endif -#ifdef _DEBUG -/// Class for printing info into console -class DPO +template +class ComPtr { public: - ~DPO(void); - static DPO& getInstance(); - void printOut(const wchar_t *format, ...); - void setVerbose(bool state); - bool verbose; + ComPtr() + { + } + ComPtr(T* lp) + { + p = lp; + } + ComPtr(_In_ const ComPtr& lp) + { + p = lp.p; + } + virtual ~ComPtr() + { + } + + T** operator&() + { + assert(p == NULL); + return p.operator&(); + } + T* operator->() const + { + assert(p != NULL); + return p.operator->(); + } + bool operator!() const + { + return p.operator==(NULL); + } + bool operator==(_In_opt_ T* pT) const + { + return p.operator==(pT); + } + bool operator!=(_In_opt_ T* pT) const + { + return p.operator!=(pT); + } + operator bool() + { + return p.operator!=(NULL); + } + + T* const* GetAddressOf() const + { + return &p; + } + + T** GetAddressOf() + { + return &p; + } + + T** ReleaseAndGetAddressOf() + { + p.Release(); + return &p; + } + + T* Get() const + { + return p; + } + + // Attach to an existing interface (does not AddRef) + void Attach(_In_opt_ T* p2) + { + p.Attach(p2); + } + // Detach the interface (does not Release) + T* Detach() + { + return p.Detach(); + } + _Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT) + { + assert(ppT != NULL); + if (ppT == NULL) + return E_POINTER; + *ppT = p; + if (p != NULL) + p->AddRef(); + return S_OK; + } + + void Reset() + { + p.Release(); + } + + // query for U interface + template + HRESULT As(_Inout_ U** lp) const + { + return p->QueryInterface(__uuidof(U), reinterpret_cast(lp)); + } + // query for U interface + template + HRESULT As(_Out_ ComPtr* lp) const + { + return p->QueryInterface(__uuidof(U), reinterpret_cast(lp->ReleaseAndGetAddressOf())); + } private: - DPO(void); + _COM_SMARTPTR_TYPEDEF(T, __uuidof(T)); + TPtr p; }; -#define DebugPrintOut(...) DPO::getInstance().printOut(__VA_ARGS__) -#else -#define DebugPrintOut(...) void() -#endif -#include "cap_msmf.hpp" +#define _ComPtr ComPtr // Structure for collecting info about types of video, which are supported by current video device struct MediaType { unsigned int MF_MT_FRAME_SIZE; - unsigned int height; - unsigned int width; + UINT32 height; + UINT32 width; unsigned int MF_MT_YUV_MATRIX; unsigned int MF_MT_VIDEO_LIGHTING; int MF_MT_DEFAULT_STRIDE; // stride is negative if image is bottom-up unsigned int MF_MT_VIDEO_CHROMA_SITING; GUID MF_MT_AM_FORMAT_TYPE; - wchar_t *pMF_MT_AM_FORMAT_TYPEName; unsigned int MF_MT_FIXED_SIZE_SAMPLES; unsigned int MF_MT_VIDEO_NOMINAL_RANGE; - unsigned int MF_MT_FRAME_RATE_NUMERATOR; - unsigned int MF_MT_FRAME_RATE_DENOMINATOR; - unsigned int MF_MT_PIXEL_ASPECT_RATIO; - unsigned int MF_MT_PIXEL_ASPECT_RATIO_low; + UINT32 MF_MT_FRAME_RATE_NUMERATOR; + UINT32 MF_MT_FRAME_RATE_DENOMINATOR; + UINT32 MF_MT_PIXEL_ASPECT_RATIO_NUMERATOR; + UINT32 MF_MT_PIXEL_ASPECT_RATIO_DENOMINATOR; unsigned int MF_MT_ALL_SAMPLES_INDEPENDENT; - unsigned int MF_MT_FRAME_RATE_RANGE_MIN; - unsigned int MF_MT_FRAME_RATE_RANGE_MIN_low; + UINT32 MF_MT_FRAME_RATE_RANGE_MIN_NUMERATOR; + UINT32 MF_MT_FRAME_RATE_RANGE_MIN_DENOMINATOR; unsigned int MF_MT_SAMPLE_SIZE; unsigned int MF_MT_VIDEO_PRIMARIES; unsigned int MF_MT_INTERLACE_MODE; - unsigned int MF_MT_FRAME_RATE_RANGE_MAX; - unsigned int MF_MT_FRAME_RATE_RANGE_MAX_low; + UINT32 MF_MT_FRAME_RATE_RANGE_MAX_NUMERATOR; + UINT32 MF_MT_FRAME_RATE_RANGE_MAX_DENOMINATOR; GUID MF_MT_MAJOR_TYPE; GUID MF_MT_SUBTYPE; - wchar_t *pMF_MT_MAJOR_TYPEName; - wchar_t *pMF_MT_SUBTYPEName; + LPCWSTR pMF_MT_MAJOR_TYPEName; + LPCWSTR pMF_MT_SUBTYPEName; MediaType(); + MediaType(IMFMediaType *pType); ~MediaType(); void Clear(); }; -/// Class for parsing info from IMFMediaType into the local MediaType -class FormatReader -{ -public: - static MediaType Read(IMFMediaType *pType); - ~FormatReader(void); -private: - FormatReader(void); -}; - -DWORD WINAPI MainThreadFunction( LPVOID lpParam ); -typedef void(*emergensyStopEventCallback)(int, void *); - -class RawImage +// Class for creating of Media Foundation context +class Media_Foundation { public: - ~RawImage(void); - // Function of creation of the instance of the class - static long CreateInstance(RawImage **ppRImage,unsigned int size); - void setCopy(const BYTE * pSampleBuffer); - void fastCopy(const BYTE * pSampleBuffer); - unsigned char * getpPixels(); - bool isNew(); - unsigned int getSize(); + ~Media_Foundation(void) { /*CV_Assert(SUCCEEDED(MFShutdown()));*/ CoUninitialize(); } + static Media_Foundation& getInstance() + { + static Media_Foundation instance; + return instance; + } private: - bool ri_new; - unsigned int ri_size; - unsigned char *ri_pixels; - RawImage(unsigned int size); + Media_Foundation(void) { CoInitialize(0); CV_Assert(SUCCEEDED(MFStartup(MF_VERSION))); } }; -class ImageGrabberCallback : public IMFSampleGrabberSinkCallback -{ -public: - void pauseGrabbing(); - void resumeGrabbing(); - RawImage *getRawImage(); - // IMFClockStateSink methods - STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset); - STDMETHODIMP OnClockStop(MFTIME hnsSystemTime); - STDMETHODIMP OnClockPause(MFTIME hnsSystemTime); - STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime); - STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate); - // IMFSampleGrabberSinkCallback methods - STDMETHODIMP OnSetPresentationClock(IMFPresentationClock* pClock); - STDMETHODIMP OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags, - LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer, - DWORD dwSampleSize); - STDMETHODIMP OnShutdown(); - - const HANDLE ig_hFrameReady; - const HANDLE ig_hFrameGrabbed; - const HANDLE ig_hFinish; -protected: - ImageGrabberCallback(bool synchronous); - bool ig_RIE; - bool ig_Close; - bool ig_Synchronous; - long m_cRef; - - RawImage *ig_RIFirst; - RawImage *ig_RISecond; - RawImage *ig_RIOut; -private: - ImageGrabberCallback& operator=(const ImageGrabberCallback&); // Declared to fix compilation warning. - }; - -#ifdef WINRT -extern const __declspec(selectany) WCHAR RuntimeClass_CV_ImageGrabberWinRT[] = L"cv.ImageGrabberWinRT"; - -class ImageGrabberWinRT : - public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>, - IMFSampleGrabberSinkCallback>, public ImageGrabberCallback -{ - InspectableClass(RuntimeClass_CV_ImageGrabberWinRT, BaseTrust) -public: - ImageGrabberWinRT(bool synchronous); - ~ImageGrabberWinRT(void); - - HRESULT initImageGrabber(MAKE_WRL_REF(_MediaCapture) pSource, - GUID VideoFormat); - HRESULT startGrabbing(MAKE_WRL_REF(_AsyncAction)* action); - HRESULT stopGrabbing(MAKE_WRL_REF(_AsyncAction)* action); - // IMFClockStateSink methods - STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) { return ImageGrabberCallback::OnClockStart(hnsSystemTime, llClockStartOffset); } - STDMETHODIMP OnClockStop(MFTIME hnsSystemTime) { return ImageGrabberCallback::OnClockStop(hnsSystemTime); } - STDMETHODIMP OnClockPause(MFTIME hnsSystemTime) { return ImageGrabberCallback::OnClockPause(hnsSystemTime); } - STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime) { return ImageGrabberCallback::OnClockRestart(hnsSystemTime); } - STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate) { return ImageGrabberCallback::OnClockSetRate(hnsSystemTime, flRate); } - // IMFSampleGrabberSinkCallback methods - STDMETHODIMP OnSetPresentationClock(IMFPresentationClock* pClock) { return ImageGrabberCallback::OnSetPresentationClock(pClock); } - STDMETHODIMP OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags, - LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer, - DWORD dwSampleSize) { return ImageGrabberCallback::OnProcessSample(guidMajorMediaType, dwSampleFlags, llSampleTime, llSampleDuration, pSampleBuffer, dwSampleSize); } - STDMETHODIMP OnShutdown() { return ImageGrabberCallback::OnShutdown(); } - // Function of creation of the instance of the class - static HRESULT CreateInstance(ImageGrabberWinRT **ppIG, bool synchronous = false); -private: - MAKE_WRL_AGILE_REF(_MediaCapture) ig_pMedCapSource; - MediaSink* ig_pMediaSink; -}; +#ifndef IF_GUID_EQUAL_RETURN +#define IF_GUID_EQUAL_RETURN(val) if(val == guid) return L#val #endif - -// Class for grabbing image from video stream -class ImageGrabber : public ImageGrabberCallback -{ -public: - ~ImageGrabber(void); - HRESULT initImageGrabber(IMFMediaSource *pSource); - HRESULT startGrabbing(void); - void stopGrabbing(); - // IUnknown methods - STDMETHODIMP QueryInterface(REFIID iid, void** ppv); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - // Function of creation of the instance of the class - static HRESULT CreateInstance(ImageGrabber **ppIG, unsigned int deviceID, bool synchronous = false); - const MediaType* getCaptureFormat() { return &captureFormat; } - -private: - unsigned int ig_DeviceID; - - IMFMediaSource *ig_pSource; - MediaType captureFormat; - IMFMediaSession *ig_pSession; - IMFTopology *ig_pTopology; - ImageGrabber(unsigned int deviceID, bool synchronous); - HRESULT CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo); - HRESULT AddSourceNode(IMFTopology *pTopology, IMFMediaSource *pSource, - IMFPresentationDescriptor *pPD, IMFStreamDescriptor *pSD, IMFTopologyNode **ppNode); - HRESULT AddOutputNode(IMFTopology *pTopology, IMFActivate *pActivate, DWORD dwId, IMFTopologyNode **ppNode); - - ImageGrabber& operator=(const ImageGrabber&); // Declared to fix comiplation error. -}; - -/// Class for controlling of thread of the grabbing raw data from video device -class ImageGrabberThread -{ - friend DWORD WINAPI MainThreadFunction( LPVOID lpParam ); -public: - ~ImageGrabberThread(void); - static HRESULT CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID, bool synchronious = false); - void start(); - void stop(); - void setEmergencyStopEvent(void *userData, void(*func)(int, void *)); - ImageGrabber *getImageGrabber(); -protected: - virtual void run(); -private: - ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID, bool synchronious); - HANDLE igt_Handle; - DWORD igt_ThreadIdArray; - ImageGrabber *igt_pImageGrabber; - emergensyStopEventCallback igt_func; - void *igt_userData; - bool igt_stop; - unsigned int igt_DeviceID; -}; - -// Structure for collecting info about one parametr of current video device -struct Parametr -{ - long CurrentValue; - long Min; - long Max; - long Step; - long Default; - long Flag; - Parametr(); -}; - -// Structure for collecting info about 17 parametrs of current video device -struct CamParametrs -{ - Parametr Brightness; - Parametr Contrast; - Parametr Hue; - Parametr Saturation; - Parametr Sharpness; - Parametr Gamma; - Parametr ColorEnable; - Parametr WhiteBalance; - Parametr BacklightCompensation; - Parametr Gain; - Parametr Pan; - Parametr Tilt; - Parametr Roll; - Parametr Zoom; - Parametr Exposure; - Parametr Iris; - Parametr Focus; -}; - -typedef std::wstring String; -typedef std::vector vectorNum; -typedef std::map SUBTYPEMap; -typedef std::map FrameRateMap; -typedef void(*emergensyStopEventCallback)(int, void *); - -/// Class for controlling of video device -class videoDevice +LPCWSTR GetGUIDNameConstNew(const GUID& guid) { -public: - videoDevice(void); - ~videoDevice(void); - void closeDevice(); - CamParametrs getParametrs(); - void setParametrs(CamParametrs parametrs); - void setEmergencyStopEvent(void *userData, void(*func)(int, void *)); -#ifdef WINRT - long readInfoOfDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice, unsigned int Num); - void waitForDevice() - { - if (vd_pAction) { -#ifdef HAVE_CONCURRENCY - CREATE_TASK DEFINE_RET_TYPE(void)(vd_pAction).wait(); + IF_GUID_EQUAL_RETURN(MF_MT_MAJOR_TYPE); + IF_GUID_EQUAL_RETURN(MF_MT_SUBTYPE); + IF_GUID_EQUAL_RETURN(MF_MT_ALL_SAMPLES_INDEPENDENT); + IF_GUID_EQUAL_RETURN(MF_MT_FIXED_SIZE_SAMPLES); + IF_GUID_EQUAL_RETURN(MF_MT_COMPRESSED); + IF_GUID_EQUAL_RETURN(MF_MT_SAMPLE_SIZE); + IF_GUID_EQUAL_RETURN(MF_MT_WRAPPED_TYPE); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_NUM_CHANNELS); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_SAMPLES_PER_SECOND); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_AVG_BYTES_PER_SECOND); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_BLOCK_ALIGNMENT); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_BITS_PER_SAMPLE); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_VALID_BITS_PER_SAMPLE); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_SAMPLES_PER_BLOCK); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_CHANNEL_MASK); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_FOLDDOWN_MATRIX); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_WMADRC_PEAKREF); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_WMADRC_PEAKTARGET); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_WMADRC_AVGREF); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_WMADRC_AVGTARGET); + IF_GUID_EQUAL_RETURN(MF_MT_AUDIO_PREFER_WAVEFORMATEX); + IF_GUID_EQUAL_RETURN(MF_MT_AAC_PAYLOAD_TYPE); + IF_GUID_EQUAL_RETURN(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION); + IF_GUID_EQUAL_RETURN(MF_MT_FRAME_SIZE); + IF_GUID_EQUAL_RETURN(MF_MT_FRAME_RATE); + IF_GUID_EQUAL_RETURN(MF_MT_FRAME_RATE_RANGE_MAX); + IF_GUID_EQUAL_RETURN(MF_MT_FRAME_RATE_RANGE_MIN); + IF_GUID_EQUAL_RETURN(MF_MT_PIXEL_ASPECT_RATIO); + IF_GUID_EQUAL_RETURN(MF_MT_DRM_FLAGS); + IF_GUID_EQUAL_RETURN(MF_MT_PAD_CONTROL_FLAGS); + IF_GUID_EQUAL_RETURN(MF_MT_SOURCE_CONTENT_HINT); + IF_GUID_EQUAL_RETURN(MF_MT_VIDEO_CHROMA_SITING); + IF_GUID_EQUAL_RETURN(MF_MT_INTERLACE_MODE); + IF_GUID_EQUAL_RETURN(MF_MT_TRANSFER_FUNCTION); + IF_GUID_EQUAL_RETURN(MF_MT_VIDEO_PRIMARIES); + IF_GUID_EQUAL_RETURN(MF_MT_CUSTOM_VIDEO_PRIMARIES); + IF_GUID_EQUAL_RETURN(MF_MT_YUV_MATRIX); + IF_GUID_EQUAL_RETURN(MF_MT_VIDEO_LIGHTING); + IF_GUID_EQUAL_RETURN(MF_MT_VIDEO_NOMINAL_RANGE); + IF_GUID_EQUAL_RETURN(MF_MT_GEOMETRIC_APERTURE); + IF_GUID_EQUAL_RETURN(MF_MT_MINIMUM_DISPLAY_APERTURE); + IF_GUID_EQUAL_RETURN(MF_MT_PAN_SCAN_APERTURE); + IF_GUID_EQUAL_RETURN(MF_MT_PAN_SCAN_ENABLED); + IF_GUID_EQUAL_RETURN(MF_MT_AVG_BITRATE); + IF_GUID_EQUAL_RETURN(MF_MT_AVG_BIT_ERROR_RATE); + IF_GUID_EQUAL_RETURN(MF_MT_MAX_KEYFRAME_SPACING); + IF_GUID_EQUAL_RETURN(MF_MT_DEFAULT_STRIDE); + IF_GUID_EQUAL_RETURN(MF_MT_PALETTE); + IF_GUID_EQUAL_RETURN(MF_MT_USER_DATA); + IF_GUID_EQUAL_RETURN(MF_MT_AM_FORMAT_TYPE); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG_START_TIME_CODE); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG2_PROFILE); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG2_LEVEL); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG2_FLAGS); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG_SEQUENCE_HEADER); + IF_GUID_EQUAL_RETURN(MF_MT_DV_AAUX_SRC_PACK_0); + IF_GUID_EQUAL_RETURN(MF_MT_DV_AAUX_CTRL_PACK_0); + IF_GUID_EQUAL_RETURN(MF_MT_DV_AAUX_SRC_PACK_1); + IF_GUID_EQUAL_RETURN(MF_MT_DV_AAUX_CTRL_PACK_1); + IF_GUID_EQUAL_RETURN(MF_MT_DV_VAUX_SRC_PACK); + IF_GUID_EQUAL_RETURN(MF_MT_DV_VAUX_CTRL_PACK); + IF_GUID_EQUAL_RETURN(MF_MT_ARBITRARY_HEADER); + IF_GUID_EQUAL_RETURN(MF_MT_ARBITRARY_FORMAT); + IF_GUID_EQUAL_RETURN(MF_MT_IMAGE_LOSS_TOLERANT); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG4_SAMPLE_DESCRIPTION); + IF_GUID_EQUAL_RETURN(MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY); + IF_GUID_EQUAL_RETURN(MF_MT_ORIGINAL_4CC); + IF_GUID_EQUAL_RETURN(MF_MT_ORIGINAL_WAVE_FORMAT_TAG); + // Media types + IF_GUID_EQUAL_RETURN(MFMediaType_Audio); + IF_GUID_EQUAL_RETURN(MFMediaType_Video); + IF_GUID_EQUAL_RETURN(MFMediaType_Protected); +#ifdef MFMediaType_Perception + IF_GUID_EQUAL_RETURN(MFMediaType_Perception); +#endif + IF_GUID_EQUAL_RETURN(MFMediaType_Stream); + IF_GUID_EQUAL_RETURN(MFMediaType_SAMI); + IF_GUID_EQUAL_RETURN(MFMediaType_Script); + IF_GUID_EQUAL_RETURN(MFMediaType_Image); + IF_GUID_EQUAL_RETURN(MFMediaType_HTML); + IF_GUID_EQUAL_RETURN(MFMediaType_Binary); + IF_GUID_EQUAL_RETURN(MFMediaType_FileTransfer); + IF_GUID_EQUAL_RETURN(MFVideoFormat_AI44); // FCC('AI44') + IF_GUID_EQUAL_RETURN(MFVideoFormat_ARGB32); // D3DFMT_A8R8G8B8 + IF_GUID_EQUAL_RETURN(MFVideoFormat_AYUV); // FCC('AYUV') + IF_GUID_EQUAL_RETURN(MFVideoFormat_DV25); // FCC('dv25') + IF_GUID_EQUAL_RETURN(MFVideoFormat_DV50); // FCC('dv50') + IF_GUID_EQUAL_RETURN(MFVideoFormat_DVH1); // FCC('dvh1') + IF_GUID_EQUAL_RETURN(MFVideoFormat_DVC); + IF_GUID_EQUAL_RETURN(MFVideoFormat_DVHD); + IF_GUID_EQUAL_RETURN(MFVideoFormat_DVSD); // FCC('dvsd') + IF_GUID_EQUAL_RETURN(MFVideoFormat_DVSL); // FCC('dvsl') + IF_GUID_EQUAL_RETURN(MFVideoFormat_H264); // FCC('H264') + IF_GUID_EQUAL_RETURN(MFVideoFormat_I420); // FCC('I420') + IF_GUID_EQUAL_RETURN(MFVideoFormat_IYUV); // FCC('IYUV') + IF_GUID_EQUAL_RETURN(MFVideoFormat_M4S2); // FCC('M4S2') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MJPG); + IF_GUID_EQUAL_RETURN(MFVideoFormat_MP43); // FCC('MP43') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MP4S); // FCC('MP4S') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MP4V); // FCC('MP4V') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MPG1); // FCC('MPG1') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MSS1); // FCC('MSS1') + IF_GUID_EQUAL_RETURN(MFVideoFormat_MSS2); // FCC('MSS2') + IF_GUID_EQUAL_RETURN(MFVideoFormat_NV11); // FCC('NV11') + IF_GUID_EQUAL_RETURN(MFVideoFormat_NV12); // FCC('NV12') + IF_GUID_EQUAL_RETURN(MFVideoFormat_P010); // FCC('P010') + IF_GUID_EQUAL_RETURN(MFVideoFormat_P016); // FCC('P016') + IF_GUID_EQUAL_RETURN(MFVideoFormat_P210); // FCC('P210') + IF_GUID_EQUAL_RETURN(MFVideoFormat_P216); // FCC('P216') + IF_GUID_EQUAL_RETURN(MFVideoFormat_RGB24); // D3DFMT_R8G8B8 + IF_GUID_EQUAL_RETURN(MFVideoFormat_RGB32); // D3DFMT_X8R8G8B8 + IF_GUID_EQUAL_RETURN(MFVideoFormat_RGB555); // D3DFMT_X1R5G5B5 + IF_GUID_EQUAL_RETURN(MFVideoFormat_RGB565); // D3DFMT_R5G6B5 + IF_GUID_EQUAL_RETURN(MFVideoFormat_RGB8); + IF_GUID_EQUAL_RETURN(MFVideoFormat_UYVY); // FCC('UYVY') + IF_GUID_EQUAL_RETURN(MFVideoFormat_v210); // FCC('v210') + IF_GUID_EQUAL_RETURN(MFVideoFormat_v410); // FCC('v410') + IF_GUID_EQUAL_RETURN(MFVideoFormat_WMV1); // FCC('WMV1') + IF_GUID_EQUAL_RETURN(MFVideoFormat_WMV2); // FCC('WMV2') + IF_GUID_EQUAL_RETURN(MFVideoFormat_WMV3); // FCC('WMV3') + IF_GUID_EQUAL_RETURN(MFVideoFormat_WVC1); // FCC('WVC1') + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y210); // FCC('Y210') + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y216); // FCC('Y216') + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y410); // FCC('Y410') + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y416); // FCC('Y416') + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y41P); + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y41T); + IF_GUID_EQUAL_RETURN(MFVideoFormat_YUY2); // FCC('YUY2') + IF_GUID_EQUAL_RETURN(MFVideoFormat_YV12); // FCC('YV12') + IF_GUID_EQUAL_RETURN(MFVideoFormat_YVYU); +#ifdef MFVideoFormat_H263 + IF_GUID_EQUAL_RETURN(MFVideoFormat_H263); +#endif +#ifdef MFVideoFormat_H265 + IF_GUID_EQUAL_RETURN(MFVideoFormat_H265); +#endif +#ifdef MFVideoFormat_H264_ES + IF_GUID_EQUAL_RETURN(MFVideoFormat_H264_ES); +#endif +#ifdef MFVideoFormat_HEVC + IF_GUID_EQUAL_RETURN(MFVideoFormat_HEVC); +#endif +#ifdef MFVideoFormat_HEVC_ES + IF_GUID_EQUAL_RETURN(MFVideoFormat_HEVC_ES); +#endif +#ifdef MFVideoFormat_MPEG2 + IF_GUID_EQUAL_RETURN(MFVideoFormat_MPEG2); +#endif +#ifdef MFVideoFormat_VP80 + IF_GUID_EQUAL_RETURN(MFVideoFormat_VP80); +#endif +#ifdef MFVideoFormat_VP90 + IF_GUID_EQUAL_RETURN(MFVideoFormat_VP90); +#endif +#ifdef MFVideoFormat_420O + IF_GUID_EQUAL_RETURN(MFVideoFormat_420O); +#endif +#ifdef MFVideoFormat_Y42T + IF_GUID_EQUAL_RETURN(MFVideoFormat_Y42T); +#endif +#ifdef MFVideoFormat_YVU9 + IF_GUID_EQUAL_RETURN(MFVideoFormat_YVU9); +#endif +#ifdef MFVideoFormat_v216 + IF_GUID_EQUAL_RETURN(MFVideoFormat_v216); +#endif +#ifdef MFVideoFormat_L8 + IF_GUID_EQUAL_RETURN(MFVideoFormat_L8); +#endif +#ifdef MFVideoFormat_L16 + IF_GUID_EQUAL_RETURN(MFVideoFormat_L16); +#endif +#ifdef MFVideoFormat_D16 + IF_GUID_EQUAL_RETURN(MFVideoFormat_D16); +#endif +#ifdef D3DFMT_X8R8G8B8 + IF_GUID_EQUAL_RETURN(D3DFMT_X8R8G8B8); +#endif +#ifdef D3DFMT_A8R8G8B8 + IF_GUID_EQUAL_RETURN(D3DFMT_A8R8G8B8); +#endif +#ifdef D3DFMT_R8G8B8 + IF_GUID_EQUAL_RETURN(D3DFMT_R8G8B8); +#endif +#ifdef D3DFMT_X1R5G5B5 + IF_GUID_EQUAL_RETURN(D3DFMT_X1R5G5B5); +#endif +#ifdef D3DFMT_A4R4G4B4 + IF_GUID_EQUAL_RETURN(D3DFMT_A4R4G4B4); +#endif +#ifdef D3DFMT_R5G6B5 + IF_GUID_EQUAL_RETURN(D3DFMT_R5G6B5); +#endif +#ifdef D3DFMT_P8 + IF_GUID_EQUAL_RETURN(D3DFMT_P8); +#endif +#ifdef D3DFMT_A2R10G10B10 + IF_GUID_EQUAL_RETURN(D3DFMT_A2R10G10B10); #endif - vd_pAction = nullptr; - } - } -#else - long readInfoOfDevice(IMFActivate *pActivate, unsigned int Num); +#ifdef D3DFMT_A2B10G10R10 + IF_GUID_EQUAL_RETURN(D3DFMT_A2B10G10R10); #endif - wchar_t *getName(); - int getCountFormats(); - unsigned int getWidth(); - unsigned int getHeight(); - unsigned int getFrameRate() const; - MediaType getFormat(unsigned int id); - bool setupDevice(unsigned int w, unsigned int h, unsigned int idealFramerate = 0); - bool setupDevice(unsigned int id); - bool isDeviceSetup(); - bool isDeviceMediaSource(); - bool isDeviceRawDataSource(); - bool isFrameNew(); - IMFMediaSource *getMediaSource(); - RawImage *getRawImageOut(); -private: - enum typeLock - { - MediaSourceLock, - RawDataLock, - OpenLock - } vd_LockOut; - wchar_t *vd_pFriendlyName; - ImageGrabberThread *vd_pImGrTh; - CamParametrs vd_PrevParametrs; - unsigned int vd_Width; - unsigned int vd_Height; - unsigned int vd_FrameRate; - unsigned int vd_CurrentNumber; - bool vd_IsSetuped; - std::map vd_CaptureFormats; - std::vector vd_CurrentFormats; - IMFMediaSource *vd_pSource; -#ifdef WINRT - MAKE_WRL_AGILE_REF(_MediaCapture) vd_pMedCap; - EventRegistrationToken vd_cookie; - ImageGrabberWinRT *vd_pImGr; - MAKE_WRL_REF(_AsyncAction) vd_pAction; -#ifdef HAVE_CONCURRENCY - Concurrency::critical_section vd_lock; +#ifdef D3DFMT_L8 + IF_GUID_EQUAL_RETURN(D3DFMT_L8); #endif +#ifdef D3DFMT_L16 + IF_GUID_EQUAL_RETURN(D3DFMT_L16); #endif - emergensyStopEventCallback vd_func; - void *vd_userData; - HRESULT enumerateCaptureFormats(IMFMediaSource *pSource); - long setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex); - void buildLibraryofTypes(); - int findType(unsigned int size, unsigned int frameRate = 0); -#ifdef WINRT - HRESULT enumerateCaptureFormats(MAKE_WRL_REF(_MediaCapture) pSource); - long setDeviceFormat(MAKE_WRL_REF(_MediaCapture) pSource, unsigned long dwFormatIndex, MAKE_WRL_REF(_AsyncAction)* pAction); - long resetDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice); -#ifdef HAVE_CONCURRENCY - long checkDevice(_DeviceClass devClass, DEFINE_TASK* pTask, MAKE_WRL_REF(_IDeviceInformation)* ppDevice); +#ifdef D3DFMT_D16 + IF_GUID_EQUAL_RETURN(D3DFMT_D16); #endif -#else - long resetDevice(IMFActivate *pActivate); - long checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice); +#ifdef MFVideoFormat_A2R10G10B10 + IF_GUID_EQUAL_RETURN(MFVideoFormat_A2R10G10B10); #endif - long initDevice(); -}; - -/// Class for managing of list of video devices -class videoDevices -{ -public: - ~videoDevices(void); -#ifdef WINRT - long initDevices(_DeviceClass devClass); - void waitInit() { - if (vds_enumTask) { -#ifdef HAVE_CONCURRENCY - CREATE_TASK DEFINE_RET_TYPE(void)(vds_enumTask).wait(); +#ifdef MFVideoFormat_A16B16G16R16F + IF_GUID_EQUAL_RETURN(MFVideoFormat_A16B16G16R16F); #endif - vds_enumTask = nullptr; - } - } -#else - long initDevices(IMFAttributes *pAttributes); + IF_GUID_EQUAL_RETURN(MFAudioFormat_PCM); // WAVE_FORMAT_PCM + IF_GUID_EQUAL_RETURN(MFAudioFormat_Float); // WAVE_FORMAT_IEEE_FLOAT + IF_GUID_EQUAL_RETURN(MFAudioFormat_DTS); // WAVE_FORMAT_DTS + IF_GUID_EQUAL_RETURN(MFAudioFormat_Dolby_AC3_SPDIF); // WAVE_FORMAT_DOLBY_AC3_SPDIF + IF_GUID_EQUAL_RETURN(MFAudioFormat_DRM); // WAVE_FORMAT_DRM + IF_GUID_EQUAL_RETURN(MFAudioFormat_WMAudioV8); // WAVE_FORMAT_WMAUDIO2 + IF_GUID_EQUAL_RETURN(MFAudioFormat_WMAudioV9); // WAVE_FORMAT_WMAUDIO3 + IF_GUID_EQUAL_RETURN(MFAudioFormat_WMAudio_Lossless); // WAVE_FORMAT_WMAUDIO_LOSSLESS + IF_GUID_EQUAL_RETURN(MFAudioFormat_WMASPDIF); // WAVE_FORMAT_WMASPDIF + IF_GUID_EQUAL_RETURN(MFAudioFormat_MSP1); // WAVE_FORMAT_WMAVOICE9 + IF_GUID_EQUAL_RETURN(MFAudioFormat_MP3); // WAVE_FORMAT_MPEGLAYER3 + IF_GUID_EQUAL_RETURN(MFAudioFormat_MPEG); // WAVE_FORMAT_MPEG + IF_GUID_EQUAL_RETURN(MFAudioFormat_AAC); // WAVE_FORMAT_MPEG_HEAAC + IF_GUID_EQUAL_RETURN(MFAudioFormat_ADTS); // WAVE_FORMAT_MPEG_ADTS_AAC +#ifdef MFAudioFormat_ALAC + IF_GUID_EQUAL_RETURN(MFAudioFormat_ALAC); #endif - static videoDevices& getInstance(); - videoDevice *getDevice(unsigned int i); - unsigned int getCount(); - void clearDevices(); -private: - UINT32 count; -#ifdef WINRT - MAKE_WRL_REF(_AsyncAction) vds_enumTask; +#ifdef MFAudioFormat_AMR_NB + IF_GUID_EQUAL_RETURN(MFAudioFormat_AMR_NB); #endif - std::vector vds_Devices; - videoDevices(void); -}; - -// Class for creating of Media Foundation context -class Media_Foundation -{ -public: - ~Media_Foundation(void) { /*CV_Assert(SUCCEEDED(MFShutdown()));*/ } - static Media_Foundation& getInstance() - { - static Media_Foundation instance; - return instance; - } -private: - Media_Foundation(void) { CV_Assert(SUCCEEDED(MFStartup(MF_VERSION))); } -}; - -/// The only visiable class for controlling of video devices in format singelton -class videoInput -{ -public: - virtual ~videoInput(void); - // Getting of static instance of videoInput class - static videoInput& getInstance(); - // Closing video device with deviceID - void closeDevice(int deviceID); - // Setting callback function for emergency events(for example: removing video device with deviceID) with userData - void setEmergencyStopEvent(int deviceID, void *userData, void(*func)(int, void *)); - // Closing all devices - void closeAllDevices(); - // Getting of parametrs of video device with deviceID - CamParametrs getParametrs(int deviceID); - // Setting of parametrs of video device with deviceID - void setParametrs(int deviceID, CamParametrs parametrs); - // Getting numbers of existence videodevices with listing in consol - unsigned int listDevices(bool silent = false); - // Getting numbers of formats, which are supported by videodevice with deviceID - unsigned int getCountFormats(int deviceID) const; - // Getting width of image, which is getting from videodevice with deviceID - unsigned int getWidth(int deviceID) const; - // Getting height of image, which is getting from videodevice with deviceID - unsigned int getHeight(int deviceID) const; - // Getting frame rate, which is getting from videodevice with deviceID - unsigned int getFrameRate(int deviceID) const; - // Getting name of videodevice with deviceID - const wchar_t *getNameVideoDevice(int deviceID); - // Getting interface MediaSource for Media Foundation from videodevice with deviceID - IMFMediaSource *getMediaSource(int deviceID); - // Getting format with id, which is supported by videodevice with deviceID - MediaType getFormat(int deviceID, int unsigned id); - // Checking of existence of the suitable video devices - bool isDevicesAcceable(); - // Checking of using the videodevice with deviceID - bool isDeviceSetup(int deviceID); - // Checking of using MediaSource from videodevice with deviceID - bool isDeviceMediaSource(int deviceID); - // Checking of using Raw Data of pixels from videodevice with deviceID - bool isDeviceRawDataSource(int deviceID); -#ifdef _DEBUG - // Setting of the state of outprinting info in console - static void setVerbose(bool state); +#ifdef MFAudioFormat_AMR_WB + IF_GUID_EQUAL_RETURN(MFAudioFormat_AMR_WB); #endif - // Initialization of video device with deviceID by media type with id - bool setupDevice(int deviceID, unsigned int id = 0); - // Initialization of video device with deviceID by wisth w, height h and fps idealFramerate - bool setupDevice(int deviceID, unsigned int w, unsigned int h, unsigned int idealFramerate = 30); - // Checking of recivig of new frame from video device with deviceID - bool isFrameNew(int deviceID); -#ifdef WINRT - void waitForDevice(int deviceID); +#ifdef MFAudioFormat_AMR_WP + IF_GUID_EQUAL_RETURN(MFAudioFormat_AMR_WP); +#endif +#ifdef MFAudioFormat_Dolby_AC3 + IF_GUID_EQUAL_RETURN(MFAudioFormat_Dolby_AC3); +#endif +#ifdef MFAudioFormat_Dolby_DDPlus + IF_GUID_EQUAL_RETURN(MFAudioFormat_Dolby_DDPlus); +#endif +#ifdef MFAudioFormat_FLAC + IF_GUID_EQUAL_RETURN(MFAudioFormat_FLAC); +#endif +#ifdef MFAudioFormat_Opus + IF_GUID_EQUAL_RETURN(MFAudioFormat_Opus); +#endif +#ifdef MEDIASUBTYPE_RAW_AAC1 + IF_GUID_EQUAL_RETURN(MEDIASUBTYPE_RAW_AAC1); +#endif +#ifdef MFAudioFormat_Float_SpatialObjects + IF_GUID_EQUAL_RETURN(MFAudioFormat_Float_SpatialObjects); +#endif +#ifdef MFAudioFormat_QCELP + IF_GUID_EQUAL_RETURN(MFAudioFormat_QCELP); #endif - // Writing of Raw Data pixels from video device with deviceID with correction of RedAndBlue flipping flipRedAndBlue and vertical flipping flipImage - bool getPixels(int deviceID, unsigned char * pixels, bool flipRedAndBlue = false, bool flipImage = false); - static void processPixels(unsigned char * src, unsigned char * dst, unsigned int width, unsigned int height, unsigned int bpp, bool bRGB, bool bFlip); -private: - Media_Foundation& MF; - bool accessToDevices; - videoInput(void); - void updateListOfDevices(); -}; -#ifdef _DEBUG -DPO::DPO(void):verbose(true) -{ + return NULL; } -DPO::~DPO(void) +bool LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, MediaType &out) { + PROPVARIANT var; + PropVariantInit(&var); + GUID guid = { 0 }; + if (SUCCEEDED(pAttr->GetItemByIndex(index, &guid, &var))) + { + if (guid == MF_MT_DEFAULT_STRIDE && var.vt == VT_INT) + out.MF_MT_DEFAULT_STRIDE = var.intVal; + else if (guid == MF_MT_FRAME_RATE && var.vt == VT_UI8) + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_FRAME_RATE_NUMERATOR, &out.MF_MT_FRAME_RATE_DENOMINATOR); + else if (guid == MF_MT_FRAME_RATE_RANGE_MAX && var.vt == VT_UI8) + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_FRAME_RATE_RANGE_MAX_NUMERATOR, &out.MF_MT_FRAME_RATE_RANGE_MAX_DENOMINATOR); + else if (guid == MF_MT_FRAME_RATE_RANGE_MIN && var.vt == VT_UI8) + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_FRAME_RATE_RANGE_MIN_NUMERATOR, &out.MF_MT_FRAME_RATE_RANGE_MIN_DENOMINATOR); + else if (guid == MF_MT_PIXEL_ASPECT_RATIO && var.vt == VT_UI8) + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.MF_MT_PIXEL_ASPECT_RATIO_NUMERATOR, &out.MF_MT_PIXEL_ASPECT_RATIO_DENOMINATOR); + else if (guid == MF_MT_YUV_MATRIX && var.vt == VT_UI4) + out.MF_MT_YUV_MATRIX = var.ulVal; + else if (guid == MF_MT_VIDEO_LIGHTING && var.vt == VT_UI4) + out.MF_MT_VIDEO_LIGHTING = var.ulVal; + else if (guid == MF_MT_DEFAULT_STRIDE && var.vt == VT_UI4) + out.MF_MT_DEFAULT_STRIDE = (int)var.ulVal; + else if (guid == MF_MT_VIDEO_CHROMA_SITING && var.vt == VT_UI4) + out.MF_MT_VIDEO_CHROMA_SITING = var.ulVal; + else if (guid == MF_MT_VIDEO_NOMINAL_RANGE && var.vt == VT_UI4) + out.MF_MT_VIDEO_NOMINAL_RANGE = var.ulVal; + else if (guid == MF_MT_ALL_SAMPLES_INDEPENDENT && var.vt == VT_UI4) + out.MF_MT_ALL_SAMPLES_INDEPENDENT = var.ulVal; + else if (guid == MF_MT_FIXED_SIZE_SAMPLES && var.vt == VT_UI4) + out.MF_MT_FIXED_SIZE_SAMPLES = var.ulVal; + else if (guid == MF_MT_SAMPLE_SIZE && var.vt == VT_UI4) + out.MF_MT_SAMPLE_SIZE = var.ulVal; + else if (guid == MF_MT_VIDEO_PRIMARIES && var.vt == VT_UI4) + out.MF_MT_VIDEO_PRIMARIES = var.ulVal; + else if (guid == MF_MT_INTERLACE_MODE && var.vt == VT_UI4) + out.MF_MT_INTERLACE_MODE = var.ulVal; + else if (guid == MF_MT_AM_FORMAT_TYPE && var.vt == VT_CLSID) + out.MF_MT_AM_FORMAT_TYPE = *var.puuid; + else if (guid == MF_MT_MAJOR_TYPE && var.vt == VT_CLSID) + out.pMF_MT_MAJOR_TYPEName = GetGUIDNameConstNew(out.MF_MT_MAJOR_TYPE = *var.puuid); + else if (guid == MF_MT_SUBTYPE && var.vt == VT_CLSID) + out.pMF_MT_SUBTYPEName = GetGUIDNameConstNew(out.MF_MT_SUBTYPE = *var.puuid); + else if (guid == MF_MT_FRAME_SIZE && var.vt == VT_UI8) + { + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &out.width, &out.height); + out.MF_MT_FRAME_SIZE = out.width * out.height; + } + PropVariantClear(&var); + return true; + } + return false; } -DPO& DPO::getInstance() +MediaType::MediaType() { - static DPO instance; - return instance; + pMF_MT_MAJOR_TYPEName = NULL; + pMF_MT_SUBTYPEName = NULL; + Clear(); } -void DPO::printOut(const wchar_t *format, ...) +MediaType::MediaType(IMFMediaType *pType) { - if(verbose) + pMF_MT_MAJOR_TYPEName = NULL; + pMF_MT_SUBTYPEName = NULL; + Clear(); + UINT32 count = 0; + if (SUCCEEDED(pType->GetCount(&count)) && + SUCCEEDED(pType->LockStore())) { - int i = 0; - wchar_t *p = NULL; - va_list args; - va_start(args, format); - if( ::IsDebuggerPresent() ) - { - WCHAR szMsg[512]; - ::StringCchVPrintfW(szMsg, sizeof(szMsg)/sizeof(szMsg[0]), format, args); - ::OutputDebugStringW(szMsg); - } - else - { - if(wcscmp(format, L"%i")) - { - i = va_arg (args, int); - } - if(wcscmp(format, L"%s")) - { - p = va_arg (args, wchar_t *); - } - wprintf(format, i,p); - } - va_end (args); + for (UINT32 i = 0; i < count; i++) + if (!LogAttributeValueByIndexNew(pType, i, *this)) + break; + pType->UnlockStore(); } } -void DPO::setVerbose(bool state) +MediaType::~MediaType() +{ + Clear(); +} + +void MediaType::Clear() { - verbose = state; + MF_MT_FRAME_SIZE = 0; + height = 0; + width = 0; + MF_MT_YUV_MATRIX = 0; + MF_MT_VIDEO_LIGHTING = 0; + MF_MT_DEFAULT_STRIDE = 0; + MF_MT_VIDEO_CHROMA_SITING = 0; + MF_MT_FIXED_SIZE_SAMPLES = 0; + MF_MT_VIDEO_NOMINAL_RANGE = 0; + MF_MT_FRAME_RATE_NUMERATOR = 0; + MF_MT_FRAME_RATE_DENOMINATOR = 0; + MF_MT_PIXEL_ASPECT_RATIO_NUMERATOR = 0; + MF_MT_PIXEL_ASPECT_RATIO_DENOMINATOR = 0; + MF_MT_ALL_SAMPLES_INDEPENDENT = 0; + MF_MT_FRAME_RATE_RANGE_MIN_NUMERATOR = 0; + MF_MT_FRAME_RATE_RANGE_MIN_DENOMINATOR = 0; + MF_MT_SAMPLE_SIZE = 0; + MF_MT_VIDEO_PRIMARIES = 0; + MF_MT_INTERLACE_MODE = 0; + MF_MT_FRAME_RATE_RANGE_MAX_NUMERATOR = 0; + MF_MT_FRAME_RATE_RANGE_MAX_DENOMINATOR = 0; + memset(&MF_MT_MAJOR_TYPE, 0, sizeof(GUID)); + memset(&MF_MT_AM_FORMAT_TYPE, 0, sizeof(GUID)); + memset(&MF_MT_SUBTYPE, 0, sizeof(GUID)); +} + } + +/******* Capturing video from camera or file via Microsoft Media Foundation **********/ +class CvCapture_MSMF : public CvCapture +{ +public: + typedef enum { + MODE_SW = 0, + MODE_HW = 1 + } MSMFCapture_Mode; + CvCapture_MSMF(); + virtual ~CvCapture_MSMF(); + virtual bool open(int index); + virtual bool open(const char* filename); + virtual void close(); + virtual double getProperty(int) const CV_OVERRIDE; + virtual bool setProperty(int, double) CV_OVERRIDE; + virtual bool grabFrame() CV_OVERRIDE; + virtual IplImage* retrieveFrame(int) CV_OVERRIDE; + virtual int getCaptureDomain() CV_OVERRIDE { return CV_CAP_MSMF; } // Return the type of the capture object: CV_CAP_VFW, etc... +protected: + double getFramerate(MediaType MT) const; + bool configureOutput(UINT32 width, UINT32 height, double prefFramerate, UINT32 aspectRatioN, UINT32 aspectRatioD, int outFormat, bool convertToFormat); + bool setTime(double time, bool rough); + bool configureHW(bool enable); + + Media_Foundation& MF; + cv::String filename; + int camid; + MSMFCapture_Mode captureMode; +#ifdef HAVE_DXVA + _ComPtr D3DDev; + _ComPtr D3DMgr; #endif + _ComPtr videoFileSource; + DWORD dwStreamIndex; + MediaType nativeFormat; + MediaType captureFormat; + int outputFormat; + bool convertFormat; + UINT32 aspectN, aspectD; + MFTIME duration; + LONGLONG frameStep; + _ComPtr videoSample; + LONGLONG sampleTime; + IplImage* frame; + bool isOpened; +}; -LPCWSTR GetGUIDNameConstNew(const GUID& guid); -HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz); -HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index); -HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, MediaType &out); +CvCapture_MSMF::CvCapture_MSMF(): + MF(Media_Foundation::getInstance()), + filename(""), + camid(-1), + captureMode(MODE_SW), +#ifdef HAVE_DXVA + D3DDev(NULL), + D3DMgr(NULL), +#endif + videoFileSource(NULL), + videoSample(NULL), + outputFormat(CV_CAP_MODE_BGR), + convertFormat(true), + aspectN(1), + aspectD(1), + sampleTime(0), + frame(NULL), + isOpened(false) +{ +} -unsigned int *GetParametr(GUID guid, MediaType &out) +CvCapture_MSMF::~CvCapture_MSMF() { - if(guid == MF_MT_YUV_MATRIX) - return &(out.MF_MT_YUV_MATRIX); - if(guid == MF_MT_VIDEO_LIGHTING) - return &(out.MF_MT_VIDEO_LIGHTING); - if(guid == MF_MT_DEFAULT_STRIDE) - return (unsigned int*)&(out.MF_MT_DEFAULT_STRIDE); - if(guid == MF_MT_VIDEO_CHROMA_SITING) - return &(out.MF_MT_VIDEO_CHROMA_SITING); - if(guid == MF_MT_VIDEO_NOMINAL_RANGE) - return &(out.MF_MT_VIDEO_NOMINAL_RANGE); - if(guid == MF_MT_ALL_SAMPLES_INDEPENDENT) - return &(out.MF_MT_ALL_SAMPLES_INDEPENDENT); - if(guid == MF_MT_FIXED_SIZE_SAMPLES) - return &(out.MF_MT_FIXED_SIZE_SAMPLES); - if(guid == MF_MT_SAMPLE_SIZE) - return &(out.MF_MT_SAMPLE_SIZE); - if(guid == MF_MT_VIDEO_PRIMARIES) - return &(out.MF_MT_VIDEO_PRIMARIES); - if(guid == MF_MT_INTERLACE_MODE) - return &(out.MF_MT_INTERLACE_MODE); - return NULL; + close(); } -HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, MediaType &out) +void CvCapture_MSMF::close() { - WCHAR *pGuidName = NULL; - WCHAR *pGuidValName = NULL; - GUID guid = { 0 }; - PROPVARIANT var; - PropVariantInit(&var); - HRESULT hr = pAttr->GetItemByIndex(index, &guid, &var); - if (FAILED(hr)) + if (isOpened) { - goto done; - } - hr = GetGUIDNameNew(guid, &pGuidName); - if (FAILED(hr)) - { - goto done; - } - hr = SpecialCaseAttributeValueNew(guid, var, out); - unsigned int *p; - if (FAILED(hr)) - { - goto done; + isOpened = false; + if (videoSample) + videoSample.Reset(); + if (videoFileSource) + videoFileSource.Reset(); + if (frame) + cvReleaseImage(&frame); + camid = -1; + filename = ""; } - if (hr == S_FALSE) - { - switch (var.vt) - { - case VT_UI4: - p = GetParametr(guid, out); - if(p) - { - *p = var.ulVal; - } - break; - case VT_UI8: - break; - case VT_R8: - break; - case VT_CLSID: - if(guid == MF_MT_AM_FORMAT_TYPE) - { - hr = GetGUIDNameNew(*var.puuid, &pGuidValName); - if (SUCCEEDED(hr)) - { - out.MF_MT_AM_FORMAT_TYPE = *var.puuid; - out.pMF_MT_AM_FORMAT_TYPEName = pGuidValName; - pGuidValName = NULL; - } - } - if(guid == MF_MT_MAJOR_TYPE) - { - hr = GetGUIDNameNew(*var.puuid, &pGuidValName); - if (SUCCEEDED(hr)) - { - out.MF_MT_MAJOR_TYPE = *var.puuid; - out.pMF_MT_MAJOR_TYPEName = pGuidValName; - pGuidValName = NULL; - } - } - if(guid == MF_MT_SUBTYPE) +} + +bool CvCapture_MSMF::configureHW(bool enable) +{ +#ifdef HAVE_DXVA + if ((enable && D3DMgr && D3DDev) || (!enable && !D3DMgr && !D3DDev)) + return true; + + bool reopen = isOpened; + int prevcam = camid; + cv::String prevfile = filename; + close(); + if (enable) + { + D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1 }; + if (SUCCEEDED(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_VIDEO_SUPPORT, + levels, sizeof(levels) / sizeof(*levels), D3D11_SDK_VERSION, D3DDev.GetAddressOf(), NULL, NULL))) + { + // NOTE: Getting ready for multi-threaded operation + _ComPtr D3DDevMT; + UINT mgrRToken; + if (SUCCEEDED(D3DDev->QueryInterface(IID_PPV_ARGS(&D3DDevMT)))) { - hr = GetGUIDNameNew(*var.puuid, &pGuidValName); - if (SUCCEEDED(hr)) + D3DDevMT->SetMultithreadProtected(TRUE); + D3DDevMT.Reset(); + if (SUCCEEDED(MFCreateDXGIDeviceManager(&mgrRToken, D3DMgr.GetAddressOf()))) { - out.MF_MT_SUBTYPE = *var.puuid; - out.pMF_MT_SUBTYPEName = pGuidValName; - pGuidValName = NULL; + if (SUCCEEDED(D3DMgr->ResetDevice(D3DDev.Get(), mgrRToken))) + { + captureMode = MODE_HW; + return reopen ? camid >= 0 ? open(prevcam) : open(prevfile.c_str()) : true; + } + D3DMgr.Reset(); } } - break; - case VT_LPWSTR: - break; - case VT_VECTOR | VT_UI1: - break; - case VT_UNKNOWN: - break; - default: - break; + D3DDev.Reset(); } + return false; } -done: - CoTaskMemFree(pGuidName); - CoTaskMemFree(pGuidValName); - PropVariantClear(&var); - return hr; + else + { + if (D3DMgr) + D3DMgr.Reset(); + if (D3DDev) + D3DDev.Reset(); + captureMode = MODE_SW; + return reopen ? camid >= 0 ? open(prevcam) : open(prevfile.c_str()) : true; + } +#else + return !enable; +#endif } -HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz) +bool CvCapture_MSMF::configureOutput(UINT32 width, UINT32 height, double prefFramerate, UINT32 aspectRatioN, UINT32 aspectRatioD, int outFormat, bool convertToFormat) { + if (width != 0 && height != 0 && + width == captureFormat.width && height == captureFormat.height && prefFramerate == getFramerate(nativeFormat) && + aspectRatioN == aspectN && aspectRatioD == aspectD && outFormat == outputFormat && convertToFormat == convertFormat) + return true; + HRESULT hr = S_OK; - WCHAR *pName = NULL; - LPCWSTR pcwsz = GetGUIDNameConstNew(guid); - if (pcwsz) + int dwStreamFallback = -1; + MediaType MTFallback; + int dwStreamBest = -1; + MediaType MTBest; + + DWORD dwMediaTypeTest = 0; + DWORD dwStreamTest = 0; + while (SUCCEEDED(hr)) { - size_t cchLength = 0; - hr = StringCchLengthW(pcwsz, STRSAFE_MAX_CCH, &cchLength); - if (FAILED(hr)) + _ComPtr pType; + hr = videoFileSource->GetNativeMediaType(dwStreamTest, dwMediaTypeTest, &pType); + if (hr == MF_E_NO_MORE_TYPES) { - goto done; - } - pName = (WCHAR*)CoTaskMemAlloc((cchLength + 1) * sizeof(WCHAR)); - if (pName == NULL) - { - hr = E_OUTOFMEMORY; - goto done; + hr = S_OK; + ++dwStreamTest; + dwMediaTypeTest = 0; } - hr = StringCchCopyW(pName, cchLength + 1, pcwsz); - if (FAILED(hr)) + else if (SUCCEEDED(hr)) { - goto done; + MediaType MT(pType.Get()); + if (MT.MF_MT_MAJOR_TYPE == MFMediaType_Video) + { + if (dwStreamFallback < 0 || + ((MT.width * MT.height) > (MTFallback.width * MTFallback.height)) || + (((MT.width * MT.height) == (MTFallback.width * MTFallback.height)) && getFramerate(MT) > getFramerate(MTFallback) && (prefFramerate == 0 || getFramerate(MT) <= prefFramerate))) + { + dwStreamFallback = (int)dwStreamTest; + MTFallback = MT; + } + if (MT.width == width && MT.height == height) + { + if (dwStreamBest < 0 || + (getFramerate(MT) > getFramerate(MTBest) && (prefFramerate == 0 || getFramerate(MT) <= prefFramerate))) + { + dwStreamBest = (int)dwStreamTest; + MTBest = MT; + } + } + } + ++dwMediaTypeTest; } } - else - { - hr = StringFromCLSID(guid, &pName); - } -done: - if (FAILED(hr)) - { - *ppwsz = NULL; - CoTaskMemFree(pName); - } - else + if (dwStreamBest >= 0 || dwStreamFallback >= 0) { - *ppwsz = pName; + // Retrieved stream media type + DWORD tryStream = (DWORD)(dwStreamBest >= 0 ? dwStreamBest : dwStreamFallback); + MediaType tryMT = dwStreamBest >= 0 ? MTBest : MTFallback; + GUID outSubtype = GUID_NULL; + UINT32 outStride = 0; + UINT32 outSize = 0; + if(convertToFormat) + switch (outFormat) + { + case CV_CAP_MODE_BGR: + case CV_CAP_MODE_RGB: + outSubtype = captureMode == MODE_HW ? MFVideoFormat_RGB32 : MFVideoFormat_RGB24; // HW accelerated mode support only RGB32 + outStride = (captureMode == MODE_HW ? 4 : 3) * tryMT.width; + outSize = outStride * tryMT.height; + break; + case CV_CAP_MODE_GRAY: + outSubtype = MFVideoFormat_NV12; + outStride = tryMT.width; + outSize = outStride * tryMT.height * 3 / 2; + break; + case CV_CAP_MODE_YUYV: + outSubtype = MFVideoFormat_YUY2; + outStride = 2 * tryMT.width; + outSize = outStride * tryMT.height; + break; + default: + return false; + } + _ComPtr mediaTypeOut; + if (// Set the output media type. + SUCCEEDED(MFCreateMediaType(&mediaTypeOut)) && + SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)) && + SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_SUBTYPE, convertToFormat ? outSubtype : tryMT.MF_MT_SUBTYPE)) && + SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, convertToFormat ? MFVideoInterlace_Progressive : tryMT.MF_MT_INTERLACE_MODE)) && + SUCCEEDED(MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, aspectRatioN, aspectRatioD)) && + SUCCEEDED(MFSetAttributeSize(mediaTypeOut.Get(), MF_MT_FRAME_SIZE, tryMT.width, tryMT.height)) && + SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, convertToFormat ? 1 : tryMT.MF_MT_FIXED_SIZE_SAMPLES)) && + SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_SAMPLE_SIZE, convertToFormat ? outSize : tryMT.MF_MT_SAMPLE_SIZE)) && + SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_DEFAULT_STRIDE, convertToFormat ? outStride : tryMT.MF_MT_DEFAULT_STRIDE)))//Assume BGR24 input + { + if (SUCCEEDED(videoFileSource->SetStreamSelection((DWORD)MF_SOURCE_READER_ALL_STREAMS, false)) && + SUCCEEDED(videoFileSource->SetStreamSelection(tryStream, true)) && + SUCCEEDED(videoFileSource->SetCurrentMediaType(tryStream, NULL, mediaTypeOut.Get())) + ) + { + dwStreamIndex = tryStream; + nativeFormat = tryMT; + aspectN = aspectRatioN; + aspectD = aspectRatioD; + outputFormat = outFormat; + convertFormat = convertToFormat; + captureFormat = MediaType(mediaTypeOut.Get()); + return true; + } + close(); + } } - return hr; -} - -void LogUINT32AsUINT64New(const PROPVARIANT& var, UINT32 &uHigh, UINT32 &uLow) -{ - Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &uHigh, &uLow); -} - -float OffsetToFloatNew(const MFOffset& offset) -{ - return offset.value + (static_cast(offset.fract) / 65536.0f); + return false; } -HRESULT LogVideoAreaNew(const PROPVARIANT& var) +// Initialize camera input +bool CvCapture_MSMF::open(int _index) { - if (var.caub.cElems < sizeof(MFVideoArea)) - { - return S_OK; - } - return S_OK; -} + close(); -HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, MediaType &out) -{ - if (guid == MF_MT_DEFAULT_STRIDE) - { - out.MF_MT_DEFAULT_STRIDE = var.intVal; - } else - if (guid == MF_MT_FRAME_SIZE) - { - UINT32 uHigh = 0, uLow = 0; - LogUINT32AsUINT64New(var, uHigh, uLow); - out.width = uHigh; - out.height = uLow; - out.MF_MT_FRAME_SIZE = out.width * out.height; - } - else - if (guid == MF_MT_FRAME_RATE) - { - UINT32 uHigh = 0, uLow = 0; - LogUINT32AsUINT64New(var, uHigh, uLow); - out.MF_MT_FRAME_RATE_NUMERATOR = uHigh; - out.MF_MT_FRAME_RATE_DENOMINATOR = uLow; - } - else - if (guid == MF_MT_FRAME_RATE_RANGE_MAX) - { - UINT32 uHigh = 0, uLow = 0; - LogUINT32AsUINT64New(var, uHigh, uLow); - out.MF_MT_FRAME_RATE_RANGE_MAX = uHigh; - out.MF_MT_FRAME_RATE_RANGE_MAX_low = uLow; - } - else - if (guid == MF_MT_FRAME_RATE_RANGE_MIN) - { - UINT32 uHigh = 0, uLow = 0; - LogUINT32AsUINT64New(var, uHigh, uLow); - out.MF_MT_FRAME_RATE_RANGE_MIN = uHigh; - out.MF_MT_FRAME_RATE_RANGE_MIN_low = uLow; - } - else - if (guid == MF_MT_PIXEL_ASPECT_RATIO) - { - UINT32 uHigh = 0, uLow = 0; - LogUINT32AsUINT64New(var, uHigh, uLow); - out.MF_MT_PIXEL_ASPECT_RATIO = uHigh; - out.MF_MT_PIXEL_ASPECT_RATIO_low = uLow; - } - else + _ComPtr msAttr = NULL; + if (SUCCEEDED(MFCreateAttributes(msAttr.GetAddressOf(), 1)) && + SUCCEEDED(msAttr->SetGUID( + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID + ))) { - return S_FALSE; + IMFActivate **ppDevices = NULL; + UINT32 count; + if (SUCCEEDED(MFEnumDeviceSources(msAttr.Get(), &ppDevices, &count))) + { + if (count > 0) + { + _index = std::min(std::max(0, _index), (int)count - 1); + for (int ind = 0; ind < (int)count; ind++) + { + if (ind == _index && ppDevices[ind]) + { + // Set source reader parameters + _ComPtr mSrc; + _ComPtr srAttr; + if (SUCCEEDED(ppDevices[ind]->ActivateObject(__uuidof(IMFMediaSource), (void**)&mSrc)) && mSrc && + SUCCEEDED(MFCreateAttributes(&srAttr, 10)) && + SUCCEEDED(srAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, false)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, false)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true))) + { +#ifdef HAVE_DXVA + if (D3DMgr) + srAttr->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, D3DMgr.Get()); +#endif + if (SUCCEEDED(MFCreateSourceReaderFromMediaSource(mSrc.Get(), srAttr.Get(), &videoFileSource))) + { + isOpened = true; + duration = 0; + if (configureOutput(0, 0, 0, aspectN, aspectD, outputFormat, convertFormat)) + { + double fps = getFramerate(nativeFormat); + frameStep = (LONGLONG)(fps > 0 ? 1e7 / fps : 0); + camid = _index; + } + } + } + } + if (ppDevices[ind]) + ppDevices[ind]->Release(); + } + } + } + CoTaskMemFree(ppDevices); } - return S_OK; -} - -#ifndef IF_EQUAL_RETURN -#define IF_EQUAL_RETURN(param, val) if(val == param) return L#val -#endif -LPCWSTR GetGUIDNameConstNew(const GUID& guid) -{ - IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE); - IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE); - IF_EQUAL_RETURN(guid, MF_MT_SUBTYPE); - IF_EQUAL_RETURN(guid, MF_MT_ALL_SAMPLES_INDEPENDENT); - IF_EQUAL_RETURN(guid, MF_MT_FIXED_SIZE_SAMPLES); - IF_EQUAL_RETURN(guid, MF_MT_COMPRESSED); - IF_EQUAL_RETURN(guid, MF_MT_SAMPLE_SIZE); - IF_EQUAL_RETURN(guid, MF_MT_WRAPPED_TYPE); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_NUM_CHANNELS); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_SECOND); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_AVG_BYTES_PER_SECOND); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BLOCK_ALIGNMENT); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BITS_PER_SAMPLE); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_VALID_BITS_PER_SAMPLE); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_BLOCK); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_CHANNEL_MASK); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FOLDDOWN_MATRIX); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKREF); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKTARGET); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGREF); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGTARGET); - IF_EQUAL_RETURN(guid, MF_MT_AUDIO_PREFER_WAVEFORMATEX); - IF_EQUAL_RETURN(guid, MF_MT_AAC_PAYLOAD_TYPE); - IF_EQUAL_RETURN(guid, MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION); - IF_EQUAL_RETURN(guid, MF_MT_FRAME_SIZE); - IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE); - IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MAX); - IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MIN); - IF_EQUAL_RETURN(guid, MF_MT_PIXEL_ASPECT_RATIO); - IF_EQUAL_RETURN(guid, MF_MT_DRM_FLAGS); - IF_EQUAL_RETURN(guid, MF_MT_PAD_CONTROL_FLAGS); - IF_EQUAL_RETURN(guid, MF_MT_SOURCE_CONTENT_HINT); - IF_EQUAL_RETURN(guid, MF_MT_VIDEO_CHROMA_SITING); - IF_EQUAL_RETURN(guid, MF_MT_INTERLACE_MODE); - IF_EQUAL_RETURN(guid, MF_MT_TRANSFER_FUNCTION); - IF_EQUAL_RETURN(guid, MF_MT_VIDEO_PRIMARIES); - IF_EQUAL_RETURN(guid, MF_MT_CUSTOM_VIDEO_PRIMARIES); - IF_EQUAL_RETURN(guid, MF_MT_YUV_MATRIX); - IF_EQUAL_RETURN(guid, MF_MT_VIDEO_LIGHTING); - IF_EQUAL_RETURN(guid, MF_MT_VIDEO_NOMINAL_RANGE); - IF_EQUAL_RETURN(guid, MF_MT_GEOMETRIC_APERTURE); - IF_EQUAL_RETURN(guid, MF_MT_MINIMUM_DISPLAY_APERTURE); - IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_APERTURE); - IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_ENABLED); - IF_EQUAL_RETURN(guid, MF_MT_AVG_BITRATE); - IF_EQUAL_RETURN(guid, MF_MT_AVG_BIT_ERROR_RATE); - IF_EQUAL_RETURN(guid, MF_MT_MAX_KEYFRAME_SPACING); - IF_EQUAL_RETURN(guid, MF_MT_DEFAULT_STRIDE); - IF_EQUAL_RETURN(guid, MF_MT_PALETTE); - IF_EQUAL_RETURN(guid, MF_MT_USER_DATA); - IF_EQUAL_RETURN(guid, MF_MT_AM_FORMAT_TYPE); - IF_EQUAL_RETURN(guid, MF_MT_MPEG_START_TIME_CODE); - IF_EQUAL_RETURN(guid, MF_MT_MPEG2_PROFILE); - IF_EQUAL_RETURN(guid, MF_MT_MPEG2_LEVEL); - IF_EQUAL_RETURN(guid, MF_MT_MPEG2_FLAGS); - IF_EQUAL_RETURN(guid, MF_MT_MPEG_SEQUENCE_HEADER); - IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_0); - IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_0); - IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_1); - IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_1); - IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_SRC_PACK); - IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_CTRL_PACK); - IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_HEADER); - IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_FORMAT); - IF_EQUAL_RETURN(guid, MF_MT_IMAGE_LOSS_TOLERANT); - IF_EQUAL_RETURN(guid, MF_MT_MPEG4_SAMPLE_DESCRIPTION); - IF_EQUAL_RETURN(guid, MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY); - IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_4CC); - IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_WAVE_FORMAT_TAG); - // Media types - IF_EQUAL_RETURN(guid, MFMediaType_Audio); - IF_EQUAL_RETURN(guid, MFMediaType_Video); - IF_EQUAL_RETURN(guid, MFMediaType_Protected); - IF_EQUAL_RETURN(guid, MFMediaType_SAMI); - IF_EQUAL_RETURN(guid, MFMediaType_Script); - IF_EQUAL_RETURN(guid, MFMediaType_Image); - IF_EQUAL_RETURN(guid, MFMediaType_HTML); - IF_EQUAL_RETURN(guid, MFMediaType_Binary); - IF_EQUAL_RETURN(guid, MFMediaType_FileTransfer); - IF_EQUAL_RETURN(guid, MFVideoFormat_AI44); // FCC('AI44') - IF_EQUAL_RETURN(guid, MFVideoFormat_ARGB32); // D3DFMT_A8R8G8B8 - IF_EQUAL_RETURN(guid, MFVideoFormat_AYUV); // FCC('AYUV') - IF_EQUAL_RETURN(guid, MFVideoFormat_DV25); // FCC('dv25') - IF_EQUAL_RETURN(guid, MFVideoFormat_DV50); // FCC('dv50') - IF_EQUAL_RETURN(guid, MFVideoFormat_DVH1); // FCC('dvh1') - IF_EQUAL_RETURN(guid, MFVideoFormat_DVSD); // FCC('dvsd') - IF_EQUAL_RETURN(guid, MFVideoFormat_DVSL); // FCC('dvsl') - IF_EQUAL_RETURN(guid, MFVideoFormat_H264); // FCC('H264') - IF_EQUAL_RETURN(guid, MFVideoFormat_I420); // FCC('I420') - IF_EQUAL_RETURN(guid, MFVideoFormat_IYUV); // FCC('IYUV') - IF_EQUAL_RETURN(guid, MFVideoFormat_M4S2); // FCC('M4S2') - IF_EQUAL_RETURN(guid, MFVideoFormat_MJPG); - IF_EQUAL_RETURN(guid, MFVideoFormat_MP43); // FCC('MP43') - IF_EQUAL_RETURN(guid, MFVideoFormat_MP4S); // FCC('MP4S') - IF_EQUAL_RETURN(guid, MFVideoFormat_MP4V); // FCC('MP4V') - IF_EQUAL_RETURN(guid, MFVideoFormat_MPG1); // FCC('MPG1') - IF_EQUAL_RETURN(guid, MFVideoFormat_MSS1); // FCC('MSS1') - IF_EQUAL_RETURN(guid, MFVideoFormat_MSS2); // FCC('MSS2') - IF_EQUAL_RETURN(guid, MFVideoFormat_NV11); // FCC('NV11') - IF_EQUAL_RETURN(guid, MFVideoFormat_NV12); // FCC('NV12') - IF_EQUAL_RETURN(guid, MFVideoFormat_P010); // FCC('P010') - IF_EQUAL_RETURN(guid, MFVideoFormat_P016); // FCC('P016') - IF_EQUAL_RETURN(guid, MFVideoFormat_P210); // FCC('P210') - IF_EQUAL_RETURN(guid, MFVideoFormat_P216); // FCC('P216') - IF_EQUAL_RETURN(guid, MFVideoFormat_RGB24); // D3DFMT_R8G8B8 - IF_EQUAL_RETURN(guid, MFVideoFormat_RGB32); // D3DFMT_X8R8G8B8 - IF_EQUAL_RETURN(guid, MFVideoFormat_RGB555); // D3DFMT_X1R5G5B5 - IF_EQUAL_RETURN(guid, MFVideoFormat_RGB565); // D3DFMT_R5G6B5 - IF_EQUAL_RETURN(guid, MFVideoFormat_RGB8); - IF_EQUAL_RETURN(guid, MFVideoFormat_UYVY); // FCC('UYVY') - IF_EQUAL_RETURN(guid, MFVideoFormat_v210); // FCC('v210') - IF_EQUAL_RETURN(guid, MFVideoFormat_v410); // FCC('v410') - IF_EQUAL_RETURN(guid, MFVideoFormat_WMV1); // FCC('WMV1') - IF_EQUAL_RETURN(guid, MFVideoFormat_WMV2); // FCC('WMV2') - IF_EQUAL_RETURN(guid, MFVideoFormat_WMV3); // FCC('WMV3') - IF_EQUAL_RETURN(guid, MFVideoFormat_WVC1); // FCC('WVC1') - IF_EQUAL_RETURN(guid, MFVideoFormat_Y210); // FCC('Y210') - IF_EQUAL_RETURN(guid, MFVideoFormat_Y216); // FCC('Y216') - IF_EQUAL_RETURN(guid, MFVideoFormat_Y410); // FCC('Y410') - IF_EQUAL_RETURN(guid, MFVideoFormat_Y416); // FCC('Y416') - IF_EQUAL_RETURN(guid, MFVideoFormat_Y41P); - IF_EQUAL_RETURN(guid, MFVideoFormat_Y41T); - IF_EQUAL_RETURN(guid, MFVideoFormat_YUY2); // FCC('YUY2') - IF_EQUAL_RETURN(guid, MFVideoFormat_YV12); // FCC('YV12') - IF_EQUAL_RETURN(guid, MFVideoFormat_YVYU); - IF_EQUAL_RETURN(guid, MFAudioFormat_PCM); // WAVE_FORMAT_PCM - IF_EQUAL_RETURN(guid, MFAudioFormat_Float); // WAVE_FORMAT_IEEE_FLOAT - IF_EQUAL_RETURN(guid, MFAudioFormat_DTS); // WAVE_FORMAT_DTS - IF_EQUAL_RETURN(guid, MFAudioFormat_Dolby_AC3_SPDIF); // WAVE_FORMAT_DOLBY_AC3_SPDIF - IF_EQUAL_RETURN(guid, MFAudioFormat_DRM); // WAVE_FORMAT_DRM - IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV8); // WAVE_FORMAT_WMAUDIO2 - IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV9); // WAVE_FORMAT_WMAUDIO3 - IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudio_Lossless); // WAVE_FORMAT_WMAUDIO_LOSSLESS - IF_EQUAL_RETURN(guid, MFAudioFormat_WMASPDIF); // WAVE_FORMAT_WMASPDIF - IF_EQUAL_RETURN(guid, MFAudioFormat_MSP1); // WAVE_FORMAT_WMAVOICE9 - IF_EQUAL_RETURN(guid, MFAudioFormat_MP3); // WAVE_FORMAT_MPEGLAYER3 - IF_EQUAL_RETURN(guid, MFAudioFormat_MPEG); // WAVE_FORMAT_MPEG - IF_EQUAL_RETURN(guid, MFAudioFormat_AAC); // WAVE_FORMAT_MPEG_HEAAC - IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS); // WAVE_FORMAT_MPEG_ADTS_AAC - return NULL; + return isOpened; } -FormatReader::FormatReader(void) +bool CvCapture_MSMF::open(const char* _filename) { -} + close(); + if (!_filename) + return false; -MediaType FormatReader::Read(IMFMediaType *pType) -{ - UINT32 count = 0; - MediaType out; - HRESULT hr = pType->LockStore(); - if (FAILED(hr)) - { - return out; - } - hr = pType->GetCount(&count); - if (FAILED(hr)) - { - return out; - } - for (UINT32 i = 0; i < count; i++) + // Set source reader parameters + _ComPtr srAttr; + if (SUCCEEDED(MFCreateAttributes(&srAttr, 10)) && + SUCCEEDED(srAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, false)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, false)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true)) + ) { - hr = LogAttributeValueByIndexNew(pType, i, out); - if (FAILED(hr)) +#ifdef HAVE_DXVA + if(D3DMgr) + srAttr->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, D3DMgr.Get()); +#endif + cv::AutoBuffer unicodeFileName(strlen(_filename) + 1); + MultiByteToWideChar(CP_ACP, 0, _filename, -1, unicodeFileName, (int)strlen(_filename) + 1); + if (SUCCEEDED(MFCreateSourceReaderFromURL(unicodeFileName, srAttr.Get(), &videoFileSource))) { - break; + isOpened = true; + sampleTime = 0; + if (configureOutput(0, 0, 0, aspectN, aspectD, outputFormat, convertFormat)) + { + double fps = getFramerate(nativeFormat); + frameStep = (LONGLONG)(fps > 0 ? 1e7 / fps : 0); + filename = _filename; + PROPVARIANT var; + HRESULT hr; + if (SUCCEEDED(hr = videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var)) && + var.vt == VT_UI8) + { + duration = var.uhVal.QuadPart; + PropVariantClear(&var); + } + else + duration = 0; + } } } - hr = pType->UnlockStore(); - if (FAILED(hr)) - { - return out; - } - return out; -} -FormatReader::~FormatReader(void) -{ + return isOpened; } -#define CHECK_HR(x) if (FAILED(x)) { goto done; } - -ImageGrabberCallback::ImageGrabberCallback(bool synchronous): - m_cRef(1), - ig_RIE(true), - ig_Close(false), - ig_Synchronous(synchronous), - ig_hFrameReady(synchronous ? CreateEvent(NULL, FALSE, FALSE, NULL): 0), - ig_hFrameGrabbed(synchronous ? CreateEvent(NULL, FALSE, FALSE, NULL): 0), - ig_hFinish(CreateEvent(NULL, TRUE, FALSE, NULL)) -{} - -ImageGrabber::ImageGrabber(unsigned int deviceID, bool synchronous): - ImageGrabberCallback(synchronous), - ig_DeviceID(deviceID), - ig_pSource(NULL), - ig_pSession(NULL), - ig_pTopology(NULL) -{} - -ImageGrabber::~ImageGrabber(void) +bool CvCapture_MSMF::grabFrame() { - if (ig_pSession) + if (isOpened) { - ig_pSession->Shutdown(); - } + DWORD streamIndex, flags; + if (videoSample) + videoSample.Reset(); + HRESULT hr; + while(SUCCEEDED(hr = videoFileSource->ReadSample( + dwStreamIndex, // Stream index. + 0, // Flags. + &streamIndex, // Receives the actual stream index. + &flags, // Receives status flags. + &sampleTime, // Receives the time stamp. + &videoSample // Receives the sample or NULL. + )) && + streamIndex == dwStreamIndex && !(flags & (MF_SOURCE_READERF_ERROR|MF_SOURCE_READERF_ALLEFFECTSREMOVED|MF_SOURCE_READERF_ENDOFSTREAM)) && + !videoSample + ) + { + if (flags & MF_SOURCE_READERF_STREAMTICK) + { + DebugPrintOut(L"\tStream tick detected. Retrying to grab the frame\n"); + } + } - CloseHandle(ig_hFinish); + if (SUCCEEDED(hr)) + { + if (streamIndex != dwStreamIndex) + { + DebugPrintOut(L"\tWrong stream readed. Abort capturing\n"); + close(); + } + else if (flags & MF_SOURCE_READERF_ERROR) + { + DebugPrintOut(L"\tStream reading error. Abort capturing\n"); + close(); + } + else if (flags & MF_SOURCE_READERF_ALLEFFECTSREMOVED) + { + DebugPrintOut(L"\tStream decoding error. Abort capturing\n"); + close(); + } + else if (flags & MF_SOURCE_READERF_ENDOFSTREAM) + { + sampleTime += frameStep; + DebugPrintOut(L"\tEnd of stream detected\n"); + } + else + { + sampleTime += frameStep; + if (flags & MF_SOURCE_READERF_NEWSTREAM) + { + DebugPrintOut(L"\tNew stream detected\n"); + } + if (flags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED) + { + DebugPrintOut(L"\tStream native media type changed\n"); + } + if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) + { + DebugPrintOut(L"\tStream current media type changed\n"); + } + return true; + } + } + } + return false; +} - if (ig_Synchronous) +IplImage* CvCapture_MSMF::retrieveFrame(int) +{ + DWORD bcnt; + if (videoSample && SUCCEEDED(videoSample->GetBufferCount(&bcnt)) && bcnt > 0) { - CloseHandle(ig_hFrameReady); - CloseHandle(ig_hFrameGrabbed); + _ComPtr buf = NULL; + if (SUCCEEDED(videoSample->GetBufferByIndex(0, &buf))) + { + DWORD maxsize, cursize; + BYTE* ptr = NULL; + if (SUCCEEDED(buf->Lock(&ptr, &maxsize, &cursize))) + { + if (convertFormat) + { + if ((unsigned int)cursize == captureFormat.MF_MT_SAMPLE_SIZE) + { + if (!frame || (int)captureFormat.width != frame->width || (int)captureFormat.height != frame->height) + { + cvReleaseImage(&frame); + unsigned int bytes = outputFormat == CV_CAP_MODE_GRAY || !convertFormat ? 1 : outputFormat == CV_CAP_MODE_YUYV ? 2 : 3; + frame = cvCreateImage(cvSize(captureFormat.width, captureFormat.height), 8, bytes); + } + switch (outputFormat) + { + case CV_CAP_MODE_YUYV: + memcpy(frame->imageData, ptr, cursize); + break; + case CV_CAP_MODE_BGR: + if (captureMode == MODE_HW) + cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC4, ptr), cv::cvarrToMat(frame), cv::COLOR_BGRA2BGR); + else + memcpy(frame->imageData, ptr, cursize); + break; + case CV_CAP_MODE_RGB: + if (captureMode == MODE_HW) + cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC4, ptr), cv::cvarrToMat(frame), cv::COLOR_BGRA2BGR); + else + cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC3, ptr), cv::cvarrToMat(frame), cv::COLOR_BGR2RGB); + break; + case CV_CAP_MODE_GRAY: + memcpy(frame->imageData, ptr, captureFormat.height*captureFormat.width); + break; + default: + cvReleaseImage(&frame); + break; + } + } + else + cvReleaseImage(&frame); + } + else + { + if (!frame || frame->width != (int)cursize || frame->height != 1) + { + cvReleaseImage(&frame); + frame = cvCreateImage(cvSize(cursize, 1), 8, 1); + } + memcpy(frame->imageData, ptr, cursize); + } + buf->Unlock(); + return frame; + } + } } - SafeRelease(&ig_pSession); - SafeRelease(&ig_pTopology); - - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Destroying instance of the ImageGrabber class\n", ig_DeviceID); + return NULL; } -#ifdef WINRT - -ImageGrabberWinRT::ImageGrabberWinRT(bool synchronous): - ImageGrabberCallback(synchronous), - ig_pMediaSink(NULL) +double CvCapture_MSMF::getFramerate(MediaType MT) const { - ig_pMedCapSource = nullptr; + if (MT.MF_MT_SUBTYPE == MFVideoFormat_MP43) //Unable to estimate FPS for MP43 + return 0; + return MT.MF_MT_FRAME_RATE_DENOMINATOR != 0 ? ((double)MT.MF_MT_FRAME_RATE_NUMERATOR) / ((double)MT.MF_MT_FRAME_RATE_DENOMINATOR) : 0; } -ImageGrabberWinRT::~ImageGrabberWinRT(void) +bool CvCapture_MSMF::setTime(double time, bool rough) { - //stop must already be performed and complete by object owner - if (ig_pMediaSink != NULL) { - ((IMFMediaSink*)ig_pMediaSink)->Shutdown(); - } - SafeRelease(&ig_pMediaSink); - RELEASE_AGILE_WRL(ig_pMedCapSource) - - CloseHandle(ig_hFinish); - - if (ig_Synchronous) + PROPVARIANT var; + if (SUCCEEDED(videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS, &var)) && + var.vt == VT_UI4 && var.ulVal & MFMEDIASOURCE_CAN_SEEK) { - CloseHandle(ig_hFrameReady); - CloseHandle(ig_hFrameGrabbed); + if (videoSample) + videoSample.Reset(); + bool useGrabbing = time > 0 && !rough && !(var.ulVal & MFMEDIASOURCE_HAS_SLOW_SEEK); + PropVariantClear(&var); + sampleTime = (useGrabbing && time >= frameStep) ? (LONGLONG)floor(time + 0.5) - frameStep : (LONGLONG)floor(time + 0.5); + var.vt = VT_I8; + var.hVal.QuadPart = sampleTime; + bool resOK = SUCCEEDED(videoFileSource->SetCurrentPosition(GUID_NULL, var)); + PropVariantClear(&var); + if (resOK && useGrabbing) + { + LONGLONG timeborder = (LONGLONG)floor(time + 0.5) - frameStep / 2; + do { resOK = grabFrame(); videoSample.Reset(); } while (resOK && sampleTime < timeborder); + } + return resOK; } - - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE: Destroying instance of the ImageGrabberWinRT class\n"); + return false; } -HRESULT ImageGrabberWinRT::initImageGrabber(MAKE_WRL_REF(_MediaCapture) pSource, - GUID VideoFormat) +double CvCapture_MSMF::getProperty( int property_id ) const { - HRESULT hr; - MAKE_WRL_OBJ(_VideoDeviceController) pDevCont; - WRL_PROP_GET(pSource, VideoDeviceController, pDevCont, hr) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps; - WRL_METHOD(pMedDevCont, GetMediaStreamProperties, pMedEncProps, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview)) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_VideoEncodingProperties, pVidProps, pMedEncProps, hr); - if (FAILED(hr)) return hr; - _ComPtr pType = NULL; - hr = MediaSink::ConvertPropertiesToMediaType(DEREF_AS_NATIVE_WRL_OBJ(ABI::Windows::Media::MediaProperties::IMediaEncodingProperties, pMedEncProps), &pType); - if (FAILED(hr)) return hr; - MediaType MT = FormatReader::Read(pType.Get()); - unsigned int sizeRawImage = 0; - if(VideoFormat == MFVideoFormat_RGB24) - { - sizeRawImage = MT.MF_MT_FRAME_SIZE * 3; - } - else if(VideoFormat == MFVideoFormat_RGB32) - { - sizeRawImage = MT.MF_MT_FRAME_SIZE * 4; - } - sizeRawImage = MT.MF_MT_SAMPLE_SIZE; - CHECK_HR(hr = RawImage::CreateInstance(&ig_RIFirst, sizeRawImage)); - CHECK_HR(hr = RawImage::CreateInstance(&ig_RISecond, sizeRawImage)); - ig_RIOut = ig_RISecond; - ig_pMedCapSource = pSource; -done: - return hr; -} - -HRESULT ImageGrabberWinRT::stopGrabbing(MAKE_WRL_REF(_AsyncAction)* action) -{ - HRESULT hr = S_OK; - if (ig_pMedCapSource != nullptr) { - GET_WRL_OBJ_FROM_REF(_MediaCaptureVideoPreview, imedPrevCap, DEREF_AGILE_WRL_OBJ(ig_pMedCapSource), hr) - if (FAILED(hr)) return hr; - MAKE_WRL_REF(_AsyncAction) pAction; - WRL_METHOD_BASE(imedPrevCap, StopPreviewAsync, pAction, hr) - if (SUCCEEDED(hr)) { -#ifdef HAVE_CONCURRENCY - DEFINE_TASK _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction); - *action = reinterpret_cast(BEGIN_CREATE_ASYNC(void, _task, this) - HRESULT hr = S_OK; - _task.wait(); - SafeRelease(&ig_pMediaSink); - SetEvent(ig_hFinish); - END_CREATE_ASYNC(hr)); -#else - *action = nullptr; -#endif - } - } - return hr; -} - -HRESULT ImageGrabberWinRT::startGrabbing(MAKE_WRL_REF(_AsyncAction)* action) -{ - HRESULT hr = S_OK; - GET_WRL_OBJ_FROM_REF(_MediaCaptureVideoPreview, imedPrevCap, DEREF_AGILE_WRL_OBJ(ig_pMedCapSource), hr) - if (FAILED(hr)) return hr; - ACTIVATE_OBJ(RuntimeClass_Windows_Foundation_Collections_PropertySet, _PropertySet, pSet, hr) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_Map, spSetting, pSet, hr) - if (FAILED(hr)) return hr; - ACTIVATE_STATIC_OBJ(RuntimeClass_Windows_Foundation_PropertyValue, MAKE_WRL_OBJ(_PropertyValueStatics), spPropVal, hr) - if (FAILED(hr)) return hr; - _ObjectObj pVal; - boolean bReplaced; - WRL_METHOD(spPropVal, CreateUInt32, pVal, hr, (unsigned int)WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview)) - if (FAILED(hr)) return hr; - WRL_METHOD(spSetting, Insert, bReplaced, hr, DEREF_WRL_OBJ(_StringReference(MF_PROP_VIDTYPE)), DEREF_WRL_OBJ(pVal)) - if (FAILED(hr)) return hr; - WRL_METHOD(spSetting, Insert, bReplaced, hr, DEREF_WRL_OBJ(_StringReference(MF_PROP_SAMPLEGRABBERCALLBACK)), reinterpret_cast<_Object>(this)) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_VideoDeviceController) pDevCont; - WRL_PROP_GET(ig_pMedCapSource, VideoDeviceController, pDevCont, hr) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps; - WRL_METHOD(pMedDevCont, GetMediaStreamProperties, pMedEncProps, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview)) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_VideoEncodingProperties, pVidProps, pMedEncProps, hr); - if (FAILED(hr)) return hr; - ACTIVATE_OBJ(RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile, _MediaEncodingProfile, pEncProps, hr) - if (FAILED(hr)) return hr; - WRL_PROP_PUT(pEncProps, Video, DEREF_WRL_OBJ(pVidProps), hr) - if (FAILED(hr)) return hr; - WRL_METHOD(spSetting, Insert, bReplaced, hr, DEREF_WRL_OBJ(_StringReference(MF_PROP_VIDENCPROPS)), DEREF_WRL_OBJ(pVidProps)) - if (SUCCEEDED(hr)) { - //can start/stop multiple times with same MediaCapture object if using activatable class - WRL_METHOD(imedPrevCap, _StartPreviewToCustomSinkIdAsync, *action, hr, DEREF_WRL_OBJ(pEncProps), DEREF_WRL_OBJ(_StringReference(RuntimeClass_CV_MediaSink)), DEREF_WRL_OBJ(pSet)) - if (FAILED(hr) && hr == REGDB_E_CLASSNOTREG) { - hr = Microsoft::WRL::Make().CopyTo(&ig_pMediaSink); - if (FAILED(hr)) return hr; - hr = ((ABI::Windows::Media::IMediaExtension*)ig_pMediaSink)->SetProperties(DEREF_AS_NATIVE_WRL_OBJ(ABI::Windows::Foundation::Collections::IPropertySet, pSet)); - if (FAILED(hr)) return hr; - WRL_METHOD(imedPrevCap, StartPreviewToCustomSinkAsync, *action, hr, DEREF_WRL_OBJ(pEncProps), reinterpret_cast(ig_pMediaSink)) - } - } - return hr; -} - -HRESULT ImageGrabberWinRT::CreateInstance(ImageGrabberWinRT **ppIG, bool synchronous) -{ - *ppIG = Microsoft::WRL::Make(synchronous).Detach(); - if (ppIG == NULL) - { - return E_OUTOFMEMORY; - } - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE: Creating instance of ImageGrabberWinRT\n"); - return S_OK; -} -#endif - -HRESULT ImageGrabber::initImageGrabber(IMFMediaSource *pSource) -{ - // Clean up. - if (ig_pSession) - { - ig_pSession->Shutdown(); - } - SafeRelease(&ig_pSession); - SafeRelease(&ig_pTopology); - - HRESULT hr; - ig_pSource = pSource; - // Configure the media type that the Sample Grabber will receive. - // Setting the major and subtype is usually enough for the topology loader - // to resolve the topology. - _ComPtr pType = NULL; - _ComPtr pSinkActivate = NULL; - CHECK_HR(hr = MFCreateMediaType(pType.GetAddressOf())); - CHECK_HR(hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)); - CHECK_HR(hr = pType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24)); - // Create the sample grabber sink. - CHECK_HR(hr = MFCreateSampleGrabberSinkActivate(pType.Get(), this, pSinkActivate.GetAddressOf())); - // To run as fast as possible, set this attribute (requires Windows 7): - CHECK_HR(hr = pSinkActivate->SetUINT32(MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, TRUE)); - // Create the Media Session. - CHECK_HR(hr = MFCreateMediaSession(NULL, &ig_pSession)); - // Create the topology. - CHECK_HR(hr = CreateTopology(pSource, pSinkActivate.Get(), &ig_pTopology)); - - CHECK_HR(hr = RawImage::CreateInstance(&ig_RIFirst, captureFormat.MF_MT_FRAME_SIZE * 3)); // Expect that output image will be RGB24 thus occupy 3 byte per point - CHECK_HR(hr = RawImage::CreateInstance(&ig_RISecond, captureFormat.MF_MT_FRAME_SIZE * 3)); - ig_RIOut = ig_RISecond; -done: - // Clean up. - if (FAILED(hr)) - { - if (ig_pSession) - { - ig_pSession->Shutdown(); - } - SafeRelease(&ig_pSession); - SafeRelease(&ig_pTopology); - } - return hr; -} - -void ImageGrabber::stopGrabbing() -{ - if(ig_pSession) - ig_pSession->Stop(); - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Stopping of of grabbing of images\n", ig_DeviceID); -} - -HRESULT ImageGrabber::startGrabbing(void) -{ - PROPVARIANT var; - PropVariantInit(&var); - HRESULT hr = ig_pSession->SetTopology(0, ig_pTopology); - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Start Grabbing of the images\n", ig_DeviceID); - hr = ig_pSession->Start(&GUID_NULL, &var); - for(;;) - { - _ComPtr pEvent = NULL; - HRESULT hrStatus = S_OK; - MediaEventType met; - if(!ig_pSession) break; - hr = ig_pSession->GetEvent(0, &pEvent); - if(!SUCCEEDED(hr)) - { - hr = S_OK; - goto done; - } - hr = pEvent->GetStatus(&hrStatus); - if(!SUCCEEDED(hr)) - { - hr = S_OK; - goto done; - } - hr = pEvent->GetType(&met); - if(!SUCCEEDED(hr)) - { - hr = S_OK; - goto done; - } - if (!SUCCEEDED(hrStatus)) - { - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Event Status Error: %u\n", ig_DeviceID, hrStatus); - goto done; - } - if (met == MESessionEnded) - { - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionEnded\n", ig_DeviceID); - ig_pSession->Stop(); - break; - } - if (met == MESessionStopped) - { - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MESessionStopped \n", ig_DeviceID); - break; - } -#if (WINVER >= 0x0602) // Available since Win 8 - if (met == MEVideoCaptureDeviceRemoved) - { - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MEVideoCaptureDeviceRemoved \n", ig_DeviceID); - break; - } -#endif - if ((met == MEError) || (met == MENonFatalError)) - { - pEvent->GetStatus(&hrStatus); - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: MEError | MENonFatalError: %u\n", ig_DeviceID, hrStatus); - break; - } - } - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Finish startGrabbing \n", ig_DeviceID); - -done: - SetEvent(ig_hFinish); - - return hr; -} - -void ImageGrabberCallback::pauseGrabbing() -{ -} - -void ImageGrabberCallback::resumeGrabbing() -{ -} - -HRESULT ImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo) -{ - HRESULT hr = S_OK; - { // "done:" scope - _ComPtr pPD = NULL; - hr = !pSource ? E_POINTER : S_OK; CHECK_HR(hr); - CHECK_HR(hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf())); - - DWORD cStreams = 0; - CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams)); - DWORD vStream = cStreams; - BOOL vStreamSelected = FALSE; - for (DWORD i = 0; i < cStreams; i++) - { - BOOL fSelected = FALSE; - _ComPtr pSD = NULL; - CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(i, &fSelected, pSD.GetAddressOf())); - - _ComPtr pHandler = NULL; - CHECK_HR(hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf())); - - GUID majorType; - CHECK_HR(hr = pHandler->GetMajorType(&majorType)); - - if (majorType == MFMediaType_Video && !vStreamSelected) - { - if (fSelected) - { - vStream = i; - vStreamSelected = TRUE; - } - else - vStream = i < vStream ? i : vStream; - } - else - { - CHECK_HR(hr = pPD->DeselectStream(i)); - } - } - - if (vStream < cStreams) - { - if (!vStreamSelected) - CHECK_HR(hr = pPD->SelectStream(vStream)); - BOOL fSelected; - _ComPtr pSD = NULL; - CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(vStream, &fSelected, pSD.GetAddressOf())); - - _ComPtr pHandler = NULL; - CHECK_HR(hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf())); - - DWORD cTypes = 0; - CHECK_HR(hr = pHandler->GetMediaTypeCount(&cTypes)); - DWORD j = 0; - for (; j < cTypes; j++) // Iterate throug available video subtypes to find supported and fill MediaType structure - { - _ComPtr pType = NULL; - CHECK_HR(hr = pHandler->GetMediaTypeByIndex(j, pType.GetAddressOf())); - MediaType MT = FormatReader::Read(pType.Get()); - if (MT.MF_MT_MAJOR_TYPE == MFMediaType_Video /*&& MT.MF_MT_SUBTYPE == MFVideoFormat_RGB24*/) - { - captureFormat = MT; - break; - } - } - - if (j < cTypes) // If there is supported video subtype create topology - { - IMFTopology* pTopology = NULL; - _ComPtr pNode1 = NULL; - _ComPtr pNode2 = NULL; - - _ComPtr pNode1c1 = NULL; - _ComPtr pNode1c2 = NULL; - - CHECK_HR(hr = MFCreateTopology(&pTopology)); - CHECK_HR(hr = AddSourceNode(pTopology, pSource, pPD.Get(), pSD.Get(), pNode1.GetAddressOf())); - CHECK_HR(hr = AddOutputNode(pTopology, pSinkActivate, 0, pNode2.GetAddressOf())); - CHECK_HR(hr = pNode1->ConnectOutput(0, pNode2.Get(), 0)); - *ppTopo = pTopology; - (*ppTopo)->AddRef(); - } - else - hr = E_INVALIDARG; - } - else - hr = E_INVALIDARG; - - } // "done:" scope -done: - return hr; -} - -HRESULT ImageGrabber::AddSourceNode( - IMFTopology *pTopology, // Topology. - IMFMediaSource *pSource, // Media source. - IMFPresentationDescriptor *pPD, // Presentation descriptor. - IMFStreamDescriptor *pSD, // Stream descriptor. - IMFTopologyNode **ppNode) // Receives the node pointer. -{ - _ComPtr pNode = NULL; - HRESULT hr = S_OK; - CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, pNode.GetAddressOf())); - CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource)); - CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD)); - CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD)); - CHECK_HR(hr = pTopology->AddNode(pNode.Get())); - // Return the pointer to the caller. - *ppNode = pNode.Get(); - (*ppNode)->AddRef(); - -done: - return hr; -} - -HRESULT ImageGrabber::AddOutputNode( - IMFTopology *pTopology, // Topology. - IMFActivate *pActivate, // Media sink activation object. - DWORD dwId, // Identifier of the stream sink. - IMFTopologyNode **ppNode) // Receives the node pointer. -{ - _ComPtr pNode = NULL; - HRESULT hr = S_OK; - CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, pNode.GetAddressOf())); - CHECK_HR(hr = pNode->SetObject(pActivate)); - CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId)); - CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE)); - CHECK_HR(hr = pTopology->AddNode(pNode.Get())); - // Return the pointer to the caller. - *ppNode = pNode.Get(); - (*ppNode)->AddRef(); - -done: - return hr; -} - -HRESULT ImageGrabber::CreateInstance(ImageGrabber **ppIG, unsigned int deviceID, bool synchronious) -{ - *ppIG = new (std::nothrow) ImageGrabber(deviceID, synchronious); - if (ppIG == NULL) - { - return E_OUTOFMEMORY; - } - DebugPrintOut(L"IMAGEGRABBER VIDEODEVICE %i: Creating instance of ImageGrabber\n", deviceID); - return S_OK; -} - -STDMETHODIMP ImageGrabber::QueryInterface(REFIID riid, void** ppv) -{ - HRESULT hr = E_NOINTERFACE; - *ppv = NULL; - if(riid == IID_IUnknown || riid == IID_IMFSampleGrabberSinkCallback) - { - *ppv = static_cast(this); - hr = S_OK; - } - if(riid == IID_IMFClockStateSink) - { - *ppv = static_cast(this); - hr = S_OK; - } - if(SUCCEEDED(hr)) - { - reinterpret_cast(*ppv)->AddRef(); - } - return hr; -} - -STDMETHODIMP_(ULONG) ImageGrabber::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - -STDMETHODIMP_(ULONG) ImageGrabber::Release() -{ - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) - { - delete this; - } - return cRef; -} - -STDMETHODIMP ImageGrabberCallback::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) -{ - (void)hnsSystemTime; - (void)llClockStartOffset; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnClockStop(MFTIME hnsSystemTime) -{ - (void)hnsSystemTime; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnClockPause(MFTIME hnsSystemTime) -{ - (void)hnsSystemTime; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnClockRestart(MFTIME hnsSystemTime) -{ - (void)hnsSystemTime; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnClockSetRate(MFTIME hnsSystemTime, float flRate) -{ - (void)flRate; - (void)hnsSystemTime; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnSetPresentationClock(IMFPresentationClock* pClock) -{ - (void)pClock; - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags, - LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer, - DWORD dwSampleSize) -{ - (void)guidMajorMediaType; - (void)llSampleTime; - (void)dwSampleFlags; - (void)llSampleDuration; - (void)dwSampleSize; - - HANDLE tmp[] = {ig_hFinish, ig_hFrameGrabbed, NULL}; - - DWORD status = WaitForMultipleObjects(2, tmp, FALSE, INFINITE); - if (status == WAIT_OBJECT_0) - { - DebugPrintOut(L"OnProcessFrame called after ig_hFinish event\n"); - return S_OK; - } - - if(ig_RIE) - { - ig_RIFirst->fastCopy(pSampleBuffer); - ig_RIOut = ig_RIFirst; - } - else - { - ig_RISecond->fastCopy(pSampleBuffer); - ig_RIOut = ig_RISecond; - } - - if (ig_Synchronous) - { - SetEvent(ig_hFrameReady); - } - else - { - ig_RIE = !ig_RIE; - } - - return S_OK; -} - -STDMETHODIMP ImageGrabberCallback::OnShutdown() -{ - SetEvent(ig_hFinish); - return S_OK; -} - -RawImage *ImageGrabberCallback::getRawImage() -{ - return ig_RIOut; -} - -DWORD WINAPI MainThreadFunction( LPVOID lpParam ) -{ - ImageGrabberThread *pIGT = (ImageGrabberThread *)lpParam; - pIGT->run(); - return 0; -} - -HRESULT ImageGrabberThread::CreateInstance(ImageGrabberThread **ppIGT, IMFMediaSource *pSource, unsigned int deviceID, bool synchronious) -{ - *ppIGT = new (std::nothrow) ImageGrabberThread(pSource, deviceID, synchronious); - if (ppIGT == NULL) - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Memory cannot be allocated\n", deviceID); - return E_OUTOFMEMORY; - } - else - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Creating of the instance of ImageGrabberThread\n", deviceID); - return S_OK; -} - -ImageGrabberThread::ImageGrabberThread(IMFMediaSource *pSource, unsigned int deviceID, bool synchronious) : - igt_func(NULL), - igt_Handle(NULL), - igt_stop(false) -{ - HRESULT hr = ImageGrabber::CreateInstance(&igt_pImageGrabber, deviceID, synchronious); - igt_DeviceID = deviceID; - if(SUCCEEDED(hr)) - { - hr = igt_pImageGrabber->initImageGrabber(pSource); - if(!SUCCEEDED(hr)) - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with initialization of the instance of the ImageGrabber class\n", deviceID); - } - else - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Initialization of instance of the ImageGrabber class\n", deviceID); - } - } - else - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with creation of the instance of the ImageGrabber class\n", deviceID); - } -} - -void ImageGrabberThread::setEmergencyStopEvent(void *userData, void(*func)(int, void *)) -{ - if(func) - { - igt_func = func; - igt_userData = userData; - } -} - -ImageGrabberThread::~ImageGrabberThread(void) -{ - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Destroying ImageGrabberThread\n", igt_DeviceID); - if (igt_Handle) - WaitForSingleObject(igt_Handle, INFINITE); - delete igt_pImageGrabber; -} - -void ImageGrabberThread::stop() -{ - igt_stop = true; - if(igt_pImageGrabber) - { - igt_pImageGrabber->stopGrabbing(); - } -} - -void ImageGrabberThread::start() -{ - igt_Handle = CreateThread( - NULL, // default security attributes - 0, // use default stack size - MainThreadFunction, // thread function name - this, // argument to thread function - 0, // use default creation flags - &igt_ThreadIdArray); // returns the thread identifier -} - -void ImageGrabberThread::run() -{ - if(igt_pImageGrabber) - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Thread for grabbing images is started\n", igt_DeviceID); - HRESULT hr = igt_pImageGrabber->startGrabbing(); - if(!SUCCEEDED(hr)) - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: There is a problem with starting the process of grabbing\n", igt_DeviceID); - } - } - else - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i The thread is finished without execution of grabbing\n", igt_DeviceID); - } - if(!igt_stop) - { - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Emergency Stop thread\n", igt_DeviceID); - if(igt_func) - { - igt_func(igt_DeviceID, igt_userData); - } - } - else - DebugPrintOut(L"IMAGEGRABBERTHREAD VIDEODEVICE %i: Finish thread\n", igt_DeviceID); -} - -ImageGrabber *ImageGrabberThread::getImageGrabber() -{ - return igt_pImageGrabber; -} - -RawImage::RawImage(unsigned int size): ri_new(false), ri_pixels(NULL) -{ - ri_size = size; - ri_pixels = new unsigned char[size]; - memset((void *)ri_pixels,0,ri_size); -} - -bool RawImage::isNew() -{ - return ri_new; -} - -unsigned int RawImage::getSize() -{ - return ri_size; -} - -RawImage::~RawImage(void) -{ - delete []ri_pixels; - ri_pixels = NULL; -} - -long RawImage::CreateInstance(RawImage **ppRImage,unsigned int size) -{ - *ppRImage = new (std::nothrow) RawImage(size); - if (ppRImage == NULL) - { - return E_OUTOFMEMORY; - } - return S_OK; -} - -void RawImage::setCopy(const BYTE * pSampleBuffer) -{ - memcpy(ri_pixels, pSampleBuffer, ri_size); - ri_new = true; -} - -void RawImage::fastCopy(const BYTE * pSampleBuffer) -{ - memcpy(ri_pixels, pSampleBuffer, ri_size); - ri_new = true; -} - -unsigned char * RawImage::getpPixels() -{ - ri_new = false; - return ri_pixels; -} - -videoDevice::videoDevice(void): vd_IsSetuped(false), vd_LockOut(OpenLock), vd_pFriendlyName(NULL), - vd_Width(0), vd_Height(0), vd_FrameRate(0), vd_pSource(NULL), vd_pImGrTh(NULL), vd_func(NULL), vd_userData(NULL) -{ -#ifdef WINRT - vd_pMedCap = nullptr; - vd_cookie.value = 0; - vd_pImGr = NULL; - vd_pAction = nullptr; -#endif -} - -void videoDevice::setParametrs(CamParametrs parametrs) -{ - if(vd_IsSetuped) - { - if(vd_pSource) - { - Parametr *pParametr = (Parametr *)(¶metrs); - Parametr *pPrevParametr = (Parametr *)(&vd_PrevParametrs); - IAMVideoProcAmp *pProcAmp = NULL; - HRESULT hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcAmp)); - if (SUCCEEDED(hr)) - { - for(unsigned int i = 0; i < 10; i++) - { - if(pPrevParametr[i].CurrentValue != pParametr[i].CurrentValue || pPrevParametr[i].Flag != pParametr[i].Flag) - hr = pProcAmp->Set(VideoProcAmp_Brightness + i, pParametr[i].CurrentValue, pParametr[i].Flag); - } - pProcAmp->Release(); - } - IAMCameraControl *pProcControl = NULL; - hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcControl)); - if (SUCCEEDED(hr)) - { - for(unsigned int i = 0; i < 7; i++) - { - if(pPrevParametr[10 + i].CurrentValue != pParametr[10 + i].CurrentValue || pPrevParametr[10 + i].Flag != pParametr[10 + i].Flag) - hr = pProcControl->Set(CameraControl_Pan+i, pParametr[10 + i].CurrentValue, pParametr[10 + i].Flag); - } - pProcControl->Release(); - } - vd_PrevParametrs = parametrs; - } - } -} - -CamParametrs videoDevice::getParametrs() -{ - CamParametrs out; - if(vd_IsSetuped) - { - if(vd_pSource) - { - Parametr *pParametr = (Parametr *)(&out); - IAMVideoProcAmp *pProcAmp = NULL; - HRESULT hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcAmp)); - if (SUCCEEDED(hr)) - { - for(unsigned int i = 0; i < 10; i++) - { - Parametr temp; - hr = pProcAmp->GetRange(VideoProcAmp_Brightness+i, &temp.Min, &temp.Max, &temp.Step, &temp.Default, &temp.Flag); - if (SUCCEEDED(hr)) - { - temp.CurrentValue = temp.Default; - pParametr[i] = temp; - } - } - pProcAmp->Release(); - } - IAMCameraControl *pProcControl = NULL; - hr = vd_pSource->QueryInterface(IID_PPV_ARGS(&pProcControl)); - if (SUCCEEDED(hr)) - { - for(unsigned int i = 0; i < 7; i++) - { - Parametr temp; - hr = pProcControl->GetRange(CameraControl_Pan+i, &temp.Min, &temp.Max, &temp.Step, &temp.Default, &temp.Flag); - if (SUCCEEDED(hr)) - { - temp.CurrentValue = temp.Default; - pParametr[10 + i] = temp; - } - } - pProcControl->Release(); - } - } - } - return out; -} - -#ifdef WINRT -long videoDevice::resetDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice) -#else -long videoDevice::resetDevice(IMFActivate *pActivate) -#endif -{ - HRESULT hr = E_FAIL; - vd_CurrentFormats.clear(); - if(vd_pFriendlyName) - CoTaskMemFree(vd_pFriendlyName); - vd_pFriendlyName = NULL; -#ifdef WINRT - if (pDevice) - { - ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCapture, _MediaCapture, pIMedCap, hr) - if (FAILED(hr)) return hr; - ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings, _MediaCaptureInitializationSettings, pCapInitSet, hr) - if (FAILED(hr)) return hr; - _StringObj str; - WRL_PROP_GET(pDevice, Name, *REF_WRL_OBJ(str), hr) - if (FAILED(hr)) return hr; - unsigned int length = 0; - PCWSTR wstr = WindowsGetStringRawBuffer(reinterpret_cast(DEREF_WRL_OBJ(str)), &length); - vd_pFriendlyName = (wchar_t*)CoTaskMemAlloc((length + 1) * sizeof(wchar_t)); - wcscpy(vd_pFriendlyName, wstr); - WRL_PROP_GET(pDevice, Id, *REF_WRL_OBJ(str), hr) - if (FAILED(hr)) return hr; - WRL_PROP_PUT(pCapInitSet, VideoDeviceId, DEREF_WRL_OBJ(str), hr) - if (FAILED(hr)) return hr; - WRL_PROP_PUT(pCapInitSet, StreamingCaptureMode, WRL_ENUM_GET(_StreamingCaptureMode, StreamingCaptureMode, Video), hr) - if (FAILED(hr)) return hr; - MAKE_WRL_REF(_AsyncAction) pAction; - WRL_METHOD(DEREF_WRL_OBJ(pIMedCap), _InitializeWithSettingsAsync, pAction, hr, DEREF_WRL_OBJ(pCapInitSet)) -#ifdef HAVE_CONCURRENCY - DEFINE_TASK _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction); - if (FAILED(hr)) return hr; - MAKE_WRL_AGILE_REF(_MediaCapture) pAgileMedCap; - pAgileMedCap = PREPARE_TRANSFER_WRL_OBJ(pIMedCap); - Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); - MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; - SAVE_CURRENT_CONTEXT(context); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, _task, pOldAction, context, &pAgileMedCap, this) - HRESULT hr = S_OK; - if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); - _task.wait(); - if (SUCCEEDED(hr)) { - //all camera capture calls only in original context - BEGIN_CALL_IN_CONTEXT(hr, context, pAgileMedCap, this) - enumerateCaptureFormats(DEREF_AGILE_WRL_OBJ(pAgileMedCap)); - END_CALL_IN_CONTEXT_BASE - } - buildLibraryofTypes(); - RELEASE_AGILE_WRL(pAgileMedCap) - END_CREATE_ASYNC(hr)); -#endif - } -#else - if(pActivate) - { - IMFMediaSource *pSource = NULL; - hr = pActivate->GetAllocatedString( - MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, - &vd_pFriendlyName, - NULL - ); - if (SUCCEEDED(hr)) - hr = pActivate->ActivateObject( - __uuidof(IMFMediaSource), - (void**)&pSource - ); - if (SUCCEEDED(hr) && pSource) - { - enumerateCaptureFormats(pSource); - buildLibraryofTypes(); - SafeRelease(&pSource); - }//end if (SUCCEEDED(hr) && pSource) - if(FAILED(hr)) - { - vd_pFriendlyName = NULL; - DebugPrintOut(L"VIDEODEVICE %i: IMFMediaSource interface cannot be created \n", vd_CurrentNumber); - } - } -#endif - return hr; -} - -#ifdef WINRT -long videoDevice::readInfoOfDevice(MAKE_WRL_REF(_IDeviceInformation) pDevice, unsigned int Num) -{ - HRESULT hr = -1; - vd_CurrentNumber = Num; - hr = resetDevice(pDevice); - return hr; -} -#else -long videoDevice::readInfoOfDevice(IMFActivate *pActivate, unsigned int Num) -{ - vd_CurrentNumber = Num; - return resetDevice(pActivate); -} -#endif - -#ifdef WINRT -#ifdef HAVE_CONCURRENCY -long videoDevice::checkDevice(_DeviceClass devClass, DEFINE_TASK* pTask, MAKE_WRL_REF(_IDeviceInformation)* ppDevice) -{ - HRESULT hr = S_OK; - ACTIVATE_STATIC_OBJ(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation, MAKE_WRL_OBJ(_DeviceInformationStatics), pDevStat, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_REF(_AsyncOperation) pAction; - WRL_METHOD(pDevStat, _FindAllAsyncDeviceClass, pAction, hr, devClass) - if (SUCCEEDED(hr)) { - *pTask = CREATE_TASK DEFINE_RET_TYPE(void)([pAction, &ppDevice, this]() -> DEFINE_RET_FORMAL(void) { - HRESULT hr = S_OK; - MAKE_WRL_OBJ(_VectorView) pVector = - CREATE_TASK DEFINE_RET_TYPE(MAKE_WRL_REF(_VectorView))(pAction).get(); - UINT32 count = 0; - if (SUCCEEDED(hr)) WRL_PROP_GET(pVector, Size, count, hr) - if (SUCCEEDED(hr) && count > 0) { - for (UINT32 i = 0; i < count; i++) { - MAKE_WRL_OBJ(_IDeviceInformation) pDevice; - WRL_METHOD(pVector, GetAt, pDevice, hr, i) - if (SUCCEEDED(hr)) { - _StringObj str; - unsigned int length = 0; - WRL_PROP_GET(pDevice, Name, *REF_WRL_OBJ(str), hr) - PCWSTR wstr = WindowsGetStringRawBuffer(reinterpret_cast(DEREF_WRL_OBJ(str)), &length); - if (wcscmp(wstr, vd_pFriendlyName) == 0) { - *ppDevice = PREPARE_TRANSFER_WRL_OBJ(pDevice); - } - } - } - } - RET_VAL_BASE; - }); - } - return hr; -} -#endif -#else -long videoDevice::checkDevice(IMFAttributes *pAttributes, IMFActivate **pDevice) -{ - IMFActivate **ppDevices = NULL; - UINT32 count; - wchar_t *newFriendlyName = NULL; - HRESULT hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count); - if (SUCCEEDED(hr)) - { - if(count > 0) - { - if(count > vd_CurrentNumber) - { - hr = ppDevices[vd_CurrentNumber]->GetAllocatedString( - MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, - &newFriendlyName, - NULL - ); - if (SUCCEEDED(hr)) - { - if(wcscmp(newFriendlyName, vd_pFriendlyName) != 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Chosen device cannot be found \n", vd_CurrentNumber); - hr = E_INVALIDARG; - pDevice = NULL; - } - else - { - *pDevice = ppDevices[vd_CurrentNumber]; - (*pDevice)->AddRef(); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: Name of device cannot be gotten \n", vd_CurrentNumber); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: Number of devices more than corrent number of the device \n", vd_CurrentNumber); - hr = E_INVALIDARG; - } - for(UINT32 i = 0; i < count; i++) - { - SafeRelease(&ppDevices[i]); - } - SafeRelease(ppDevices); - } - else - hr = E_FAIL; - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: List of DeviceSources cannot be enumerated \n", vd_CurrentNumber); - } - return hr; -} -#endif - -long videoDevice::initDevice() -{ - HRESULT hr = S_OK; - CoInitialize(NULL); -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); - MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; - SAVE_CURRENT_CONTEXT(context); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, pOldAction, context, this) - HRESULT hr; - if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); - DEFINE_TASK pTask; - MAKE_WRL_OBJ(_IDeviceInformation) pDevInfo; - hr = checkDevice(WRL_ENUM_GET(_DeviceClass, DeviceClass, VideoCapture), &pTask, REF_WRL_OBJ(pDevInfo)); - if (SUCCEEDED(hr)) pTask.wait(); - if (SUCCEEDED(hr)) { - DEFINE_TASK _task; - BEGIN_CALL_IN_CONTEXT(hr, context, pDevInfo, &_task, context, this) - HRESULT hr; - ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCapture, _MediaCapture, pIMedCap, hr) - if (SUCCEEDED(hr)) { - RELEASE_WRL(vd_pMedCap); - vd_pMedCap = PREPARE_TRANSFER_WRL_OBJ(pIMedCap); - ACTIVATE_OBJ(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings, _MediaCaptureInitializationSettings, pCapInitSet, hr) - _StringObj str; - if (SUCCEEDED(hr)) { - WRL_PROP_GET(pDevInfo, Id, *REF_WRL_OBJ(str), hr) - if (SUCCEEDED(hr)) { - WRL_PROP_PUT(pCapInitSet, VideoDeviceId, DEREF_WRL_OBJ(str), hr) - } - } - if (SUCCEEDED(hr)) - WRL_PROP_PUT(pCapInitSet, StreamingCaptureMode, WRL_ENUM_GET(_StreamingCaptureMode, StreamingCaptureMode, Video), hr) - if (SUCCEEDED(hr)) reinterpret_cast(DEREF_AGILE_WRL_OBJ(vd_pMedCap))->add_Failed(Microsoft::WRL::Callback([this, context](ABI::Windows::Media::Capture::IMediaCapture*, ABI::Windows::Media::Capture::IMediaCaptureFailedEventArgs*) -> HRESULT { - HRESULT hr; - BEGIN_CALL_IN_CONTEXT(hr, context, this) - closeDevice(); - END_CALL_IN_CONTEXT_BASE - return hr; - }).Get(), &vd_cookie); - MAKE_WRL_OBJ(_AsyncAction) pAction; - if (SUCCEEDED(hr)) WRL_METHOD(vd_pMedCap, _InitializeWithSettingsAsync, *REF_WRL_OBJ(pAction), hr, DEREF_WRL_OBJ(pCapInitSet)) - if (SUCCEEDED(hr)) _task = CREATE_TASK DEFINE_RET_TYPE(void)(DEREF_WRL_OBJ(pAction)); - } - END_CALL_IN_CONTEXT(hr) - _task.wait(); - } - END_CREATE_ASYNC(hr)); -#endif -#else - _ComPtr pAttributes = NULL; - IMFActivate *vd_pActivate = NULL; - hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1); - if (SUCCEEDED(hr)) - { - hr = pAttributes->SetGUID( - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID - ); - } - if (SUCCEEDED(hr)) - { - hr = checkDevice(pAttributes.Get(), &vd_pActivate); - if (SUCCEEDED(hr) && vd_pActivate) - { - SafeRelease(&vd_pSource); - hr = vd_pActivate->ActivateObject( - __uuidof(IMFMediaSource), - (void**)&vd_pSource - ); - if (SUCCEEDED(hr)) - { - } - SafeRelease(&vd_pActivate); - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: Device there is not \n", vd_CurrentNumber); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: The attribute of video cameras cannot be getting \n", vd_CurrentNumber); - } -#endif - return hr; -} - -MediaType videoDevice::getFormat(unsigned int id) -{ - if(id < vd_CurrentFormats.size()) - { - return vd_CurrentFormats[id]; - } - else return MediaType(); -} -int videoDevice::getCountFormats() -{ - return (int)vd_CurrentFormats.size(); -} -void videoDevice::setEmergencyStopEvent(void *userData, void(*func)(int, void *)) -{ - vd_func = func; - vd_userData = userData; -} -void videoDevice::closeDevice() -{ - if(vd_IsSetuped) - { - vd_IsSetuped = false; - -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - if (DEREF_AGILE_WRL_OBJ(vd_pMedCap)) { - MAKE_WRL_REF(_AsyncAction) action; - Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); - MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; - vd_pImGr->stopGrabbing(&action); - reinterpret_cast(DEREF_AGILE_WRL_OBJ(vd_pMedCap))->remove_Failed(vd_cookie); - vd_cookie.value = 0; - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, action, pOldAction, this) - HRESULT hr = S_OK; - if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); - CREATE_TASK DEFINE_RET_TYPE(void)(action).wait(); - RELEASE_WRL(vd_pMedCap) - if(vd_LockOut == RawDataLock) { - delete vd_pImGr; - } - vd_pImGr = NULL; - vd_LockOut = OpenLock; - END_CREATE_ASYNC(hr)); - return; - } -#endif -#endif - - vd_pSource->Shutdown(); - SafeRelease(&vd_pSource); - if(vd_LockOut == RawDataLock) - { - vd_pImGrTh->stop(); - Sleep(500); - delete vd_pImGrTh; - } - vd_pImGrTh = NULL; - vd_LockOut = OpenLock; - DebugPrintOut(L"VIDEODEVICE %i: Device is stopped \n", vd_CurrentNumber); - } -} -unsigned int videoDevice::getWidth() -{ - if(vd_IsSetuped) - return vd_Width; - else - return 0; -} -unsigned int videoDevice::getHeight() -{ - if(vd_IsSetuped) - return vd_Height; - else - return 0; -} - -unsigned int videoDevice::getFrameRate() const -{ - if(vd_IsSetuped) - return vd_FrameRate; - else - return 0; -} - -IMFMediaSource *videoDevice::getMediaSource() -{ - IMFMediaSource *out = NULL; - if(vd_LockOut == OpenLock) - { - vd_LockOut = MediaSourceLock; - out = vd_pSource; - } - return out; -} -int videoDevice::findType(unsigned int size, unsigned int frameRate) -{ - // For required frame size look for the suitable video format. - // If not found, get the format for the largest available frame size. - FrameRateMap FRM; - std::map::const_iterator fmt; - fmt = vd_CaptureFormats.find(size); - if( fmt != vd_CaptureFormats.end() ) - FRM = fmt->second; - else if( !vd_CaptureFormats.empty() ) - FRM = vd_CaptureFormats.rbegin()->second; - - if( FRM.empty() ) - return -1; - - UINT64 frameRateMax = 0; SUBTYPEMap STMMax; - if(frameRate == 0) - { - std::map::iterator f = FRM.begin(); - for(; f != FRM.end(); f++) - { - // Looking for highest possible frame rate. - if((*f).first >= frameRateMax) - { - frameRateMax = (*f).first; - STMMax = (*f).second; - } - } - } - else - { - std::map::iterator f = FRM.begin(); - for(; f != FRM.end(); f++) - { - // Looking for frame rate higher that recently found but not higher then demanded. - if( (*f).first >= frameRateMax && (*f).first <= frameRate ) - { - frameRateMax = (*f).first; - STMMax = (*f).second; - } - } - } - // Get first (default) item from the list if no suitable frame rate found. - if( STMMax.empty() ) - STMMax = FRM.begin()->second; - - // Check if there are any format types on the list. - if( STMMax.empty() ) - return -1; - - vectorNum VN = STMMax.begin()->second; - if( VN.empty() ) - return -1; - - return VN[0]; -} - -void videoDevice::buildLibraryofTypes() -{ - unsigned int size; - unsigned int framerate; - std::vector::iterator i = vd_CurrentFormats.begin(); - int count = 0; - for(; i != vd_CurrentFormats.end(); i++) - { - // Count only supported video formats. - if( (*i).MF_MT_SUBTYPE == MFVideoFormat_RGB24 ) - { - size = (*i).MF_MT_FRAME_SIZE; - framerate = (*i).MF_MT_FRAME_RATE_NUMERATOR / (*i).MF_MT_FRAME_RATE_DENOMINATOR; - FrameRateMap FRM = vd_CaptureFormats[size]; - SUBTYPEMap STM = FRM[framerate]; - String subType((*i).pMF_MT_SUBTYPEName); - vectorNum VN = STM[subType]; - VN.push_back(count); - STM[subType] = VN; - FRM[framerate] = STM; - vd_CaptureFormats[size] = FRM; - } - count++; - } -} - -#ifdef WINRT -long videoDevice::setDeviceFormat(MAKE_WRL_REF(_MediaCapture) pSource, unsigned long dwFormatIndex, MAKE_WRL_REF(_AsyncAction)* pAction) -{ - HRESULT hr; - MAKE_WRL_OBJ(_VideoDeviceController) pDevCont; - WRL_PROP_GET(pSource, VideoDeviceController, pDevCont, hr) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_VectorView) pVector; - WRL_METHOD(pMedDevCont, GetAvailableMediaStreamProperties, pVector, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview)) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps; - WRL_METHOD(pVector, GetAt, pMedEncProps, hr, dwFormatIndex) - if (FAILED(hr)) return hr; - WRL_METHOD(pMedDevCont, SetMediaStreamPropertiesAsync, *pAction, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview), DEREF_WRL_OBJ(pMedEncProps)) - return hr; -} -#endif - -long videoDevice::setDeviceFormat(IMFMediaSource *pSource, unsigned long dwFormatIndex) -{ - _ComPtr pPD = NULL; - _ComPtr pSD = NULL; - _ComPtr pHandler = NULL; - _ComPtr pType = NULL; - HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - BOOL fSelected; - hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, pSD.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - hr = pHandler->GetMediaTypeByIndex((DWORD)dwFormatIndex, pType.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - hr = pHandler->SetCurrentMediaType(pType.Get()); - -done: - return hr; -} - -bool videoDevice::isDeviceSetup() -{ - return vd_IsSetuped; -} - -RawImage * videoDevice::getRawImageOut() -{ - if(!vd_IsSetuped) return NULL; -#ifdef WINRT - if(vd_pImGr) return vd_pImGr->getRawImage(); -#endif - if(vd_pImGrTh) - return vd_pImGrTh->getImageGrabber()->getRawImage(); - else - { - DebugPrintOut(L"VIDEODEVICE %i: The instance of ImageGrabberThread class does not exist \n", vd_CurrentNumber); - } - return NULL; -} - -bool videoDevice::isFrameNew() -{ - if(!vd_IsSetuped) return false; - if(vd_LockOut == RawDataLock || vd_LockOut == OpenLock) - { - if(vd_LockOut == OpenLock) - { - vd_LockOut = RawDataLock; - - //must already be closed -#ifdef WINRT - if (DEREF_AGILE_WRL_OBJ(vd_pMedCap)) { - MAKE_WRL_REF(_AsyncAction) action; - if (FAILED(ImageGrabberWinRT::CreateInstance(&vd_pImGr))) return false; - if (FAILED(vd_pImGr->initImageGrabber(DEREF_AGILE_WRL_OBJ(vd_pMedCap), MFVideoFormat_RGB24)) || FAILED(vd_pImGr->startGrabbing(&action))) { - delete vd_pImGr; - return false; - } -#ifdef HAVE_CONCURRENCY - Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); - MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; - DEFINE_TASK _task = CREATE_TASK DEFINE_RET_TYPE(void)(action); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, _task, pOldAction, this) - HRESULT hr = S_OK; - if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); - _task.wait(); - END_CREATE_ASYNC(hr)); -#endif - return true; - } -#endif - HRESULT hr = ImageGrabberThread::CreateInstance(&vd_pImGrTh, vd_pSource, vd_CurrentNumber); - if(FAILED(hr)) - { - DebugPrintOut(L"VIDEODEVICE %i: The instance of ImageGrabberThread class cannot be created.\n", vd_CurrentNumber); - return false; - } - vd_pImGrTh->setEmergencyStopEvent(vd_userData, vd_func); - vd_pImGrTh->start(); - return true; - } -#ifdef WINRT - if(vd_pImGr) - return vd_pImGr->getRawImage()->isNew(); -#endif - if(vd_pImGrTh) - return vd_pImGrTh->getImageGrabber()->getRawImage()->isNew(); - } - return false; -} - -bool videoDevice::isDeviceMediaSource() -{ - if(vd_LockOut == MediaSourceLock) return true; - return false; -} - -bool videoDevice::isDeviceRawDataSource() -{ - if(vd_LockOut == RawDataLock) return true; - return false; -} - -bool videoDevice::setupDevice(unsigned int id) -{ - if(!vd_IsSetuped) - { - HRESULT hr = initDevice(); - if(SUCCEEDED(hr)) - { -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - Concurrency::critical_section::scoped_lock _LockHolder(vd_lock); - MAKE_WRL_REF(_AsyncAction) pOldAction = vd_pAction; - SAVE_CURRENT_CONTEXT(context); - vd_pAction = reinterpret_cast(BEGIN_CREATE_ASYNC(void, pOldAction, context, id, this) - HRESULT hr; - if (pOldAction) CREATE_TASK DEFINE_RET_TYPE(void)(pOldAction).wait(); -#endif -#endif - vd_Width = vd_CurrentFormats[id].width; - vd_Height = vd_CurrentFormats[id].height; - vd_FrameRate = vd_CurrentFormats[id].MF_MT_FRAME_RATE_NUMERATOR / - vd_CurrentFormats[id].MF_MT_FRAME_RATE_DENOMINATOR; -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - if (DEREF_AGILE_WRL_OBJ(vd_pMedCap)) { - DEFINE_TASK _task; - BEGIN_CALL_IN_CONTEXT(hr, context, id, &_task, this) - MAKE_WRL_REF(_AsyncAction) pAction; - HRESULT hr = setDeviceFormat(DEREF_AGILE_WRL_OBJ(vd_pMedCap), (DWORD) id, &pAction); - if (SUCCEEDED(hr)) _task = CREATE_TASK DEFINE_RET_TYPE(void)(pAction); - END_CALL_IN_CONTEXT(hr) - if (SUCCEEDED(hr)) _task.wait(); - } else -#endif -#endif - hr = setDeviceFormat(vd_pSource, (DWORD) id); - vd_IsSetuped = (SUCCEEDED(hr)); - if(vd_IsSetuped) - DebugPrintOut(L"\n\nVIDEODEVICE %i: Device is setuped \n", vd_CurrentNumber); - vd_PrevParametrs = getParametrs(); -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - END_CREATE_ASYNC(hr)); -#endif - return true; -#else - return vd_IsSetuped; -#endif - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: Interface IMFMediaSource cannot be got \n", vd_CurrentNumber); - return false; - } - } - else - { - DebugPrintOut(L"VIDEODEVICE %i: Device is setuped already \n", vd_CurrentNumber); - return false; - } -} - -bool videoDevice::setupDevice(unsigned int w, unsigned int h, unsigned int idealFramerate) -{ - int id = findType(w * h, idealFramerate); - if( id < 0 ) - return false; - - return setupDevice(id); -} - -wchar_t *videoDevice::getName() -{ - return vd_pFriendlyName; -} - -videoDevice::~videoDevice(void) -{ - closeDevice(); -#ifdef WINRT - RELEASE_WRL(vd_pMedCap) -#endif - SafeRelease(&vd_pSource); - if(vd_pFriendlyName) - CoTaskMemFree(vd_pFriendlyName); -} - -#ifdef WINRT -HRESULT videoDevice::enumerateCaptureFormats(MAKE_WRL_REF(_MediaCapture) pSource) -{ - HRESULT hr; - MAKE_WRL_OBJ(_VideoDeviceController) pDevCont; - WRL_PROP_GET(pSource, VideoDeviceController, pDevCont, hr) - if (FAILED(hr)) return hr; - GET_WRL_OBJ_FROM_OBJ(_MediaDeviceController, pMedDevCont, pDevCont, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_OBJ(_VectorView) pVector; - WRL_METHOD(pMedDevCont, GetAvailableMediaStreamProperties, pVector, hr, WRL_ENUM_GET(_MediaStreamType, MediaStreamType, VideoPreview)) - if (FAILED(hr)) return hr; - UINT32 count; - WRL_PROP_GET(pVector, Size, count, hr) - if (FAILED(hr)) return hr; - for (UINT32 i = 0; i < count; i++) { - MAKE_WRL_OBJ(_MediaEncodingProperties) pMedEncProps; - WRL_METHOD(pVector, GetAt, pMedEncProps, hr, i) - if (FAILED(hr)) return hr; - _ComPtr pType = NULL; - hr = MediaSink::ConvertPropertiesToMediaType(DEREF_AS_NATIVE_WRL_OBJ(ABI::Windows::Media::MediaProperties::IMediaEncodingProperties, pMedEncProps), &pType); - if (FAILED(hr)) return hr; - MediaType MT = FormatReader::Read(pType.Get()); - vd_CurrentFormats.push_back(MT); - } - return hr; -} -#endif - -HRESULT videoDevice::enumerateCaptureFormats(IMFMediaSource *pSource) -{ - HRESULT hr = S_OK; - { // "done:" scope - - _ComPtr pPD = NULL; - _ComPtr pSD = NULL; - _ComPtr pHandler = NULL; - _ComPtr pType = NULL; - hr = !pSource ? E_POINTER : S_OK; - if (FAILED(hr)) - { - goto done; - } - hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - BOOL fSelected; - hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, pSD.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - hr = pSD->GetMediaTypeHandler(pHandler.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - DWORD cTypes = 0; - hr = pHandler->GetMediaTypeCount(&cTypes); - if (FAILED(hr)) - { - goto done; - } - for (DWORD i = 0; i < cTypes; i++) - { - hr = pHandler->GetMediaTypeByIndex(i, pType.GetAddressOf()); - if (FAILED(hr)) - { - goto done; - } - MediaType MT = FormatReader::Read(pType.Get()); - vd_CurrentFormats.push_back(MT); - } - - } // "done:" scope -done: - return hr; -} - -videoDevices::videoDevices(void): count(0) -{ -#ifdef WINRT - vds_enumTask = nullptr; -#endif -} - -void videoDevices::clearDevices() -{ - std::vector::iterator i = vds_Devices.begin(); - for(; i != vds_Devices.end(); ++i) - delete (*i); - vds_Devices.clear(); -} - -videoDevices::~videoDevices(void) -{ - clearDevices(); -} - -videoDevice * videoDevices::getDevice(unsigned int i) -{ - if(i >= vds_Devices.size()) - { - return NULL; - } - if(i < 0) - { - return NULL; - } - return vds_Devices[i]; -} - -#ifdef WINRT -long videoDevices::initDevices(_DeviceClass devClass) -{ - HRESULT hr = S_OK; - ACTIVATE_STATIC_OBJ(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation, MAKE_WRL_OBJ(_DeviceInformationStatics), pDevStat, hr) - if (FAILED(hr)) return hr; - MAKE_WRL_REF(_AsyncOperation) pAction; - WRL_METHOD(pDevStat, _FindAllAsyncDeviceClass, pAction, hr, devClass) - if (SUCCEEDED(hr)) { -#ifdef HAVE_CONCURRENCY - SAVE_CURRENT_CONTEXT(context); - vds_enumTask = reinterpret_cast(BEGIN_CREATE_ASYNC(void, pAction, context, this) - HRESULT hr = S_OK; - MAKE_WRL_OBJ(_VectorView) pVector = - CREATE_TASK DEFINE_RET_TYPE(MAKE_WRL_REF(_VectorView))(pAction).get(); - if (SUCCEEDED(hr)) WRL_PROP_GET(pVector, Size, count, hr) - if (SUCCEEDED(hr) && count > 0) { - for (UINT32 i = 0; i < count; i++) { - videoDevice *vd = new videoDevice; - MAKE_WRL_OBJ(_IDeviceInformation) pDevice; - WRL_METHOD(pVector, GetAt, pDevice, hr, i) - if (SUCCEEDED(hr)) { - BEGIN_CALL_IN_CONTEXT(hr, context, vd, pDevice, i) - vd->readInfoOfDevice(DEREF_WRL_OBJ(pDevice), i); - END_CALL_IN_CONTEXT_BASE - vds_Devices.push_back(vd); - } - } - } - END_CREATE_ASYNC(hr)); -#endif - } - return hr; -} -#else -long videoDevices::initDevices(IMFAttributes *pAttributes) -{ - clearDevices(); - IMFActivate **ppDevices = NULL; - HRESULT hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count); - if (SUCCEEDED(hr)) - { - if(count > 0) - { - for(UINT32 i = 0; i < count; i++) - { - videoDevice *vd = new videoDevice; - vd->readInfoOfDevice(ppDevices[i], i); - vds_Devices.push_back(vd); - SafeRelease(&ppDevices[i]); - } - SafeRelease(ppDevices); - } - else - hr = E_INVALIDARG; - } - else - { - DebugPrintOut(L"VIDEODEVICES: The instances of the videoDevice class cannot be created\n"); - } - return hr; -} -#endif - -unsigned int videoDevices::getCount() -{ - return (unsigned int)vds_Devices.size(); -} - -videoDevices& videoDevices::getInstance() -{ - static videoDevices instance; - return instance; -} - -Parametr::Parametr() -{ - CurrentValue = 0; - Min = 0; - Max = 0; - Step = 0; - Default = 0; - Flag = 0; -} - -MediaType::MediaType() -{ - pMF_MT_AM_FORMAT_TYPEName = NULL; - pMF_MT_MAJOR_TYPEName = NULL; - pMF_MT_SUBTYPEName = NULL; - Clear(); -} - -MediaType::~MediaType() -{ - Clear(); -} - -void MediaType::Clear() -{ - MF_MT_FRAME_SIZE = 0; - height = 0; - width = 0; - MF_MT_YUV_MATRIX = 0; - MF_MT_VIDEO_LIGHTING = 0; - MF_MT_DEFAULT_STRIDE = 0; - MF_MT_VIDEO_CHROMA_SITING = 0; - MF_MT_FIXED_SIZE_SAMPLES = 0; - MF_MT_VIDEO_NOMINAL_RANGE = 0; - MF_MT_FRAME_RATE_NUMERATOR = 0; - MF_MT_FRAME_RATE_DENOMINATOR = 0; - MF_MT_PIXEL_ASPECT_RATIO = 0; - MF_MT_PIXEL_ASPECT_RATIO_low = 0; - MF_MT_ALL_SAMPLES_INDEPENDENT = 0; - MF_MT_FRAME_RATE_RANGE_MIN = 0; - MF_MT_FRAME_RATE_RANGE_MIN_low = 0; - MF_MT_SAMPLE_SIZE = 0; - MF_MT_VIDEO_PRIMARIES = 0; - MF_MT_INTERLACE_MODE = 0; - MF_MT_FRAME_RATE_RANGE_MAX = 0; - MF_MT_FRAME_RATE_RANGE_MAX_low = 0; - memset(&MF_MT_MAJOR_TYPE, 0, sizeof(GUID)); - memset(&MF_MT_AM_FORMAT_TYPE, 0, sizeof(GUID)); - memset(&MF_MT_SUBTYPE, 0, sizeof(GUID)); -} - -videoInput::videoInput(void): MF(Media_Foundation::getInstance()), accessToDevices(false) -{ - DebugPrintOut(L"\n***** VIDEOINPUT LIBRARY - 2013 (Author: Evgeny Pereguda) *****\n\n"); - updateListOfDevices(); - if(!accessToDevices) - DebugPrintOut(L"INITIALIZATION: There is not any suitable video device\n"); -} - -void videoInput::updateListOfDevices() -{ - HRESULT hr = S_OK; -#ifdef WINRT - videoDevices *vDs = &videoDevices::getInstance(); - hr = vDs->initDevices(WRL_ENUM_GET(_DeviceClass, DeviceClass, VideoCapture)); -#else - _ComPtr pAttributes = NULL; - CoInitialize(NULL); - hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1); - if (SUCCEEDED(hr)) - { - hr = pAttributes->SetGUID( - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID - ); - } - if (SUCCEEDED(hr)) - { - videoDevices *vDs = &videoDevices::getInstance(); - hr = vDs->initDevices(pAttributes.Get()); - } -#endif - if (FAILED(hr)) - { - DebugPrintOut(L"MEDIA FOUNDATION: The access to the video cameras denied\n"); - } - - accessToDevices = (SUCCEEDED(hr)); - - if(!accessToDevices) - DebugPrintOut(L"UPDATING: There is not any suitable video device\n"); -} - -videoInput::~videoInput(void) -{ - DebugPrintOut(L"\n***** CLOSE VIDEOINPUT LIBRARY - 2013 *****\n\n"); -} - -IMFMediaSource *videoInput::getMediaSource(int deviceID) -{ - if(accessToDevices) - { - videoDevice * VD = videoDevices::getInstance().getDevice(deviceID); - if(VD) - { - IMFMediaSource *out = VD->getMediaSource(); - if(!out) - DebugPrintOut(L"VideoDevice %i: There is not any suitable IMFMediaSource interface\n", deviceID); - return out; - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return NULL; -} - -bool videoInput::setupDevice(int deviceID, unsigned int id) -{ - if (deviceID < 0 ) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - { - bool out = VD->setupDevice(id); - if(!out) - DebugPrintOut(L"VIDEODEVICE %i: This device cannot be started\n", deviceID); - return out; - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return false; -} - -bool videoInput::setupDevice(int deviceID, unsigned int w, unsigned int h, unsigned int idealFramerate) -{ - if (deviceID < 0 ) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - { - bool out = VD->setupDevice(w, h, idealFramerate); - if(!out) - DebugPrintOut(L"VIDEODEVICE %i: this device cannot be started\n", deviceID); - return out; - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n", deviceID); - } - return false; -} - -MediaType videoInput::getFormat(int deviceID, unsigned int id) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return MediaType(); - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->getFormat(id); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return MediaType(); -} - -bool videoInput::isDeviceSetup(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->isDeviceSetup(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return false; -} - -bool videoInput::isDeviceMediaSource(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->isDeviceMediaSource(); - } - else - { - DebugPrintOut(L"Device(s): There is not any suitable video device\n"); - } - return false; -} - -bool videoInput::isDeviceRawDataSource(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - { - bool isRaw = VD->isDeviceRawDataSource(); - return isRaw; - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return false; -} - -bool videoInput::isFrameNew(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return false; - } - if(accessToDevices) - { - if(!isDeviceSetup(deviceID)) - { - if(isDeviceMediaSource(deviceID)) - return false; - } - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - { - return VD->isFrameNew(); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return false; -} - -#ifdef WINRT -void videoInput::waitForDevice(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return; - } - if(accessToDevices) - { - if(!isDeviceSetup(deviceID)) - { - if(isDeviceMediaSource(deviceID)) - return; - } - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - { - VD->waitForDevice(); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return; -} -#endif - -unsigned int videoInput::getCountFormats(int deviceID) const -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return 0; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->getCountFormats(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return 0; -} - -void videoInput::closeAllDevices() -{ - videoDevices *VDS = &videoDevices::getInstance(); - for(unsigned int i = 0; i < VDS->getCount(); i++) - closeDevice(i); -} - -void videoInput::setParametrs(int deviceID, CamParametrs parametrs) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice *VD = VDS->getDevice(deviceID); - if(VD) - VD->setParametrs(parametrs); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } -} - -CamParametrs videoInput::getParametrs(int deviceID) -{ - CamParametrs out; - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return out; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice *VD = VDS->getDevice(deviceID); - if(VD) - out = VD->getParametrs(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return out; -} - -void videoInput::closeDevice(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice *VD = VDS->getDevice(deviceID); - if(VD) - VD->closeDevice(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } -} - -unsigned int videoInput::getWidth(int deviceID) const -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return 0; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->getWidth(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return 0; -} - -unsigned int videoInput::getHeight(int deviceID) const -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return 0; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->getHeight(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return 0; -} - -unsigned int videoInput::getFrameRate(int deviceID) const -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return 0; - } - if(accessToDevices) - { - videoDevice * VD = videoDevices::getInstance().getDevice(deviceID); - if(VD) - return VD->getFrameRate(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return 0; -} - -const wchar_t *videoInput::getNameVideoDevice(int deviceID) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return NULL; - } - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - return VD->getName(); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return L"Empty"; -} - -unsigned int videoInput::listDevices(bool silent) -{ - int out = 0; - if(accessToDevices) - { - videoDevices *VDS = &videoDevices::getInstance(); -#ifdef WINRT - VDS->waitInit(); -#endif - out = VDS->getCount(); - if(!silent) DebugPrintOut(L"\nVIDEOINPUT SPY MODE!\n\n"); - if(!silent) DebugPrintOut(L"SETUP: Looking For Capture Devices\n"); - for(int i = 0; i < out; i++) - { - if(!silent) DebugPrintOut(L"SETUP: %i) %s \n",i, getNameVideoDevice(i)); - } - if(!silent) DebugPrintOut(L"SETUP: %i Device(s) found\n\n", out); - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return out; -} - -videoInput& videoInput::getInstance() -{ - static videoInput instance; - return instance; -} - -bool videoInput::isDevicesAcceable() -{ - return accessToDevices; -} - -#ifdef _DEBUG -void videoInput::setVerbose(bool state) -{ - DPO *dpo = &DPO::getInstance(); - dpo->setVerbose(state); -} -#endif - -void videoInput::setEmergencyStopEvent(int deviceID, void *userData, void(*func)(int, void *)) -{ - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return; - } - if(accessToDevices) - { - if(func) - { - videoDevices *VDS = &videoDevices::getInstance(); - videoDevice * VD = VDS->getDevice(deviceID); - if(VD) - VD->setEmergencyStopEvent(userData, func); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } -} - -bool videoInput::getPixels(int deviceID, unsigned char * dstBuffer, bool flipRedAndBlue, bool flipImage) -{ - bool success = false; - if (deviceID < 0) - { - DebugPrintOut(L"VIDEODEVICE %i: Invalid device ID\n", deviceID); - return success; - } - if(accessToDevices) - { - bool isRaw = isDeviceRawDataSource(deviceID); - if(isRaw) + IAMVideoProcAmp *pProcAmp = NULL; + IAMCameraControl *pProcControl = NULL; + // image format properties + if (property_id == CV_CAP_PROP_FORMAT) + return outputFormat; + else if (property_id == CV_CAP_PROP_MODE) + return captureMode; + else if (property_id == CV_CAP_PROP_CONVERT_RGB) + return convertFormat ? 1 : 0; + else if (property_id == CV_CAP_PROP_SAR_NUM) + return aspectN; + else if (property_id == CV_CAP_PROP_SAR_DEN) + return aspectD; + else if (isOpened) + switch (property_id) { - videoDevice *VD = videoDevices::getInstance().getDevice(deviceID); - RawImage *RIOut = VD->getRawImageOut(); - if(RIOut) + case CV_CAP_PROP_FRAME_WIDTH: + return captureFormat.width; + case CV_CAP_PROP_FRAME_HEIGHT: + return captureFormat.height; + case CV_CAP_PROP_FOURCC: + return nativeFormat.MF_MT_SUBTYPE.Data1; + case CV_CAP_PROP_FPS: + return getFramerate(nativeFormat); + case CV_CAP_PROP_FRAME_COUNT: + if (duration != 0) + return floor(((double)duration / 1e7)*getFramerate(nativeFormat) + 0.5); + else + break; + case CV_CAP_PROP_POS_FRAMES: + return floor(((double)sampleTime / 1e7)*getFramerate(nativeFormat) + 0.5); + case CV_CAP_PROP_POS_MSEC: + return (double)sampleTime / 1e4; + case CV_CAP_PROP_POS_AVI_RATIO: + if (duration != 0) + return (double)sampleTime / duration; + else + break; + case CV_CAP_PROP_BRIGHTNESS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - const unsigned int bytes = 3; - const unsigned int height = VD->getHeight(); - const unsigned int width = VD->getWidth(); - const unsigned int size = bytes * width * height; - if(size == RIOut->getSize()) - { - processPixels(RIOut->getpPixels(), dstBuffer, width, height, bytes, flipRedAndBlue, flipImage); - success = true; - } - else - { - DebugPrintOut(L"ERROR: GetPixels() - bufferSizes do not match!\n"); - } + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Brightness, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if(FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Brightness, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; } - else + break; + case CV_CAP_PROP_CONTRAST: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - DebugPrintOut(L"ERROR: GetPixels() - Unable to grab frame for device %i\n", deviceID); + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Contrast, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Contrast, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; } - } - else - { - DebugPrintOut(L"ERROR: GetPixels() - Not raw data source device %i\n", deviceID); - } - } - else - { - DebugPrintOut(L"VIDEODEVICE(s): There is not any suitable video device\n"); - } - return success; -} - -void videoInput::processPixels(unsigned char * src, unsigned char * dst, unsigned int width, - unsigned int height, unsigned int bpp, bool bRGB, bool bFlip) -{ - unsigned int widthInBytes = width * bpp; - unsigned int numBytes = widthInBytes * height; - int *dstInt, *srcInt; - if(!bRGB) - { - if(bFlip) - { - for(unsigned int y = 0; y < height; y++) + break; + case CV_CAP_PROP_SATURATION: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - dstInt = (int *)(dst + (y * widthInBytes)); - srcInt = (int *)(src + ( (height -y -1) * widthInBytes)); - memcpy(dstInt, srcInt, widthInBytes); + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Saturation, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Saturation, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; } - } - else - { - memcpy(dst, src, numBytes); - } - } - else - { - if(bFlip) - { - unsigned int x = 0; - unsigned int y = (height - 1) * widthInBytes; - src += y; - for(unsigned int i = 0; i < numBytes; i+=3) + break; + case CV_CAP_PROP_HUE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - if(x >= width) - { - x = 0; - src -= widthInBytes*2; - } - *dst = *(src+2); - dst++; - *dst = *(src+1); - dst++; - *dst = *src; - dst++; - src+=3; - x++; + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Hue, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Hue, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; } - } - else - { - for(unsigned int i = 0; i < numBytes; i+=3) + break; + case CV_CAP_PROP_GAIN: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - *dst = *(src+2); - dst++; - *dst = *(src+1); - dst++; - *dst = *src; - dst++; - src+=3; + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Gain, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Gain, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; } - } - } -} -} - -/******* Capturing video from camera via Microsoft Media Foundation **********/ -class CvCaptureCAM_MSMF : public CvCapture -{ -public: - CvCaptureCAM_MSMF(); - virtual ~CvCaptureCAM_MSMF(); - virtual bool open( int index ); - virtual void close(); - virtual double getProperty(int) const CV_OVERRIDE; - virtual bool setProperty(int, double) CV_OVERRIDE; - virtual bool grabFrame() CV_OVERRIDE; - virtual IplImage* retrieveFrame(int) CV_OVERRIDE; - virtual int getCaptureDomain() CV_OVERRIDE { return CV_CAP_MSMF; } // Return the type of the capture object: CV_CAP_VFW, etc... -protected: - void init(); - int index, width, height, fourcc; - IplImage* frame; - videoInput VI; -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - DEFINE_TASK openTask; - Concurrency::critical_section lock; -#endif -#endif -}; - -#ifdef _DEBUG -struct SuppressVideoInputMessages -{ - SuppressVideoInputMessages() { videoInput::setVerbose(true); } -}; - -static SuppressVideoInputMessages do_it; -#endif - -CvCaptureCAM_MSMF::CvCaptureCAM_MSMF(): - index(-1), - width(-1), - height(-1), - fourcc(-1), - frame(NULL), - VI(videoInput::getInstance()) -{ - CoInitialize(0); -} - -CvCaptureCAM_MSMF::~CvCaptureCAM_MSMF() -{ - close(); - CoUninitialize(); -} - -void CvCaptureCAM_MSMF::close() -{ - if( index >= 0 ) - { - VI.closeDevice(index); - index = -1; - cvReleaseImage(&frame); - } - width = height = -1; -} - -// Initialize camera input -bool CvCaptureCAM_MSMF::open( int _index ) -{ -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - SAVE_CURRENT_CONTEXT(context); - auto func = [_index, context, this](DEFINE_RET_VAL(bool)) -> DEFINE_RET_FORMAL(bool) { -#endif -#endif - int try_index = _index; - int devices = 0; - close(); - devices = VI.listDevices(true); - if (devices == 0) - return false; - try_index = try_index < 0 ? 0 : (try_index > devices-1 ? devices-1 : try_index); -#ifdef WINRT - HRESULT hr; -#ifdef HAVE_CONCURRENCY - BEGIN_CALL_IN_CONTEXT(hr, context, this, try_index) -#endif -#endif - VI.setupDevice(try_index, 0, 0, 0); // With maximum frame size. -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - END_CALL_IN_CONTEXT_BASE - VI.waitForDevice(try_index); - BEGIN_CALL_IN_CONTEXT(hr, context, this, try_index) - HRESULT hr = S_OK; -#endif -#endif - if( !VI.isFrameNew(try_index) ) -#ifdef WINRT - hr = E_FAIL; -#else - return false; -#endif - index = try_index; -#ifdef WINRT -#ifdef HAVE_CONCURRENCY - END_CALL_IN_CONTEXT_BASE - RET_VAL(true) - }; - Concurrency::critical_section::scoped_lock _LockHolder(lock); - CREATE_OR_CONTINUE_TASK(openTask, bool, func) -#endif -#endif - return true; -} - -bool CvCaptureCAM_MSMF::grabFrame() -{ - while (VI.isDeviceSetup(index) && !VI.isFrameNew(index)) - Sleep(1); - return VI.isDeviceSetup(index); -} + break; + case CV_CAP_PROP_SHARPNESS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Sharpness, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Sharpness, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_GAMMA: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_Gamma, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_Gamma, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_BACKLIGHT: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_BacklightCompensation, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_BacklightCompensation, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_MONOCHROME: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_ColorEnable, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_ColorEnable, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal == 0 ? 1 : 0; + } + break; + case CV_CAP_PROP_TEMPERATURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcAmp->Get(VideoProcAmp_WhiteBalance, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcAmp->GetRange(VideoProcAmp_WhiteBalance, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcAmp->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: + case CV_CAP_PROP_WHITE_BALANCE_RED_V: + break; + case CV_CAP_PROP_PAN: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Pan, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Pan, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_TILT: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Tilt, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Tilt, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_ROLL: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Roll, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Roll, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_IRIS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Iris, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Iris, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_EXPOSURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Exposure, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Exposure, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + case CV_CAP_PROP_AUTO_EXPOSURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Exposure, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Exposure, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramFlag == VideoProcAmp_Flags_Auto; + } + break; + case CV_CAP_PROP_ZOOM: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Zoom, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Zoom, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + break; + case CV_CAP_PROP_FOCUS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Focus, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Focus, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramVal; + } + case CV_CAP_PROP_AUTOFOCUS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal, paramFlag; + HRESULT hr = pProcControl->Get(CameraControl_Focus, ¶mVal, ¶mFlag); + long minVal, maxVal, stepVal; + if (FAILED(hr)) + hr = pProcControl->GetRange(CameraControl_Focus, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag);//Unable to get the property, trying to return default value + pProcControl->Release(); + if (SUCCEEDED(hr)) + return paramFlag == VideoProcAmp_Flags_Auto; + } + break; -IplImage* CvCaptureCAM_MSMF::retrieveFrame(int) -{ - const int w = (int)VI.getWidth(index); - const int h = (int)VI.getHeight(index); - if( !frame || w != frame->width || h != frame->height ) - { - if (frame) - cvReleaseImage( &frame ); - frame = cvCreateImage( cvSize(w,h), 8, 3 ); - } - VI.getPixels( index, (uchar*)frame->imageData, false, true ); - return frame; -} + case CV_CAP_PROP_RECTIFICATION: + case CV_CAP_PROP_TRIGGER: + case CV_CAP_PROP_TRIGGER_DELAY: + case CV_CAP_PROP_GUID: + case CV_CAP_PROP_ISO_SPEED: + case CV_CAP_PROP_SETTINGS: + case CV_CAP_PROP_BUFFERSIZE: + default: + break; + } -double CvCaptureCAM_MSMF::getProperty( int property_id ) const -{ - // image format proprrties - switch( property_id ) - { - case CV_CAP_PROP_FRAME_WIDTH: - return VI.getWidth(index); - case CV_CAP_PROP_FRAME_HEIGHT: - return VI.getHeight(index); - case CV_CAP_PROP_FPS: - return VI.getFrameRate(index); - default: - break; - } - return 0; + return -1; } -bool CvCaptureCAM_MSMF::setProperty( int property_id, double value ) + +bool CvCapture_MSMF::setProperty( int property_id, double value ) { + IAMVideoProcAmp *pProcAmp = NULL; + IAMCameraControl *pProcControl = NULL; // image capture properties - unsigned int fps = 0; - bool handled = false; - switch( property_id ) + if (property_id == CV_CAP_PROP_FORMAT) { - case CV_CAP_PROP_FRAME_WIDTH: - width = cvRound(value); - fps = VI.getFrameRate(index); - handled = true; - break; - case CV_CAP_PROP_FRAME_HEIGHT: - height = cvRound(value); - fps = VI.getFrameRate(index); - handled = true; - break; - case CV_CAP_PROP_FPS: - width = (int)VI.getHeight(index); - height = (int)VI.getWidth(index); - fps = cvRound(value); - break; + if (isOpened) + return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), aspectN, aspectD, (int)cvRound(value), convertFormat); + else + outputFormat = (int)cvRound(value); + return true; } - - if ( handled ) { - if( width > 0 && height > 0 ) + else if (property_id == CV_CAP_PROP_MODE) + { + switch ((MSMFCapture_Mode)((int)value)) { - if( (width != (int)VI.getWidth(index) || height != (int)VI.getHeight(index) || fps != VI.getFrameRate(index)) - && VI.isDeviceSetup(index))//|| fourcc != VI.getFourcc(index) ) - { - VI.closeDevice(index); - VI.setupDevice(index, width, height, fps); - } - width = height = -1; - return VI.isDeviceSetup(index); + case MODE_SW: + return configureHW(false); + case MODE_HW: + return configureHW(true); + default: + return false; } + } + else if (property_id == CV_CAP_PROP_CONVERT_RGB) + { + if (isOpened) + return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), aspectN, aspectD, outputFormat, value != 0); + else + convertFormat = value != 0; return true; } - - return false; -} - -class CvCaptureFile_MSMF : public CvCapture -{ -public: - CvCaptureFile_MSMF(); - virtual ~CvCaptureFile_MSMF(); - - virtual bool open( const char* filename ); - virtual void close(); - - virtual double getProperty(int) const; - virtual bool setProperty(int, double); - virtual bool grabFrame(); - virtual IplImage* retrieveFrame(int); - virtual int getCaptureDomain() { return CV_CAP_MSMF; } -protected: - Media_Foundation& MF; - _ComPtr videoFileSource; - DWORD dwStreamIndex; - MediaType captureFormat; - _ComPtr videoSample; - IplImage* frame; - bool isOpened; - - HRESULT getSourceDuration(MFTIME *pDuration) const; -}; - -CvCaptureFile_MSMF::CvCaptureFile_MSMF(): - MF(Media_Foundation::getInstance()), - videoFileSource(NULL), - videoSample(NULL), - frame(NULL), - isOpened(false) -{ -} - -CvCaptureFile_MSMF::~CvCaptureFile_MSMF() -{ - close(); -} - -bool CvCaptureFile_MSMF::open(const char* filename) -{ - if (isOpened) - close(); - if (!filename) - return false; - - // Set source reader parameters - _ComPtr srAttr; - if (SUCCEEDED(MFCreateAttributes(&srAttr, 10)) && - SUCCEEDED(srAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)) && - SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, false)) && - SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, false)) && - SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true)) - ) + else if (property_id == CV_CAP_PROP_SAR_NUM && value > 0) { - //ToDo: Enable D3D MF_SOURCE_READER_D3D_MANAGER attribute - cv::AutoBuffer unicodeFileName(strlen(filename) + 1); - MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, (int)strlen(filename) + 1); - if (SUCCEEDED(MFCreateSourceReaderFromURL(unicodeFileName, srAttr.Get(), &videoFileSource))) - { - HRESULT hr = S_OK; - DWORD dwMediaTypeIndex = 0; - dwStreamIndex = 0; - while (SUCCEEDED(hr)) - { - _ComPtr pType; - hr = videoFileSource->GetNativeMediaType(dwStreamIndex, dwMediaTypeIndex, &pType); - if (hr == MF_E_NO_MORE_TYPES) - { - hr = S_OK; - ++dwStreamIndex; - dwMediaTypeIndex = 0; - } - else if (SUCCEEDED(hr)) - { - MediaType MT = FormatReader::Read(pType.Get()); - if (MT.MF_MT_MAJOR_TYPE == MFMediaType_Video) - { - captureFormat = MT; - break; - } - ++dwMediaTypeIndex; - } - } - - _ComPtr mediaTypeOut; - if (// Retrieved stream media type - SUCCEEDED(hr) && - // Set the output media type. - SUCCEEDED(MFCreateMediaType(&mediaTypeOut)) && - SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)) && - SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24)) && - SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive)) && - SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_DEFAULT_STRIDE, 3 * captureFormat.width)) && //Assume BGR24 input - SUCCEEDED(MFSetAttributeSize(mediaTypeOut.Get(), MF_MT_FRAME_SIZE, captureFormat.width, captureFormat.height)) && - SUCCEEDED(MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1)) && - SUCCEEDED(videoFileSource->SetStreamSelection((DWORD)MF_SOURCE_READER_ALL_STREAMS, false)) && - SUCCEEDED(videoFileSource->SetStreamSelection(dwStreamIndex, true)) && - SUCCEEDED(videoFileSource->SetCurrentMediaType(dwStreamIndex, NULL, mediaTypeOut.Get())) - ) - { - isOpened = true; - return true; - } - } + if (isOpened) + return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), (UINT32)cvRound(value), aspectD, outputFormat, convertFormat); + else + aspectN = (UINT32)cvRound(value); + return true; } - - return false; -} - -void CvCaptureFile_MSMF::close() -{ - if (isOpened) + else if (property_id == CV_CAP_PROP_SAR_DEN && value > 0) { - isOpened = false; - if (videoSample) - videoSample.Reset(); - if (videoFileSource) - videoFileSource.Reset(); - if (frame) - cvReleaseImage(&frame); + if (isOpened) + return configureOutput(captureFormat.width, captureFormat.height, getFramerate(nativeFormat), aspectN, (UINT32)cvRound(value), outputFormat, convertFormat); + else + aspectD = (UINT32)cvRound(value); + return true; } -} - -bool CvCaptureFile_MSMF::setProperty(int property_id, double value) -{ - // image capture properties - // FIXME: implement method in VideoInput back end - (void) property_id; - (void) value; - return false; -} - -double CvCaptureFile_MSMF::getProperty(int property_id) const -{ - // image format properties - if (isOpened) - switch( property_id ) + else if (isOpened) + switch (property_id) { case CV_CAP_PROP_FRAME_WIDTH: - return captureFormat.width; + if (value > 0) + return configureOutput((UINT32)cvRound(value), captureFormat.height, getFramerate(nativeFormat), aspectN, aspectD, outputFormat, convertFormat); + break; case CV_CAP_PROP_FRAME_HEIGHT: - return captureFormat.height; + if (value > 0) + return configureOutput(captureFormat.width, (UINT32)cvRound(value), getFramerate(nativeFormat), aspectN, aspectD, outputFormat, convertFormat); + break; + case CV_CAP_PROP_FPS: + if (value >= 0) + return configureOutput(captureFormat.width, captureFormat.height, value, aspectN, aspectD, outputFormat, convertFormat); + break; + case CV_CAP_PROP_FOURCC: + break; case CV_CAP_PROP_FRAME_COUNT: + break; + case CV_CAP_PROP_POS_AVI_RATIO: + if (duration != 0) + return setTime(duration * value, true); + break; + case CV_CAP_PROP_POS_FRAMES: + if (getFramerate(nativeFormat) != 0) + return setTime(value * 1e7 / getFramerate(nativeFormat), false); + break; + case CV_CAP_PROP_POS_MSEC: + return setTime(value * 1e4, false); + case CV_CAP_PROP_BRIGHTNESS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - if(captureFormat.MF_MT_SUBTYPE == MFVideoFormat_MP43) //Unable to estimate FPS for MP43 - return 0; - MFTIME duration; - getSourceDuration(&duration); - double fps = ((double)captureFormat.MF_MT_FRAME_RATE_NUMERATOR) / - ((double)captureFormat.MF_MT_FRAME_RATE_DENOMINATOR); - return (double)floor(((double)duration/1e7)*fps+0.5); + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Brightness, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); } - case CV_CAP_PROP_FOURCC: - return captureFormat.MF_MT_SUBTYPE.Data1; - case CV_CAP_PROP_FPS: - if (captureFormat.MF_MT_SUBTYPE == MFVideoFormat_MP43) //Unable to estimate FPS for MP43 - return 0; - return ((double)captureFormat.MF_MT_FRAME_RATE_NUMERATOR) / - ((double)captureFormat.MF_MT_FRAME_RATE_DENOMINATOR); - } - - return -1; -} - -bool CvCaptureFile_MSMF::grabFrame() -{ - if (isOpened) - { - DWORD streamIndex, flags; - LONGLONG llTimeStamp; - if (videoSample) - videoSample.Reset(); - if (SUCCEEDED(videoFileSource->ReadSample( - dwStreamIndex, // Stream index. - 0, // Flags. - &streamIndex, // Receives the actual stream index. - &flags, // Receives status flags. - &llTimeStamp, // Receives the time stamp. - &videoSample // Receives the sample or NULL. - ))) - { - if (streamIndex != dwStreamIndex) + break; + case CV_CAP_PROP_CONTRAST: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - DebugPrintOut(L"\tWrong stream readed. Abort capturing\n"); - close(); + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Contrast, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); } - else if (flags & MF_SOURCE_READERF_ERROR) + break; + case CV_CAP_PROP_SATURATION: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - DebugPrintOut(L"\tStream reading error. Abort capturing\n"); - close(); + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Saturation, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); } - else if (flags & MF_SOURCE_READERF_ALLEFFECTSREMOVED) + break; + case CV_CAP_PROP_HUE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - DebugPrintOut(L"\tStream decoding error. Abort capturing\n"); - close(); + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Hue, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); } - else if (flags & MF_SOURCE_READERF_ENDOFSTREAM) + break; + case CV_CAP_PROP_GAIN: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - DebugPrintOut(L"\tEnd of stream detected\n"); + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Gain, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); } - else + break; + case CV_CAP_PROP_SHARPNESS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - if (flags & MF_SOURCE_READERF_NEWSTREAM) - { - DebugPrintOut(L"\tNew stream detected\n"); - } - if (flags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED) - { - DebugPrintOut(L"\tStream native media type changed\n"); - } - if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) - { - DebugPrintOut(L"\tStream current media type changed\n"); - } - if (flags & MF_SOURCE_READERF_STREAMTICK) - { - DebugPrintOut(L"\tStream tick detected\n"); - } - return true; + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Sharpness, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); } - } - } - return false; -} - -IplImage* CvCaptureFile_MSMF::retrieveFrame(int) -{ - unsigned int width = captureFormat.width; - unsigned int height = captureFormat.height; - unsigned int bytes = 3; //Suppose output format is BGR24 - if( !frame || (int)width != frame->width || (int)height != frame->height ) - { - if (frame) - cvReleaseImage( &frame ); - frame = cvCreateImage( cvSize(width,height), 8, bytes ); - } - - unsigned int size = bytes * width * height; - DWORD bcnt; - if (videoSample && SUCCEEDED(videoSample->GetBufferCount(&bcnt)) && bcnt > 0) - { - _ComPtr buf = NULL; - if (SUCCEEDED(videoSample->GetBufferByIndex(0, &buf))) - { - DWORD maxsize, cursize; - BYTE* ptr = NULL; - if (SUCCEEDED(buf->Lock(&ptr, &maxsize, &cursize))) + break; + case CV_CAP_PROP_GAMMA: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) { - if ((unsigned int)cursize == size) - { - memcpy(frame->imageData, ptr, size); - buf->Unlock(); - return frame; - } - buf->Unlock(); + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_Gamma, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); } - } - } - - return NULL; -} + break; + case CV_CAP_PROP_BACKLIGHT: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_BacklightCompensation, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_MONOCHROME: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = value != 0 ? 0 : 1; + HRESULT hr = pProcAmp->Set(VideoProcAmp_ColorEnable, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_TEMPERATURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) + { + long paramVal = (long)value; + HRESULT hr = pProcAmp->Set(VideoProcAmp_WhiteBalance, paramVal, VideoProcAmp_Flags_Manual); + pProcAmp->Release(); + return SUCCEEDED(hr); + } + case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: + case CV_CAP_PROP_WHITE_BALANCE_RED_V: + break; + case CV_CAP_PROP_PAN: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Pan, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_TILT: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Tilt, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_ROLL: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Roll, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_IRIS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Iris, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_EXPOSURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Exposure, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + case CV_CAP_PROP_AUTO_EXPOSURE: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = 0; + HRESULT hr = pProcControl->Set(CameraControl_Exposure, paramVal, value != 0 ? VideoProcAmp_Flags_Auto : VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_ZOOM: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Zoom, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; + case CV_CAP_PROP_FOCUS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = (long)value; + HRESULT hr = pProcControl->Set(CameraControl_Focus, paramVal, VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + case CV_CAP_PROP_AUTOFOCUS: + if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcControl)))) + { + long paramVal = 0; + HRESULT hr = pProcControl->Set(CameraControl_Focus, paramVal, value != 0 ? VideoProcAmp_Flags_Auto : VideoProcAmp_Flags_Manual); + pProcControl->Release(); + return SUCCEEDED(hr); + } + break; -HRESULT CvCaptureFile_MSMF::getSourceDuration(MFTIME *pDuration) const -{ - *pDuration = 0; + case CV_CAP_PROP_RECTIFICATION: + case CV_CAP_PROP_TRIGGER: + case CV_CAP_PROP_TRIGGER_DELAY: + case CV_CAP_PROP_GUID: + case CV_CAP_PROP_ISO_SPEED: + case CV_CAP_PROP_SETTINGS: + case CV_CAP_PROP_BUFFERSIZE: + default: + break; + } - PROPVARIANT var; - HRESULT hr = videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var); - if (SUCCEEDED(hr) && var.vt == VT_I8) - { - *pDuration = var.hVal.QuadPart; - PropVariantClear(&var); - } - return hr; + return false; } CvCapture* cvCreateCameraCapture_MSMF( int index ) { - CvCaptureCAM_MSMF* capture = new CvCaptureCAM_MSMF; + CvCapture_MSMF* capture = new CvCapture_MSMF; try { if( capture->open( index )) @@ -3929,7 +1797,7 @@ CvCapture* cvCreateCameraCapture_MSMF( int index ) CvCapture* cvCreateFileCapture_MSMF (const char* filename) { - CvCaptureFile_MSMF* capture = new CvCaptureFile_MSMF; + CvCapture_MSMF* capture = new CvCapture_MSMF; try { if( capture->open(filename) ) diff --git a/modules/videoio/src/cap_msmf.hpp b/modules/videoio/src/cap_msmf.hpp index 2d48f86d94..e69de29bb2 100644 --- a/modules/videoio/src/cap_msmf.hpp +++ b/modules/videoio/src/cap_msmf.hpp @@ -1,3113 +0,0 @@ -#ifdef WINRT -#define ICustomStreamSink StreamSink -#ifndef __cplusplus_winrt -#include "wrl.h" -#endif -#else -EXTERN_C const IID IID_ICustomStreamSink; - -class DECLSPEC_UUID("4F8A1939-2FD3-46DB-AE70-DB7E0DD79B73") DECLSPEC_NOVTABLE ICustomStreamSink : public IUnknown -{ -public: - virtual HRESULT Initialize() = 0; - virtual HRESULT Shutdown() = 0; - virtual HRESULT Start(MFTIME start) = 0; - virtual HRESULT Pause() = 0; - virtual HRESULT Restart() = 0; - virtual HRESULT Stop() = 0; -}; -#endif - -#define MF_PROP_SAMPLEGRABBERCALLBACK L"samplegrabbercallback" -#define MF_PROP_VIDTYPE L"vidtype" -#define MF_PROP_VIDENCPROPS L"videncprops" - -#include - -// MF_MEDIASINK_SAMPLEGRABBERCALLBACK: {26957AA7-AFF4-464c-BB8B-07BA65CE11DF} -// Type: IUnknown* -DEFINE_GUID(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, - 0x26957aa7, 0xaff4, 0x464c, 0xbb, 0x8b, 0x7, 0xba, 0x65, 0xce, 0x11, 0xdf); - -// {4BD133CC-EB9B-496E-8865-0813BFBC6FAA} -DEFINE_GUID(MF_STREAMSINK_ID, 0x4bd133cc, 0xeb9b, 0x496e, 0x88, 0x65, 0x8, 0x13, 0xbf, 0xbc, 0x6f, 0xaa); - -// {C9E22A8C-6A50-4D78-9183-0834A02A3780} -DEFINE_GUID(MF_STREAMSINK_MEDIASINKINTERFACE, - 0xc9e22a8c, 0x6a50, 0x4d78, 0x91, 0x83, 0x8, 0x34, 0xa0, 0x2a, 0x37, 0x80); - -// {DABD13AB-26B7-47C2-97C1-4B04C187B838} -DEFINE_GUID(MF_MEDIASINK_PREFERREDTYPE, - 0xdabd13ab, 0x26b7, 0x47c2, 0x97, 0xc1, 0x4b, 0x4, 0xc1, 0x87, 0xb8, 0x38); - -#include -#ifdef _UNICODE -#define MAKE_MAP(e) std::map -#define MAKE_ENUM(e) std::pair -#define MAKE_ENUM_PAIR(e, str) std::pair(str, L#str) -#else -#define MAKE_MAP(e) std::map -#define MAKE_ENUM(e) std::pair -#define MAKE_ENUM_PAIR(e, str) std::pair(str, #str) -#endif - -MAKE_ENUM(MediaEventType) MediaEventTypePairs[] = { - MAKE_ENUM_PAIR(MediaEventType, MEUnknown), - MAKE_ENUM_PAIR(MediaEventType, MEError), - MAKE_ENUM_PAIR(MediaEventType, MEExtendedType), - MAKE_ENUM_PAIR(MediaEventType, MENonFatalError), - MAKE_ENUM_PAIR(MediaEventType, MEGenericV1Anchor), - MAKE_ENUM_PAIR(MediaEventType, MESessionUnknown), - MAKE_ENUM_PAIR(MediaEventType, MESessionTopologySet), - MAKE_ENUM_PAIR(MediaEventType, MESessionTopologiesCleared), - MAKE_ENUM_PAIR(MediaEventType, MESessionStarted), - MAKE_ENUM_PAIR(MediaEventType, MESessionPaused), - MAKE_ENUM_PAIR(MediaEventType, MESessionStopped), - MAKE_ENUM_PAIR(MediaEventType, MESessionClosed), - MAKE_ENUM_PAIR(MediaEventType, MESessionEnded), - MAKE_ENUM_PAIR(MediaEventType, MESessionRateChanged), - MAKE_ENUM_PAIR(MediaEventType, MESessionScrubSampleComplete), - MAKE_ENUM_PAIR(MediaEventType, MESessionCapabilitiesChanged), - MAKE_ENUM_PAIR(MediaEventType, MESessionTopologyStatus), - MAKE_ENUM_PAIR(MediaEventType, MESessionNotifyPresentationTime), - MAKE_ENUM_PAIR(MediaEventType, MENewPresentation), - MAKE_ENUM_PAIR(MediaEventType, MELicenseAcquisitionStart), - MAKE_ENUM_PAIR(MediaEventType, MELicenseAcquisitionCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEIndividualizationStart), - MAKE_ENUM_PAIR(MediaEventType, MEIndividualizationCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEEnablerProgress), - MAKE_ENUM_PAIR(MediaEventType, MEEnablerCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEPolicyError), - MAKE_ENUM_PAIR(MediaEventType, MEPolicyReport), - MAKE_ENUM_PAIR(MediaEventType, MEBufferingStarted), - MAKE_ENUM_PAIR(MediaEventType, MEBufferingStopped), - MAKE_ENUM_PAIR(MediaEventType, MEConnectStart), - MAKE_ENUM_PAIR(MediaEventType, MEConnectEnd), - MAKE_ENUM_PAIR(MediaEventType, MEReconnectStart), - MAKE_ENUM_PAIR(MediaEventType, MEReconnectEnd), - MAKE_ENUM_PAIR(MediaEventType, MERendererEvent), - MAKE_ENUM_PAIR(MediaEventType, MESessionStreamSinkFormatChanged), - MAKE_ENUM_PAIR(MediaEventType, MESessionV1Anchor), - MAKE_ENUM_PAIR(MediaEventType, MESourceUnknown), - MAKE_ENUM_PAIR(MediaEventType, MESourceStarted), - MAKE_ENUM_PAIR(MediaEventType, MEStreamStarted), - MAKE_ENUM_PAIR(MediaEventType, MESourceSeeked), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSeeked), - MAKE_ENUM_PAIR(MediaEventType, MENewStream), - MAKE_ENUM_PAIR(MediaEventType, MEUpdatedStream), - MAKE_ENUM_PAIR(MediaEventType, MESourceStopped), - MAKE_ENUM_PAIR(MediaEventType, MEStreamStopped), - MAKE_ENUM_PAIR(MediaEventType, MESourcePaused), - MAKE_ENUM_PAIR(MediaEventType, MEStreamPaused), - MAKE_ENUM_PAIR(MediaEventType, MEEndOfPresentation), - MAKE_ENUM_PAIR(MediaEventType, MEEndOfStream), - MAKE_ENUM_PAIR(MediaEventType, MEMediaSample), - MAKE_ENUM_PAIR(MediaEventType, MEStreamTick), - MAKE_ENUM_PAIR(MediaEventType, MEStreamThinMode), - MAKE_ENUM_PAIR(MediaEventType, MEStreamFormatChanged), - MAKE_ENUM_PAIR(MediaEventType, MESourceRateChanged), - MAKE_ENUM_PAIR(MediaEventType, MEEndOfPresentationSegment), - MAKE_ENUM_PAIR(MediaEventType, MESourceCharacteristicsChanged), - MAKE_ENUM_PAIR(MediaEventType, MESourceRateChangeRequested), - MAKE_ENUM_PAIR(MediaEventType, MESourceMetadataChanged), - MAKE_ENUM_PAIR(MediaEventType, MESequencerSourceTopologyUpdated), - MAKE_ENUM_PAIR(MediaEventType, MESourceV1Anchor), - MAKE_ENUM_PAIR(MediaEventType, MESinkUnknown), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkStarted), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkStopped), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkPaused), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkRateChanged), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkRequestSample), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkMarker), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkPrerolled), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkScrubSampleComplete), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkFormatChanged), - MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkDeviceChanged), - MAKE_ENUM_PAIR(MediaEventType, MEQualityNotify), - MAKE_ENUM_PAIR(MediaEventType, MESinkInvalidated), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionNameChanged), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionVolumeChanged), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionDeviceRemoved), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionServerShutdown), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionGroupingParamChanged), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionIconChanged), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionFormatChanged), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionDisconnected), - MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionExclusiveModeOverride), - MAKE_ENUM_PAIR(MediaEventType, MESinkV1Anchor), -#if (WINVER >= 0x0602) // Available since Win 8 - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionVolumeChanged), - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionDeviceRemoved), - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionFormatChanged), - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionDisconnected), - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionExclusiveModeOverride), - MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionServerShutdown), - MAKE_ENUM_PAIR(MediaEventType, MESinkV2Anchor), -#endif - MAKE_ENUM_PAIR(MediaEventType, METrustUnknown), - MAKE_ENUM_PAIR(MediaEventType, MEPolicyChanged), - MAKE_ENUM_PAIR(MediaEventType, MEContentProtectionMessage), - MAKE_ENUM_PAIR(MediaEventType, MEPolicySet), - MAKE_ENUM_PAIR(MediaEventType, METrustV1Anchor), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseBackupCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseBackupProgress), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseRestoreCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseRestoreProgress), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseAcquisitionCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMIndividualizationCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMIndividualizationProgress), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMProximityCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseStoreCleaned), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMRevocationDownloadCompleted), - MAKE_ENUM_PAIR(MediaEventType, MEWMDRMV1Anchor), - MAKE_ENUM_PAIR(MediaEventType, METransformUnknown), - MAKE_ENUM_PAIR(MediaEventType, METransformNeedInput), - MAKE_ENUM_PAIR(MediaEventType, METransformHaveOutput), - MAKE_ENUM_PAIR(MediaEventType, METransformDrainComplete), - MAKE_ENUM_PAIR(MediaEventType, METransformMarker), -#if (WINVER >= 0x0602) // Available since Win 8 - MAKE_ENUM_PAIR(MediaEventType, MEByteStreamCharacteristicsChanged), - MAKE_ENUM_PAIR(MediaEventType, MEVideoCaptureDeviceRemoved), - MAKE_ENUM_PAIR(MediaEventType, MEVideoCaptureDevicePreempted), -#endif - MAKE_ENUM_PAIR(MediaEventType, MEReservedMax) -}; -MAKE_MAP(MediaEventType) MediaEventTypeMap(MediaEventTypePairs, MediaEventTypePairs + sizeof(MediaEventTypePairs) / sizeof(MediaEventTypePairs[0])); - -MAKE_ENUM(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypePairs[] = { - MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_DEFAULT), - MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_ENDOFSEGMENT), - MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_TICK), - MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_EVENT) -}; -MAKE_MAP(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypeMap(StreamSinkMarkerTypePairs, StreamSinkMarkerTypePairs + sizeof(StreamSinkMarkerTypePairs) / sizeof(StreamSinkMarkerTypePairs[0])); - -#ifdef WINRT - -#ifdef __cplusplus_winrt -#define _ContextCallback Concurrency::details::_ContextCallback -#define BEGIN_CALL_IN_CONTEXT(hr, var, ...) hr = S_OK;\ - var._CallInContext([__VA_ARGS__]() { -#define END_CALL_IN_CONTEXT(hr) if (FAILED(hr)) throw Platform::Exception::CreateException(hr);\ -}); -#define END_CALL_IN_CONTEXT_BASE }); -#else -#define _ContextCallback Concurrency_winrt::details::_ContextCallback -#define BEGIN_CALL_IN_CONTEXT(hr, var, ...) hr = var._CallInContext([__VA_ARGS__]() -> HRESULT { -#define END_CALL_IN_CONTEXT(hr) return hr;\ -}); -#define END_CALL_IN_CONTEXT_BASE return S_OK;\ -}); -#endif -#define GET_CURRENT_CONTEXT _ContextCallback::_CaptureCurrent() -#define SAVE_CURRENT_CONTEXT(var) _ContextCallback var = GET_CURRENT_CONTEXT - -#define COMMA , - -#ifdef __cplusplus_winrt -#define _Object Platform::Object^ -#define _ObjectObj Platform::Object^ -#define _String Platform::String^ -#define _StringObj Platform::String^ -#define _StringReference ref new Platform::String -#define _StringReferenceObj Platform::String^ -#define _DeviceInformationCollection Windows::Devices::Enumeration::DeviceInformationCollection -#define _MediaCapture Windows::Media::Capture::MediaCapture -#define _MediaCaptureVideoPreview Windows::Media::Capture::MediaCapture -#define _MediaCaptureInitializationSettings Windows::Media::Capture::MediaCaptureInitializationSettings -#define _VideoDeviceController Windows::Media::Devices::VideoDeviceController -#define _MediaDeviceController Windows::Media::Devices::VideoDeviceController -#define _MediaEncodingProperties Windows::Media::MediaProperties::IMediaEncodingProperties -#define _VideoEncodingProperties Windows::Media::MediaProperties::VideoEncodingProperties -#define _MediaStreamType Windows::Media::Capture::MediaStreamType -#define _AsyncInfo Windows::Foundation::IAsyncInfo -#define _AsyncAction Windows::Foundation::IAsyncAction -#define _AsyncOperation Windows::Foundation::IAsyncOperation -#define _DeviceClass Windows::Devices::Enumeration::DeviceClass -#define _IDeviceInformation Windows::Devices::Enumeration::DeviceInformation -#define _DeviceInformation Windows::Devices::Enumeration::DeviceInformation -#define _DeviceInformationStatics Windows::Devices::Enumeration::DeviceInformation -#define _MediaEncodingProfile Windows::Media::MediaProperties::MediaEncodingProfile -#define _StreamingCaptureMode Windows::Media::Capture::StreamingCaptureMode -#define _PropertySet Windows::Foundation::Collections::PropertySet -#define _Map Windows::Foundation::Collections::PropertySet -#define _PropertyValueStatics Windows::Foundation::PropertyValue -#define _VectorView Windows::Foundation::Collections::IVectorView -#define _StartPreviewToCustomSinkIdAsync StartPreviewToCustomSinkAsync -#define _InitializeWithSettingsAsync InitializeAsync -#define _FindAllAsyncDeviceClass FindAllAsync -#define _MediaExtension Windows::Media::IMediaExtension -#define BEGIN_CREATE_ASYNC(type, ...) (Concurrency::create_async([__VA_ARGS__]() { -#define END_CREATE_ASYNC(hr) if (FAILED(hr)) throw Platform::Exception::CreateException(hr);\ -})) -#define DEFINE_TASK Concurrency::task -#define CREATE_TASK Concurrency::create_task -#define CREATE_OR_CONTINUE_TASK(_task, rettype, func) _task = (_task == Concurrency::task()) ? Concurrency::create_task(func) : _task.then([func](rettype) -> rettype { return func(); }); -#define DEFINE_RET_VAL(x) -#define DEFINE_RET_TYPE(x) -#define DEFINE_RET_FORMAL(x) x -#define RET_VAL(x) return x; -#define RET_VAL_BASE -#define MAKE_STRING(str) str -#define GET_STL_STRING(str) std::wstring(str->Data()) -#define GET_STL_STRING_RAW(str) std::wstring(str->Data()) -#define MAKE_WRL_OBJ(x) x^ -#define MAKE_WRL_REF(x) x^ -#define MAKE_OBJ_REF(x) x^ -#define MAKE_WRL_AGILE_REF(x) Platform::Agile -#define MAKE_PROPERTY_BACKING(Type, PropName) property Type PropName; -#define MAKE_PROPERTY(Type, PropName, PropValue) -#define MAKE_PROPERTY_STRING(Type, PropName, PropValue) -#define MAKE_READONLY_PROPERTY(Type, PropName, PropValue) property Type PropName\ -{\ - Type get() { return PropValue; }\ -} -#define THROW_INVALID_ARG throw ref new Platform::InvalidArgumentException(); -#define RELEASE_AGILE_WRL(x) x = nullptr; -#define RELEASE_WRL(x) x = nullptr; -#define GET_WRL_OBJ_FROM_REF(objtype, obj, orig, hr) objtype^ obj = orig;\ -hr = S_OK; -#define GET_WRL_OBJ_FROM_OBJ(objtype, obj, orig, hr) objtype^ obj = safe_cast(orig);\ -hr = S_OK; -#define WRL_ENUM_GET(obj, prefix, prop) obj::##prop -#define WRL_PROP_GET(obj, prop, arg, hr) arg = obj->##prop;\ -hr = S_OK; -#define WRL_PROP_PUT(obj, prop, arg, hr) obj->##prop = arg;\ -hr = S_OK; -#define WRL_METHOD_BASE(obj, method, ret, hr) ret = obj->##method();\ -hr = S_OK; -#define WRL_METHOD(obj, method, ret, hr, ...) ret = obj->##method(__VA_ARGS__);\ -hr = S_OK; -#define WRL_METHOD_NORET_BASE(obj, method, hr) obj->##method();\ - hr = S_OK; -#define WRL_METHOD_NORET(obj, method, hr, ...) obj->##method(__VA_ARGS__);\ - hr = S_OK; -#define REF_WRL_OBJ(obj) &obj -#define DEREF_WRL_OBJ(obj) obj -#define DEREF_AGILE_WRL_OBJ(obj) obj.Get() -#define DEREF_AS_NATIVE_WRL_OBJ(type, obj) reinterpret_cast(obj) -#define PREPARE_TRANSFER_WRL_OBJ(obj) obj -#define ACTIVATE_LOCAL_OBJ_BASE(objtype) ref new objtype() -#define ACTIVATE_LOCAL_OBJ(objtype, ...) ref new objtype(__VA_ARGS__) -#define ACTIVATE_EVENT_HANDLER(objtype, ...) ref new objtype(__VA_ARGS__) -#define ACTIVATE_OBJ(rtclass, objtype, obj, hr) MAKE_WRL_OBJ(objtype) obj = ref new objtype();\ -hr = S_OK; -#define ACTIVATE_STATIC_OBJ(rtclass, objtype, obj, hr) objtype obj;\ -hr = S_OK; -#else -#define _Object IInspectable* -#define _ObjectObj Microsoft::WRL::ComPtr -#define _String HSTRING -#define _StringObj Microsoft::WRL::Wrappers::HString -#define _StringReference Microsoft::WRL::Wrappers::HStringReference -#define _StringReferenceObj Microsoft::WRL::Wrappers::HStringReference -#define _DeviceInformationCollection ABI::Windows::Devices::Enumeration::DeviceInformationCollection -#define _MediaCapture ABI::Windows::Media::Capture::IMediaCapture -#define _MediaCaptureVideoPreview ABI::Windows::Media::Capture::IMediaCaptureVideoPreview -#define _MediaCaptureInitializationSettings ABI::Windows::Media::Capture::IMediaCaptureInitializationSettings -#define _VideoDeviceController ABI::Windows::Media::Devices::IVideoDeviceController -#define _MediaDeviceController ABI::Windows::Media::Devices::IMediaDeviceController -#define _MediaEncodingProperties ABI::Windows::Media::MediaProperties::IMediaEncodingProperties -#define _VideoEncodingProperties ABI::Windows::Media::MediaProperties::IVideoEncodingProperties -#define _MediaStreamType ABI::Windows::Media::Capture::MediaStreamType -#define _AsyncInfo ABI::Windows::Foundation::IAsyncInfo -#define _AsyncAction ABI::Windows::Foundation::IAsyncAction -#define _AsyncOperation ABI::Windows::Foundation::IAsyncOperation -#define _DeviceClass ABI::Windows::Devices::Enumeration::DeviceClass -#define _IDeviceInformation ABI::Windows::Devices::Enumeration::IDeviceInformation -#define _DeviceInformation ABI::Windows::Devices::Enumeration::DeviceInformation -#define _DeviceInformationStatics ABI::Windows::Devices::Enumeration::IDeviceInformationStatics -#define _MediaEncodingProfile ABI::Windows::Media::MediaProperties::IMediaEncodingProfile -#define _StreamingCaptureMode ABI::Windows::Media::Capture::StreamingCaptureMode -#define _PropertySet ABI::Windows::Foundation::Collections::IPropertySet -#define _Map ABI::Windows::Foundation::Collections::IMap -#define _PropertyValueStatics ABI::Windows::Foundation::IPropertyValueStatics -#define _VectorView ABI::Windows::Foundation::Collections::IVectorView -#define _StartPreviewToCustomSinkIdAsync StartPreviewToCustomSinkIdAsync -#define _InitializeWithSettingsAsync InitializeWithSettingsAsync -#define _FindAllAsyncDeviceClass FindAllAsyncDeviceClass -#define _MediaExtension ABI::Windows::Media::IMediaExtension -#define BEGIN_CREATE_ASYNC(type, ...) Concurrency_winrt::create_async([__VA_ARGS__]() -> HRESULT { -#define END_CREATE_ASYNC(hr) return hr;\ -}) -#define DEFINE_TASK Concurrency_winrt::task -#define CREATE_TASK Concurrency_winrt::create_task -#define CREATE_OR_CONTINUE_TASK(_task, rettype, func) _task = (_task == Concurrency_winrt::task()) ? Concurrency_winrt::create_task(func) : _task.then([func](rettype, rettype* retVal) -> HRESULT { return func(retVal); }); -#define DEFINE_RET_VAL(x) x* retVal -#define DEFINE_RET_TYPE(x) -#define DEFINE_RET_FORMAL(x) HRESULT -#define RET_VAL(x) *retVal = x;\ -return S_OK; -#define RET_VAL_BASE return S_OK; -#define MAKE_STRING(str) Microsoft::WRL::Wrappers::HStringReference(L##str) -#define GET_STL_STRING(str) std::wstring(str.GetRawBuffer(NULL)) -#define GET_STL_STRING_RAW(str) WindowsGetStringRawBuffer(str, NULL) -#define MAKE_WRL_OBJ(x) Microsoft::WRL::ComPtr -#define MAKE_WRL_REF(x) x* -#define MAKE_OBJ_REF(x) x -#define MAKE_WRL_AGILE_REF(x) x* -#define MAKE_PROPERTY_BACKING(Type, PropName) Type PropName; -#define MAKE_PROPERTY(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { *pVal = PropValue; } else { return E_INVALIDARG; } return S_OK; }\ - STDMETHODIMP put_##PropName(Type Val) { PropValue = Val; return S_OK; } -#define MAKE_PROPERTY_STRING(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { return ::WindowsDuplicateString(PropValue.Get(), pVal); } else { return E_INVALIDARG; } }\ - STDMETHODIMP put_##PropName(Type Val) { return PropValue.Set(Val); } -#define MAKE_READONLY_PROPERTY(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { *pVal = PropValue; } else { return E_INVALIDARG; } return S_OK; } -#define THROW_INVALID_ARG RoOriginateError(E_INVALIDARG, nullptr); -#define RELEASE_AGILE_WRL(x) if (x) { (x)->Release(); x = nullptr; } -#define RELEASE_WRL(x) if (x) { (x)->Release(); x = nullptr; } -#define GET_WRL_OBJ_FROM_REF(objtype, obj, orig, hr) Microsoft::WRL::ComPtr obj;\ -hr = orig->QueryInterface(__uuidof(objtype), &obj); -#define GET_WRL_OBJ_FROM_OBJ(objtype, obj, orig, hr) Microsoft::WRL::ComPtr obj;\ -hr = orig.As(&obj); -#define WRL_ENUM_GET(obj, prefix, prop) obj::prefix##_##prop -#define WRL_PROP_GET(obj, prop, arg, hr) hr = obj->get_##prop(&arg); -#define WRL_PROP_PUT(obj, prop, arg, hr) hr = obj->put_##prop(arg); -#define WRL_METHOD_BASE(obj, method, ret, hr) hr = obj->##method(&ret); -#define WRL_METHOD(obj, method, ret, hr, ...) hr = obj->##method(__VA_ARGS__, &ret); -#define WRL_METHOD_NORET_BASE(obj, method, hr) hr = obj->##method(); -#define REF_WRL_OBJ(obj) obj.GetAddressOf() -#define DEREF_WRL_OBJ(obj) obj.Get() -#define DEREF_AGILE_WRL_OBJ(obj) obj -#define DEREF_AS_NATIVE_WRL_OBJ(type, obj) obj.Get() -#define PREPARE_TRANSFER_WRL_OBJ(obj) obj.Detach() -#define ACTIVATE_LOCAL_OBJ_BASE(objtype) Microsoft::WRL::Make() -#define ACTIVATE_LOCAL_OBJ(objtype, ...) Microsoft::WRL::Make(__VA_ARGS__) -#define ACTIVATE_EVENT_HANDLER(objtype, ...) Microsoft::WRL::Callback(__VA_ARGS__).Get() -#define ACTIVATE_OBJ(rtclass, objtype, obj, hr) MAKE_WRL_OBJ(objtype) obj;\ -{\ - Microsoft::WRL::ComPtr objFactory;\ - hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(rtclass).Get(), objFactory.ReleaseAndGetAddressOf());\ - if (SUCCEEDED(hr)) {\ - Microsoft::WRL::ComPtr pInsp;\ - hr = objFactory->ActivateInstance(pInsp.GetAddressOf());\ - if (SUCCEEDED(hr)) hr = pInsp.As(&obj);\ - }\ -} -#define ACTIVATE_STATIC_OBJ(rtclass, objtype, obj, hr) objtype obj;\ -{\ - Microsoft::WRL::ComPtr objFactory;\ - hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(rtclass).Get(), objFactory.ReleaseAndGetAddressOf());\ - if (SUCCEEDED(hr)) {\ - if (SUCCEEDED(hr)) hr = objFactory.As(&obj);\ - }\ -} -#endif - -#define _ComPtr Microsoft::WRL::ComPtr -#else - -#define _COM_SMARTPTR_DECLARE(T,var) T ## Ptr var - -template -class ComPtr -{ -public: - ComPtr() throw() - { - } - ComPtr(T* lp) throw() - { - p = lp; - } - ComPtr(_In_ const ComPtr& lp) throw() - { - p = lp.p; - } - virtual ~ComPtr() - { - } - - T** operator&() throw() - { - assert(p == NULL); - return p.operator&(); - } - T* operator->() const throw() - { - assert(p != NULL); - return p.operator->(); - } - bool operator!() const throw() - { - return p.operator==(NULL); - } - bool operator==(_In_opt_ T* pT) const throw() - { - return p.operator==(pT); - } - bool operator!=(_In_opt_ T* pT) const throw() - { - return p.operator!=(pT); - } - operator bool() - { - return p.operator!=(NULL); - } - - T* const* GetAddressOf() const throw() - { - return &p; - } - - T** GetAddressOf() throw() - { - return &p; - } - - T** ReleaseAndGetAddressOf() throw() - { - p.Release(); - return &p; - } - - T* Get() const throw() - { - return p; - } - - // Attach to an existing interface (does not AddRef) - void Attach(_In_opt_ T* p2) throw() - { - p.Attach(p2); - } - // Detach the interface (does not Release) - T* Detach() throw() - { - return p.Detach(); - } - _Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT) throw() - { - assert(ppT != NULL); - if (ppT == NULL) - return E_POINTER; - *ppT = p; - if (p != NULL) - p->AddRef(); - return S_OK; - } - - void Reset() - { - p.Release(); - } - - // query for U interface - template - HRESULT As(_Inout_ U** lp) const throw() - { - return p->QueryInterface(__uuidof(U), reinterpret_cast(lp)); - } - // query for U interface - template - HRESULT As(_Out_ ComPtr* lp) const throw() - { - return p->QueryInterface(__uuidof(U), reinterpret_cast(lp->ReleaseAndGetAddressOf())); - } -private: - _COM_SMARTPTR_TYPEDEF(T, __uuidof(T)); - _COM_SMARTPTR_DECLARE(T, p); -}; - -#define _ComPtr ComPtr -#endif - -template -class CBaseAttributes : public TBase -{ -protected: - // This version of the constructor does not initialize the - // attribute store. The derived class must call Initialize() in - // its own constructor. - CBaseAttributes() - { - } - - // This version of the constructor initializes the attribute - // store, but the derived class must pass an HRESULT parameter - // to the constructor. - - CBaseAttributes(HRESULT& hr, UINT32 cInitialSize = 0) - { - hr = Initialize(cInitialSize); - } - - // The next version of the constructor uses a caller-provided - // implementation of IMFAttributes. - - // (Sometimes you want to delegate IMFAttributes calls to some - // other object that implements IMFAttributes, rather than using - // MFCreateAttributes.) - - CBaseAttributes(HRESULT& hr, IUnknown *pUnk) - { - hr = Initialize(pUnk); - } - - virtual ~CBaseAttributes() - { - } - - // Initializes the object by creating the standard Media Foundation attribute store. - HRESULT Initialize(UINT32 cInitialSize = 0) - { - if (_spAttributes.Get() == nullptr) - { - return MFCreateAttributes(&_spAttributes, cInitialSize); - } - else - { - return S_OK; - } - } - - // Initializes this object from a caller-provided attribute store. - // pUnk: Pointer to an object that exposes IMFAttributes. - HRESULT Initialize(IUnknown *pUnk) - { - if (_spAttributes) - { - _spAttributes.Reset(); - _spAttributes = nullptr; - } - - - return pUnk->QueryInterface(IID_PPV_ARGS(&_spAttributes)); - } - -public: - - // IMFAttributes methods - - STDMETHODIMP GetItem(REFGUID guidKey, PROPVARIANT* pValue) - { - assert(_spAttributes); - return _spAttributes->GetItem(guidKey, pValue); - } - - STDMETHODIMP GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType) - { - assert(_spAttributes); - return _spAttributes->GetItemType(guidKey, pType); - } - - STDMETHODIMP CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult) - { - assert(_spAttributes); - return _spAttributes->CompareItem(guidKey, Value, pbResult); - } - - STDMETHODIMP Compare( - IMFAttributes* pTheirs, - MF_ATTRIBUTES_MATCH_TYPE MatchType, - BOOL* pbResult - ) - { - assert(_spAttributes); - return _spAttributes->Compare(pTheirs, MatchType, pbResult); - } - - STDMETHODIMP GetUINT32(REFGUID guidKey, UINT32* punValue) - { - assert(_spAttributes); - return _spAttributes->GetUINT32(guidKey, punValue); - } - - STDMETHODIMP GetUINT64(REFGUID guidKey, UINT64* punValue) - { - assert(_spAttributes); - return _spAttributes->GetUINT64(guidKey, punValue); - } - - STDMETHODIMP GetDouble(REFGUID guidKey, double* pfValue) - { - assert(_spAttributes); - return _spAttributes->GetDouble(guidKey, pfValue); - } - - STDMETHODIMP GetGUID(REFGUID guidKey, GUID* pguidValue) - { - assert(_spAttributes); - return _spAttributes->GetGUID(guidKey, pguidValue); - } - - STDMETHODIMP GetStringLength(REFGUID guidKey, UINT32* pcchLength) - { - assert(_spAttributes); - return _spAttributes->GetStringLength(guidKey, pcchLength); - } - - STDMETHODIMP GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength) - { - assert(_spAttributes); - return _spAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength); - } - - STDMETHODIMP GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength) - { - assert(_spAttributes); - return _spAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength); - } - - STDMETHODIMP GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize) - { - assert(_spAttributes); - return _spAttributes->GetBlobSize(guidKey, pcbBlobSize); - } - - STDMETHODIMP GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize) - { - assert(_spAttributes); - return _spAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize); - } - - STDMETHODIMP GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize) - { - assert(_spAttributes); - return _spAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize); - } - - STDMETHODIMP GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv) - { - assert(_spAttributes); - return _spAttributes->GetUnknown(guidKey, riid, ppv); - } - - STDMETHODIMP SetItem(REFGUID guidKey, REFPROPVARIANT Value) - { - assert(_spAttributes); - return _spAttributes->SetItem(guidKey, Value); - } - - STDMETHODIMP DeleteItem(REFGUID guidKey) - { - assert(_spAttributes); - return _spAttributes->DeleteItem(guidKey); - } - - STDMETHODIMP DeleteAllItems() - { - assert(_spAttributes); - return _spAttributes->DeleteAllItems(); - } - - STDMETHODIMP SetUINT32(REFGUID guidKey, UINT32 unValue) - { - assert(_spAttributes); - return _spAttributes->SetUINT32(guidKey, unValue); - } - - STDMETHODIMP SetUINT64(REFGUID guidKey,UINT64 unValue) - { - assert(_spAttributes); - return _spAttributes->SetUINT64(guidKey, unValue); - } - - STDMETHODIMP SetDouble(REFGUID guidKey, double fValue) - { - assert(_spAttributes); - return _spAttributes->SetDouble(guidKey, fValue); - } - - STDMETHODIMP SetGUID(REFGUID guidKey, REFGUID guidValue) - { - assert(_spAttributes); - return _spAttributes->SetGUID(guidKey, guidValue); - } - - STDMETHODIMP SetString(REFGUID guidKey, LPCWSTR wszValue) - { - assert(_spAttributes); - return _spAttributes->SetString(guidKey, wszValue); - } - - STDMETHODIMP SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize) - { - assert(_spAttributes); - return _spAttributes->SetBlob(guidKey, pBuf, cbBufSize); - } - - STDMETHODIMP SetUnknown(REFGUID guidKey, IUnknown* pUnknown) - { - assert(_spAttributes); - return _spAttributes->SetUnknown(guidKey, pUnknown); - } - - STDMETHODIMP LockStore() - { - assert(_spAttributes); - return _spAttributes->LockStore(); - } - - STDMETHODIMP UnlockStore() - { - assert(_spAttributes); - return _spAttributes->UnlockStore(); - } - - STDMETHODIMP GetCount(UINT32* pcItems) - { - assert(_spAttributes); - return _spAttributes->GetCount(pcItems); - } - - STDMETHODIMP GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue) - { - assert(_spAttributes); - return _spAttributes->GetItemByIndex(unIndex, pguidKey, pValue); - } - - STDMETHODIMP CopyAllItems(IMFAttributes* pDest) - { - assert(_spAttributes); - return _spAttributes->CopyAllItems(pDest); - } - - // Helper functions - - HRESULT SerializeToStream(DWORD dwOptions, IStream* pStm) - // dwOptions: Flags from MF_ATTRIBUTE_SERIALIZE_OPTIONS - { - assert(_spAttributes); - return MFSerializeAttributesToStream(_spAttributes.Get(), dwOptions, pStm); - } - - HRESULT DeserializeFromStream(DWORD dwOptions, IStream* pStm) - { - assert(_spAttributes); - return MFDeserializeAttributesFromStream(_spAttributes.Get(), dwOptions, pStm); - } - - // SerializeToBlob: Stores the attributes in a byte array. - // - // ppBuf: Receives a pointer to the byte array. - // pcbSize: Receives the size of the byte array. - // - // The caller must free the array using CoTaskMemFree. - HRESULT SerializeToBlob(UINT8 **ppBuffer, UINT *pcbSize) - { - assert(_spAttributes); - - if (ppBuffer == NULL) - { - return E_POINTER; - } - if (pcbSize == NULL) - { - return E_POINTER; - } - - HRESULT hr = S_OK; - UINT32 cbSize = 0; - BYTE *pBuffer = NULL; - - CHECK_HR(hr = MFGetAttributesAsBlobSize(_spAttributes.Get(), &cbSize)); - - pBuffer = (BYTE*)CoTaskMemAlloc(cbSize); - if (pBuffer == NULL) - { - CHECK_HR(hr = E_OUTOFMEMORY); - } - - CHECK_HR(hr = MFGetAttributesAsBlob(_spAttributes.Get(), pBuffer, cbSize)); - - *ppBuffer = pBuffer; - *pcbSize = cbSize; - -done: - if (FAILED(hr)) - { - *ppBuffer = NULL; - *pcbSize = 0; - CoTaskMemFree(pBuffer); - } - return hr; - } - - HRESULT DeserializeFromBlob(const UINT8* pBuffer, UINT cbSize) - { - assert(_spAttributes); - return MFInitAttributesFromBlob(_spAttributes.Get(), pBuffer, cbSize); - } - - HRESULT GetRatio(REFGUID guidKey, UINT32* pnNumerator, UINT32* punDenominator) - { - assert(_spAttributes); - return MFGetAttributeRatio(_spAttributes.Get(), guidKey, pnNumerator, punDenominator); - } - - HRESULT SetRatio(REFGUID guidKey, UINT32 unNumerator, UINT32 unDenominator) - { - assert(_spAttributes); - return MFSetAttributeRatio(_spAttributes.Get(), guidKey, unNumerator, unDenominator); - } - - // Gets an attribute whose value represents the size of something (eg a video frame). - HRESULT GetSize(REFGUID guidKey, UINT32* punWidth, UINT32* punHeight) - { - assert(_spAttributes); - return MFGetAttributeSize(_spAttributes.Get(), guidKey, punWidth, punHeight); - } - - // Sets an attribute whose value represents the size of something (eg a video frame). - HRESULT SetSize(REFGUID guidKey, UINT32 unWidth, UINT32 unHeight) - { - assert(_spAttributes); - return MFSetAttributeSize (_spAttributes.Get(), guidKey, unWidth, unHeight); - } - -protected: - _ComPtr _spAttributes; -}; - -class StreamSink : -#ifdef WINRT - public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::ClassicCom>, - IMFStreamSink, - IMFMediaEventGenerator, - IMFMediaTypeHandler, - CBaseAttributes<> > -#else - public IMFStreamSink, - public IMFMediaTypeHandler, - public CBaseAttributes<>, - public ICustomStreamSink -#endif -{ -public: - // IUnknown methods -#if defined(_MSC_VER) && _MSC_VER >= 1700 // '_Outptr_result_nullonfailure_' SAL is avaialable since VS 2012 - STDMETHOD(QueryInterface)(REFIID riid, _Outptr_result_nullonfailure_ void **ppv) -#else - STDMETHOD(QueryInterface)(REFIID riid, void **ppv) -#endif - { - if (ppv == nullptr) { - return E_POINTER; - } - (*ppv) = nullptr; - HRESULT hr = S_OK; - if (riid == IID_IMarshal) { - return MarshalQI(riid, ppv); - } else { -#ifdef WINRT - hr = RuntimeClassT::QueryInterface(riid, ppv); -#else - if (riid == IID_IUnknown || riid == IID_IMFStreamSink) { - *ppv = static_cast(this); - AddRef(); - } else if (riid == IID_IMFMediaEventGenerator) { - *ppv = static_cast(this); - AddRef(); - } else if (riid == IID_IMFMediaTypeHandler) { - *ppv = static_cast(this); - AddRef(); - } else if (riid == IID_IMFAttributes) { - *ppv = static_cast(this); - AddRef(); - } else if (riid == IID_ICustomStreamSink) { - *ppv = static_cast(this); - AddRef(); - } else - hr = E_NOINTERFACE; -#endif - } - - return hr; - } - -#ifdef WINRT - STDMETHOD(RuntimeClassInitialize)() { return S_OK; } -#else - ULONG STDMETHODCALLTYPE AddRef() - { - return InterlockedIncrement(&m_cRef); - } - ULONG STDMETHODCALLTYPE Release() - { - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) - { - delete this; - } - return cRef; - } -#endif - HRESULT MarshalQI(REFIID riid, LPVOID* ppv) - { - HRESULT hr = S_OK; - if (m_spFTM == nullptr) { - EnterCriticalSection(&m_critSec); - if (m_spFTM == nullptr) { - hr = CoCreateFreeThreadedMarshaler((IMFStreamSink*)this, &m_spFTM); - } - LeaveCriticalSection(&m_critSec); - } - - if (SUCCEEDED(hr)) { - if (m_spFTM == nullptr) { - hr = E_UNEXPECTED; - } - else { - hr = m_spFTM.Get()->QueryInterface(riid, ppv); - } - } - return hr; - } - enum State - { - State_TypeNotSet = 0, // No media type is set - State_Ready, // Media type is set, Start has never been called. - State_Started, - State_Stopped, - State_Paused, - State_Count // Number of states - }; - StreamSink() : m_IsShutdown(false), - m_StartTime(0), m_fGetStartTimeFromSample(false), m_fWaitingForFirstSample(false), - m_state(State_TypeNotSet), m_pParent(nullptr), - m_imageWidthInPixels(0), m_imageHeightInPixels(0) { -#ifdef WINRT - m_token.value = 0; -#else - m_bConnected = false; -#endif - InitializeCriticalSectionEx(&m_critSec, 3000, 0); - ZeroMemory(&m_guiCurrentSubtype, sizeof(m_guiCurrentSubtype)); - CBaseAttributes::Initialize(0U); - DebugPrintOut(L"StreamSink::StreamSink\n"); - } - virtual ~StreamSink() { - DeleteCriticalSection(&m_critSec); - assert(m_IsShutdown); - DebugPrintOut(L"StreamSink::~StreamSink\n"); - } - - HRESULT Initialize() - { - HRESULT hr; - // Create the event queue helper. - hr = MFCreateEventQueue(&m_spEventQueue); - if (SUCCEEDED(hr)) - { - _ComPtr pMedSink; - hr = CBaseAttributes<>::GetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, __uuidof(IMFMediaSink), (LPVOID*)pMedSink.GetAddressOf()); - assert(pMedSink.Get() != NULL); - if (SUCCEEDED(hr)) { - hr = pMedSink.Get()->QueryInterface(IID_PPV_ARGS(&m_pParent)); - } - } - return hr; - } - - HRESULT CheckShutdown() const - { - if (m_IsShutdown) - { - return MF_E_SHUTDOWN; - } - else - { - return S_OK; - } - } - // Called when the presentation clock starts. - HRESULT Start(MFTIME start) - { - HRESULT hr = S_OK; - EnterCriticalSection(&m_critSec); - if (m_state != State_TypeNotSet) { - if (start != PRESENTATION_CURRENT_POSITION) - { - m_StartTime = start; // Cache the start time. - m_fGetStartTimeFromSample = false; - } - else - { - m_fGetStartTimeFromSample = true; - } - m_state = State_Started; - GUID guiMajorType; - m_fWaitingForFirstSample = SUCCEEDED(m_spCurrentType->GetMajorType(&guiMajorType)) && (guiMajorType == MFMediaType_Video); - hr = QueueEvent(MEStreamSinkStarted, GUID_NULL, hr, NULL); - if (SUCCEEDED(hr)) { - hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, hr, NULL); - } - } - else hr = MF_E_NOT_INITIALIZED; - LeaveCriticalSection(&m_critSec); - return hr; - } - - // Called when the presentation clock pauses. - HRESULT Pause() - { - EnterCriticalSection(&m_critSec); - - HRESULT hr = S_OK; - - if (m_state != State_Stopped && m_state != State_TypeNotSet) { - m_state = State_Paused; - hr = QueueEvent(MEStreamSinkPaused, GUID_NULL, hr, NULL); - } else if (hr == State_TypeNotSet) - hr = MF_E_NOT_INITIALIZED; - else - hr = MF_E_INVALIDREQUEST; - LeaveCriticalSection(&m_critSec); - return hr; - } - // Called when the presentation clock restarts. - HRESULT Restart() - { - EnterCriticalSection(&m_critSec); - - HRESULT hr = S_OK; - - if (m_state == State_Paused) { - m_state = State_Started; - hr = QueueEvent(MEStreamSinkStarted, GUID_NULL, hr, NULL); - if (SUCCEEDED(hr)) { - hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, hr, NULL); - } - } else if (hr == State_TypeNotSet) - hr = MF_E_NOT_INITIALIZED; - else - hr = MF_E_INVALIDREQUEST; - LeaveCriticalSection(&m_critSec); - return hr; - } - // Called when the presentation clock stops. - HRESULT Stop() - { - EnterCriticalSection(&m_critSec); - - HRESULT hr = S_OK; - if (m_state != State_TypeNotSet) { - m_state = State_Stopped; - hr = QueueEvent(MEStreamSinkStopped, GUID_NULL, hr, NULL); - } - else hr = MF_E_NOT_INITIALIZED; - LeaveCriticalSection(&m_critSec); - return hr; - } - - // Shuts down the stream sink. - HRESULT Shutdown() - { - _ComPtr pSampleCallback; - HRESULT hr = S_OK; - assert(!m_IsShutdown); - hr = m_pParent->GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - if (SUCCEEDED(hr)) { - hr = pSampleCallback->OnShutdown(); - } - - if (m_spEventQueue) { - hr = m_spEventQueue->Shutdown(); - } - if (m_pParent) - m_pParent->Release(); - m_spCurrentType.Reset(); - m_IsShutdown = TRUE; - - return hr; - } - - //IMFStreamSink - HRESULT STDMETHODCALLTYPE GetMediaSink( - /* [out] */ __RPC__deref_out_opt IMFMediaSink **ppMediaSink) { - if (ppMediaSink == NULL) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - _ComPtr pMedSink; - hr = CBaseAttributes<>::GetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, __uuidof(IMFMediaSink), (LPVOID*)pMedSink.GetAddressOf()); - if (SUCCEEDED(hr)) { - *ppMediaSink = pMedSink.Detach(); - } - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetMediaSink: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetIdentifier( - /* [out] */ __RPC__out DWORD *pdwIdentifier) { - if (pdwIdentifier == NULL) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = GetUINT32(MF_STREAMSINK_ID, (UINT32*)pdwIdentifier); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetIdentifier: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetMediaTypeHandler( - /* [out] */ __RPC__deref_out_opt IMFMediaTypeHandler **ppHandler) { - if (ppHandler == NULL) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - // This stream object acts as its own type handler, so we QI ourselves. - if (SUCCEEDED(hr)) - { - hr = QueryInterface(IID_IMFMediaTypeHandler, (void**)ppHandler); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetMediaTypeHandler: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE ProcessSample(IMFSample *pSample) { - _ComPtr pInput; - _ComPtr pSampleCallback; - BYTE *pSrc = NULL; // Source buffer. - // Stride if the buffer does not support IMF2DBuffer - LONGLONG hnsTime = 0; - LONGLONG hnsDuration = 0; - DWORD cbMaxLength; - DWORD cbCurrentLength = 0; - GUID guidMajorType; - if (pSample == NULL) - { - return E_INVALIDARG; - } - HRESULT hr = S_OK; - - EnterCriticalSection(&m_critSec); - - if (m_state != State_Started && m_state != State_Paused) { - if (m_state == State_TypeNotSet) - hr = MF_E_NOT_INITIALIZED; - else - hr = MF_E_INVALIDREQUEST; - } - if (SUCCEEDED(hr)) - hr = CheckShutdown(); - if (SUCCEEDED(hr)) { - hr = pSample->ConvertToContiguousBuffer(&pInput); - if (SUCCEEDED(hr)) { - hr = pSample->GetSampleTime(&hnsTime); - } - if (SUCCEEDED(hr)) { - hr = pSample->GetSampleDuration(&hnsDuration); - } - if (SUCCEEDED(hr)) { - hr = GetMajorType(&guidMajorType); - } - if (SUCCEEDED(hr)) { - hr = m_pParent->GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - } - if (SUCCEEDED(hr)) { - hr = pInput->Lock(&pSrc, &cbMaxLength, &cbCurrentLength); - } - if (SUCCEEDED(hr)) { - hr = pSampleCallback->OnProcessSample(guidMajorType, 0, hnsTime, hnsDuration, pSrc, cbCurrentLength); - pInput->Unlock(); - } - if (SUCCEEDED(hr)) { - hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL); - } - } - LeaveCriticalSection(&m_critSec); - return hr; - } - - HRESULT STDMETHODCALLTYPE PlaceMarker( - /* [in] */ MFSTREAMSINK_MARKER_TYPE eMarkerType, - /* [in] */ __RPC__in const PROPVARIANT * /*pvarMarkerValue*/, - /* [in] */ __RPC__in const PROPVARIANT * /*pvarContextValue*/) { - eMarkerType; - EnterCriticalSection(&m_critSec); - - HRESULT hr = S_OK; - if (m_state == State_TypeNotSet) - hr = MF_E_NOT_INITIALIZED; - - if (SUCCEEDED(hr)) - hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - //at shutdown will receive MFSTREAMSINK_MARKER_ENDOFSEGMENT - hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::PlaceMarker: HRESULT=%i %s\n", hr, StreamSinkMarkerTypeMap.at(eMarkerType).c_str()); - return hr; - } - - HRESULT STDMETHODCALLTYPE Flush(void) { - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::Flush: HRESULT=%i\n", hr); - return hr; - } - - //IMFMediaEventGenerator - HRESULT STDMETHODCALLTYPE GetEvent( - DWORD dwFlags, IMFMediaEvent **ppEvent) { - // NOTE: - // GetEvent can block indefinitely, so we don't hold the lock. - // This requires some juggling with the event queue pointer. - - HRESULT hr = S_OK; - - _ComPtr pQueue; - - { - EnterCriticalSection(&m_critSec); - - // Check shutdown - hr = CheckShutdown(); - - // Get the pointer to the event queue. - if (SUCCEEDED(hr)) - { - pQueue = m_spEventQueue.Get(); - } - LeaveCriticalSection(&m_critSec); - } - - // Now get the event. - if (SUCCEEDED(hr)) - { - hr = pQueue->GetEvent(dwFlags, ppEvent); - } - MediaEventType meType = MEUnknown; - if (SUCCEEDED(hr) && SUCCEEDED((*ppEvent)->GetType(&meType)) && meType == MEStreamSinkStopped) { - } - HRESULT hrStatus = S_OK; - if (SUCCEEDED(hr)) - hr = (*ppEvent)->GetStatus(&hrStatus); - if (SUCCEEDED(hr)) - DebugPrintOut(L"StreamSink::GetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str()); - else - DebugPrintOut(L"StreamSink::GetEvent: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE BeginGetEvent( - IMFAsyncCallback *pCallback, IUnknown *punkState) { - HRESULT hr = S_OK; - - EnterCriticalSection(&m_critSec); - - hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = m_spEventQueue->BeginGetEvent(pCallback, punkState); - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::BeginGetEvent: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE EndGetEvent( - IMFAsyncResult *pResult, IMFMediaEvent **ppEvent) { - HRESULT hr = S_OK; - - EnterCriticalSection(&m_critSec); - - hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = m_spEventQueue->EndGetEvent(pResult, ppEvent); - } - - MediaEventType meType = MEUnknown; - if (SUCCEEDED(hr) && SUCCEEDED((*ppEvent)->GetType(&meType)) && meType == MEStreamSinkStopped) { - } - - LeaveCriticalSection(&m_critSec); - HRESULT hrStatus = S_OK; - if (SUCCEEDED(hr)) - hr = (*ppEvent)->GetStatus(&hrStatus); - if (SUCCEEDED(hr)) - DebugPrintOut(L"StreamSink::EndGetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str()); - else - DebugPrintOut(L"StreamSink::EndGetEvent: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE QueueEvent( - MediaEventType met, REFGUID guidExtendedType, - HRESULT hrStatus, const PROPVARIANT *pvValue) { - HRESULT hr = S_OK; - - EnterCriticalSection(&m_critSec); - - hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = m_spEventQueue->QueueEventParamVar(met, guidExtendedType, hrStatus, pvValue); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::QueueEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(met).c_str()); - DebugPrintOut(L"StreamSink::QueueEvent: HRESULT=%i\n", hr); - return hr; - } - - /// IMFMediaTypeHandler methods - - // Check if a media type is supported. - STDMETHODIMP IsMediaTypeSupported( - /* [in] */ IMFMediaType *pMediaType, - /* [out] */ IMFMediaType **ppMediaType) - { - if (pMediaType == nullptr) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - GUID majorType = GUID_NULL; - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = pMediaType->GetGUID(MF_MT_MAJOR_TYPE, &majorType); - } - - // First make sure it's video or audio type. - if (SUCCEEDED(hr)) - { - if (majorType != MFMediaType_Video && majorType != MFMediaType_Audio) - { - hr = MF_E_INVALIDTYPE; - } - } - - if (SUCCEEDED(hr) && m_spCurrentType != nullptr) - { - GUID guiNewSubtype; - if (FAILED(pMediaType->GetGUID(MF_MT_SUBTYPE, &guiNewSubtype)) || - guiNewSubtype != m_guiCurrentSubtype) - { - hr = MF_E_INVALIDTYPE; - } - } - // We don't return any "close match" types. - if (ppMediaType) - { - *ppMediaType = nullptr; - } - - if (ppMediaType && SUCCEEDED(hr)) { - _ComPtr pType; - hr = MFCreateMediaType(ppMediaType); - if (SUCCEEDED(hr)) { - hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType); - } - if (SUCCEEDED(hr)) { - hr = pType->LockStore(); - } - bool bLocked = false; - if (SUCCEEDED(hr)) { - bLocked = true; - UINT32 uiCount; - UINT32 uiTotal; - hr = pType->GetCount(&uiTotal); - for (uiCount = 0; SUCCEEDED(hr) && uiCount < uiTotal; uiCount++) { - GUID guid; - PROPVARIANT propval; - hr = pType->GetItemByIndex(uiCount, &guid, &propval); - if (SUCCEEDED(hr) && (guid == MF_MT_FRAME_SIZE || guid == MF_MT_MAJOR_TYPE || guid == MF_MT_PIXEL_ASPECT_RATIO || - guid == MF_MT_ALL_SAMPLES_INDEPENDENT || guid == MF_MT_INTERLACE_MODE || guid == MF_MT_SUBTYPE)) { - hr = (*ppMediaType)->SetItem(guid, propval); - PropVariantClear(&propval); - } - } - } - if (bLocked) { - hr = pType->UnlockStore(); - } - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::IsMediaTypeSupported: HRESULT=%i\n", hr); - return hr; - } - - - // Return the number of preferred media types. - STDMETHODIMP GetMediaTypeCount(DWORD *pdwTypeCount) - { - if (pdwTypeCount == nullptr) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - // We've got only one media type - *pdwTypeCount = 1; - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetMediaTypeCount: HRESULT=%i\n", hr); - return hr; - } - - - // Return a preferred media type by index. - STDMETHODIMP GetMediaTypeByIndex( - /* [in] */ DWORD dwIndex, - /* [out] */ IMFMediaType **ppType) - { - if (ppType == NULL) { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (dwIndex > 0) - { - hr = MF_E_NO_MORE_TYPES; - } else { - //return preferred type based on media capture library 6 elements preferred preview type - //hr = m_spCurrentType.CopyTo(ppType); - if (SUCCEEDED(hr)) { - _ComPtr pType; - hr = MFCreateMediaType(ppType); - if (SUCCEEDED(hr)) { - hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType); - } - if (SUCCEEDED(hr)) { - hr = pType->LockStore(); - } - bool bLocked = false; - if (SUCCEEDED(hr)) { - bLocked = true; - UINT32 uiCount; - UINT32 uiTotal; - hr = pType->GetCount(&uiTotal); - for (uiCount = 0; SUCCEEDED(hr) && uiCount < uiTotal; uiCount++) { - GUID guid; - PROPVARIANT propval; - hr = pType->GetItemByIndex(uiCount, &guid, &propval); - if (SUCCEEDED(hr) && (guid == MF_MT_FRAME_SIZE || guid == MF_MT_MAJOR_TYPE || guid == MF_MT_PIXEL_ASPECT_RATIO || - guid == MF_MT_ALL_SAMPLES_INDEPENDENT || guid == MF_MT_INTERLACE_MODE || guid == MF_MT_SUBTYPE)) { - hr = (*ppType)->SetItem(guid, propval); - PropVariantClear(&propval); - } - } - } - if (bLocked) { - hr = pType->UnlockStore(); - } - } - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetMediaTypeByIndex: HRESULT=%i\n", hr); - return hr; - } - - - // Set the current media type. - STDMETHODIMP SetCurrentMediaType(IMFMediaType *pMediaType) - { - if (pMediaType == NULL) { - return E_INVALIDARG; - } - EnterCriticalSection(&m_critSec); - - HRESULT hr = S_OK; - if (m_state != State_TypeNotSet && m_state != State_Ready) - hr = MF_E_INVALIDREQUEST; - if (SUCCEEDED(hr)) - hr = CheckShutdown(); - - // We don't allow format changes after streaming starts. - - // We set media type already - if (m_state >= State_Ready) - { - if (SUCCEEDED(hr)) - { - hr = IsMediaTypeSupported(pMediaType, NULL); - } - } - - if (SUCCEEDED(hr)) - { - hr = MFCreateMediaType(m_spCurrentType.ReleaseAndGetAddressOf()); - if (SUCCEEDED(hr)) - { - hr = pMediaType->CopyAllItems(m_spCurrentType.Get()); - } - if (SUCCEEDED(hr)) - { - hr = m_spCurrentType->GetGUID(MF_MT_SUBTYPE, &m_guiCurrentSubtype); - } - GUID guid; - if (SUCCEEDED(hr)) { - hr = m_spCurrentType->GetMajorType(&guid); - } - if (SUCCEEDED(hr) && guid == MFMediaType_Video) { - hr = MFGetAttributeSize(m_spCurrentType.Get(), MF_MT_FRAME_SIZE, &m_imageWidthInPixels, &m_imageHeightInPixels); - } - if (SUCCEEDED(hr)) - { - m_state = State_Ready; - } - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::SetCurrentMediaType: HRESULT=%i\n", hr); - return hr; - } - - // Return the current media type, if any. - STDMETHODIMP GetCurrentMediaType(IMFMediaType **ppMediaType) - { - if (ppMediaType == NULL) { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) { - if (m_spCurrentType == nullptr) { - hr = MF_E_NOT_INITIALIZED; - } - } - - if (SUCCEEDED(hr)) { - hr = m_spCurrentType.CopyTo(ppMediaType); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"StreamSink::GetCurrentMediaType: HRESULT=%i\n", hr); - return hr; - } - - - // Return the major type GUID. - STDMETHODIMP GetMajorType(GUID *pguidMajorType) - { - HRESULT hr; - if (pguidMajorType == nullptr) { - return E_INVALIDARG; - } - - _ComPtr pType; - hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType); - if (SUCCEEDED(hr)) { - hr = pType->GetMajorType(pguidMajorType); - } - DebugPrintOut(L"StreamSink::GetMajorType: HRESULT=%i\n", hr); - return hr; - } -private: -#ifdef WINRT - EventRegistrationToken m_token; -#else - bool m_bConnected; -#endif - - bool m_IsShutdown; // Flag to indicate if Shutdown() method was called. - CRITICAL_SECTION m_critSec; -#ifndef WINRT - long m_cRef; -#endif - IMFAttributes* m_pParent; - _ComPtr m_spCurrentType; - _ComPtr m_spEventQueue; // Event queue - - _ComPtr m_spFTM; - State m_state; - bool m_fGetStartTimeFromSample; - bool m_fWaitingForFirstSample; - MFTIME m_StartTime; // Presentation time when the clock started. - GUID m_guiCurrentSubtype; - UINT32 m_imageWidthInPixels; - UINT32 m_imageHeightInPixels; -}; - -// Notes: -// -// The List class template implements a simple double-linked list. -// It uses STL's copy semantics. - -// There are two versions of the Clear() method: -// Clear(void) clears the list w/out cleaning up the object. -// Clear(FN fn) takes a functor object that releases the objects, if they need cleanup. - -// The List class supports enumeration. Example of usage: -// -// List::POSIITON pos = list.GetFrontPosition(); -// while (pos != list.GetEndPosition()) -// { -// T item; -// hr = list.GetItemPos(&item); -// pos = list.Next(pos); -// } - -// The ComPtrList class template derives from List<> and implements a list of COM pointers. - -template -struct NoOp -{ - void operator()(T& /*t*/) - { - } -}; - -template -class List -{ -protected: - - // Nodes in the linked list - struct Node - { - Node *prev; - Node *next; - T item; - - Node() : prev(nullptr), next(nullptr) - { - } - - Node(T item) : prev(nullptr), next(nullptr) - { - this->item = item; - } - - T Item() const { return item; } - }; - -public: - - // Object for enumerating the list. - class POSITION - { - friend class List; - - public: - POSITION() : pNode(nullptr) - { - } - - bool operator==(const POSITION &p) const - { - return pNode == p.pNode; - } - - bool operator!=(const POSITION &p) const - { - return pNode != p.pNode; - } - - private: - const Node *pNode; - - POSITION(Node *p) : pNode(p) - { - } - }; - -protected: - Node m_anchor; // Anchor node for the linked list. - DWORD m_count; // Number of items in the list. - - Node* Front() const - { - return m_anchor.next; - } - - Node* Back() const - { - return m_anchor.prev; - } - - virtual HRESULT InsertAfter(T item, Node *pBefore) - { - if (pBefore == nullptr) - { - return E_POINTER; - } - - Node *pNode = new Node(item); - if (pNode == nullptr) - { - return E_OUTOFMEMORY; - } - - Node *pAfter = pBefore->next; - - pBefore->next = pNode; - pAfter->prev = pNode; - - pNode->prev = pBefore; - pNode->next = pAfter; - - m_count++; - - return S_OK; - } - - virtual HRESULT GetItem(const Node *pNode, T* ppItem) - { - if (pNode == nullptr || ppItem == nullptr) - { - return E_POINTER; - } - - *ppItem = pNode->item; - return S_OK; - } - - // RemoveItem: - // Removes a node and optionally returns the item. - // ppItem can be nullptr. - virtual HRESULT RemoveItem(Node *pNode, T *ppItem) - { - if (pNode == nullptr) - { - return E_POINTER; - } - - assert(pNode != &m_anchor); // We should never try to remove the anchor node. - if (pNode == &m_anchor) - { - return E_INVALIDARG; - } - - - T item; - - // The next node's previous is this node's previous. - pNode->next->prev = pNode->prev; - - // The previous node's next is this node's next. - pNode->prev->next = pNode->next; - - item = pNode->item; - delete pNode; - - m_count--; - - if (ppItem) - { - *ppItem = item; - } - - return S_OK; - } - -public: - - List() - { - m_anchor.next = &m_anchor; - m_anchor.prev = &m_anchor; - - m_count = 0; - } - - virtual ~List() - { - Clear(); - } - - // Insertion functions - HRESULT InsertBack(T item) - { - return InsertAfter(item, m_anchor.prev); - } - - - HRESULT InsertFront(T item) - { - return InsertAfter(item, &m_anchor); - } - - HRESULT InsertPos(POSITION pos, T item) - { - if (pos.pNode == nullptr) - { - return InsertBack(item); - } - - return InsertAfter(item, pos.pNode->prev); - } - - // RemoveBack: Removes the tail of the list and returns the value. - // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.) - HRESULT RemoveBack(T *ppItem) - { - if (IsEmpty()) - { - return E_FAIL; - } - else - { - return RemoveItem(Back(), ppItem); - } - } - - // RemoveFront: Removes the head of the list and returns the value. - // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.) - HRESULT RemoveFront(T *ppItem) - { - if (IsEmpty()) - { - return E_FAIL; - } - else - { - return RemoveItem(Front(), ppItem); - } - } - - // GetBack: Gets the tail item. - HRESULT GetBack(T *ppItem) - { - if (IsEmpty()) - { - return E_FAIL; - } - else - { - return GetItem(Back(), ppItem); - } - } - - // GetFront: Gets the front item. - HRESULT GetFront(T *ppItem) - { - if (IsEmpty()) - { - return E_FAIL; - } - else - { - return GetItem(Front(), ppItem); - } - } - - - // GetCount: Returns the number of items in the list. - DWORD GetCount() const { return m_count; } - - bool IsEmpty() const - { - return (GetCount() == 0); - } - - // Clear: Takes a functor object whose operator() - // frees the object on the list. - template - void Clear(FN& clear_fn) - { - Node *n = m_anchor.next; - - // Delete the nodes - while (n != &m_anchor) - { - clear_fn(n->item); - - Node *tmp = n->next; - delete n; - n = tmp; - } - - // Reset the anchor to point at itself - m_anchor.next = &m_anchor; - m_anchor.prev = &m_anchor; - - m_count = 0; - } - - // Clear: Clears the list. (Does not delete or release the list items.) - virtual void Clear() - { - NoOp clearOp; - Clear<>(clearOp); - } - - - // Enumerator functions - - POSITION FrontPosition() - { - if (IsEmpty()) - { - return POSITION(nullptr); - } - else - { - return POSITION(Front()); - } - } - - POSITION EndPosition() const - { - return POSITION(); - } - - HRESULT GetItemPos(POSITION pos, T *ppItem) - { - if (pos.pNode) - { - return GetItem(pos.pNode, ppItem); - } - else - { - return E_FAIL; - } - } - - POSITION Next(const POSITION pos) - { - if (pos.pNode && (pos.pNode->next != &m_anchor)) - { - return POSITION(pos.pNode->next); - } - else - { - return POSITION(nullptr); - } - } - - // Remove an item at a position. - // The item is returns in ppItem, unless ppItem is nullptr. - // NOTE: This method invalidates the POSITION object. - HRESULT Remove(POSITION& pos, T *ppItem) - { - if (pos.pNode) - { - // Remove const-ness temporarily... - Node *pNode = const_cast(pos.pNode); - - pos = POSITION(); - - return RemoveItem(pNode, ppItem); - } - else - { - return E_INVALIDARG; - } - } - -}; - - - -// Typical functors for Clear method. - -// ComAutoRelease: Releases COM pointers. -// MemDelete: Deletes pointers to new'd memory. - -class ComAutoRelease -{ -public: - void operator()(IUnknown *p) - { - if (p) - { - p->Release(); - } - } -}; - -class MemDelete -{ -public: - void operator()(void *p) - { - if (p) - { - delete p; - } - } -}; - - -// ComPtrList class -// Derived class that makes it safer to store COM pointers in the List<> class. -// It automatically AddRef's the pointers that are inserted onto the list -// (unless the insertion method fails). -// -// T must be a COM interface type. -// example: ComPtrList -// -// NULLABLE: If true, client can insert nullptr pointers. This means GetItem can -// succeed but return a nullptr pointer. By default, the list does not allow nullptr -// pointers. - -template -class ComPtrList : public List -{ -public: - typedef typename List::Node Node; - typedef T* Ptr; - - void Clear() - { - ComAutoRelease car; - List::Clear(car); - } - - ~ComPtrList() - { - Clear(); - } - -protected: - HRESULT InsertAfter(Ptr item, Node *pBefore) - { - // Do not allow nullptr item pointers unless NULLABLE is true. - if (item == nullptr && !NULLABLE) - { - return E_POINTER; - } - - if (item) - { - item->AddRef(); - } - - HRESULT hr = List::InsertAfter(item, pBefore); - if (FAILED(hr) && item != nullptr) - { - item->Release(); - } - return hr; - } - - HRESULT GetItem(const Node *pNode, Ptr* ppItem) - { - Ptr pItem = nullptr; - - // The base class gives us the pointer without AddRef'ing it. - // If we return the pointer to the caller, we must AddRef(). - HRESULT hr = List::GetItem(pNode, &pItem); - if (SUCCEEDED(hr)) - { - assert(pItem || NULLABLE); - if (pItem) - { - *ppItem = pItem; - (*ppItem)->AddRef(); - } - } - return hr; - } - - HRESULT RemoveItem(Node *pNode, Ptr *ppItem) - { - // ppItem can be nullptr, but we need to get the - // item so that we can release it. - - // If ppItem is not nullptr, we will AddRef it on the way out. - - Ptr pItem = nullptr; - - HRESULT hr = List::RemoveItem(pNode, &pItem); - - if (SUCCEEDED(hr)) - { - assert(pItem || NULLABLE); - if (ppItem && pItem) - { - *ppItem = pItem; - (*ppItem)->AddRef(); - } - - if (pItem) - { - pItem->Release(); - pItem = nullptr; - } - } - - return hr; - } -}; - -/* Be sure to declare webcam device capability in manifest - For better media capture support, add the following snippet with correct module name to the project manifest - (videoio needs DLL activation class factoryentry points): - - - - modulename - - - - */ - -extern const __declspec(selectany) WCHAR RuntimeClass_CV_MediaSink[] = L"cv.MediaSink"; - -class MediaSink : -#ifdef WINRT - public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >, - Microsoft::WRL::Implements, - IMFMediaSink, - IMFClockStateSink, - Microsoft::WRL::FtmBase, - CBaseAttributes<>> -#else - public IMFMediaSink, public IMFClockStateSink, public CBaseAttributes<> -#endif -{ -#ifdef WINRT - InspectableClass(RuntimeClass_CV_MediaSink, BaseTrust) -public: -#else -public: - ULONG STDMETHODCALLTYPE AddRef() - { - return InterlockedIncrement(&m_cRef); - } - ULONG STDMETHODCALLTYPE Release() - { - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) - { - delete this; - } - return cRef; - } -#if defined(_MSC_VER) && _MSC_VER >= 1700 // '_Outptr_result_nullonfailure_' SAL is avaialable since VS 2012 - STDMETHOD(QueryInterface)(REFIID riid, _Outptr_result_nullonfailure_ void **ppv) -#else - STDMETHOD(QueryInterface)(REFIID riid, void **ppv) -#endif - { - if (ppv == nullptr) { - return E_POINTER; - } - (*ppv) = nullptr; - HRESULT hr = S_OK; - if (riid == IID_IUnknown || - riid == IID_IMFMediaSink) { - (*ppv) = static_cast(this); - AddRef(); - } else if (riid == IID_IMFClockStateSink) { - (*ppv) = static_cast(this); - AddRef(); - } else if (riid == IID_IMFAttributes) { - (*ppv) = static_cast(this); - AddRef(); - } else { - hr = E_NOINTERFACE; - } - - return hr; - } -#endif - MediaSink() : m_IsShutdown(false), m_llStartTime(0) { - CBaseAttributes<>::Initialize(0U); - InitializeCriticalSectionEx(&m_critSec, 3000, 0); - DebugPrintOut(L"MediaSink::MediaSink\n"); - } - - virtual ~MediaSink() { - DebugPrintOut(L"MediaSink::~MediaSink\n"); - DeleteCriticalSection(&m_critSec); - assert(m_IsShutdown); - } - HRESULT CheckShutdown() const - { - if (m_IsShutdown) - { - return MF_E_SHUTDOWN; - } - else - { - return S_OK; - } - } -#ifdef WINRT - STDMETHODIMP SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration) - { - HRESULT hr = S_OK; - if (pConfiguration) { - Microsoft::WRL::ComPtr spInsp; - Microsoft::WRL::ComPtr> spSetting; - Microsoft::WRL::ComPtr spPropVal; - Microsoft::WRL::ComPtr pMedEncProps; - UINT32 uiType = ABI::Windows::Media::Capture::MediaStreamType_VideoPreview; - - hr = pConfiguration->QueryInterface(IID_PPV_ARGS(&spSetting)); - if (FAILED(hr)) { - hr = E_FAIL; - } - - if (SUCCEEDED(hr)) { - hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_SAMPLEGRABBERCALLBACK).Get(), spInsp.ReleaseAndGetAddressOf()); - if (FAILED(hr)) { - hr = E_INVALIDARG; - } - if (SUCCEEDED(hr)) { - hr = SetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, spInsp.Get()); - } - } - if (SUCCEEDED(hr)) { - hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_VIDTYPE).Get(), spInsp.ReleaseAndGetAddressOf()); - if (FAILED(hr)) { - hr = E_INVALIDARG; - } - if (SUCCEEDED(hr)) { - if (SUCCEEDED(hr = spInsp.As(&spPropVal))) { - hr = spPropVal->GetUInt32(&uiType); - } - } - } - if (SUCCEEDED(hr)) { - hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_VIDENCPROPS).Get(), spInsp.ReleaseAndGetAddressOf()); - if (FAILED(hr)) { - hr = E_INVALIDARG; - } - if (SUCCEEDED(hr)) { - hr = spInsp.As(&pMedEncProps); - } - } - if (SUCCEEDED(hr)) { - hr = SetMediaStreamProperties((ABI::Windows::Media::Capture::MediaStreamType)uiType, pMedEncProps.Get()); - } - } - - return hr; - } - static DWORD GetStreamId(ABI::Windows::Media::Capture::MediaStreamType mediaStreamType) - { - return 3 - mediaStreamType; - } - static HRESULT AddAttribute(_In_ GUID guidKey, _In_ ABI::Windows::Foundation::IPropertyValue *pValue, _In_ IMFAttributes* pAttr) - { - HRESULT hr = S_OK; - PROPVARIANT var; - ABI::Windows::Foundation::PropertyType type; - hr = pValue->get_Type(&type); - ZeroMemory(&var, sizeof(var)); - - if (SUCCEEDED(hr)) - { - switch (type) - { - case ABI::Windows::Foundation::PropertyType_UInt8Array: - { - UINT32 cbBlob; - BYTE *pbBlog = nullptr; - hr = pValue->GetUInt8Array(&cbBlob, &pbBlog); - if (SUCCEEDED(hr)) - { - if (pbBlog == nullptr) - { - hr = E_INVALIDARG; - } - else - { - hr = pAttr->SetBlob(guidKey, pbBlog, cbBlob); - } - } - CoTaskMemFree(pbBlog); - } - break; - - case ABI::Windows::Foundation::PropertyType_Double: - { - DOUBLE value; - hr = pValue->GetDouble(&value); - if (SUCCEEDED(hr)) - { - hr = pAttr->SetDouble(guidKey, value); - } - } - break; - - case ABI::Windows::Foundation::PropertyType_Guid: - { - GUID value; - hr = pValue->GetGuid(&value); - if (SUCCEEDED(hr)) - { - hr = pAttr->SetGUID(guidKey, value); - } - } - break; - - case ABI::Windows::Foundation::PropertyType_String: - { - Microsoft::WRL::Wrappers::HString value; - hr = pValue->GetString(value.GetAddressOf()); - if (SUCCEEDED(hr)) - { - UINT32 len = 0; - LPCWSTR szValue = WindowsGetStringRawBuffer(value.Get(), &len); - hr = pAttr->SetString(guidKey, szValue); - } - } - break; - - case ABI::Windows::Foundation::PropertyType_UInt32: - { - UINT32 value; - hr = pValue->GetUInt32(&value); - if (SUCCEEDED(hr)) - { - pAttr->SetUINT32(guidKey, value); - } - } - break; - - case ABI::Windows::Foundation::PropertyType_UInt64: - { - UINT64 value; - hr = pValue->GetUInt64(&value); - if (SUCCEEDED(hr)) - { - hr = pAttr->SetUINT64(guidKey, value); - } - } - break; - - case ABI::Windows::Foundation::PropertyType_Inspectable: - { - Microsoft::WRL::ComPtr value; - hr = TYPE_E_TYPEMISMATCH; - if (SUCCEEDED(hr)) - { - pAttr->SetUnknown(guidKey, value.Get()); - } - } - break; - - // ignore unknown values - } - } - - return hr; - } - static HRESULT ConvertPropertiesToMediaType(_In_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties *pMEP, _Outptr_ IMFMediaType **ppMT) - { - HRESULT hr = S_OK; - _ComPtr spMT; - Microsoft::WRL::ComPtr> spMap; - Microsoft::WRL::ComPtr*>> spIterable; - Microsoft::WRL::ComPtr*>> spIterator; - - if (pMEP == nullptr || ppMT == nullptr) - { - return E_INVALIDARG; - } - *ppMT = nullptr; - - hr = pMEP->get_Properties(spMap.GetAddressOf()); - - if (SUCCEEDED(hr)) - { - hr = spMap.As(&spIterable); - } - if (SUCCEEDED(hr)) - { - hr = spIterable->First(&spIterator); - } - if (SUCCEEDED(hr)) - { - MFCreateMediaType(spMT.ReleaseAndGetAddressOf()); - } - - boolean hasCurrent = false; - if (SUCCEEDED(hr)) - { - hr = spIterator->get_HasCurrent(&hasCurrent); - } - - while (hasCurrent) - { - Microsoft::WRL::ComPtr > spKeyValuePair; - Microsoft::WRL::ComPtr spValue; - Microsoft::WRL::ComPtr spPropValue; - GUID guidKey; - - hr = spIterator->get_Current(&spKeyValuePair); - if (FAILED(hr)) - { - break; - } - hr = spKeyValuePair->get_Key(&guidKey); - if (FAILED(hr)) - { - break; - } - hr = spKeyValuePair->get_Value(&spValue); - if (FAILED(hr)) - { - break; - } - hr = spValue.As(&spPropValue); - if (FAILED(hr)) - { - break; - } - hr = AddAttribute(guidKey, spPropValue.Get(), spMT.Get()); - if (FAILED(hr)) - { - break; - } - - hr = spIterator->MoveNext(&hasCurrent); - if (FAILED(hr)) - { - break; - } - } - - - if (SUCCEEDED(hr)) - { - Microsoft::WRL::ComPtr spValue; - Microsoft::WRL::ComPtr spPropValue; - GUID guiMajorType; - - hr = spMap->Lookup(MF_MT_MAJOR_TYPE, spValue.GetAddressOf()); - - if (SUCCEEDED(hr)) - { - hr = spValue.As(&spPropValue); - } - if (SUCCEEDED(hr)) - { - hr = spPropValue->GetGuid(&guiMajorType); - } - if (SUCCEEDED(hr)) - { - if (guiMajorType != MFMediaType_Video && guiMajorType != MFMediaType_Audio) - { - hr = E_UNEXPECTED; - } - } - } - - if (SUCCEEDED(hr)) - { - *ppMT = spMT.Detach(); - } - - return hr; - } - //this should be passed through SetProperties! - HRESULT SetMediaStreamProperties(ABI::Windows::Media::Capture::MediaStreamType MediaStreamType, - _In_opt_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties *mediaEncodingProperties) - { - HRESULT hr = S_OK; - _ComPtr spMediaType; - - if (MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_VideoPreview && - MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_VideoRecord && - MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_Audio) - { - return E_INVALIDARG; - } - - RemoveStreamSink(GetStreamId(MediaStreamType)); - - if (mediaEncodingProperties != nullptr) - { - _ComPtr spStreamSink; - hr = ConvertPropertiesToMediaType(mediaEncodingProperties, &spMediaType); - if (SUCCEEDED(hr)) - { - hr = AddStreamSink(GetStreamId(MediaStreamType), nullptr, spStreamSink.GetAddressOf()); - } - if (SUCCEEDED(hr)) { - hr = SetUnknown(MF_MEDIASINK_PREFERREDTYPE, spMediaType.Detach()); - } - } - - return hr; - } -#endif - //IMFMediaSink - HRESULT STDMETHODCALLTYPE GetCharacteristics( - /* [out] */ __RPC__out DWORD *pdwCharacteristics) { - HRESULT hr; - if (pdwCharacteristics == NULL) return E_INVALIDARG; - EnterCriticalSection(&m_critSec); - if (SUCCEEDED(hr = CheckShutdown())) { - //if had an activation object for the sink, shut down would be managed and MF_STREAM_SINK_SUPPORTS_ROTATION appears to be setable to TRUE - *pdwCharacteristics = MEDIASINK_FIXED_STREAMS;// | MEDIASINK_REQUIRE_REFERENCE_MEDIATYPE; - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::GetCharacteristics: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE AddStreamSink( - DWORD dwStreamSinkIdentifier, IMFMediaType * /*pMediaType*/, IMFStreamSink **ppStreamSink) { - _ComPtr spMFStream; - _ComPtr pStream; - EnterCriticalSection(&m_critSec); - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - hr = GetStreamSinkById(dwStreamSinkIdentifier, &spMFStream); - } - - if (SUCCEEDED(hr)) - { - hr = MF_E_STREAMSINK_EXISTS; - } - else - { - hr = S_OK; - } - - if (SUCCEEDED(hr)) - { -#ifdef WINRT - pStream = Microsoft::WRL::Make(); - if (pStream == nullptr) { - hr = E_OUTOFMEMORY; - } - if (SUCCEEDED(hr)) - hr = pStream.As(&spMFStream); -#else - StreamSink* pSink = new StreamSink(); - if (pSink) { - hr = pSink->QueryInterface(IID_IMFStreamSink, (void**)spMFStream.GetAddressOf()); - if (SUCCEEDED(hr)) { - hr = spMFStream.As(&pStream); - } - if (FAILED(hr)) delete pSink; - } -#endif - } - - // Initialize the stream. - _ComPtr pAttr; - if (SUCCEEDED(hr)) { - hr = pStream.As(&pAttr); - } - if (SUCCEEDED(hr)) { - hr = pAttr->SetUINT32(MF_STREAMSINK_ID, dwStreamSinkIdentifier); - if (SUCCEEDED(hr)) { - hr = pAttr->SetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, (IMFMediaSink*)this); - } - } - if (SUCCEEDED(hr)) { - hr = pStream->Initialize(); - } - - if (SUCCEEDED(hr)) - { - ComPtrList::POSITION pos = m_streams.FrontPosition(); - ComPtrList::POSITION posEnd = m_streams.EndPosition(); - - // Insert in proper position - for (; pos != posEnd; pos = m_streams.Next(pos)) - { - DWORD dwCurrId; - _ComPtr spCurr; - hr = m_streams.GetItemPos(pos, &spCurr); - if (FAILED(hr)) - { - break; - } - hr = spCurr->GetIdentifier(&dwCurrId); - if (FAILED(hr)) - { - break; - } - - if (dwCurrId > dwStreamSinkIdentifier) - { - break; - } - } - - if (SUCCEEDED(hr)) - { - hr = m_streams.InsertPos(pos, spMFStream.Get()); - } - } - - if (SUCCEEDED(hr)) - { - *ppStreamSink = spMFStream.Detach(); - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::AddStreamSink: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE RemoveStreamSink(DWORD dwStreamSinkIdentifier) { - EnterCriticalSection(&m_critSec); - HRESULT hr = CheckShutdown(); - ComPtrList::POSITION pos = m_streams.FrontPosition(); - ComPtrList::POSITION endPos = m_streams.EndPosition(); - _ComPtr spStream; - - if (SUCCEEDED(hr)) - { - for (; pos != endPos; pos = m_streams.Next(pos)) - { - hr = m_streams.GetItemPos(pos, &spStream); - DWORD dwId; - - if (FAILED(hr)) - { - break; - } - - hr = spStream->GetIdentifier(&dwId); - if (FAILED(hr) || dwId == dwStreamSinkIdentifier) - { - break; - } - } - - if (pos == endPos) - { - hr = MF_E_INVALIDSTREAMNUMBER; - } - } - - if (SUCCEEDED(hr)) - { - hr = m_streams.Remove(pos, nullptr); - _ComPtr spCustomSink; -#ifdef WINRT - spCustomSink = static_cast(spStream.Get()); - hr = S_OK; -#else - hr = spStream.As(&spCustomSink); -#endif - if (SUCCEEDED(hr)) - hr = spCustomSink->Shutdown(); - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::RemoveStreamSink: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetStreamSinkCount(DWORD *pStreamSinkCount) { - if (pStreamSinkCount == NULL) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - *pStreamSinkCount = m_streams.GetCount(); - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::GetStreamSinkCount: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetStreamSinkByIndex( - DWORD dwIndex, IMFStreamSink **ppStreamSink) { - if (ppStreamSink == NULL) - { - return E_INVALIDARG; - } - - _ComPtr spStream; - EnterCriticalSection(&m_critSec); - DWORD cStreams = m_streams.GetCount(); - - if (dwIndex >= cStreams) - { - return MF_E_INVALIDINDEX; - } - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - ComPtrList::POSITION pos = m_streams.FrontPosition(); - ComPtrList::POSITION endPos = m_streams.EndPosition(); - DWORD dwCurrent = 0; - - for (; pos != endPos && dwCurrent < dwIndex; pos = m_streams.Next(pos), ++dwCurrent) - { - // Just move to proper position - } - - if (pos == endPos) - { - hr = MF_E_UNEXPECTED; - } - else - { - hr = m_streams.GetItemPos(pos, &spStream); - } - } - - if (SUCCEEDED(hr)) - { - *ppStreamSink = spStream.Detach(); - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::GetStreamSinkByIndex: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetStreamSinkById( - DWORD dwStreamSinkIdentifier, IMFStreamSink **ppStreamSink) { - if (ppStreamSink == NULL) - { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - HRESULT hr = CheckShutdown(); - _ComPtr spResult; - - if (SUCCEEDED(hr)) - { - ComPtrList::POSITION pos = m_streams.FrontPosition(); - ComPtrList::POSITION endPos = m_streams.EndPosition(); - - for (; pos != endPos; pos = m_streams.Next(pos)) - { - _ComPtr spStream; - hr = m_streams.GetItemPos(pos, &spStream); - DWORD dwId; - - if (FAILED(hr)) - { - break; - } - - hr = spStream->GetIdentifier(&dwId); - if (FAILED(hr)) - { - break; - } - else if (dwId == dwStreamSinkIdentifier) - { - spResult = spStream; - break; - } - } - - if (pos == endPos) - { - hr = MF_E_INVALIDSTREAMNUMBER; - } - } - - if (SUCCEEDED(hr)) - { - assert(spResult); - *ppStreamSink = spResult.Detach(); - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::GetStreamSinkById: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE SetPresentationClock( - IMFPresentationClock *pPresentationClock) { - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - // If we already have a clock, remove ourselves from that clock's - // state notifications. - if (SUCCEEDED(hr)) { - if (m_spClock) { - hr = m_spClock->RemoveClockStateSink(this); - } - } - - // Register ourselves to get state notifications from the new clock. - if (SUCCEEDED(hr)) { - if (pPresentationClock) { - hr = pPresentationClock->AddClockStateSink(this); - } - } - - _ComPtr pSampleCallback; - if (SUCCEEDED(hr)) { - // Release the pointer to the old clock. - // Store the pointer to the new clock. - m_spClock = pPresentationClock; - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - } - LeaveCriticalSection(&m_critSec); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnSetPresentationClock(pPresentationClock); - DebugPrintOut(L"MediaSink::SetPresentationClock: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE GetPresentationClock( - IMFPresentationClock **ppPresentationClock) { - if (ppPresentationClock == NULL) { - return E_INVALIDARG; - } - - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) { - if (!m_spClock) { - hr = MF_E_NO_CLOCK; // There is no presentation clock. - } else { - // Return the pointer to the caller. - hr = m_spClock.CopyTo(ppPresentationClock); - } - } - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::GetPresentationClock: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE Shutdown(void) { - EnterCriticalSection(&m_critSec); - - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) { - ForEach(m_streams, ShutdownFunc()); - m_streams.Clear(); - m_spClock.ReleaseAndGetAddressOf(); - - _ComPtr pType; - hr = CBaseAttributes<>::GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)pType.GetAddressOf()); - if (SUCCEEDED(hr)) { - hr = DeleteItem(MF_MEDIASINK_PREFERREDTYPE); - } - m_IsShutdown = true; - } - - LeaveCriticalSection(&m_critSec); - DebugPrintOut(L"MediaSink::Shutdown: HRESULT=%i\n", hr); - return hr; - } - class ShutdownFunc - { - public: - HRESULT operator()(IMFStreamSink *pStream) const - { - _ComPtr spCustomSink; - HRESULT hr; -#ifdef WINRT - spCustomSink = static_cast(pStream); -#else - hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); - if (FAILED(hr)) return hr; -#endif - hr = spCustomSink->Shutdown(); - return hr; - } - }; - - class StartFunc - { - public: - StartFunc(LONGLONG llStartTime) - : _llStartTime(llStartTime) - { - } - - HRESULT operator()(IMFStreamSink *pStream) const - { - _ComPtr spCustomSink; - HRESULT hr; -#ifdef WINRT - spCustomSink = static_cast(pStream); -#else - hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); - if (FAILED(hr)) return hr; -#endif - hr = spCustomSink->Start(_llStartTime); - return hr; - } - - LONGLONG _llStartTime; - }; - - class StopFunc - { - public: - HRESULT operator()(IMFStreamSink *pStream) const - { - _ComPtr spCustomSink; - HRESULT hr; -#ifdef WINRT - spCustomSink = static_cast(pStream); -#else - hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf())); - if (FAILED(hr)) return hr; -#endif - hr = spCustomSink->Stop(); - return hr; - } - }; - - template - HRESULT ForEach(ComPtrList &col, TFunc fn) - { - ComPtrList::POSITION pos = col.FrontPosition(); - ComPtrList::POSITION endPos = col.EndPosition(); - HRESULT hr = S_OK; - - for (; pos != endPos; pos = col.Next(pos)) - { - _ComPtr spStream; - - hr = col.GetItemPos(pos, &spStream); - if (FAILED(hr)) - { - break; - } - - hr = fn(spStream.Get()); - } - - return hr; - } - //IMFClockStateSink - HRESULT STDMETHODCALLTYPE OnClockStart( - MFTIME hnsSystemTime, - LONGLONG llClockStartOffset) { - EnterCriticalSection(&m_critSec); - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - // Start each stream. - m_llStartTime = llClockStartOffset; - hr = ForEach(m_streams, StartFunc(llClockStartOffset)); - } - _ComPtr pSampleCallback; - if (SUCCEEDED(hr)) - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - LeaveCriticalSection(&m_critSec); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnClockStart(hnsSystemTime, llClockStartOffset); - DebugPrintOut(L"MediaSink::OnClockStart: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE OnClockStop( - MFTIME hnsSystemTime) { - EnterCriticalSection(&m_critSec); - HRESULT hr = CheckShutdown(); - - if (SUCCEEDED(hr)) - { - // Stop each stream - hr = ForEach(m_streams, StopFunc()); - } - _ComPtr pSampleCallback; - if (SUCCEEDED(hr)) - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - LeaveCriticalSection(&m_critSec); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnClockStop(hnsSystemTime); - DebugPrintOut(L"MediaSink::OnClockStop: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE OnClockPause( - MFTIME hnsSystemTime) { - HRESULT hr; - _ComPtr pSampleCallback; - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnClockPause(hnsSystemTime); - DebugPrintOut(L"MediaSink::OnClockPause: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE OnClockRestart( - MFTIME hnsSystemTime) { - HRESULT hr; - _ComPtr pSampleCallback; - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnClockRestart(hnsSystemTime); - DebugPrintOut(L"MediaSink::OnClockRestart: HRESULT=%i\n", hr); - return hr; - } - - HRESULT STDMETHODCALLTYPE OnClockSetRate( - MFTIME hnsSystemTime, - float flRate) { - HRESULT hr; - _ComPtr pSampleCallback; - hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf()); - if (SUCCEEDED(hr)) - hr = pSampleCallback->OnClockSetRate(hnsSystemTime, flRate); - DebugPrintOut(L"MediaSink::OnClockSetRate: HRESULT=%i\n", hr); - return hr; - } -private: -#ifndef WINRT - long m_cRef; -#endif - CRITICAL_SECTION m_critSec; - bool m_IsShutdown; - ComPtrList m_streams; - _ComPtr m_spClock; - LONGLONG m_llStartTime; -}; - -#ifdef WINRT -ActivatableClass(MediaSink); -#endif