1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html
7 Media Foundation-based Video Capturing module is based on
8 videoInput library by Evgeny Pereguda:
9 http://www.codeproject.com/Articles/559437/Capturing-of-video-from-web-camera-on-Windows-7-an
10 Originally licensed under The Code Project Open License (CPOL) 1.02:
11 http://www.codeproject.com/info/cpol10.aspx
13 //require Windows 8 for some of the formats defined otherwise could baseline on lower version
14 #if WINVER < _WIN32_WINNT_WIN8
16 #define WINVER _WIN32_WINNT_WIN8
24 #include <mfobjects.h>
27 #include <mfreadwrite.h>
42 #pragma warning(disable:4503)
43 #pragma comment(lib, "mfplat")
44 #pragma comment(lib, "mf")
45 #pragma comment(lib, "mfuuid")
46 #pragma comment(lib, "Strmiids")
47 #pragma comment(lib, "Mfreadwrite")
49 #pragma comment(lib, "d3d11")
50 // MFCreateDXGIDeviceManager() is available since Win8 only.
51 // To avoid OpenCV loading failure on Win7 use dynamic detection of this symbol.
52 // Details: https://github.com/opencv/opencv/issues/11858
53 typedef HRESULT (WINAPI *FN_MFCreateDXGIDeviceManager)(UINT *resetToken, IMFDXGIDeviceManager **ppDeviceManager);
54 static bool pMFCreateDXGIDeviceManager_initialized = false;
55 static FN_MFCreateDXGIDeviceManager pMFCreateDXGIDeviceManager = NULL;
56 static void init_MFCreateDXGIDeviceManager()
58 HMODULE h = LoadLibraryExA("mfplat.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
61 pMFCreateDXGIDeviceManager = (FN_MFCreateDXGIDeviceManager)GetProcAddress(h, "MFCreateDXGIDeviceManager");
63 pMFCreateDXGIDeviceManager_initialized = true;
66 #pragma comment(lib, "Shlwapi.lib")
73 #include <shlwapi.h> // QISearch
77 struct IMFMediaSource;
80 #define CV_CAP_MODE_BGR CV_FOURCC_MACRO('B','G','R','3')
81 #define CV_CAP_MODE_RGB CV_FOURCC_MACRO('R','G','B','3')
82 #define CV_CAP_MODE_GRAY CV_FOURCC_MACRO('G','R','E','Y')
83 #define CV_CAP_MODE_YUYV CV_FOURCC_MACRO('Y', 'U', 'Y', 'V')
99 ComPtr(_In_ const ComPtr<T>& lp)
109 CV_Assert(p == NULL);
110 return p.operator&();
112 T* operator->() const
114 CV_Assert(p != NULL);
115 return p.operator->();
119 return p.operator!=(NULL);
133 // query for U interface
135 HRESULT As(_Out_ ComPtr<U>& lp) const
138 return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>((T**)&lp));
141 _COM_SMARTPTR_TYPEDEF(T, __uuidof(T));
145 #define _ComPtr ComPtr
147 template <typename T> inline T absDiff(T a, T b) { return a >= b ? a - b : b - a; }
149 //==================================================================================================
151 // Structure for collecting info about types of video which are supported by current video device
156 INT32 stride; // stride is negative if image is bottom-up
159 UINT32 frameRateDenom;
160 UINT32 aspectRatioNum;
161 UINT32 aspectRatioDenom;
163 UINT32 interlaceMode;
164 GUID majorType; // video or audio
165 GUID subType; // fourCC
166 MediaType(IMFMediaType *pType = 0) :
170 frameRateNum(1), frameRateDenom(1),
171 aspectRatioNum(1), aspectRatioDenom(1),
174 majorType(MFMediaType_Video),
179 MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
180 pType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&stride); // value is stored as UINT32 but should be casted to INT3)
181 pType->GetUINT32(MF_MT_FIXED_SIZE_SAMPLES, &isFixedSize);
182 MFGetAttributeRatio(pType, MF_MT_FRAME_RATE, &frameRateNum, &frameRateDenom);
183 MFGetAttributeRatio(pType, MF_MT_PIXEL_ASPECT_RATIO, &aspectRatioNum, &aspectRatioDenom);
184 pType->GetUINT32(MF_MT_SAMPLE_SIZE, &sampleSize);
185 pType->GetUINT32(MF_MT_INTERLACE_MODE, &interlaceMode);
186 pType->GetGUID(MF_MT_MAJOR_TYPE, &majorType);
187 pType->GetGUID(MF_MT_SUBTYPE, &subType);
190 static MediaType createDefault()
195 res.setFramerate(30.0);
198 inline bool isEmpty() const
200 return width == 0 && height == 0;
202 _ComPtr<IMFMediaType> createMediaType() const
204 _ComPtr<IMFMediaType> res;
205 MFCreateMediaType(&res);
206 if (width != 0 || height != 0)
207 MFSetAttributeSize(res.Get(), MF_MT_FRAME_SIZE, width, height);
209 res->SetUINT32(MF_MT_DEFAULT_STRIDE, stride);
210 res->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, isFixedSize);
211 if (frameRateNum != 0 || frameRateDenom != 0)
212 MFSetAttributeRatio(res.Get(), MF_MT_FRAME_RATE, frameRateNum, frameRateDenom);
213 if (aspectRatioNum != 0 || aspectRatioDenom != 0)
214 MFSetAttributeRatio(res.Get(), MF_MT_PIXEL_ASPECT_RATIO, aspectRatioNum, aspectRatioDenom);
216 res->SetUINT32(MF_MT_SAMPLE_SIZE, sampleSize);
217 res->SetUINT32(MF_MT_INTERLACE_MODE, interlaceMode);
218 if (majorType != GUID())
219 res->SetGUID(MF_MT_MAJOR_TYPE, majorType);
220 if (subType != GUID())
221 res->SetGUID(MF_MT_SUBTYPE, subType);
224 void setFramerate(double fps)
226 frameRateNum = (UINT32)cvRound(fps * 1000.0);
227 frameRateDenom = 1000;
229 double getFramerate() const
231 return frameRateDenom != 0 ? ((double)frameRateNum) / ((double)frameRateDenom) : 0;
233 LONGLONG getFrameStep() const
235 const double fps = getFramerate();
236 return (LONGLONG)(fps > 0 ? 1e7 / fps : 0);
238 inline unsigned long resolutionDiff(const MediaType& other) const
240 const unsigned long wdiff = absDiff(width, other.width);
241 const unsigned long hdiff = absDiff(height, other.height);
242 return wdiff + hdiff;
244 // check if 'this' is better than 'other' comparing to reference
245 bool isBetterThan(const MediaType& other, const MediaType& ref) const
247 const unsigned long thisDiff = resolutionDiff(ref);
248 const unsigned long otherDiff = other.resolutionDiff(ref);
249 if (thisDiff < otherDiff)
251 if (thisDiff == otherDiff)
253 if (width > other.width)
255 if (width == other.width && height > other.height)
257 if (width == other.width && height == other.height)
259 const double thisRateDiff = absDiff(getFramerate(), ref.getFramerate());
260 const double otherRateDiff = absDiff(other.getFramerate(), ref.getFramerate());
261 if (thisRateDiff < otherRateDiff)
269 void printFormat(std::ostream& out, const GUID& fmt)
271 #define PRNT(FMT) else if (fmt == FMT) out << #FMT;
272 if (fmt == MFVideoFormat_Base) out << "Base";
273 PRNT(MFVideoFormat_RGB32)
274 PRNT(MFVideoFormat_ARGB32)
275 PRNT(MFVideoFormat_RGB24)
276 PRNT(MFVideoFormat_RGB555)
277 PRNT(MFVideoFormat_RGB565)
278 PRNT(MFVideoFormat_RGB8)
281 char fourcc[5] = { 0 };
282 memcpy(fourcc, &fmt.Data1, 4);
288 std::ostream& operator<<(std::ostream& out, const MediaType& mt)
290 out << "(" << mt.width << "x" << mt.height << " @ " << mt.getFramerate() << ") ";
291 printFormat(out, mt.subType);
295 //==================================================================================================
297 // Class for creating of Media Foundation context
298 class Media_Foundation
301 ~Media_Foundation(void) { /*CV_Assert(SUCCEEDED(MFShutdown()));*/ CoUninitialize(); }
302 static Media_Foundation& getInstance()
304 static Media_Foundation instance;
308 Media_Foundation(void) { CoInitialize(0); CV_Assert(SUCCEEDED(MFStartup(MF_VERSION))); }
311 //==================================================================================================
313 class SourceReaderCB : public IMFSourceReaderCallback
317 m_nRefCount(0), m_hEvent(CreateEvent(NULL, FALSE, FALSE, NULL)), m_bEOS(FALSE), m_hrStatus(S_OK), m_reader(NULL), m_dwStreamIndex(0)
322 STDMETHODIMP QueryInterface(REFIID iid, void** ppv) CV_OVERRIDE
325 #pragma warning(push)
326 #pragma warning(disable:4838)
328 static const QITAB qit[] =
330 QITABENT(SourceReaderCB, IMFSourceReaderCallback),
336 return QISearch(this, qit, iid, ppv);
338 STDMETHODIMP_(ULONG) AddRef() CV_OVERRIDE
340 return InterlockedIncrement(&m_nRefCount);
342 STDMETHODIMP_(ULONG) Release() CV_OVERRIDE
344 ULONG uCount = InterlockedDecrement(&m_nRefCount);
352 STDMETHODIMP OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample) CV_OVERRIDE
355 cv::AutoLock lock(m_mutex);
357 if (SUCCEEDED(hrStatus))
361 CV_LOG_DEBUG(NULL, "videoio(MSMF): got frame at " << llTimestamp);
362 if (m_lastSample.Get())
364 CV_LOG_DEBUG(NULL, "videoio(MSMF): drop frame (not processed)");
366 m_lastSampleTimestamp = llTimestamp;
367 m_lastSample = pSample;
372 CV_LOG_WARNING(NULL, "videoio(MSMF): OnReadSample() is called with error status: " << hrStatus);
375 if (MF_SOURCE_READERF_ENDOFSTREAM & dwStreamFlags)
377 // Reached the end of the stream.
380 m_hrStatus = hrStatus;
382 if (FAILED(hr = m_reader->ReadSample(dwStreamIndex, 0, NULL, NULL, NULL, NULL)))
384 CV_LOG_WARNING(NULL, "videoio(MSMF): async ReadSample() call is failed with error status: " << hr);
388 if (pSample || m_bEOS)
395 STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *) CV_OVERRIDE
399 STDMETHODIMP OnFlush(DWORD) CV_OVERRIDE
404 HRESULT Wait(DWORD dwMilliseconds, _ComPtr<IMFSample>& videoSample, BOOL& pbEOS)
408 DWORD dwResult = WaitForSingleObject(m_hEvent, dwMilliseconds);
409 if (dwResult == WAIT_TIMEOUT)
413 else if (dwResult != WAIT_OBJECT_0)
415 return HRESULT_FROM_WIN32(GetLastError());
421 cv::AutoLock lock(m_mutex);
422 videoSample = m_lastSample;
423 CV_Assert(videoSample);
424 m_lastSample.Release();
425 ResetEvent(m_hEvent); // event is auto-reset, but we need this forced reset due time gap between wait() and mutex hold.
431 // Destructor is private. Caller should call Release.
432 virtual ~SourceReaderCB()
434 CV_LOG_WARNING(NULL, "terminating async callback");
438 long m_nRefCount; // Reference count.
444 IMFSourceReader *m_reader;
445 DWORD m_dwStreamIndex;
446 LONGLONG m_lastSampleTimestamp;
447 _ComPtr<IMFSample> m_lastSample;
450 //==================================================================================================
452 // Enumerate and store supported formats and finds format which is most similar to the one requested
460 MediaID() : stream(0), media(0) {}
470 bool operator<(const MediaID& other) const
472 return (stream < other.stream) || (stream == other.stream && media < other.media);
475 void read(IMFSourceReader* source)
479 while (SUCCEEDED(hr))
481 _ComPtr<IMFMediaType> raw_type;
482 hr = source->GetNativeMediaType(cur.stream, cur.media, &raw_type);
483 if (hr == MF_E_NO_MORE_TYPES)
488 else if (SUCCEEDED(hr))
490 formats[cur] = MediaType(raw_type.Get());
495 std::pair<MediaID, MediaType> findBestVideoFormat(const MediaType& newType)
497 std::pair<MediaID, MediaType> best;
498 std::map<MediaID, MediaType>::const_iterator i = formats.begin();
499 for (; i != formats.end(); ++i)
501 if (i->second.majorType != MFMediaType_Video)
503 if (newType.isEmpty()) // file input - choose first returned media type
508 if (best.second.isEmpty() || i->second.isBetterThan(best.second, newType))
516 std::map<MediaID, MediaType> formats;
519 //==================================================================================================
521 // Enumerates devices and activates one of them
525 DeviceList() : devices(NULL), count(0) {}
530 for (UINT32 i = 0; i < count; ++i)
532 devices[i]->Release();
533 CoTaskMemFree(devices);
536 UINT32 read(IID sourceType = MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)
538 _ComPtr<IMFAttributes> attr;
539 if (FAILED(MFCreateAttributes(&attr, 1)) ||
540 FAILED(attr->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, sourceType)))
542 CV_Error(CV_StsError, "Failed to create attributes");
544 if (FAILED(MFEnumDeviceSources(attr.Get(), &devices, &count)))
546 CV_LOG_DEBUG(NULL, "Failed to enumerate MSMF devices");
551 _ComPtr<IMFMediaSource> activateSource(UINT32 index)
553 _ComPtr<IMFMediaSource> result;
554 if (count == 0 || index >= count || FAILED(devices[index]->ActivateObject(__uuidof(IMFMediaSource), (void**)&result)))
556 CV_LOG_DEBUG(NULL, "Failed to activate media source (device " << index << ")");
561 IMFActivate** devices;
567 //==================================================================================================
569 /******* Capturing video from camera or file via Microsoft Media Foundation **********/
570 class CvCapture_MSMF : public cv::IVideoCapture
578 virtual ~CvCapture_MSMF();
579 virtual bool open(int);
580 virtual bool open(const cv::String&);
581 virtual void close();
582 virtual double getProperty(int) const CV_OVERRIDE;
583 virtual bool setProperty(int, double) CV_OVERRIDE;
584 virtual bool grabFrame() CV_OVERRIDE;
585 virtual bool retrieveFrame(int, cv::OutputArray) CV_OVERRIDE;
586 virtual bool isOpened() const CV_OVERRIDE { return isOpen; }
587 virtual int getCaptureDomain() CV_OVERRIDE { return CV_CAP_MSMF; }
589 bool configureOutput(MediaType newType, cv::uint32_t outFormat);
590 bool setTime(double time, bool rough);
591 bool configureHW(bool enable);
593 template <typename CtrlT>
594 bool readComplexPropery(long prop, long& val) const;
595 template <typename CtrlT>
596 bool writeComplexProperty(long prop, double val, long flags);
597 _ComPtr<IMFAttributes> getDefaultSourceConfig(UINT32 num = 10);
598 bool initStream(DWORD streamID, const MediaType& mt);
600 Media_Foundation& MF;
603 MSMFCapture_Mode captureMode;
604 #ifdef HAVE_MSMF_DXVA
605 _ComPtr<ID3D11Device> D3DDev;
606 _ComPtr<IMFDXGIDeviceManager> D3DMgr;
608 _ComPtr<IMFSourceReader> videoFileSource;
610 MediaType nativeFormat;
611 MediaType captureFormat;
616 _ComPtr<IMFSample> videoSample;
619 _ComPtr<IMFSourceReaderCallback> readCallback; // non-NULL for "live" streams (camera capture)
622 CvCapture_MSMF::CvCapture_MSMF():
623 MF(Media_Foundation::getInstance()),
626 captureMode(MODE_SW),
627 #ifdef HAVE_MSMF_DXVA
631 videoFileSource(NULL),
633 outputFormat(CV_CAP_MODE_BGR),
641 CvCapture_MSMF::~CvCapture_MSMF()
647 void CvCapture_MSMF::close()
652 videoSample.Release();
653 videoFileSource.Release();
657 readCallback.Release();
660 bool CvCapture_MSMF::initStream(DWORD streamID, const MediaType& mt)
662 CV_LOG_DEBUG(NULL, "Init stream " << streamID << " with MediaType " << mt);
663 _ComPtr<IMFMediaType> mediaTypeOut = mt.createMediaType();
664 if (FAILED(videoFileSource->SetStreamSelection((DWORD)MF_SOURCE_READER_ALL_STREAMS, false)))
666 CV_LOG_WARNING(NULL, "Failed to reset streams");
669 if (FAILED(videoFileSource->SetStreamSelection(streamID, true)))
671 CV_LOG_WARNING(NULL, "Failed to select stream " << streamID);
674 HRESULT hr = videoFileSource->SetCurrentMediaType(streamID, NULL, mediaTypeOut.Get());
675 if (hr == MF_E_TOPO_CODEC_NOT_FOUND)
677 CV_LOG_WARNING(NULL, "Failed to set mediaType (stream " << streamID << ", " << mt << "(codec not found)");
680 else if (hr == MF_E_INVALIDMEDIATYPE)
682 CV_LOG_WARNING(NULL, "Failed to set mediaType (stream " << streamID << ", " << mt << "(unsupported media type)");
687 CV_LOG_WARNING(NULL, "Failed to set mediaType (stream " << streamID << ", " << mt << "(HRESULT " << hr << ")");
694 _ComPtr<IMFAttributes> CvCapture_MSMF::getDefaultSourceConfig(UINT32 num)
697 _ComPtr<IMFAttributes> res;
698 if (FAILED(MFCreateAttributes(&res, num)) ||
699 FAILED(res->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)) ||
700 FAILED(res->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, false)) ||
701 FAILED(res->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, false)) ||
702 FAILED(res->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true))
705 CV_Error(CV_StsError, "Failed to create attributes");
707 #ifdef HAVE_MSMF_DXVA
710 if (FAILED(res->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, D3DMgr.Get())))
712 CV_Error(CV_StsError, "Failed to create attributes");
719 bool CvCapture_MSMF::configureHW(bool enable)
721 #ifdef HAVE_MSMF_DXVA
722 if ((enable && D3DMgr && D3DDev) || (!enable && !D3DMgr && !D3DDev))
724 if (!pMFCreateDXGIDeviceManager_initialized)
725 init_MFCreateDXGIDeviceManager();
726 if (enable && !pMFCreateDXGIDeviceManager)
729 bool reopen = isOpen;
731 cv::String prevfile = filename;
735 D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0,
736 D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0,
737 D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1 };
738 if (SUCCEEDED(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
739 levels, sizeof(levels) / sizeof(*levels), D3D11_SDK_VERSION, &D3DDev, NULL, NULL)))
741 // NOTE: Getting ready for multi-threaded operation
742 _ComPtr<ID3D11Multithread> D3DDevMT;
744 if (SUCCEEDED(D3DDev->QueryInterface(IID_PPV_ARGS(&D3DDevMT))))
746 D3DDevMT->SetMultithreadProtected(TRUE);
748 if (SUCCEEDED(pMFCreateDXGIDeviceManager(&mgrRToken, &D3DMgr)))
750 if (SUCCEEDED(D3DMgr->ResetDevice(D3DDev.Get(), mgrRToken)))
752 captureMode = MODE_HW;
753 return reopen ? (prevcam >= 0 ? open(prevcam) : open(prevfile.c_str())) : true;
768 captureMode = MODE_SW;
769 return reopen ? (prevcam >= 0 ? open(prevcam) : open(prevfile.c_str())) : true;
776 bool CvCapture_MSMF::configureOutput(MediaType newType, cv::uint32_t outFormat)
778 FormatStorage formats;
779 formats.read(videoFileSource.Get());
780 std::pair<FormatStorage::MediaID, MediaType> bestMatch = formats.findBestVideoFormat(newType);
781 if (bestMatch.second.isEmpty())
783 CV_LOG_DEBUG(NULL, "Can not find video stream with requested parameters");
786 dwStreamIndex = bestMatch.first.stream;
787 nativeFormat = bestMatch.second;
788 MediaType newFormat = nativeFormat;
793 case CV_CAP_MODE_BGR:
794 case CV_CAP_MODE_RGB:
795 newFormat.subType = captureMode == MODE_HW ? MFVideoFormat_RGB32 : MFVideoFormat_RGB24;
796 newFormat.stride = (captureMode == MODE_HW ? 4 : 3) * newFormat.width;
797 newFormat.sampleSize = newFormat.stride * newFormat.height;
799 case CV_CAP_MODE_GRAY:
800 newFormat.subType = MFVideoFormat_YUY2;
801 newFormat.stride = newFormat.width;
802 newFormat.sampleSize = newFormat.stride * newFormat.height * 3 / 2;
804 case CV_CAP_MODE_YUYV:
805 newFormat.subType = MFVideoFormat_YUY2;
806 newFormat.stride = 2 * newFormat.width;
807 newFormat.sampleSize = newFormat.stride * newFormat.height;
812 newFormat.interlaceMode = MFVideoInterlace_Progressive;
813 newFormat.isFixedSize = true;
814 if (nativeFormat.subType == MFVideoFormat_MP43) //Unable to estimate FPS for MP43
815 newFormat.frameRateNum = 0;
817 // we select native format first and then our requested format (related issue #12822)
818 if (!newType.isEmpty()) // camera input
819 initStream(dwStreamIndex, nativeFormat);
820 return initStream(dwStreamIndex, newFormat);
823 bool CvCapture_MSMF::open(int index)
829 UINT32 count = devices.read();
830 if (count == 0 || static_cast<UINT32>(index) > count)
832 CV_LOG_DEBUG(NULL, "Device " << index << " not found (total " << count << " devices)");
835 _ComPtr<IMFAttributes> attr = getDefaultSourceConfig();
836 _ComPtr<IMFSourceReaderCallback> cb = new SourceReaderCB();
837 attr->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, cb.Get());
838 _ComPtr<IMFMediaSource> src = devices.activateSource(index);
839 if (!src.Get() || FAILED(MFCreateSourceReaderFromMediaSource(src.Get(), attr.Get(), &videoFileSource)))
841 CV_LOG_DEBUG(NULL, "Failed to create source reader");
849 if (configureOutput(MediaType::createDefault(), outputFormat))
851 frameStep = captureFormat.getFrameStep();
856 bool CvCapture_MSMF::open(const cv::String& _filename)
859 if (_filename.empty())
862 // Set source reader parameters
863 _ComPtr<IMFAttributes> attr = getDefaultSourceConfig();
864 cv::AutoBuffer<wchar_t> unicodeFileName(_filename.length() + 1);
865 MultiByteToWideChar(CP_ACP, 0, _filename.c_str(), -1, unicodeFileName.data(), (int)_filename.length() + 1);
866 if (SUCCEEDED(MFCreateSourceReaderFromURL(unicodeFileName.data(), attr.Get(), &videoFileSource)))
870 if (configureOutput(MediaType(), outputFormat))
872 frameStep = captureFormat.getFrameStep();
873 filename = _filename;
876 if (SUCCEEDED(hr = videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var)) &&
879 duration = var.uhVal.QuadPart;
880 PropVariantClear(&var);
890 bool CvCapture_MSMF::grabFrame()
893 if (readCallback) // async "live" capture mode
896 SourceReaderCB* reader = ((SourceReaderCB*)readCallback.Get());
897 if (!reader->m_reader)
899 // Initiate capturing with async callback
900 reader->m_reader = videoFileSource.Get();
901 reader->m_dwStreamIndex = dwStreamIndex;
902 if (FAILED(hr = videoFileSource->ReadSample(dwStreamIndex, 0, NULL, NULL, NULL, NULL)))
904 CV_LOG_ERROR(NULL, "videoio(MSMF): can't grab frame - initial async ReadSample() call failed: " << hr);
905 reader->m_reader = NULL;
910 if (FAILED(hr = reader->Wait(10000, videoSample, bEOS))) // 10 sec
912 CV_LOG_WARNING(NULL, "videoio(MSMF): can't grab frame. Error: " << hr);
917 CV_LOG_WARNING(NULL, "videoio(MSMF): EOS signal. Capture stream is lost");
920 sampleTime = reader->m_lastSampleTimestamp;
925 DWORD streamIndex, flags;
926 videoSample.Release();
930 CV_TRACE_REGION("ReadSample");
931 if (!SUCCEEDED(hr = videoFileSource->ReadSample(
932 dwStreamIndex, // Stream index.
934 &streamIndex, // Receives the actual stream index.
935 &flags, // Receives status flags.
936 &sampleTime, // Receives the time stamp.
937 &videoSample // Receives the sample or NULL.
940 if (streamIndex != dwStreamIndex)
942 if (flags & (MF_SOURCE_READERF_ERROR | MF_SOURCE_READERF_ALLEFFECTSREMOVED | MF_SOURCE_READERF_ENDOFSTREAM))
946 if (flags & MF_SOURCE_READERF_STREAMTICK)
948 CV_LOG_DEBUG(NULL, "videoio(MSMF): Stream tick detected. Retrying to grab the frame");
954 if (streamIndex != dwStreamIndex)
956 CV_LOG_DEBUG(NULL, "videoio(MSMF): Wrong stream read. Abort capturing");
959 else if (flags & MF_SOURCE_READERF_ERROR)
961 CV_LOG_DEBUG(NULL, "videoio(MSMF): Stream reading error. Abort capturing");
964 else if (flags & MF_SOURCE_READERF_ALLEFFECTSREMOVED)
966 CV_LOG_DEBUG(NULL, "videoio(MSMF): Stream decoding error. Abort capturing");
969 else if (flags & MF_SOURCE_READERF_ENDOFSTREAM)
971 sampleTime += frameStep;
972 CV_LOG_DEBUG(NULL, "videoio(MSMF): End of stream detected");
976 sampleTime += frameStep;
977 if (flags & MF_SOURCE_READERF_NEWSTREAM)
979 CV_LOG_DEBUG(NULL, "videoio(MSMF): New stream detected");
981 if (flags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED)
983 CV_LOG_DEBUG(NULL, "videoio(MSMF): Stream native media type changed");
985 if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
987 CV_LOG_DEBUG(NULL, "videoio(MSMF): Stream current media type changed");
996 bool CvCapture_MSMF::retrieveFrame(int, cv::OutputArray frame)
1004 _ComPtr<IMFMediaBuffer> buf = NULL;
1006 CV_TRACE_REGION("get_contiguous_buffer");
1007 if (!SUCCEEDED(videoSample->ConvertToContiguousBuffer(&buf)))
1009 CV_TRACE_REGION("get_buffer");
1011 if (!SUCCEEDED(videoSample->GetBufferCount(&bcnt)))
1015 if (!SUCCEEDED(videoSample->GetBufferByIndex(0, &buf)))
1019 bool lock2d = false;
1022 DWORD maxsize = 0, cursize = 0;
1024 // "For 2-D buffers, the Lock2D method is more efficient than the Lock method"
1025 // see IMFMediaBuffer::Lock method documentation: https://msdn.microsoft.com/en-us/library/windows/desktop/bb970366(v=vs.85).aspx
1026 _ComPtr<IMF2DBuffer> buffer2d;
1029 if (SUCCEEDED(buf.As<IMF2DBuffer>(buffer2d)))
1031 CV_TRACE_REGION_NEXT("lock2d");
1032 if (SUCCEEDED(buffer2d->Lock2D(&ptr, &pitch)))
1040 CV_Assert(lock2d == false);
1041 CV_TRACE_REGION_NEXT("lock");
1042 if (!SUCCEEDED(buf->Lock(&ptr, &maxsize, &cursize)))
1051 if (lock2d || (unsigned int)cursize == captureFormat.sampleSize)
1053 switch (outputFormat)
1055 case CV_CAP_MODE_YUYV:
1056 cv::Mat(captureFormat.height, captureFormat.width, CV_8UC2, ptr, pitch).copyTo(frame);
1058 case CV_CAP_MODE_BGR:
1059 if (captureMode == MODE_HW)
1060 cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC4, ptr, pitch), frame, cv::COLOR_BGRA2BGR);
1062 cv::Mat(captureFormat.height, captureFormat.width, CV_8UC3, ptr, pitch).copyTo(frame);
1064 case CV_CAP_MODE_RGB:
1065 if (captureMode == MODE_HW)
1066 cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC4, ptr, pitch), frame, cv::COLOR_BGRA2BGR);
1068 cv::cvtColor(cv::Mat(captureFormat.height, captureFormat.width, CV_8UC3, ptr, pitch), frame, cv::COLOR_BGR2RGB);
1070 case CV_CAP_MODE_GRAY:
1071 cv::Mat(captureFormat.height, captureFormat.width, CV_8UC1, ptr, pitch).copyTo(frame);
1083 cv::Mat(1, cursize, CV_8UC1, ptr, pitch).copyTo(frame);
1085 CV_TRACE_REGION_NEXT("unlock");
1087 buffer2d->Unlock2D();
1090 return !frame.empty();
1097 bool CvCapture_MSMF::setTime(double time, bool rough)
1100 if (SUCCEEDED(videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS, &var)) &&
1101 var.vt == VT_UI4 && var.ulVal & MFMEDIASOURCE_CAN_SEEK)
1103 videoSample.Release();
1104 bool useGrabbing = time > 0 && !rough && !(var.ulVal & MFMEDIASOURCE_HAS_SLOW_SEEK);
1105 PropVariantClear(&var);
1106 sampleTime = (useGrabbing && time >= frameStep) ? (LONGLONG)floor(time + 0.5) - frameStep : (LONGLONG)floor(time + 0.5);
1108 var.hVal.QuadPart = sampleTime;
1109 bool resOK = SUCCEEDED(videoFileSource->SetCurrentPosition(GUID_NULL, var));
1110 PropVariantClear(&var);
1111 if (resOK && useGrabbing)
1113 LONGLONG timeborder = (LONGLONG)floor(time + 0.5) - frameStep / 2;
1114 do { resOK = grabFrame(); videoSample.Release(); } while (resOK && sampleTime < timeborder);
1121 template <typename CtrlT>
1122 bool CvCapture_MSMF::readComplexPropery(long prop, long & val) const
1124 _ComPtr<CtrlT> ctrl;
1125 if (FAILED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&ctrl))))
1127 CV_LOG_DEBUG(NULL, "Failed to get service for stream");
1130 long paramVal, paramFlag;
1131 if (FAILED(ctrl->Get(prop, ¶mVal, ¶mFlag)))
1133 CV_LOG_DEBUG(NULL, "Failed to get property " << prop);
1136 // fallback - get default value
1137 long minVal, maxVal, stepVal;
1138 if (FAILED(ctrl->GetRange(prop, &minVal, &maxVal, &stepVal, ¶mVal, ¶mFlag)))
1140 CV_LOG_DEBUG(NULL, "Failed to get default value for property " << prop);
1147 double CvCapture_MSMF::getProperty( int property_id ) const
1151 switch (property_id)
1153 case CV_CAP_PROP_MODE:
1155 case CV_CAP_PROP_CONVERT_RGB:
1156 return convertFormat ? 1 : 0;
1157 case CV_CAP_PROP_SAR_NUM:
1158 return captureFormat.aspectRatioNum;
1159 case CV_CAP_PROP_SAR_DEN:
1160 return captureFormat.aspectRatioDenom;
1161 case CV_CAP_PROP_FRAME_WIDTH:
1162 return captureFormat.width;
1163 case CV_CAP_PROP_FRAME_HEIGHT:
1164 return captureFormat.height;
1165 case CV_CAP_PROP_FOURCC:
1166 return captureFormat.subType.Data1;
1167 case CV_CAP_PROP_FPS:
1168 return captureFormat.getFramerate();
1169 case CV_CAP_PROP_FRAME_COUNT:
1171 return floor(((double)duration / 1e7)* captureFormat.getFramerate() + 0.5);
1174 case CV_CAP_PROP_POS_FRAMES:
1175 return floor(((double)sampleTime / 1e7)* captureFormat.getFramerate() + 0.5);
1176 case CV_CAP_PROP_POS_MSEC:
1177 return (double)sampleTime / 1e4;
1178 case CV_CAP_PROP_POS_AVI_RATIO:
1180 return (double)sampleTime / duration;
1183 case CV_CAP_PROP_BRIGHTNESS:
1184 if (readComplexPropery<IAMVideoProcAmp>(VideoProcAmp_Brightness, cVal))
1187 case CV_CAP_PROP_CONTRAST:
1188 if (readComplexPropery<IAMVideoProcAmp>(VideoProcAmp_Contrast, cVal))
1191 case CV_CAP_PROP_SATURATION:
1192 if (readComplexPropery<IAMVideoProcAmp>(VideoProcAmp_Saturation, cVal))
1195 case CV_CAP_PROP_HUE:
1196 if (readComplexPropery<IAMVideoProcAmp>(VideoProcAmp_Hue, cVal))
1199 case CV_CAP_PROP_GAIN:
1200 if (readComplexPropery<IAMVideoProcAmp>(VideoProcAmp_Gain, cVal))
1203 case CV_CAP_PROP_SHARPNESS:
1204 if (readComplexPropery<IAMVideoProcAmp>(VideoProcAmp_Sharpness, cVal))
1207 case CV_CAP_PROP_GAMMA:
1208 if (readComplexPropery<IAMVideoProcAmp>(VideoProcAmp_Gamma, cVal))
1211 case CV_CAP_PROP_BACKLIGHT:
1212 if (readComplexPropery<IAMVideoProcAmp>(VideoProcAmp_BacklightCompensation, cVal))
1215 case CV_CAP_PROP_MONOCHROME:
1216 if (readComplexPropery<IAMVideoProcAmp>(VideoProcAmp_ColorEnable, cVal))
1217 return cVal == 0 ? 1 : 0;
1219 case CV_CAP_PROP_TEMPERATURE:
1220 if (readComplexPropery<IAMVideoProcAmp>(VideoProcAmp_WhiteBalance, cVal))
1223 case CV_CAP_PROP_PAN:
1224 if (readComplexPropery<IAMCameraControl>(CameraControl_Pan, cVal))
1227 case CV_CAP_PROP_TILT:
1228 if (readComplexPropery<IAMCameraControl>(CameraControl_Tilt, cVal))
1231 case CV_CAP_PROP_ROLL:
1232 if (readComplexPropery<IAMCameraControl>(CameraControl_Roll, cVal))
1235 case CV_CAP_PROP_IRIS:
1236 if (readComplexPropery<IAMCameraControl>(CameraControl_Iris, cVal))
1239 case CV_CAP_PROP_EXPOSURE:
1240 case CV_CAP_PROP_AUTO_EXPOSURE:
1241 if (readComplexPropery<IAMCameraControl>(CameraControl_Exposure, cVal))
1243 if (property_id == CV_CAP_PROP_EXPOSURE)
1246 return cVal == VideoProcAmp_Flags_Auto;
1249 case CV_CAP_PROP_ZOOM:
1250 if (readComplexPropery<IAMCameraControl>(CameraControl_Zoom, cVal))
1253 case CV_CAP_PROP_FOCUS:
1254 case CV_CAP_PROP_AUTOFOCUS:
1255 if (readComplexPropery<IAMCameraControl>(CameraControl_Focus, cVal))
1257 if (property_id == CV_CAP_PROP_FOCUS)
1260 return cVal == VideoProcAmp_Flags_Auto;
1263 case CV_CAP_PROP_WHITE_BALANCE_BLUE_U:
1264 case CV_CAP_PROP_WHITE_BALANCE_RED_V:
1265 case CV_CAP_PROP_RECTIFICATION:
1266 case CV_CAP_PROP_TRIGGER:
1267 case CV_CAP_PROP_TRIGGER_DELAY:
1268 case CV_CAP_PROP_GUID:
1269 case CV_CAP_PROP_ISO_SPEED:
1270 case CV_CAP_PROP_SETTINGS:
1271 case CV_CAP_PROP_BUFFERSIZE:
1278 template <typename CtrlT>
1279 bool CvCapture_MSMF::writeComplexProperty(long prop, double val, long flags)
1281 _ComPtr<CtrlT> ctrl;
1282 if (FAILED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&ctrl))))
1284 CV_LOG_DEBUG(NULL, "Failed get service for stream");
1287 if (FAILED(ctrl->Set(prop, (long)val, flags)))
1289 CV_LOG_DEBUG(NULL, "Failed to set property " << prop);
1295 bool CvCapture_MSMF::setProperty( int property_id, double value )
1297 MediaType newFormat = captureFormat;
1299 switch (property_id)
1301 case CV_CAP_PROP_MODE:
1302 switch ((MSMFCapture_Mode)((int)value))
1305 return configureHW(false);
1307 return configureHW(true);
1311 case CV_CAP_PROP_FOURCC:
1312 return configureOutput(newFormat, (int)cvRound(value));
1313 case CV_CAP_PROP_FORMAT:
1314 return configureOutput(newFormat, (int)cvRound(value));
1315 case CV_CAP_PROP_CONVERT_RGB:
1316 convertFormat = (value != 0);
1317 return configureOutput(newFormat, outputFormat);
1318 case CV_CAP_PROP_SAR_NUM:
1321 newFormat.aspectRatioNum = (UINT32)cvRound(value);
1322 return configureOutput(newFormat, outputFormat);
1325 case CV_CAP_PROP_SAR_DEN:
1328 newFormat.aspectRatioDenom = (UINT32)cvRound(value);
1329 return configureOutput(newFormat, outputFormat);
1332 case CV_CAP_PROP_FRAME_WIDTH:
1335 newFormat.width = (UINT32)cvRound(value);
1336 return configureOutput(newFormat, outputFormat);
1339 case CV_CAP_PROP_FRAME_HEIGHT:
1342 newFormat.height = (UINT32)cvRound(value);
1343 return configureOutput(newFormat, outputFormat);
1346 case CV_CAP_PROP_FPS:
1349 newFormat.setFramerate(value);
1350 return configureOutput(newFormat, outputFormat);
1353 case CV_CAP_PROP_FRAME_COUNT:
1355 case CV_CAP_PROP_POS_AVI_RATIO:
1357 return setTime(duration * value, true);
1359 case CV_CAP_PROP_POS_FRAMES:
1360 if (std::fabs(captureFormat.getFramerate()) > 0)
1361 return setTime(value * 1e7 / captureFormat.getFramerate(), false);
1363 case CV_CAP_PROP_POS_MSEC:
1364 return setTime(value * 1e4, false);
1365 case CV_CAP_PROP_BRIGHTNESS:
1366 return writeComplexProperty<IAMVideoProcAmp>(VideoProcAmp_Brightness, value, VideoProcAmp_Flags_Manual);
1367 case CV_CAP_PROP_CONTRAST:
1368 return writeComplexProperty<IAMVideoProcAmp>(VideoProcAmp_Contrast, value, VideoProcAmp_Flags_Manual);
1369 case CV_CAP_PROP_SATURATION:
1370 return writeComplexProperty<IAMVideoProcAmp>(VideoProcAmp_Saturation, value, VideoProcAmp_Flags_Manual);
1371 case CV_CAP_PROP_HUE:
1372 return writeComplexProperty<IAMVideoProcAmp>(VideoProcAmp_Hue, value, VideoProcAmp_Flags_Manual);
1373 case CV_CAP_PROP_GAIN:
1374 return writeComplexProperty<IAMVideoProcAmp>(VideoProcAmp_Gain, value, VideoProcAmp_Flags_Manual);
1375 case CV_CAP_PROP_SHARPNESS:
1376 return writeComplexProperty<IAMVideoProcAmp>(VideoProcAmp_Sharpness, value, VideoProcAmp_Flags_Manual);
1377 case CV_CAP_PROP_GAMMA:
1378 return writeComplexProperty<IAMVideoProcAmp>(VideoProcAmp_Gamma, value, VideoProcAmp_Flags_Manual);
1379 case CV_CAP_PROP_BACKLIGHT:
1380 return writeComplexProperty<IAMVideoProcAmp>(VideoProcAmp_BacklightCompensation, value, VideoProcAmp_Flags_Manual);
1381 case CV_CAP_PROP_MONOCHROME:
1382 return writeComplexProperty<IAMVideoProcAmp>(VideoProcAmp_ColorEnable, value, VideoProcAmp_Flags_Manual);
1383 case CV_CAP_PROP_TEMPERATURE:
1384 return writeComplexProperty<IAMVideoProcAmp>(VideoProcAmp_WhiteBalance, value, VideoProcAmp_Flags_Manual);
1385 case CV_CAP_PROP_PAN:
1386 return writeComplexProperty<IAMCameraControl>(CameraControl_Pan, value, CameraControl_Flags_Manual);
1387 case CV_CAP_PROP_TILT:
1388 return writeComplexProperty<IAMCameraControl>(CameraControl_Tilt, value, CameraControl_Flags_Manual);
1389 case CV_CAP_PROP_ROLL:
1390 return writeComplexProperty<IAMCameraControl>(CameraControl_Roll, value, CameraControl_Flags_Manual);
1391 case CV_CAP_PROP_IRIS:
1392 return writeComplexProperty<IAMCameraControl>(CameraControl_Iris, value, CameraControl_Flags_Manual);
1393 case CV_CAP_PROP_EXPOSURE:
1394 return writeComplexProperty<IAMCameraControl>(CameraControl_Exposure, value, CameraControl_Flags_Manual);
1395 case CV_CAP_PROP_AUTO_EXPOSURE:
1396 return writeComplexProperty<IAMCameraControl>(CameraControl_Exposure, value, value != 0 ? VideoProcAmp_Flags_Auto : VideoProcAmp_Flags_Manual);
1397 case CV_CAP_PROP_ZOOM:
1398 return writeComplexProperty<IAMCameraControl>(CameraControl_Zoom, value, CameraControl_Flags_Manual);
1399 case CV_CAP_PROP_FOCUS:
1400 return writeComplexProperty<IAMCameraControl>(CameraControl_Focus, value, CameraControl_Flags_Manual);
1401 case CV_CAP_PROP_AUTOFOCUS:
1402 return writeComplexProperty<IAMCameraControl>(CameraControl_Focus, value, value != 0 ? CameraControl_Flags_Auto : CameraControl_Flags_Manual);
1403 case CV_CAP_PROP_WHITE_BALANCE_BLUE_U:
1404 case CV_CAP_PROP_WHITE_BALANCE_RED_V:
1405 case CV_CAP_PROP_RECTIFICATION:
1406 case CV_CAP_PROP_TRIGGER:
1407 case CV_CAP_PROP_TRIGGER_DELAY:
1408 case CV_CAP_PROP_GUID:
1409 case CV_CAP_PROP_ISO_SPEED:
1410 case CV_CAP_PROP_SETTINGS:
1411 case CV_CAP_PROP_BUFFERSIZE:
1418 cv::Ptr<cv::IVideoCapture> cv::cvCreateCapture_MSMF( int index )
1420 cv::Ptr<CvCapture_MSMF> capture = cv::makePtr<CvCapture_MSMF>();
1423 capture->open(index);
1424 if (capture->isOpened())
1427 return cv::Ptr<cv::IVideoCapture>();
1430 cv::Ptr<cv::IVideoCapture> cv::cvCreateCapture_MSMF (const cv::String& filename)
1432 cv::Ptr<CvCapture_MSMF> capture = cv::makePtr<CvCapture_MSMF>();
1435 capture->open(filename);
1436 if (capture->isOpened())
1439 return cv::Ptr<cv::IVideoCapture>();
1444 // Media Foundation-based Video Writer
1448 class CvVideoWriter_MSMF : public cv::IVideoWriter
1451 CvVideoWriter_MSMF();
1452 virtual ~CvVideoWriter_MSMF();
1453 virtual bool open(const cv::String& filename, int fourcc,
1454 double fps, cv::Size frameSize, bool isColor);
1455 virtual void close();
1456 virtual void write(cv::InputArray);
1458 virtual double getProperty(int) const { return 0; }
1459 virtual bool setProperty(int, double) { return false; }
1460 virtual bool isOpened() const { return initiated; }
1462 int getCaptureDomain() const CV_OVERRIDE { return cv::CAP_MSMF; }
1464 Media_Foundation& MF;
1470 GUID encodingFormat;
1474 _ComPtr<IMFSinkWriter> sinkWriter;
1481 static const GUID FourCC2GUID(int fourcc);
1484 CvVideoWriter_MSMF::CvVideoWriter_MSMF():
1485 MF(Media_Foundation::getInstance()),
1500 CvVideoWriter_MSMF::~CvVideoWriter_MSMF()
1505 const GUID CvVideoWriter_MSMF::FourCC2GUID(int fourcc)
1509 case CV_FOURCC_MACRO('d', 'v', '2', '5'):
1510 return MFVideoFormat_DV25; break;
1511 case CV_FOURCC_MACRO('d', 'v', '5', '0'):
1512 return MFVideoFormat_DV50; break;
1513 case CV_FOURCC_MACRO('d', 'v', 'c', ' '):
1514 return MFVideoFormat_DVC; break;
1515 case CV_FOURCC_MACRO('d', 'v', 'h', '1'):
1516 return MFVideoFormat_DVH1; break;
1517 case CV_FOURCC_MACRO('d', 'v', 'h', 'd'):
1518 return MFVideoFormat_DVHD; break;
1519 case CV_FOURCC_MACRO('d', 'v', 's', 'd'):
1520 return MFVideoFormat_DVSD; break;
1521 case CV_FOURCC_MACRO('d', 'v', 's', 'l'):
1522 return MFVideoFormat_DVSL; break;
1523 #if (WINVER >= 0x0602)
1524 case CV_FOURCC_MACRO('H', '2', '6', '3'): // Available only for Win 8 target.
1525 return MFVideoFormat_H263; break;
1527 case CV_FOURCC_MACRO('H', '2', '6', '4'):
1528 return MFVideoFormat_H264; break;
1529 case CV_FOURCC_MACRO('M', '4', 'S', '2'):
1530 return MFVideoFormat_M4S2; break;
1531 case CV_FOURCC_MACRO('M', 'J', 'P', 'G'):
1532 return MFVideoFormat_MJPG; break;
1533 case CV_FOURCC_MACRO('M', 'P', '4', '3'):
1534 return MFVideoFormat_MP43; break;
1535 case CV_FOURCC_MACRO('M', 'P', '4', 'S'):
1536 return MFVideoFormat_MP4S; break;
1537 case CV_FOURCC_MACRO('M', 'P', '4', 'V'):
1538 return MFVideoFormat_MP4V; break;
1539 case CV_FOURCC_MACRO('M', 'P', 'G', '1'):
1540 return MFVideoFormat_MPG1; break;
1541 case CV_FOURCC_MACRO('M', 'S', 'S', '1'):
1542 return MFVideoFormat_MSS1; break;
1543 case CV_FOURCC_MACRO('M', 'S', 'S', '2'):
1544 return MFVideoFormat_MSS2; break;
1545 case CV_FOURCC_MACRO('W', 'M', 'V', '1'):
1546 return MFVideoFormat_WMV1; break;
1547 case CV_FOURCC_MACRO('W', 'M', 'V', '2'):
1548 return MFVideoFormat_WMV2; break;
1549 case CV_FOURCC_MACRO('W', 'M', 'V', '3'):
1550 return MFVideoFormat_WMV3; break;
1551 case CV_FOURCC_MACRO('W', 'V', 'C', '1'):
1552 return MFVideoFormat_WVC1; break;
1554 return MFVideoFormat_H264;
1558 bool CvVideoWriter_MSMF::open( const cv::String& filename, int fourcc,
1559 double _fps, cv::Size _frameSize, bool /*isColor*/ )
1563 videoWidth = _frameSize.width;
1564 videoHeight = _frameSize.height;
1566 bitRate = (UINT32)fps*videoWidth*videoHeight; // 1-bit per pixel
1567 encodingFormat = FourCC2GUID(fourcc);
1568 inputFormat = MFVideoFormat_RGB32;
1570 _ComPtr<IMFMediaType> mediaTypeOut;
1571 _ComPtr<IMFMediaType> mediaTypeIn;
1572 _ComPtr<IMFAttributes> spAttr;
1573 if (// Set the output media type.
1574 SUCCEEDED(MFCreateMediaType(&mediaTypeOut)) &&
1575 SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)) &&
1576 SUCCEEDED(mediaTypeOut->SetGUID(MF_MT_SUBTYPE, encodingFormat)) &&
1577 SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, bitRate)) &&
1578 SUCCEEDED(mediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive)) &&
1579 SUCCEEDED(MFSetAttributeSize(mediaTypeOut.Get(), MF_MT_FRAME_SIZE, videoWidth, videoHeight)) &&
1580 SUCCEEDED(MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_FRAME_RATE, (UINT32)(fps * 1000), 1000)) &&
1581 SUCCEEDED(MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1)) &&
1582 // Set the input media type.
1583 SUCCEEDED(MFCreateMediaType(&mediaTypeIn)) &&
1584 SUCCEEDED(mediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)) &&
1585 SUCCEEDED(mediaTypeIn->SetGUID(MF_MT_SUBTYPE, inputFormat)) &&
1586 SUCCEEDED(mediaTypeIn->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive)) &&
1587 SUCCEEDED(mediaTypeIn->SetUINT32(MF_MT_DEFAULT_STRIDE, 4 * videoWidth)) && //Assume BGR32 input
1588 SUCCEEDED(MFSetAttributeSize(mediaTypeIn.Get(), MF_MT_FRAME_SIZE, videoWidth, videoHeight)) &&
1589 SUCCEEDED(MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_FRAME_RATE, (UINT32)(fps * 1000), 1000)) &&
1590 SUCCEEDED(MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1)) &&
1591 // Set sink writer parameters
1592 SUCCEEDED(MFCreateAttributes(&spAttr, 10)) &&
1593 SUCCEEDED(spAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)) &&
1594 SUCCEEDED(spAttr->SetUINT32(MF_SINK_WRITER_DISABLE_THROTTLING, true))
1597 // Create the sink writer
1598 cv::AutoBuffer<wchar_t> unicodeFileName(filename.length() + 1);
1599 MultiByteToWideChar(CP_ACP, 0, filename.c_str(), -1, unicodeFileName.data(), (int)filename.length() + 1);
1600 HRESULT hr = MFCreateSinkWriterFromURL(unicodeFileName.data(), NULL, spAttr.Get(), &sinkWriter);
1603 // Configure the sink writer and tell it start to start accepting data
1604 if (SUCCEEDED(sinkWriter->AddStream(mediaTypeOut.Get(), &streamIndex)) &&
1605 SUCCEEDED(sinkWriter->SetInputMediaType(streamIndex, mediaTypeIn.Get(), NULL)) &&
1606 SUCCEEDED(sinkWriter->BeginWriting()))
1610 MFFrameRateToAverageTimePerFrame((UINT32)(fps * 1000), 1000, &rtDuration);
1619 void CvVideoWriter_MSMF::close()
1624 sinkWriter->Finalize();
1625 sinkWriter.Release();
1629 void CvVideoWriter_MSMF::write(cv::InputArray img)
1632 (img.channels() != 1 && img.channels() != 3 && img.channels() != 4) ||
1633 (UINT32)img.cols() != videoWidth || (UINT32)img.rows() != videoHeight)
1636 const LONG cbWidth = 4 * videoWidth;
1637 const DWORD cbBuffer = cbWidth * videoHeight;
1638 _ComPtr<IMFSample> sample;
1639 _ComPtr<IMFMediaBuffer> buffer;
1641 // Prepare a media sample.
1642 if (SUCCEEDED(MFCreateSample(&sample)) &&
1643 // Set sample time stamp and duration.
1644 SUCCEEDED(sample->SetSampleTime(rtStart)) &&
1645 SUCCEEDED(sample->SetSampleDuration(rtDuration)) &&
1646 // Create a memory buffer.
1647 SUCCEEDED(MFCreateMemoryBuffer(cbBuffer, &buffer)) &&
1648 // Set the data length of the buffer.
1649 SUCCEEDED(buffer->SetCurrentLength(cbBuffer)) &&
1650 // Add the buffer to the sample.
1651 SUCCEEDED(sample->AddBuffer(buffer.Get())) &&
1653 SUCCEEDED(buffer->Lock(&pData, NULL, NULL)))
1655 // Copy the video frame to the buffer.
1656 cv::cvtColor(img.getMat(), cv::Mat(videoHeight, videoWidth, CV_8UC4, pData, cbWidth), img.channels() > 1 ? cv::COLOR_BGR2BGRA : cv::COLOR_GRAY2BGRA);
1658 // Send media sample to the Sink Writer.
1659 if (SUCCEEDED(sinkWriter->WriteSample(streamIndex, sample.Get())))
1661 rtStart += rtDuration;
1666 cv::Ptr<cv::IVideoWriter> cv::cvCreateVideoWriter_MSMF( const std::string& filename, int fourcc,
1667 double fps, const cv::Size& frameSize,
1668 const VideoWriterParameters& params)
1670 cv::Ptr<CvVideoWriter_MSMF> writer = cv::makePtr<CvVideoWriter_MSMF>();
1673 const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
1674 writer->open(filename, fourcc, fps, frameSize, isColor);
1675 if (writer->isOpened())
1678 return cv::Ptr<cv::IVideoWriter>();
1681 #if defined(BUILD_PLUGIN)
1683 #include "plugin_api.hpp"
1687 typedef CvCapture_MSMF CaptureT;
1688 typedef CvVideoWriter_MSMF WriterT;
1691 CvResult CV_API_CALL cv_capture_open(const char* filename, int camera_index, CV_OUT CvPluginCapture* handle)
1694 return CV_ERROR_FAIL;
1697 return CV_ERROR_FAIL;
1701 cap = new CaptureT();
1704 res = cap->open(std::string(filename));
1706 res = cap->open(camera_index);
1709 *handle = (CvPluginCapture)cap;
1718 return CV_ERROR_FAIL;
1722 CvResult CV_API_CALL cv_capture_release(CvPluginCapture handle)
1725 return CV_ERROR_FAIL;
1726 CaptureT* instance = (CaptureT*)handle;
1733 CvResult CV_API_CALL cv_capture_get_prop(CvPluginCapture handle, int prop, CV_OUT double* val)
1736 return CV_ERROR_FAIL;
1738 return CV_ERROR_FAIL;
1741 CaptureT* instance = (CaptureT*)handle;
1742 *val = instance->getProperty(prop);
1747 return CV_ERROR_FAIL;
1752 CvResult CV_API_CALL cv_capture_set_prop(CvPluginCapture handle, int prop, double val)
1755 return CV_ERROR_FAIL;
1758 CaptureT* instance = (CaptureT*)handle;
1759 return instance->setProperty(prop, val) ? CV_ERROR_OK : CV_ERROR_FAIL;
1763 return CV_ERROR_FAIL;
1768 CvResult CV_API_CALL cv_capture_grab(CvPluginCapture handle)
1771 return CV_ERROR_FAIL;
1774 CaptureT* instance = (CaptureT*)handle;
1775 return instance->grabFrame() ? CV_ERROR_OK : CV_ERROR_FAIL;
1779 return CV_ERROR_FAIL;
1784 CvResult CV_API_CALL cv_capture_retrieve(CvPluginCapture handle, int stream_idx, cv_videoio_retrieve_cb_t callback, void* userdata)
1787 return CV_ERROR_FAIL;
1790 CaptureT* instance = (CaptureT*)handle;
1792 if (instance->retrieveFrame(stream_idx, img))
1793 return callback(stream_idx, img.data, (int)img.step, img.cols, img.rows, img.channels(), userdata);
1794 return CV_ERROR_FAIL;
1798 return CV_ERROR_FAIL;
1803 CvResult CV_API_CALL cv_writer_open(const char* filename, int fourcc, double fps, int width, int height, int isColor, CV_OUT CvPluginWriter* handle)
1808 wrt = new WriterT();
1809 Size sz(width, height);
1810 if (wrt && wrt->open(filename, fourcc, fps, sz, isColor != 0))
1812 *handle = (CvPluginWriter)wrt;
1821 return CV_ERROR_FAIL;
1825 CvResult CV_API_CALL cv_writer_release(CvPluginWriter handle)
1828 return CV_ERROR_FAIL;
1829 WriterT* instance = (WriterT*)handle;
1835 CvResult CV_API_CALL cv_writer_get_prop(CvPluginWriter /*handle*/, int /*prop*/, CV_OUT double* /*val*/)
1837 return CV_ERROR_FAIL;
1841 CvResult CV_API_CALL cv_writer_set_prop(CvPluginWriter /*handle*/, int /*prop*/, double /*val*/)
1843 return CV_ERROR_FAIL;
1847 CvResult CV_API_CALL cv_writer_write(CvPluginWriter handle, const unsigned char* data, int step, int width, int height, int cn)
1850 return CV_ERROR_FAIL;
1853 CV_Assert(step >= 0);
1854 WriterT* instance = (WriterT*)handle;
1855 Size sz(width, height);
1856 Mat img(sz, CV_MAKETYPE(CV_8U, cn), (void*)data, (size_t)step);
1857 instance->write(img);
1862 return CV_ERROR_FAIL;
1866 static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
1869 sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
1870 CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
1871 "Microsoft Media Foundation OpenCV Video I/O plugin"
1874 /* 2*/cv_capture_open,
1875 /* 3*/cv_capture_release,
1876 /* 4*/cv_capture_get_prop,
1877 /* 5*/cv_capture_set_prop,
1878 /* 6*/cv_capture_grab,
1879 /* 7*/cv_capture_retrieve,
1880 /* 8*/cv_writer_open,
1881 /* 9*/cv_writer_release,
1882 /* 10*/cv_writer_get_prop,
1883 /* 11*/cv_writer_set_prop,
1884 /* 12*/cv_writer_write
1889 const OpenCV_VideoIO_Plugin_API_preview* opencv_videoio_plugin_init_v0(int requested_abi_version, int requested_api_version, void* /*reserved=NULL*/) CV_NOEXCEPT
1891 if (requested_abi_version != 0)
1893 if (requested_api_version != 0)
1895 return &cv::plugin_api_v0;
1898 #endif // BUILD_PLUGIN