2020-02-07 20:03:20 +08:00
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
2013-04-03 09:01:20 +08:00
# include "precomp.hpp"
/*
Media Foundation - based Video Capturing module is based on
videoInput library by Evgeny Pereguda :
http : //www.codeproject.com/Articles/559437/Capturing-of-video-from-web-camera-on-Windows-7-an
2018-02-14 00:28:11 +08:00
Originally licensed under The Code Project Open License ( CPOL ) 1.02 :
2013-04-03 09:01:20 +08:00
http : //www.codeproject.com/info/cpol10.aspx
*/
Add support for WinRT in the MF capture framework by removing the disallowed calls to enumerate devices and create a sample grabber sink and adding framework for the MediaCapture interface and a custom sink which interfaces with the sample grabber callback interface. The change requires discussion for making it completely functional as redundancy is required given that if the source is a video file, the old code pathways must be used. Otherwise all IMFMediaSession, IMFMediaSource, and IMFActivate code must use a MediaCapture code path and all sink code must use the CMediaSink custom sink.
Support for the custom sink is extended to non-WinRT not for compatibility as Windows Vista client is a minimum regardless, but because it offers more flexibility, could be faster and is able to be used as an optionally different code path during sink creation based on a future configuration parameter.
My discussion and proposal to finish this change:
Devices are so easily enumerated through WinRT Windows.Devices namespace that wrapping the calls in a library is quite a chore for little benefit though to get the various modes and formats could still be a worthwhile project. For now conditional compilation to remove videodevices and any offending non-video file related activity in videodevice. In my opinion, this is a different , far less fundamental and important change which can possibly be done as a future project and also much more easily implemented in C++/CX.
ImageGrabber has the IMFSampleGrabberSinkCallback replaced with a base class (SharedSampleGrabber) which also be is base class for ImageGrabberRT. This change is necessary as the custom sink does not require a thread to pump events which is done through MediaCapture already. IMFSampleGrabberSinkCallback is the common element between both models and that piece can be shared. Initializing the new ImageGrabberRT is as simple as passing an already initialized MediaCapture object and any video format/encoding parameters.
The concurrency event is necessary to wait for completion and is the way the underlying, IAsyncAction wrappers in the task library work as well. Native WIN32 event objects would be an option if HAVE_CONCURRENCY is not defined. I could even imagine doing it with sleep/thread yield and InterlockedCompareExchange yet I am not enthusiastic about that approach either. Since there is a specific compiler HAVE_ for concurrency, I do not like pulling it in though I think for WinRT it is safe to say we will always have it available though should probably conditionally compile with the Interlocked option as WIN32 events would require HAVE_WIN32.
It looks like C++/CX cannot be used for the IMediaExtension sink (which should not be a problem) as using COM objects requires WRL and though deriving from IMediaExtension can be done, there is little purpose without COM. Objects from C++/CX can be swapped to interact with objects from native C++ as Inspectable* can reinterpret_cast to the ref object IInspectable^ and vice-versa. A solution to the COM class with C++/CX would be great so we could have dual support. Also without #define for every WRL object in use, the code will get quite muddy given that the */^ would need to be ifdef'd everywhere.
Fixed bugs and completed the change. I believe the new classes need to be moved to a header file as the file has become to large and more classes need to be added for handling all the asynchronous problems (one wrapping IAsyncAction in a task and another for making a task out of IAsyncAction). Unfortunately, blocking on the UI thread is not an option in WinRT so a synchronous architecture is considered "illegal" by Microsoft's standards even if implementable (C++/CX ppltasks library throws errors if you try it). Worse, either by design or a bug in the MF MediaCapture class with Custom Sinks causes a crash if stop/start previewing without reinitializing (spPreferredPreviewMediaType is fatally nulled). After decompiling Windows.Media.dll, I worked around this in my own projects by using an activate-able custom sink ID which strangely assigns 1 to this pointer allowing it to be reinitialized in what can only be described as a hack by Microsoft. This would add additional overhead to the project to implement especially for static libraries as it requires IDL/DLL exporting followed by manifest declaration. Better to document that it is not supported.
Furthermore, an additional class for IMFAttributes should be implemented to make clean architecture for passing around attributes as opposed to directly calling non-COM interface calls on the objects and making use of SetProperties which would also be a set up for an object that uses the RuntimeClass activation ID.
The remaining changes are not difficult and will be complete soon along with debug tracing messages.
Update and rename cap_msmf.h to cap_msmf.hpp
Successful test - samples are grabbed
Library updated and cleaned up with comments, marshaling, exceptions and linker settings
Fixed trailing whitespace
VS 2013 support and cleanup consistency plus C++/CX new object fixed
Conflicts:
modules/highgui/src/cap_msmf.cpp
modules/highgui/src/cap_msmf.hpp
modules/highgui/src/ppltasks_winrt.h
Fix merge conflicts
VS 2013 Update 2 library bug fix integrated
a-wi's changed integrated
2013-12-14 16:53:30 +08:00
//require Windows 8 for some of the formats defined otherwise could baseline on lower version
2018-03-28 19:03:22 +08:00
# if WINVER < _WIN32_WINNT_WIN8
Add support for WinRT in the MF capture framework by removing the disallowed calls to enumerate devices and create a sample grabber sink and adding framework for the MediaCapture interface and a custom sink which interfaces with the sample grabber callback interface. The change requires discussion for making it completely functional as redundancy is required given that if the source is a video file, the old code pathways must be used. Otherwise all IMFMediaSession, IMFMediaSource, and IMFActivate code must use a MediaCapture code path and all sink code must use the CMediaSink custom sink.
Support for the custom sink is extended to non-WinRT not for compatibility as Windows Vista client is a minimum regardless, but because it offers more flexibility, could be faster and is able to be used as an optionally different code path during sink creation based on a future configuration parameter.
My discussion and proposal to finish this change:
Devices are so easily enumerated through WinRT Windows.Devices namespace that wrapping the calls in a library is quite a chore for little benefit though to get the various modes and formats could still be a worthwhile project. For now conditional compilation to remove videodevices and any offending non-video file related activity in videodevice. In my opinion, this is a different , far less fundamental and important change which can possibly be done as a future project and also much more easily implemented in C++/CX.
ImageGrabber has the IMFSampleGrabberSinkCallback replaced with a base class (SharedSampleGrabber) which also be is base class for ImageGrabberRT. This change is necessary as the custom sink does not require a thread to pump events which is done through MediaCapture already. IMFSampleGrabberSinkCallback is the common element between both models and that piece can be shared. Initializing the new ImageGrabberRT is as simple as passing an already initialized MediaCapture object and any video format/encoding parameters.
The concurrency event is necessary to wait for completion and is the way the underlying, IAsyncAction wrappers in the task library work as well. Native WIN32 event objects would be an option if HAVE_CONCURRENCY is not defined. I could even imagine doing it with sleep/thread yield and InterlockedCompareExchange yet I am not enthusiastic about that approach either. Since there is a specific compiler HAVE_ for concurrency, I do not like pulling it in though I think for WinRT it is safe to say we will always have it available though should probably conditionally compile with the Interlocked option as WIN32 events would require HAVE_WIN32.
It looks like C++/CX cannot be used for the IMediaExtension sink (which should not be a problem) as using COM objects requires WRL and though deriving from IMediaExtension can be done, there is little purpose without COM. Objects from C++/CX can be swapped to interact with objects from native C++ as Inspectable* can reinterpret_cast to the ref object IInspectable^ and vice-versa. A solution to the COM class with C++/CX would be great so we could have dual support. Also without #define for every WRL object in use, the code will get quite muddy given that the */^ would need to be ifdef'd everywhere.
Fixed bugs and completed the change. I believe the new classes need to be moved to a header file as the file has become to large and more classes need to be added for handling all the asynchronous problems (one wrapping IAsyncAction in a task and another for making a task out of IAsyncAction). Unfortunately, blocking on the UI thread is not an option in WinRT so a synchronous architecture is considered "illegal" by Microsoft's standards even if implementable (C++/CX ppltasks library throws errors if you try it). Worse, either by design or a bug in the MF MediaCapture class with Custom Sinks causes a crash if stop/start previewing without reinitializing (spPreferredPreviewMediaType is fatally nulled). After decompiling Windows.Media.dll, I worked around this in my own projects by using an activate-able custom sink ID which strangely assigns 1 to this pointer allowing it to be reinitialized in what can only be described as a hack by Microsoft. This would add additional overhead to the project to implement especially for static libraries as it requires IDL/DLL exporting followed by manifest declaration. Better to document that it is not supported.
Furthermore, an additional class for IMFAttributes should be implemented to make clean architecture for passing around attributes as opposed to directly calling non-COM interface calls on the objects and making use of SetProperties which would also be a set up for an object that uses the RuntimeClass activation ID.
The remaining changes are not difficult and will be complete soon along with debug tracing messages.
Update and rename cap_msmf.h to cap_msmf.hpp
Successful test - samples are grabbed
Library updated and cleaned up with comments, marshaling, exceptions and linker settings
Fixed trailing whitespace
VS 2013 support and cleanup consistency plus C++/CX new object fixed
Conflicts:
modules/highgui/src/cap_msmf.cpp
modules/highgui/src/cap_msmf.hpp
modules/highgui/src/ppltasks_winrt.h
Fix merge conflicts
VS 2013 Update 2 library bug fix integrated
a-wi's changed integrated
2013-12-14 16:53:30 +08:00
# undef WINVER
2018-03-28 19:03:22 +08:00
# define WINVER _WIN32_WINNT_WIN8
Add support for WinRT in the MF capture framework by removing the disallowed calls to enumerate devices and create a sample grabber sink and adding framework for the MediaCapture interface and a custom sink which interfaces with the sample grabber callback interface. The change requires discussion for making it completely functional as redundancy is required given that if the source is a video file, the old code pathways must be used. Otherwise all IMFMediaSession, IMFMediaSource, and IMFActivate code must use a MediaCapture code path and all sink code must use the CMediaSink custom sink.
Support for the custom sink is extended to non-WinRT not for compatibility as Windows Vista client is a minimum regardless, but because it offers more flexibility, could be faster and is able to be used as an optionally different code path during sink creation based on a future configuration parameter.
My discussion and proposal to finish this change:
Devices are so easily enumerated through WinRT Windows.Devices namespace that wrapping the calls in a library is quite a chore for little benefit though to get the various modes and formats could still be a worthwhile project. For now conditional compilation to remove videodevices and any offending non-video file related activity in videodevice. In my opinion, this is a different , far less fundamental and important change which can possibly be done as a future project and also much more easily implemented in C++/CX.
ImageGrabber has the IMFSampleGrabberSinkCallback replaced with a base class (SharedSampleGrabber) which also be is base class for ImageGrabberRT. This change is necessary as the custom sink does not require a thread to pump events which is done through MediaCapture already. IMFSampleGrabberSinkCallback is the common element between both models and that piece can be shared. Initializing the new ImageGrabberRT is as simple as passing an already initialized MediaCapture object and any video format/encoding parameters.
The concurrency event is necessary to wait for completion and is the way the underlying, IAsyncAction wrappers in the task library work as well. Native WIN32 event objects would be an option if HAVE_CONCURRENCY is not defined. I could even imagine doing it with sleep/thread yield and InterlockedCompareExchange yet I am not enthusiastic about that approach either. Since there is a specific compiler HAVE_ for concurrency, I do not like pulling it in though I think for WinRT it is safe to say we will always have it available though should probably conditionally compile with the Interlocked option as WIN32 events would require HAVE_WIN32.
It looks like C++/CX cannot be used for the IMediaExtension sink (which should not be a problem) as using COM objects requires WRL and though deriving from IMediaExtension can be done, there is little purpose without COM. Objects from C++/CX can be swapped to interact with objects from native C++ as Inspectable* can reinterpret_cast to the ref object IInspectable^ and vice-versa. A solution to the COM class with C++/CX would be great so we could have dual support. Also without #define for every WRL object in use, the code will get quite muddy given that the */^ would need to be ifdef'd everywhere.
Fixed bugs and completed the change. I believe the new classes need to be moved to a header file as the file has become to large and more classes need to be added for handling all the asynchronous problems (one wrapping IAsyncAction in a task and another for making a task out of IAsyncAction). Unfortunately, blocking on the UI thread is not an option in WinRT so a synchronous architecture is considered "illegal" by Microsoft's standards even if implementable (C++/CX ppltasks library throws errors if you try it). Worse, either by design or a bug in the MF MediaCapture class with Custom Sinks causes a crash if stop/start previewing without reinitializing (spPreferredPreviewMediaType is fatally nulled). After decompiling Windows.Media.dll, I worked around this in my own projects by using an activate-able custom sink ID which strangely assigns 1 to this pointer allowing it to be reinitialized in what can only be described as a hack by Microsoft. This would add additional overhead to the project to implement especially for static libraries as it requires IDL/DLL exporting followed by manifest declaration. Better to document that it is not supported.
Furthermore, an additional class for IMFAttributes should be implemented to make clean architecture for passing around attributes as opposed to directly calling non-COM interface calls on the objects and making use of SetProperties which would also be a set up for an object that uses the RuntimeClass activation ID.
The remaining changes are not difficult and will be complete soon along with debug tracing messages.
Update and rename cap_msmf.h to cap_msmf.hpp
Successful test - samples are grabbed
Library updated and cleaned up with comments, marshaling, exceptions and linker settings
Fixed trailing whitespace
VS 2013 support and cleanup consistency plus C++/CX new object fixed
Conflicts:
modules/highgui/src/cap_msmf.cpp
modules/highgui/src/cap_msmf.hpp
modules/highgui/src/ppltasks_winrt.h
Fix merge conflicts
VS 2013 Update 2 library bug fix integrated
a-wi's changed integrated
2013-12-14 16:53:30 +08:00
# endif
2018-12-26 20:50:20 +08:00
2013-04-03 09:01:20 +08:00
# include <windows.h>
# include <guiddef.h>
# include <mfidl.h>
2018-12-13 19:53:48 +08:00
# include <mfapi.h>
2013-04-03 09:01:20 +08:00
# include <mfplay.h>
# include <mfobjects.h>
Add support for WinRT in the MF capture framework by removing the disallowed calls to enumerate devices and create a sample grabber sink and adding framework for the MediaCapture interface and a custom sink which interfaces with the sample grabber callback interface. The change requires discussion for making it completely functional as redundancy is required given that if the source is a video file, the old code pathways must be used. Otherwise all IMFMediaSession, IMFMediaSource, and IMFActivate code must use a MediaCapture code path and all sink code must use the CMediaSink custom sink.
Support for the custom sink is extended to non-WinRT not for compatibility as Windows Vista client is a minimum regardless, but because it offers more flexibility, could be faster and is able to be used as an optionally different code path during sink creation based on a future configuration parameter.
My discussion and proposal to finish this change:
Devices are so easily enumerated through WinRT Windows.Devices namespace that wrapping the calls in a library is quite a chore for little benefit though to get the various modes and formats could still be a worthwhile project. For now conditional compilation to remove videodevices and any offending non-video file related activity in videodevice. In my opinion, this is a different , far less fundamental and important change which can possibly be done as a future project and also much more easily implemented in C++/CX.
ImageGrabber has the IMFSampleGrabberSinkCallback replaced with a base class (SharedSampleGrabber) which also be is base class for ImageGrabberRT. This change is necessary as the custom sink does not require a thread to pump events which is done through MediaCapture already. IMFSampleGrabberSinkCallback is the common element between both models and that piece can be shared. Initializing the new ImageGrabberRT is as simple as passing an already initialized MediaCapture object and any video format/encoding parameters.
The concurrency event is necessary to wait for completion and is the way the underlying, IAsyncAction wrappers in the task library work as well. Native WIN32 event objects would be an option if HAVE_CONCURRENCY is not defined. I could even imagine doing it with sleep/thread yield and InterlockedCompareExchange yet I am not enthusiastic about that approach either. Since there is a specific compiler HAVE_ for concurrency, I do not like pulling it in though I think for WinRT it is safe to say we will always have it available though should probably conditionally compile with the Interlocked option as WIN32 events would require HAVE_WIN32.
It looks like C++/CX cannot be used for the IMediaExtension sink (which should not be a problem) as using COM objects requires WRL and though deriving from IMediaExtension can be done, there is little purpose without COM. Objects from C++/CX can be swapped to interact with objects from native C++ as Inspectable* can reinterpret_cast to the ref object IInspectable^ and vice-versa. A solution to the COM class with C++/CX would be great so we could have dual support. Also without #define for every WRL object in use, the code will get quite muddy given that the */^ would need to be ifdef'd everywhere.
Fixed bugs and completed the change. I believe the new classes need to be moved to a header file as the file has become to large and more classes need to be added for handling all the asynchronous problems (one wrapping IAsyncAction in a task and another for making a task out of IAsyncAction). Unfortunately, blocking on the UI thread is not an option in WinRT so a synchronous architecture is considered "illegal" by Microsoft's standards even if implementable (C++/CX ppltasks library throws errors if you try it). Worse, either by design or a bug in the MF MediaCapture class with Custom Sinks causes a crash if stop/start previewing without reinitializing (spPreferredPreviewMediaType is fatally nulled). After decompiling Windows.Media.dll, I worked around this in my own projects by using an activate-able custom sink ID which strangely assigns 1 to this pointer allowing it to be reinitialized in what can only be described as a hack by Microsoft. This would add additional overhead to the project to implement especially for static libraries as it requires IDL/DLL exporting followed by manifest declaration. Better to document that it is not supported.
Furthermore, an additional class for IMFAttributes should be implemented to make clean architecture for passing around attributes as opposed to directly calling non-COM interface calls on the objects and making use of SetProperties which would also be a set up for an object that uses the RuntimeClass activation ID.
The remaining changes are not difficult and will be complete soon along with debug tracing messages.
Update and rename cap_msmf.h to cap_msmf.hpp
Successful test - samples are grabbed
Library updated and cleaned up with comments, marshaling, exceptions and linker settings
Fixed trailing whitespace
VS 2013 support and cleanup consistency plus C++/CX new object fixed
Conflicts:
modules/highgui/src/cap_msmf.cpp
modules/highgui/src/cap_msmf.hpp
modules/highgui/src/ppltasks_winrt.h
Fix merge conflicts
VS 2013 Update 2 library bug fix integrated
a-wi's changed integrated
2013-12-14 16:53:30 +08:00
# include <tchar.h>
2013-05-15 21:09:03 +08:00
# include <strsafe.h>
2021-03-01 23:51:04 +08:00
# include <codecvt>
2018-12-26 20:50:20 +08:00
# include <mfreadwrite.h>
2018-12-13 19:53:48 +08:00
# ifdef HAVE_MSMF_DXVA
# include <d3d11.h>
# include <d3d11_4.h>
2022-08-19 15:44:57 +08:00
# include <locale>
2018-04-23 21:48:57 +08:00
# endif
2013-04-03 09:01:20 +08:00
# include <new>
# include <map>
2021-12-06 14:54:48 +08:00
# include <queue>
2013-04-03 09:01:20 +08:00
# include <vector>
# include <string>
2018-04-12 20:26:18 +08:00
# include <algorithm>
2021-10-20 21:18:24 +08:00
# include <deque>
2013-04-03 09:01:20 +08:00
# include <stdio.h>
# include <stdarg.h>
# include <string.h>
2013-04-16 21:25:10 +08:00
2014-10-01 18:02:28 +08:00
# ifdef _MSC_VER
2013-04-03 09:01:20 +08:00
# pragma warning(disable:4503)
# pragma comment(lib, "mfplat")
# pragma comment(lib, "mf")
# pragma comment(lib, "mfuuid")
# pragma comment(lib, "Strmiids")
2013-05-06 18:36:51 +08:00
# pragma comment(lib, "Mfreadwrite")
2021-03-01 23:51:04 +08:00
# pragma comment(lib, "dxgi")
2018-12-13 19:53:48 +08:00
# ifdef HAVE_MSMF_DXVA
2018-04-23 21:48:57 +08:00
# pragma comment(lib, "d3d11")
2018-06-30 03:54:58 +08:00
// MFCreateDXGIDeviceManager() is available since Win8 only.
// To avoid OpenCV loading failure on Win7 use dynamic detection of this symbol.
// Details: https://github.com/opencv/opencv/issues/11858
2018-07-03 20:28:55 +08:00
typedef HRESULT ( WINAPI * FN_MFCreateDXGIDeviceManager ) ( UINT * resetToken , IMFDXGIDeviceManager * * ppDeviceManager ) ;
2018-06-30 03:54:58 +08:00
static bool pMFCreateDXGIDeviceManager_initialized = false ;
static FN_MFCreateDXGIDeviceManager pMFCreateDXGIDeviceManager = NULL ;
static void init_MFCreateDXGIDeviceManager ( )
{
2018-07-27 23:25:55 +08:00
HMODULE h = LoadLibraryExA ( " mfplat.dll " , NULL , LOAD_LIBRARY_SEARCH_SYSTEM32 ) ;
2018-06-30 03:54:58 +08:00
if ( h )
{
pMFCreateDXGIDeviceManager = ( FN_MFCreateDXGIDeviceManager ) GetProcAddress ( h , " MFCreateDXGIDeviceManager " ) ;
}
pMFCreateDXGIDeviceManager_initialized = true ;
}
2018-04-23 21:48:57 +08:00
# endif
2018-12-12 09:06:01 +08:00
# pragma comment(lib, "Shlwapi.lib")
2014-10-01 18:02:28 +08:00
# endif
2013-04-16 21:25:10 +08:00
Update cap_msmf.cpp
Add support for WinRT in the MF capture framework by removing the disallowed calls to enumerate devices and create a sample grabber sink and adding framework for the MediaCapture interface and a custom sink which interfaces with the sample grabber callback interface. The change requires discussion for making it completely functional as redundancy is required given that if the source is a video file, the old code pathways must be used. Otherwise all IMFMediaSession, IMFMediaSource, and IMFActivate code must use a MediaCapture code path and all sink code must use the CMediaSink custom sink.
Support for the custom sink is extended to non-WinRT not for compatibility as Windows Vista client is a minimum regardless, but because it offers more flexibility, could be faster and is able to be used as an optionally different code path during sink creation based on a future configuration parameter.
My discussion and proposal to finish this change:
Devices are so easily enumerated through WinRT Windows.Devices namespace that wrapping the calls in a library is quite a chore for little benefit though to get the various modes and formats could still be a worthwhile project. For now conditional compilation to remove videodevices and any offending non-video file related activity in videodevice. In my opinion, this is a different , far less fundamental and important change which can possibly be done as a future project and also much more easily implemented in C++/CX.
ImageGrabber has the IMFSampleGrabberSinkCallback replaced with a base class (SharedSampleGrabber) which also be is base class for ImageGrabberRT. This change is necessary as the custom sink does not require a thread to pump events which is done through MediaCapture already. IMFSampleGrabberSinkCallback is the common element between both models and that piece can be shared. Initializing the new ImageGrabberRT is as simple as passing an already initialized MediaCapture object and any video format/encoding parameters.
The concurrency event is necessary to wait for completion and is the way the underlying, IAsyncAction wrappers in the task library work as well. Native WIN32 event objects would be an option if HAVE_CONCURRENCY is not defined. I could even imagine doing it with sleep/thread yield and InterlockedCompareExchange yet I am not enthusiastic about that approach either. Since there is a specific compiler HAVE_ for concurrency, I do not like pulling it in though I think for WinRT it is safe to say we will always have it available though should probably conditionally compile with the Interlocked option as WIN32 events would require HAVE_WIN32.
It looks like C++/CX cannot be used for the IMediaExtension sink (which should not be a problem) as using COM objects requires WRL and though deriving from IMediaExtension can be done, there is little purpose without COM. Objects from C++/CX can be swapped to interact with objects from native C++ as Inspectable* can reinterpret_cast to the ref object IInspectable^ and vice-versa. A solution to the COM class with C++/CX would be great so we could have dual support. Also without #define for every WRL object in use, the code will get quite muddy given that the */^ would need to be ifdef'd everywhere.
Update cap_msmf.cpp
Fixed bugs and completed the change. I believe the new classes need to be moved to a header file as the file has become to large and more classes need to be added for handling all the asynchronous problems (one wrapping IAsyncAction in a task and another for making a task out of IAsyncAction). Unfortunately, blocking on the UI thread is not an option in WinRT so a synchronous architecture is considered "illegal" by Microsoft's standards even if implementable (C++/CX ppltasks library throws errors if you try it). Worse, either by design or a bug in the MF MediaCapture class with Custom Sinks causes a crash if stop/start previewing without reinitializing (spPreferredPreviewMediaType is fatally nulled). After decompiling Windows.Media.dll, I worked around this in my own projects by using an activate-able custom sink ID which strangely assigns 1 to this pointer allowing it to be reinitialized in what can only be described as a hack by Microsoft. This would add additional overhead to the project to implement especially for static libraries as it requires IDL/DLL exporting followed by manifest declaration. Better to document that it is not supported.
Furthermore, an additional class for IMFAttributes should be implemented to make clean architecture for passing around attributes as opposed to directly calling non-COM interface calls on the objects and making use of SetProperties which would also be a set up for an object that uses the RuntimeClass activation ID.
The remaining changes are not difficult and will be complete soon along with debug tracing messages.
Update cap_msmf.cpp
Create cap_msmf.h
Update cap_msmf.cpp
Update cap_msmf.h
Update cap_msmf.cpp
Update cap_msmf.h
Update and rename cap_msmf.h to cap_msmf.hpp
Update cap_msmf.cpp
Update CMakeLists.txt
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.cpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Successful test - samples are grabbed
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Create ppltasks_winrt.h
Update cap_msmf.hpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update ppltasks_winrt.h
Library updated and cleaned up with comments, marshaling, exceptions and linker settings
Update ppltasks_winrt.h
Fixed trailing whitespace
2013-12-14 16:53:30 +08:00
# include <mferror.h>
2014-10-01 18:02:28 +08:00
# include <comdef.h>
Update cap_msmf.cpp
Add support for WinRT in the MF capture framework by removing the disallowed calls to enumerate devices and create a sample grabber sink and adding framework for the MediaCapture interface and a custom sink which interfaces with the sample grabber callback interface. The change requires discussion for making it completely functional as redundancy is required given that if the source is a video file, the old code pathways must be used. Otherwise all IMFMediaSession, IMFMediaSource, and IMFActivate code must use a MediaCapture code path and all sink code must use the CMediaSink custom sink.
Support for the custom sink is extended to non-WinRT not for compatibility as Windows Vista client is a minimum regardless, but because it offers more flexibility, could be faster and is able to be used as an optionally different code path during sink creation based on a future configuration parameter.
My discussion and proposal to finish this change:
Devices are so easily enumerated through WinRT Windows.Devices namespace that wrapping the calls in a library is quite a chore for little benefit though to get the various modes and formats could still be a worthwhile project. For now conditional compilation to remove videodevices and any offending non-video file related activity in videodevice. In my opinion, this is a different , far less fundamental and important change which can possibly be done as a future project and also much more easily implemented in C++/CX.
ImageGrabber has the IMFSampleGrabberSinkCallback replaced with a base class (SharedSampleGrabber) which also be is base class for ImageGrabberRT. This change is necessary as the custom sink does not require a thread to pump events which is done through MediaCapture already. IMFSampleGrabberSinkCallback is the common element between both models and that piece can be shared. Initializing the new ImageGrabberRT is as simple as passing an already initialized MediaCapture object and any video format/encoding parameters.
The concurrency event is necessary to wait for completion and is the way the underlying, IAsyncAction wrappers in the task library work as well. Native WIN32 event objects would be an option if HAVE_CONCURRENCY is not defined. I could even imagine doing it with sleep/thread yield and InterlockedCompareExchange yet I am not enthusiastic about that approach either. Since there is a specific compiler HAVE_ for concurrency, I do not like pulling it in though I think for WinRT it is safe to say we will always have it available though should probably conditionally compile with the Interlocked option as WIN32 events would require HAVE_WIN32.
It looks like C++/CX cannot be used for the IMediaExtension sink (which should not be a problem) as using COM objects requires WRL and though deriving from IMediaExtension can be done, there is little purpose without COM. Objects from C++/CX can be swapped to interact with objects from native C++ as Inspectable* can reinterpret_cast to the ref object IInspectable^ and vice-versa. A solution to the COM class with C++/CX would be great so we could have dual support. Also without #define for every WRL object in use, the code will get quite muddy given that the */^ would need to be ifdef'd everywhere.
Update cap_msmf.cpp
Fixed bugs and completed the change. I believe the new classes need to be moved to a header file as the file has become to large and more classes need to be added for handling all the asynchronous problems (one wrapping IAsyncAction in a task and another for making a task out of IAsyncAction). Unfortunately, blocking on the UI thread is not an option in WinRT so a synchronous architecture is considered "illegal" by Microsoft's standards even if implementable (C++/CX ppltasks library throws errors if you try it). Worse, either by design or a bug in the MF MediaCapture class with Custom Sinks causes a crash if stop/start previewing without reinitializing (spPreferredPreviewMediaType is fatally nulled). After decompiling Windows.Media.dll, I worked around this in my own projects by using an activate-able custom sink ID which strangely assigns 1 to this pointer allowing it to be reinitialized in what can only be described as a hack by Microsoft. This would add additional overhead to the project to implement especially for static libraries as it requires IDL/DLL exporting followed by manifest declaration. Better to document that it is not supported.
Furthermore, an additional class for IMFAttributes should be implemented to make clean architecture for passing around attributes as opposed to directly calling non-COM interface calls on the objects and making use of SetProperties which would also be a set up for an object that uses the RuntimeClass activation ID.
The remaining changes are not difficult and will be complete soon along with debug tracing messages.
Update cap_msmf.cpp
Create cap_msmf.h
Update cap_msmf.cpp
Update cap_msmf.h
Update cap_msmf.cpp
Update cap_msmf.h
Update and rename cap_msmf.h to cap_msmf.hpp
Update cap_msmf.cpp
Update CMakeLists.txt
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.cpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Successful test - samples are grabbed
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Create ppltasks_winrt.h
Update cap_msmf.hpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update ppltasks_winrt.h
Library updated and cleaned up with comments, marshaling, exceptions and linker settings
Update ppltasks_winrt.h
Fixed trailing whitespace
2013-12-14 16:53:30 +08:00
2018-06-13 17:47:53 +08:00
# include <shlwapi.h> // QISearch
2013-04-03 09:01:20 +08:00
struct IMFMediaType ;
struct IMFActivate ;
struct IMFMediaSource ;
struct IMFAttributes ;
2013-04-16 21:25:10 +08:00
2018-11-13 22:53:35 +08:00
# define CV_CAP_MODE_BGR CV_FOURCC_MACRO('B','G','R','3')
# define CV_CAP_MODE_RGB CV_FOURCC_MACRO('R','G','B','3')
# define CV_CAP_MODE_GRAY CV_FOURCC_MACRO('G','R','E','Y')
# define CV_CAP_MODE_YUYV CV_FOURCC_MACRO('Y', 'U', 'Y', 'V')
2021-03-01 23:51:04 +08:00
using namespace cv ;
2013-04-03 09:01:20 +08:00
namespace
{
2013-04-16 21:25:10 +08:00
2018-04-13 20:43:41 +08:00
template < class T >
class ComPtr
{
public :
2018-04-24 21:18:39 +08:00
ComPtr ( )
2018-04-13 20:43:41 +08:00
{
}
2018-04-24 21:18:39 +08:00
ComPtr ( T * lp )
2018-04-13 20:43:41 +08:00
{
p = lp ;
}
2018-04-24 21:18:39 +08:00
ComPtr ( _In_ const ComPtr < T > & lp )
2018-04-13 20:43:41 +08:00
{
p = lp . p ;
}
virtual ~ ComPtr ( )
{
}
2021-10-20 21:18:24 +08:00
void swap ( _In_ ComPtr < T > & lp )
{
ComPtr < T > tmp ( p ) ;
p = lp . p ;
lp . p = tmp . p ;
tmp = NULL ;
}
2018-04-24 21:18:39 +08:00
T * * operator & ( )
2018-04-13 20:43:41 +08:00
{
2018-06-10 20:32:09 +08:00
CV_Assert ( p = = NULL ) ;
2018-04-13 20:43:41 +08:00
return p . operator & ( ) ;
}
2018-04-24 21:18:39 +08:00
T * operator - > ( ) const
2018-04-13 20:43:41 +08:00
{
2018-06-10 20:32:09 +08:00
CV_Assert ( p ! = NULL ) ;
2018-04-13 20:43:41 +08:00
return p . operator - > ( ) ;
}
operator bool ( )
{
return p . operator ! = ( NULL ) ;
}
2018-04-24 21:18:39 +08:00
T * Get ( ) const
2018-04-13 20:43:41 +08:00
{
return p ;
}
2018-06-10 20:32:09 +08:00
void Release ( )
2018-04-13 20:43:41 +08:00
{
2018-06-10 20:32:09 +08:00
if ( p )
p . Release ( ) ;
2018-04-13 20:43:41 +08:00
}
// query for U interface
template < typename U >
2018-06-10 20:32:09 +08:00
HRESULT As ( _Out_ ComPtr < U > & lp ) const
2018-04-13 20:43:41 +08:00
{
2018-06-10 20:32:09 +08:00
lp . Release ( ) ;
return p - > QueryInterface ( __uuidof ( U ) , reinterpret_cast < void * * > ( ( T * * ) & lp ) ) ;
2018-04-13 20:43:41 +08:00
}
private :
_COM_SMARTPTR_TYPEDEF ( T , __uuidof ( T ) ) ;
TPtr p ;
} ;
# define _ComPtr ComPtr
Update cap_msmf.cpp
Add support for WinRT in the MF capture framework by removing the disallowed calls to enumerate devices and create a sample grabber sink and adding framework for the MediaCapture interface and a custom sink which interfaces with the sample grabber callback interface. The change requires discussion for making it completely functional as redundancy is required given that if the source is a video file, the old code pathways must be used. Otherwise all IMFMediaSession, IMFMediaSource, and IMFActivate code must use a MediaCapture code path and all sink code must use the CMediaSink custom sink.
Support for the custom sink is extended to non-WinRT not for compatibility as Windows Vista client is a minimum regardless, but because it offers more flexibility, could be faster and is able to be used as an optionally different code path during sink creation based on a future configuration parameter.
My discussion and proposal to finish this change:
Devices are so easily enumerated through WinRT Windows.Devices namespace that wrapping the calls in a library is quite a chore for little benefit though to get the various modes and formats could still be a worthwhile project. For now conditional compilation to remove videodevices and any offending non-video file related activity in videodevice. In my opinion, this is a different , far less fundamental and important change which can possibly be done as a future project and also much more easily implemented in C++/CX.
ImageGrabber has the IMFSampleGrabberSinkCallback replaced with a base class (SharedSampleGrabber) which also be is base class for ImageGrabberRT. This change is necessary as the custom sink does not require a thread to pump events which is done through MediaCapture already. IMFSampleGrabberSinkCallback is the common element between both models and that piece can be shared. Initializing the new ImageGrabberRT is as simple as passing an already initialized MediaCapture object and any video format/encoding parameters.
The concurrency event is necessary to wait for completion and is the way the underlying, IAsyncAction wrappers in the task library work as well. Native WIN32 event objects would be an option if HAVE_CONCURRENCY is not defined. I could even imagine doing it with sleep/thread yield and InterlockedCompareExchange yet I am not enthusiastic about that approach either. Since there is a specific compiler HAVE_ for concurrency, I do not like pulling it in though I think for WinRT it is safe to say we will always have it available though should probably conditionally compile with the Interlocked option as WIN32 events would require HAVE_WIN32.
It looks like C++/CX cannot be used for the IMediaExtension sink (which should not be a problem) as using COM objects requires WRL and though deriving from IMediaExtension can be done, there is little purpose without COM. Objects from C++/CX can be swapped to interact with objects from native C++ as Inspectable* can reinterpret_cast to the ref object IInspectable^ and vice-versa. A solution to the COM class with C++/CX would be great so we could have dual support. Also without #define for every WRL object in use, the code will get quite muddy given that the */^ would need to be ifdef'd everywhere.
Update cap_msmf.cpp
Fixed bugs and completed the change. I believe the new classes need to be moved to a header file as the file has become to large and more classes need to be added for handling all the asynchronous problems (one wrapping IAsyncAction in a task and another for making a task out of IAsyncAction). Unfortunately, blocking on the UI thread is not an option in WinRT so a synchronous architecture is considered "illegal" by Microsoft's standards even if implementable (C++/CX ppltasks library throws errors if you try it). Worse, either by design or a bug in the MF MediaCapture class with Custom Sinks causes a crash if stop/start previewing without reinitializing (spPreferredPreviewMediaType is fatally nulled). After decompiling Windows.Media.dll, I worked around this in my own projects by using an activate-able custom sink ID which strangely assigns 1 to this pointer allowing it to be reinitialized in what can only be described as a hack by Microsoft. This would add additional overhead to the project to implement especially for static libraries as it requires IDL/DLL exporting followed by manifest declaration. Better to document that it is not supported.
Furthermore, an additional class for IMFAttributes should be implemented to make clean architecture for passing around attributes as opposed to directly calling non-COM interface calls on the objects and making use of SetProperties which would also be a set up for an object that uses the RuntimeClass activation ID.
The remaining changes are not difficult and will be complete soon along with debug tracing messages.
Update cap_msmf.cpp
Create cap_msmf.h
Update cap_msmf.cpp
Update cap_msmf.h
Update cap_msmf.cpp
Update cap_msmf.h
Update and rename cap_msmf.h to cap_msmf.hpp
Update cap_msmf.cpp
Update CMakeLists.txt
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.cpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Successful test - samples are grabbed
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update cap_msmf.hpp
Create ppltasks_winrt.h
Update cap_msmf.hpp
Update cap_msmf.hpp
Update cap_msmf.cpp
Update ppltasks_winrt.h
Library updated and cleaned up with comments, marshaling, exceptions and linker settings
Update ppltasks_winrt.h
Fixed trailing whitespace
2013-12-14 16:53:30 +08:00
2020-02-07 20:03:20 +08:00
template < typename T > inline T absDiff ( T a , T b ) { return a > = b ? a - b : b - a ; }
//==================================================================================================
// Structure for collecting info about types of video which are supported by current video device
2013-04-03 09:01:20 +08:00
struct MediaType
{
2021-10-20 21:18:24 +08:00
//video param
2018-04-13 20:43:41 +08:00
UINT32 width ;
2020-02-07 20:03:20 +08:00
UINT32 height ;
INT32 stride ; // stride is negative if image is bottom-up
UINT32 isFixedSize ;
UINT32 frameRateNum ;
UINT32 frameRateDenom ;
UINT32 aspectRatioNum ;
UINT32 aspectRatioDenom ;
UINT32 sampleSize ;
UINT32 interlaceMode ;
2021-10-20 21:18:24 +08:00
//audio param
UINT32 bit_per_sample ;
UINT32 nChannels ;
UINT32 nAvgBytesPerSec ;
UINT32 nSamplesPerSec ;
2020-02-07 20:03:20 +08:00
GUID majorType ; // video or audio
GUID subType ; // fourCC
2021-10-20 21:18:24 +08:00
_ComPtr < IMFMediaType > Type ;
2020-02-07 20:03:20 +08:00
MediaType ( IMFMediaType * pType = 0 ) :
2021-10-20 21:18:24 +08:00
Type ( pType ) ,
2020-02-07 20:03:20 +08:00
width ( 0 ) , height ( 0 ) ,
stride ( 0 ) ,
isFixedSize ( true ) ,
frameRateNum ( 1 ) , frameRateDenom ( 1 ) ,
aspectRatioNum ( 1 ) , aspectRatioDenom ( 1 ) ,
sampleSize ( 0 ) ,
interlaceMode ( 0 ) ,
2021-10-20 21:18:24 +08:00
bit_per_sample ( 0 ) ,
nChannels ( 0 ) ,
nAvgBytesPerSec ( 0 ) ,
nSamplesPerSec ( 0 ) ,
majorType ( { 0 } ) , //MFMediaType_Video
2020-02-07 20:03:20 +08:00
subType ( { 0 } )
2013-04-03 09:01:20 +08:00
{
2020-02-07 20:03:20 +08:00
if ( pType )
{
pType - > GetGUID ( MF_MT_MAJOR_TYPE , & majorType ) ;
pType - > GetGUID ( MF_MT_SUBTYPE , & subType ) ;
2021-10-20 21:18:24 +08:00
if ( majorType = = MFMediaType_Audio )
{
pType - > GetUINT32 ( MF_MT_AUDIO_BITS_PER_SAMPLE , & bit_per_sample ) ;
pType - > GetUINT32 ( MF_MT_AUDIO_NUM_CHANNELS , & nChannels ) ;
pType - > GetUINT32 ( MF_MT_AUDIO_AVG_BYTES_PER_SECOND , & nAvgBytesPerSec ) ;
pType - > GetUINT32 ( MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND , & nSamplesPerSec ) ;
}
else if ( majorType = = MFMediaType_Video )
{
MFGetAttributeSize ( pType , MF_MT_FRAME_SIZE , & width , & height ) ;
pType - > GetUINT32 ( MF_MT_DEFAULT_STRIDE , ( UINT32 * ) & stride ) ; // value is stored as UINT32 but should be casted to INT3)
pType - > GetUINT32 ( MF_MT_FIXED_SIZE_SAMPLES , & isFixedSize ) ;
MFGetAttributeRatio ( pType , MF_MT_FRAME_RATE , & frameRateNum , & frameRateDenom ) ;
MFGetAttributeRatio ( pType , MF_MT_PIXEL_ASPECT_RATIO , & aspectRatioNum , & aspectRatioDenom ) ;
pType - > GetUINT32 ( MF_MT_SAMPLE_SIZE , & sampleSize ) ;
pType - > GetUINT32 ( MF_MT_INTERLACE_MODE , & interlaceMode ) ;
pType - > GetUINT32 ( MF_MT_INTERLACE_MODE , & interlaceMode ) ;
}
2020-02-07 20:03:20 +08:00
}
2013-04-03 09:01:20 +08:00
}
2021-10-20 21:18:24 +08:00
static MediaType createDefault_Video ( )
2020-02-07 20:03:20 +08:00
{
MediaType res ;
res . width = 640 ;
res . height = 480 ;
res . setFramerate ( 30.0 ) ;
return res ;
}
2021-10-20 21:18:24 +08:00
static MediaType createDefault_Audio ( )
{
MediaType res ;
res . majorType = MFMediaType_Audio ;
res . subType = MFAudioFormat_PCM ;
res . bit_per_sample = 16 ;
res . nChannels = 1 ;
res . nSamplesPerSec = 44100 ;
return res ;
}
inline bool isEmpty ( bool flag = false ) const
2020-02-07 20:03:20 +08:00
{
2021-10-20 21:18:24 +08:00
if ( ! flag )
return width = = 0 & & height = = 0 ;
else
return nChannels = = 0 ;
2020-02-07 20:03:20 +08:00
}
2021-10-20 21:18:24 +08:00
_ComPtr < IMFMediaType > createMediaType_Video ( ) const
2018-04-13 20:43:41 +08:00
{
2020-02-07 20:03:20 +08:00
_ComPtr < IMFMediaType > res ;
MFCreateMediaType ( & res ) ;
if ( width ! = 0 | | height ! = 0 )
MFSetAttributeSize ( res . Get ( ) , MF_MT_FRAME_SIZE , width , height ) ;
if ( stride ! = 0 )
res - > SetUINT32 ( MF_MT_DEFAULT_STRIDE , stride ) ;
res - > SetUINT32 ( MF_MT_FIXED_SIZE_SAMPLES , isFixedSize ) ;
if ( frameRateNum ! = 0 | | frameRateDenom ! = 0 )
MFSetAttributeRatio ( res . Get ( ) , MF_MT_FRAME_RATE , frameRateNum , frameRateDenom ) ;
if ( aspectRatioNum ! = 0 | | aspectRatioDenom ! = 0 )
MFSetAttributeRatio ( res . Get ( ) , MF_MT_PIXEL_ASPECT_RATIO , aspectRatioNum , aspectRatioDenom ) ;
if ( sampleSize > 0 )
res - > SetUINT32 ( MF_MT_SAMPLE_SIZE , sampleSize ) ;
res - > SetUINT32 ( MF_MT_INTERLACE_MODE , interlaceMode ) ;
if ( majorType ! = GUID ( ) )
res - > SetGUID ( MF_MT_MAJOR_TYPE , majorType ) ;
if ( subType ! = GUID ( ) )
res - > SetGUID ( MF_MT_SUBTYPE , subType ) ;
return res ;
}
2021-10-20 21:18:24 +08:00
_ComPtr < IMFMediaType > createMediaType_Audio ( ) const
{
_ComPtr < IMFMediaType > res ;
MFCreateMediaType ( & res ) ;
if ( majorType ! = GUID ( ) )
res - > SetGUID ( MF_MT_MAJOR_TYPE , majorType ) ;
if ( subType ! = GUID ( ) )
res - > SetGUID ( MF_MT_SUBTYPE , subType ) ;
if ( bit_per_sample ! = 0 )
res - > SetUINT32 ( MF_MT_AUDIO_BITS_PER_SAMPLE , bit_per_sample ) ;
if ( nChannels ! = 0 )
res - > SetUINT32 ( MF_MT_AUDIO_NUM_CHANNELS , nChannels ) ;
if ( nSamplesPerSec ! = 0 )
res - > SetUINT32 ( MF_MT_AUDIO_SAMPLES_PER_SECOND , nSamplesPerSec ) ;
return res ;
}
2020-02-07 20:03:20 +08:00
void setFramerate ( double fps )
{
frameRateNum = ( UINT32 ) cvRound ( fps * 1000.0 ) ;
frameRateDenom = 1000 ;
}
double getFramerate ( ) const
{
return frameRateDenom ! = 0 ? ( ( double ) frameRateNum ) / ( ( double ) frameRateDenom ) : 0 ;
}
LONGLONG getFrameStep ( ) const
{
const double fps = getFramerate ( ) ;
return ( LONGLONG ) ( fps > 0 ? 1e7 / fps : 0 ) ;
}
inline unsigned long resolutionDiff ( const MediaType & other ) const
{
const unsigned long wdiff = absDiff ( width , other . width ) ;
const unsigned long hdiff = absDiff ( height , other . height ) ;
return wdiff + hdiff ;
}
// check if 'this' is better than 'other' comparing to reference
2021-10-20 21:18:24 +08:00
bool VideoIsBetterThan ( const MediaType & other , const MediaType & ref ) const
2020-02-07 20:03:20 +08:00
{
const unsigned long thisDiff = resolutionDiff ( ref ) ;
const unsigned long otherDiff = other . resolutionDiff ( ref ) ;
if ( thisDiff < otherDiff )
return true ;
if ( thisDiff = = otherDiff )
2018-04-13 20:43:41 +08:00
{
2020-02-07 20:03:20 +08:00
if ( width > other . width )
return true ;
if ( width = = other . width & & height > other . height )
return true ;
if ( width = = other . width & & height = = other . height )
{
const double thisRateDiff = absDiff ( getFramerate ( ) , ref . getFramerate ( ) ) ;
const double otherRateDiff = absDiff ( other . getFramerate ( ) , ref . getFramerate ( ) ) ;
if ( thisRateDiff < otherRateDiff )
return true ;
}
2018-04-13 20:43:41 +08:00
}
2020-02-07 20:03:20 +08:00
return false ;
2018-04-13 20:43:41 +08:00
}
2021-10-20 21:18:24 +08:00
bool AudioIsBetterThan ( const MediaType & other , const MediaType & ref ) const
{
double thisDiff = absDiff ( nChannels , ref . nChannels ) ;
double otherDiff = absDiff ( other . nChannels , ref . nChannels ) ;
if ( otherDiff < thisDiff )
{
thisDiff = absDiff ( bit_per_sample , ref . bit_per_sample ) ;
otherDiff = absDiff ( bit_per_sample , ref . bit_per_sample ) ;
if ( otherDiff < thisDiff )
{
thisDiff = absDiff ( nSamplesPerSec , ref . nSamplesPerSec ) ;
otherDiff = absDiff ( nSamplesPerSec , ref . nSamplesPerSec ) ;
if ( otherDiff < thisDiff )
return true ;
}
}
return false ;
}
2022-08-06 01:52:33 +08:00
bool VideoIsAvailable ( ) const
{
return ( ( subType = = MFVideoFormat_RGB32 ) | |
( subType = = MFVideoFormat_RGB24 ) | |
( subType = = MFVideoFormat_YUY2 ) ) ;
}
2020-02-07 20:03:20 +08:00
} ;
2013-05-23 00:50:54 +08:00
2020-02-07 20:03:20 +08:00
void printFormat ( std : : ostream & out , const GUID & fmt )
2013-04-03 09:01:20 +08:00
{
2020-02-07 20:03:20 +08:00
# define PRNT(FMT) else if (fmt == FMT) out << #FMT;
if ( fmt = = MFVideoFormat_Base ) out < < " Base " ;
PRNT ( MFVideoFormat_RGB32 )
PRNT ( MFVideoFormat_ARGB32 )
PRNT ( MFVideoFormat_RGB24 )
PRNT ( MFVideoFormat_RGB555 )
PRNT ( MFVideoFormat_RGB565 )
PRNT ( MFVideoFormat_RGB8 )
else
2013-04-03 09:01:20 +08:00
{
2020-02-07 20:03:20 +08:00
char fourcc [ 5 ] = { 0 } ;
memcpy ( fourcc , & fmt . Data1 , 4 ) ;
out < < fourcc ;
2013-04-03 09:01:20 +08:00
}
2020-02-07 20:03:20 +08:00
# undef PRNT
2013-04-03 09:01:20 +08:00
}
2013-04-16 21:25:10 +08:00
2020-02-07 20:03:20 +08:00
std : : ostream & operator < < ( std : : ostream & out , const MediaType & mt )
2013-04-03 09:01:20 +08:00
{
2020-02-07 20:03:20 +08:00
out < < " ( " < < mt . width < < " x " < < mt . height < < " @ " < < mt . getFramerate ( ) < < " ) " ;
printFormat ( out , mt . subType ) ;
return out ;
2013-04-03 09:01:20 +08:00
}
2013-04-16 21:25:10 +08:00
2020-02-07 20:03:20 +08:00
//==================================================================================================
// Class for creating of Media Foundation context
class Media_Foundation
2013-04-03 09:01:20 +08:00
{
2020-02-07 20:03:20 +08:00
public :
~ Media_Foundation ( void ) { /*CV_Assert(SUCCEEDED(MFShutdown()));*/ CoUninitialize ( ) ; }
static Media_Foundation & getInstance ( )
{
static Media_Foundation instance ;
return instance ;
}
private :
Media_Foundation ( void ) { CoInitialize ( 0 ) ; CV_Assert ( SUCCEEDED ( MFStartup ( MF_VERSION ) ) ) ; }
} ;
2013-04-16 21:25:10 +08:00
2020-02-07 20:03:20 +08:00
//==================================================================================================
2013-04-16 21:25:10 +08:00
2018-06-13 17:47:53 +08:00
class SourceReaderCB : public IMFSourceReaderCallback
{
public :
2021-12-06 14:54:48 +08:00
static const size_t MSMF_READER_MAX_QUEUE_SIZE = 3 ;
2018-06-13 17:47:53 +08:00
SourceReaderCB ( ) :
2021-12-06 14:54:48 +08:00
m_nRefCount ( 0 ) , m_hEvent ( CreateEvent ( NULL , FALSE , FALSE , NULL ) ) , m_bEOS ( FALSE ) , m_hrStatus ( S_OK ) , m_reader ( NULL ) , m_dwStreamIndex ( 0 )
2018-06-13 17:47:53 +08:00
{
}
// IUnknown methods
STDMETHODIMP QueryInterface ( REFIID iid , void * * ppv ) CV_OVERRIDE
{
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4838)
# endif
static const QITAB qit [ ] =
{
QITABENT ( SourceReaderCB , IMFSourceReaderCallback ) ,
{ 0 } ,
} ;
# ifdef _MSC_VER
# pragma warning(pop)
# endif
return QISearch ( this , qit , iid , ppv ) ;
}
STDMETHODIMP_ ( ULONG ) AddRef ( ) CV_OVERRIDE
{
return InterlockedIncrement ( & m_nRefCount ) ;
}
STDMETHODIMP_ ( ULONG ) Release ( ) CV_OVERRIDE
{
ULONG uCount = InterlockedDecrement ( & m_nRefCount ) ;
if ( uCount = = 0 )
{
delete this ;
}
return uCount ;
}
2020-02-07 20:03:20 +08:00
STDMETHODIMP OnReadSample ( HRESULT hrStatus , DWORD dwStreamIndex , DWORD dwStreamFlags , LONGLONG llTimestamp , IMFSample * pSample ) CV_OVERRIDE
{
HRESULT hr = 0 ;
cv : : AutoLock lock ( m_mutex ) ;
if ( SUCCEEDED ( hrStatus ) )
{
if ( pSample )
{
CV_LOG_DEBUG ( NULL , " videoio(MSMF): got frame at " < < llTimestamp ) ;
2021-12-06 14:54:48 +08:00
if ( m_capturedFrames . size ( ) > = MSMF_READER_MAX_QUEUE_SIZE )
2020-02-07 20:03:20 +08:00
{
2021-12-06 14:54:48 +08:00
#if 0
CV_LOG_DEBUG ( NULL , " videoio(MSMF): drop frame (not processed). Timestamp= " < < m_capturedFrames . front ( ) . timestamp ) ;
m_capturedFrames . pop ( ) ;
# else
// this branch reduces latency if we drop frames due to slow processing.
// avoid fetching of already outdated frames from the queue's front.
CV_LOG_DEBUG ( NULL , " videoio(MSMF): drop previous frames (not processed): " < < m_capturedFrames . size ( ) ) ;
std : : queue < CapturedFrameInfo > ( ) . swap ( m_capturedFrames ) ; // similar to missing m_capturedFrames.clean();
# endif
2020-02-07 20:03:20 +08:00
}
2021-12-06 14:54:48 +08:00
m_capturedFrames . emplace ( CapturedFrameInfo { llTimestamp , _ComPtr < IMFSample > ( pSample ) , hrStatus } ) ;
2020-02-07 20:03:20 +08:00
}
}
else
{
CV_LOG_WARNING ( NULL , " videoio(MSMF): OnReadSample() is called with error status: " < < hrStatus ) ;
}
if ( MF_SOURCE_READERF_ENDOFSTREAM & dwStreamFlags )
{
// Reached the end of the stream.
m_bEOS = true ;
}
m_hrStatus = hrStatus ;
if ( FAILED ( hr = m_reader - > ReadSample ( dwStreamIndex , 0 , NULL , NULL , NULL , NULL ) ) )
{
CV_LOG_WARNING ( NULL , " videoio(MSMF): async ReadSample() call is failed with error status: " < < hr ) ;
m_bEOS = true ;
}
if ( pSample | | m_bEOS )
{
SetEvent ( m_hEvent ) ;
}
return S_OK ;
}
2018-06-13 17:47:53 +08:00
STDMETHODIMP OnEvent ( DWORD , IMFMediaEvent * ) CV_OVERRIDE
{
return S_OK ;
}
STDMETHODIMP OnFlush ( DWORD ) CV_OVERRIDE
{
return S_OK ;
}
2021-12-06 14:54:48 +08:00
HRESULT Wait ( DWORD dwMilliseconds , _ComPtr < IMFSample > & mediaSample , LONGLONG & sampleTimestamp , BOOL & pbEOS )
2020-02-07 20:03:20 +08:00
{
pbEOS = FALSE ;
2021-12-06 14:54:48 +08:00
for ( ; ; )
2020-02-07 20:03:20 +08:00
{
2021-12-06 14:54:48 +08:00
{
cv : : AutoLock lock ( m_mutex ) ;
2020-02-07 20:03:20 +08:00
2021-12-06 14:54:48 +08:00
pbEOS = m_bEOS & & m_capturedFrames . empty ( ) ;
if ( pbEOS )
return m_hrStatus ;
if ( ! m_capturedFrames . empty ( ) )
{
CV_Assert ( ! m_capturedFrames . empty ( ) ) ;
CapturedFrameInfo frameInfo = m_capturedFrames . front ( ) ; m_capturedFrames . pop ( ) ;
CV_LOG_DEBUG ( NULL , " videoio(MSMF): handle frame at " < < frameInfo . timestamp ) ;
mediaSample = frameInfo . sample ;
CV_Assert ( mediaSample ) ;
sampleTimestamp = frameInfo . timestamp ;
ResetEvent ( m_hEvent ) ; // event is auto-reset, but we need this forced reset due time gap between wait() and mutex hold.
return frameInfo . hrStatus ;
}
}
CV_LOG_DEBUG ( NULL , " videoio(MSMF): waiting for frame... " ) ;
DWORD dwResult = WaitForSingleObject ( m_hEvent , dwMilliseconds ) ;
if ( dwResult = = WAIT_TIMEOUT )
{
return E_PENDING ;
}
else if ( dwResult ! = WAIT_OBJECT_0 )
{
return HRESULT_FROM_WIN32 ( GetLastError ( ) ) ;
}
2020-02-07 20:03:20 +08:00
}
}
2021-10-20 21:18:24 +08:00
2018-06-13 17:47:53 +08:00
private :
// Destructor is private. Caller should call Release.
virtual ~ SourceReaderCB ( )
{
2022-01-10 17:16:01 +08:00
CV_LOG_INFO ( NULL , " terminating async callback " ) ;
2018-06-13 17:47:53 +08:00
}
public :
long m_nRefCount ; // Reference count.
cv : : Mutex m_mutex ;
HANDLE m_hEvent ;
BOOL m_bEOS ;
HRESULT m_hrStatus ;
2018-09-03 20:56:38 +08:00
IMFSourceReader * m_reader ;
2018-06-13 17:47:53 +08:00
DWORD m_dwStreamIndex ;
2021-12-06 14:54:48 +08:00
struct CapturedFrameInfo {
LONGLONG timestamp ;
_ComPtr < IMFSample > sample ;
HRESULT hrStatus ;
} ;
std : : queue < CapturedFrameInfo > m_capturedFrames ;
2018-06-13 17:47:53 +08:00
} ;
2020-02-07 20:03:20 +08:00
//==================================================================================================
// Enumerate and store supported formats and finds format which is most similar to the one requested
class FormatStorage
{
public :
struct MediaID
{
DWORD stream ;
DWORD media ;
MediaID ( ) : stream ( 0 ) , media ( 0 ) { }
void nextStream ( )
{
stream + + ;
media = 0 ;
}
void nextMedia ( )
{
media + + ;
}
bool operator < ( const MediaID & other ) const
{
return ( stream < other . stream ) | | ( stream = = other . stream & & media < other . media ) ;
}
} ;
void read ( IMFSourceReader * source )
{
HRESULT hr = S_OK ;
MediaID cur ;
while ( SUCCEEDED ( hr ) )
{
_ComPtr < IMFMediaType > raw_type ;
hr = source - > GetNativeMediaType ( cur . stream , cur . media , & raw_type ) ;
if ( hr = = MF_E_NO_MORE_TYPES )
{
hr = S_OK ;
cur . nextStream ( ) ;
}
else if ( SUCCEEDED ( hr ) )
{
formats [ cur ] = MediaType ( raw_type . Get ( ) ) ;
cur . nextMedia ( ) ;
}
}
}
2021-10-20 21:18:24 +08:00
void countNumberOfAudioStreams ( DWORD & numberOfAudioStreams )
{
std : : pair < MediaID , MediaType > best ;
std : : map < MediaID , MediaType > : : const_iterator i = formats . begin ( ) ;
for ( ; i ! = formats . end ( ) ; + + i )
{
if ( i - > second . majorType = = MFMediaType_Audio )
{
if ( best . second . isEmpty ( ) | | i - > first . stream ! = best . first . stream )
{
numberOfAudioStreams + + ;
best = * i ;
}
}
}
}
2020-05-27 22:52:17 +08:00
std : : pair < MediaID , MediaType > findBestVideoFormat ( const MediaType & newType )
2020-02-07 20:03:20 +08:00
{
std : : pair < MediaID , MediaType > best ;
std : : map < MediaID , MediaType > : : const_iterator i = formats . begin ( ) ;
for ( ; i ! = formats . end ( ) ; + + i )
{
2021-10-20 21:18:24 +08:00
if ( i - > second . majorType = = MFMediaType_Video )
2020-02-07 20:03:20 +08:00
{
2022-08-06 01:52:33 +08:00
if ( best . second . isEmpty ( ) | | ( i - > second . VideoIsBetterThan ( best . second , newType ) & & i - > second . VideoIsAvailable ( ) ) )
2021-10-20 21:18:24 +08:00
{
best = * i ;
}
2020-02-07 20:03:20 +08:00
}
2021-10-20 21:18:24 +08:00
}
return best ;
}
std : : pair < MediaID , MediaType > findBestAudioFormat ( const MediaType & newType )
{
std : : pair < MediaID , MediaType > best ;
std : : map < MediaID , MediaType > : : const_iterator i = formats . begin ( ) ;
best = * i ;
for ( ; i ! = formats . end ( ) ; + + i )
{
if ( i - > second . majorType = = MFMediaType_Audio )
{
if ( i - > second . AudioIsBetterThan ( best . second , newType ) )
{
best = * i ;
}
}
}
return best ;
}
std : : pair < MediaID , MediaType > findAudioFormatByStream ( const DWORD StreamIndex )
{
std : : pair < MediaID , MediaType > best ;
std : : map < MediaID , MediaType > : : const_iterator i = formats . begin ( ) ;
for ( ; i ! = formats . end ( ) ; + + i )
{
if ( i - > second . majorType = = MFMediaType_Audio )
2020-02-07 20:03:20 +08:00
{
2021-10-20 21:18:24 +08:00
if ( ( * i ) . first . stream = = StreamIndex )
{
best = * i ;
}
2020-02-07 20:03:20 +08:00
}
}
return best ;
}
private :
std : : map < MediaID , MediaType > formats ;
} ;
//==================================================================================================
// Enumerates devices and activates one of them
class DeviceList
{
public :
DeviceList ( ) : devices ( NULL ) , count ( 0 ) { }
~ DeviceList ( )
{
if ( devices )
{
for ( UINT32 i = 0 ; i < count ; + + i )
if ( devices [ i ] )
devices [ i ] - > Release ( ) ;
CoTaskMemFree ( devices ) ;
}
}
UINT32 read ( IID sourceType = MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID )
{
_ComPtr < IMFAttributes > attr ;
if ( FAILED ( MFCreateAttributes ( & attr , 1 ) ) | |
FAILED ( attr - > SetGUID ( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE , sourceType ) ) )
{
CV_Error ( CV_StsError , " Failed to create attributes " ) ;
}
if ( FAILED ( MFEnumDeviceSources ( attr . Get ( ) , & devices , & count ) ) )
{
CV_LOG_DEBUG ( NULL , " Failed to enumerate MSMF devices " ) ;
return 0 ;
}
return count ;
}
_ComPtr < IMFMediaSource > activateSource ( UINT32 index )
{
_ComPtr < IMFMediaSource > result ;
if ( count = = 0 | | index > = count | | FAILED ( devices [ index ] - > ActivateObject ( __uuidof ( IMFMediaSource ) , ( void * * ) & result ) ) )
{
CV_LOG_DEBUG ( NULL , " Failed to activate media source (device " < < index < < " ) " ) ;
}
return result ;
}
private :
IMFActivate * * devices ;
UINT32 count ;
} ;
} // namespace::
//==================================================================================================
2018-06-13 17:47:53 +08:00
2018-04-19 23:24:02 +08:00
/******* Capturing video from camera or file via Microsoft Media Foundation **********/
2018-04-25 23:19:14 +08:00
class CvCapture_MSMF : public cv : : IVideoCapture
2013-04-03 09:01:20 +08:00
{
2018-04-12 20:26:18 +08:00
public :
2018-04-23 21:48:57 +08:00
typedef enum {
MODE_SW = 0 ,
MODE_HW = 1
} MSMFCapture_Mode ;
2018-04-19 23:24:02 +08:00
CvCapture_MSMF ( ) ;
virtual ~ CvCapture_MSMF ( ) ;
2021-03-01 23:51:04 +08:00
bool configureHW ( const cv : : VideoCaptureParameters & params ) ;
virtual bool open ( int , const cv : : VideoCaptureParameters * params ) ;
virtual bool open ( const cv : : String & , const cv : : VideoCaptureParameters * params ) ;
2018-04-12 20:26:18 +08:00
virtual void close ( ) ;
virtual double getProperty ( int ) const CV_OVERRIDE ;
virtual bool setProperty ( int , double ) CV_OVERRIDE ;
2021-10-26 22:33:53 +08:00
bool configureAudioFrame ( ) ;
2021-10-20 21:18:24 +08:00
bool grabAudioFrame ( ) ;
bool grabVideoFrame ( ) ;
2018-04-12 20:26:18 +08:00
virtual bool grabFrame ( ) CV_OVERRIDE ;
2021-10-20 21:18:24 +08:00
bool retrieveAudioFrame ( int , OutputArray ) ;
bool retrieveVideoFrame ( OutputArray ) ;
2018-04-25 23:19:14 +08:00
virtual bool retrieveFrame ( int , cv : : OutputArray ) CV_OVERRIDE ;
virtual bool isOpened ( ) const CV_OVERRIDE { return isOpen ; }
2018-09-16 04:54:03 +08:00
virtual int getCaptureDomain ( ) CV_OVERRIDE { return CV_CAP_MSMF ; }
2018-04-12 20:26:18 +08:00
protected :
2021-10-20 21:18:24 +08:00
bool configureOutput ( ) ;
bool configureAudioOutput ( MediaType newType ) ;
bool configureVideoOutput ( MediaType newType , cv : : uint32_t outFormat ) ;
2018-04-19 23:24:02 +08:00
bool setTime ( double time , bool rough ) ;
2021-10-20 21:18:24 +08:00
bool setTime ( int numberFrame ) ;
2018-04-23 21:48:57 +08:00
bool configureHW ( bool enable ) ;
2021-10-20 21:18:24 +08:00
bool configureStreams ( const cv : : VideoCaptureParameters & ) ;
bool setAudioProperties ( const cv : : VideoCaptureParameters & ) ;
2021-12-04 18:37:10 +08:00
bool checkAudioProperties ( ) ;
2018-04-19 23:24:02 +08:00
2020-02-07 20:03:20 +08:00
template < typename CtrlT >
bool readComplexPropery ( long prop , long & val ) const ;
template < typename CtrlT >
bool writeComplexProperty ( long prop , double val , long flags ) ;
_ComPtr < IMFAttributes > getDefaultSourceConfig ( UINT32 num = 10 ) ;
2021-10-20 21:18:24 +08:00
bool initStream ( DWORD streamID , const MediaType mt ) ;
2020-02-07 20:03:20 +08:00
2021-03-01 23:51:04 +08:00
bool openFinalize_ ( const VideoCaptureParameters * params ) ;
2018-04-12 20:26:18 +08:00
Media_Foundation & MF ;
2018-04-23 21:48:57 +08:00
cv : : String filename ;
int camid ;
MSMFCapture_Mode captureMode ;
2021-03-01 23:51:04 +08:00
VideoAccelerationType va_type ;
int hwDeviceIndex ;
2018-12-13 19:53:48 +08:00
# ifdef HAVE_MSMF_DXVA
2018-04-23 21:48:57 +08:00
_ComPtr < ID3D11Device > D3DDev ;
_ComPtr < IMFDXGIDeviceManager > D3DMgr ;
# endif
2018-04-12 20:26:18 +08:00
_ComPtr < IMFSourceReader > videoFileSource ;
2021-03-03 17:10:00 +08:00
_ComPtr < IMFSourceReaderCallback > readCallback ; // non-NULL for "live" streams (camera capture)
2021-10-20 21:18:24 +08:00
std : : vector < DWORD > dwStreamIndices ;
std : : vector < _ComPtr < IMFSample > > audioSamples ;
_ComPtr < IMFSample > impendingVideoSample ;
_ComPtr < IMFSample > usedVideoSample ;
DWORD dwVideoStreamIndex ;
DWORD dwAudioStreamIndex ;
2018-04-19 23:24:02 +08:00
MediaType nativeFormat ;
2021-10-20 21:18:24 +08:00
MediaType captureVideoFormat ;
MediaType captureAudioFormat ;
bool device_status ; //on or off
int videoStream ; // look at CAP_PROP_VIDEO_STREAM
int audioStream ; // look at CAP_PROP_AUDIO_STREAM
bool vEOS ;
bool aEOS ;
unsigned int audioBaseIndex ;
int outputVideoFormat ;
int outputAudioFormat ;
2021-12-04 18:37:10 +08:00
UINT32 audioSamplesPerSecond ;
2018-04-19 23:24:02 +08:00
bool convertFormat ;
MFTIME duration ;
2018-04-24 21:18:39 +08:00
LONGLONG frameStep ;
2021-10-20 21:18:24 +08:00
LONGLONG nFrame ;
LONGLONG impendingVideoSampleTime ;
LONGLONG usedVideoSampleTime ;
LONGLONG videoStartOffset ;
LONGLONG videoSampleDuration ;
LONGLONG requiredAudioTime ;
LONGLONG audioSampleTime ;
LONGLONG audioStartOffset ;
LONGLONG audioSampleDuration ;
LONGLONG audioTime ;
LONGLONG chunkLengthOfBytes ;
LONGLONG givenAudioTime ;
LONGLONG numberOfAdditionalAudioBytes ; // the number of additional bytes required to align the audio chunk
double bufferedAudioDuration ;
LONGLONG audioSamplePos ;
DWORD numberOfAudioStreams ;
Mat audioFrame ;
std : : deque < BYTE > bufferAudioData ;
2018-04-25 23:19:14 +08:00
bool isOpen ;
2021-10-20 21:18:24 +08:00
bool grabIsDone ;
bool syncLastFrame ;
bool lastFrame ;
2018-04-12 20:26:18 +08:00
} ;
2018-04-05 18:55:42 +08:00
2018-04-19 23:24:02 +08:00
CvCapture_MSMF : : CvCapture_MSMF ( ) :
2018-04-12 20:26:18 +08:00
MF ( Media_Foundation : : getInstance ( ) ) ,
2018-04-23 21:48:57 +08:00
filename ( " " ) ,
camid ( - 1 ) ,
captureMode ( MODE_SW ) ,
2021-03-01 23:51:04 +08:00
va_type ( VIDEO_ACCELERATION_NONE ) ,
hwDeviceIndex ( - 1 ) ,
2018-12-13 19:53:48 +08:00
# ifdef HAVE_MSMF_DXVA
2018-04-23 21:48:57 +08:00
D3DDev ( NULL ) ,
D3DMgr ( NULL ) ,
# endif
2018-04-12 20:26:18 +08:00
videoFileSource ( NULL ) ,
2021-03-03 17:10:00 +08:00
readCallback ( NULL ) ,
2021-10-20 21:18:24 +08:00
impendingVideoSample ( NULL ) ,
usedVideoSample ( NULL ) ,
dwVideoStreamIndex ( 0 ) ,
dwAudioStreamIndex ( 0 ) ,
device_status ( false ) ,
videoStream ( 0 ) ,
audioStream ( - 1 ) ,
vEOS ( false ) ,
aEOS ( false ) ,
audioBaseIndex ( 1 ) ,
outputVideoFormat ( CV_CAP_MODE_BGR ) ,
outputAudioFormat ( CV_16S ) ,
2021-12-04 18:37:10 +08:00
audioSamplesPerSecond ( 0 ) ,
2018-04-19 23:24:02 +08:00
convertFormat ( true ) ,
2021-03-03 17:10:00 +08:00
duration ( 0 ) ,
frameStep ( 0 ) ,
2021-10-20 21:18:24 +08:00
nFrame ( 0 ) ,
impendingVideoSampleTime ( 0 ) ,
usedVideoSampleTime ( 0 ) ,
videoStartOffset ( - 1 ) ,
videoSampleDuration ( 0 ) ,
requiredAudioTime ( 0 ) ,
audioSampleTime ( 0 ) ,
audioStartOffset ( - 1 ) ,
audioSampleDuration ( 0 ) ,
audioTime ( 0 ) ,
chunkLengthOfBytes ( 0 ) ,
givenAudioTime ( 0 ) ,
numberOfAdditionalAudioBytes ( 0 ) ,
bufferedAudioDuration ( 0 ) ,
audioSamplePos ( 0 ) ,
numberOfAudioStreams ( 0 ) ,
isOpen ( false ) ,
grabIsDone ( false ) ,
syncLastFrame ( true ) ,
lastFrame ( false )
2018-04-12 20:26:18 +08:00
{
2013-04-03 09:01:20 +08:00
}
2013-04-16 21:25:10 +08:00
2018-04-19 23:24:02 +08:00
CvCapture_MSMF : : ~ CvCapture_MSMF ( )
2013-04-03 09:01:20 +08:00
{
2018-04-12 20:26:18 +08:00
close ( ) ;
2018-06-06 21:00:55 +08:00
configureHW ( false ) ;
2013-04-03 09:01:20 +08:00
}
2013-04-16 21:25:10 +08:00
2018-04-19 23:24:02 +08:00
void CvCapture_MSMF : : close ( )
2013-04-03 09:01:20 +08:00
{
2018-04-25 23:19:14 +08:00
if ( isOpen )
2013-04-03 09:01:20 +08:00
{
2018-04-25 23:19:14 +08:00
isOpen = false ;
2021-10-20 21:18:24 +08:00
usedVideoSample . Release ( ) ;
for ( auto item : audioSamples )
item . Release ( ) ;
2018-06-10 20:32:09 +08:00
videoFileSource . Release ( ) ;
2021-10-20 21:18:24 +08:00
device_status = false ;
2018-04-23 21:48:57 +08:00
camid = - 1 ;
2018-06-10 20:32:09 +08:00
filename . clear ( ) ;
2013-04-03 09:01:20 +08:00
}
2018-06-13 17:47:53 +08:00
readCallback . Release ( ) ;
2013-04-03 09:01:20 +08:00
}
2013-04-16 21:25:10 +08:00
2021-10-20 21:18:24 +08:00
bool CvCapture_MSMF : : initStream ( DWORD streamID , const MediaType mt )
2020-02-07 20:03:20 +08:00
{
CV_LOG_DEBUG ( NULL , " Init stream " < < streamID < < " with MediaType " < < mt ) ;
2021-10-20 21:18:24 +08:00
_ComPtr < IMFMediaType > mediaTypesOut ;
if ( mt . majorType = = MFMediaType_Audio )
2020-02-07 20:03:20 +08:00
{
2021-10-20 21:18:24 +08:00
captureAudioFormat = mt ;
mediaTypesOut = mt . createMediaType_Audio ( ) ;
}
if ( mt . majorType = = MFMediaType_Video )
{
captureVideoFormat = mt ;
mediaTypesOut = mt . createMediaType_Video ( ) ;
2020-02-07 20:03:20 +08:00
}
if ( FAILED ( videoFileSource - > SetStreamSelection ( streamID , true ) ) )
{
CV_LOG_WARNING ( NULL , " Failed to select stream " < < streamID ) ;
return false ;
}
2021-10-20 21:18:24 +08:00
HRESULT hr = videoFileSource - > SetCurrentMediaType ( streamID , NULL , mediaTypesOut . Get ( ) ) ;
2020-02-07 20:03:20 +08:00
if ( hr = = MF_E_TOPO_CODEC_NOT_FOUND )
{
CV_LOG_WARNING ( NULL , " Failed to set mediaType (stream " < < streamID < < " , " < < mt < < " (codec not found) " ) ;
return false ;
}
else if ( hr = = MF_E_INVALIDMEDIATYPE )
{
CV_LOG_WARNING ( NULL , " Failed to set mediaType (stream " < < streamID < < " , " < < mt < < " (unsupported media type) " ) ;
return false ;
}
else if ( FAILED ( hr ) )
{
CV_LOG_WARNING ( NULL , " Failed to set mediaType (stream " < < streamID < < " , " < < mt < < " (HRESULT " < < hr < < " ) " ) ;
return false ;
}
2021-10-20 21:18:24 +08:00
2020-02-07 20:03:20 +08:00
return true ;
}
_ComPtr < IMFAttributes > CvCapture_MSMF : : getDefaultSourceConfig ( UINT32 num )
{
CV_Assert ( num > 0 ) ;
2021-07-01 06:08:24 +08:00
const bool OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS = utils : : getConfigurationParameterBool ( " OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS " , true ) ;
2020-02-07 20:03:20 +08:00
_ComPtr < IMFAttributes > res ;
if ( FAILED ( MFCreateAttributes ( & res , num ) ) | |
2021-07-01 06:08:24 +08:00
FAILED ( res - > SetUINT32 ( MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS , OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS ) ) | |
2020-02-07 20:03:20 +08:00
FAILED ( res - > SetUINT32 ( MF_SOURCE_READER_DISABLE_DXVA , false ) ) | |
FAILED ( res - > SetUINT32 ( MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING , false ) ) | |
FAILED ( res - > SetUINT32 ( MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING , true ) )
)
{
CV_Error ( CV_StsError , " Failed to create attributes " ) ;
}
# ifdef HAVE_MSMF_DXVA
if ( D3DMgr )
{
if ( FAILED ( res - > SetUnknown ( MF_SOURCE_READER_D3D_MANAGER , D3DMgr . Get ( ) ) ) )
{
CV_Error ( CV_StsError , " Failed to create attributes " ) ;
}
}
# endif
return res ;
}
2018-04-23 21:48:57 +08:00
bool CvCapture_MSMF : : configureHW ( bool enable )
{
2018-12-13 19:53:48 +08:00
# ifdef HAVE_MSMF_DXVA
2018-04-23 21:48:57 +08:00
if ( ( enable & & D3DMgr & & D3DDev ) | | ( ! enable & & ! D3DMgr & & ! D3DDev ) )
return true ;
2018-06-30 03:54:58 +08:00
if ( ! pMFCreateDXGIDeviceManager_initialized )
init_MFCreateDXGIDeviceManager ( ) ;
if ( enable & & ! pMFCreateDXGIDeviceManager )
return false ;
2018-04-23 21:48:57 +08:00
2018-04-25 23:19:14 +08:00
bool reopen = isOpen ;
2018-04-23 21:48:57 +08:00
int prevcam = camid ;
cv : : String prevfile = filename ;
close ( ) ;
if ( enable )
{
2021-03-01 23:51:04 +08:00
_ComPtr < IDXGIAdapter > pAdapter ;
if ( hwDeviceIndex > = 0 ) {
_ComPtr < IDXGIFactory2 > pDXGIFactory ;
if ( FAILED ( CreateDXGIFactory ( __uuidof ( IDXGIFactory2 ) , ( void * * ) & pDXGIFactory ) ) | |
FAILED ( pDXGIFactory - > EnumAdapters ( hwDeviceIndex , & pAdapter ) ) ) {
return false ;
}
}
2018-04-23 21:48:57 +08:00
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 } ;
2021-03-01 23:51:04 +08:00
D3D_DRIVER_TYPE driverType = pAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE ;
if ( SUCCEEDED ( D3D11CreateDevice ( pAdapter . Get ( ) , driverType , NULL , D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_VIDEO_SUPPORT ,
2018-06-10 20:32:09 +08:00
levels , sizeof ( levels ) / sizeof ( * levels ) , D3D11_SDK_VERSION , & D3DDev , NULL , NULL ) ) )
2018-04-23 21:48:57 +08:00
{
// NOTE: Getting ready for multi-threaded operation
_ComPtr < ID3D11Multithread > D3DDevMT ;
UINT mgrRToken ;
if ( SUCCEEDED ( D3DDev - > QueryInterface ( IID_PPV_ARGS ( & D3DDevMT ) ) ) )
{
D3DDevMT - > SetMultithreadProtected ( TRUE ) ;
2018-06-10 20:32:09 +08:00
D3DDevMT . Release ( ) ;
2018-06-30 03:54:58 +08:00
if ( SUCCEEDED ( pMFCreateDXGIDeviceManager ( & mgrRToken , & D3DMgr ) ) )
2018-04-23 21:48:57 +08:00
{
if ( SUCCEEDED ( D3DMgr - > ResetDevice ( D3DDev . Get ( ) , mgrRToken ) ) )
{
captureMode = MODE_HW ;
2021-03-01 23:51:04 +08:00
if ( hwDeviceIndex < 0 )
hwDeviceIndex = 0 ;
// Log adapter description
_ComPtr < IDXGIDevice > dxgiDevice ;
if ( SUCCEEDED ( D3DDev - > QueryInterface ( __uuidof ( IDXGIDevice ) , reinterpret_cast < void * * > ( & dxgiDevice ) ) ) ) {
_ComPtr < IDXGIAdapter > adapter ;
if ( SUCCEEDED ( dxgiDevice - > GetAdapter ( & adapter ) ) ) {
DXGI_ADAPTER_DESC desc ;
if ( SUCCEEDED ( adapter - > GetDesc ( & desc ) ) ) {
std : : wstring name ( desc . Description ) ;
std : : wstring_convert < std : : codecvt_utf8_utf16 < wchar_t > > conv ;
CV_LOG_INFO ( NULL , " MSMF: Using D3D11 video acceleration on GPU device: " < < conv . to_bytes ( name ) ) ;
}
}
}
// Reopen if needed
return reopen ? ( prevcam > = 0 ? open ( prevcam , NULL ) : open ( prevfile . c_str ( ) , NULL ) ) : true ;
2018-04-23 21:48:57 +08:00
}
2018-06-10 20:32:09 +08:00
D3DMgr . Release ( ) ;
2018-04-23 21:48:57 +08:00
}
}
2018-06-10 20:32:09 +08:00
D3DDev . Release ( ) ;
2018-04-23 21:48:57 +08:00
}
return false ;
}
else
{
if ( D3DMgr )
2018-06-10 20:32:09 +08:00
D3DMgr . Release ( ) ;
2018-04-23 21:48:57 +08:00
if ( D3DDev )
2018-06-10 20:32:09 +08:00
D3DDev . Release ( ) ;
2018-04-23 21:48:57 +08:00
captureMode = MODE_SW ;
2021-03-01 23:51:04 +08:00
return reopen ? ( prevcam > = 0 ? open ( prevcam , NULL ) : open ( prevfile . c_str ( ) , NULL ) ) : true ;
2018-04-23 21:48:57 +08:00
}
# else
return ! enable ;
# endif
}
2021-03-01 23:51:04 +08:00
bool CvCapture_MSMF : : configureHW ( const VideoCaptureParameters & params )
{
va_type = params . get < VideoAccelerationType > ( CAP_PROP_HW_ACCELERATION , VIDEO_ACCELERATION_ANY ) ;
hwDeviceIndex = params . get < int > ( CAP_PROP_HW_DEVICE , - 1 ) ;
# ifndef HAVE_MSMF_DXVA
if ( va_type ! = VIDEO_ACCELERATION_NONE & & va_type ! = VIDEO_ACCELERATION_ANY )
{
CV_LOG_INFO ( NULL , " VIDEOIO/MSMF: MSMF backend is build without DXVA acceleration support. Can't handle CAP_PROP_HW_ACCELERATION parameter: " < < va_type ) ;
}
# endif
return configureHW ( va_type = = VIDEO_ACCELERATION_D3D11 | | va_type = = VIDEO_ACCELERATION_ANY ) ;
}
2021-10-20 21:18:24 +08:00
bool CvCapture_MSMF : : configureAudioOutput ( MediaType newType )
{
FormatStorage formats ;
formats . read ( videoFileSource . Get ( ) ) ;
std : : pair < FormatStorage : : MediaID , MediaType > bestMatch ;
formats . countNumberOfAudioStreams ( numberOfAudioStreams ) ;
if ( device_status )
bestMatch = formats . findBestAudioFormat ( newType ) ;
else
bestMatch = formats . findAudioFormatByStream ( audioStream ) ;
if ( bestMatch . second . isEmpty ( true ) )
{
CV_LOG_DEBUG ( NULL , " Can not find audio stream with requested parameters " ) ;
2021-10-26 22:33:53 +08:00
isOpen = false ;
2021-10-20 21:18:24 +08:00
return false ;
}
dwAudioStreamIndex = bestMatch . first . stream ;
dwStreamIndices . push_back ( dwAudioStreamIndex ) ;
MediaType newFormat = bestMatch . second ;
newFormat . majorType = MFMediaType_Audio ;
2021-12-04 18:37:10 +08:00
newFormat . nSamplesPerSec = ( audioSamplesPerSecond = = 0 ) ? 44100 : audioSamplesPerSecond ;
2021-10-20 21:18:24 +08:00
switch ( outputAudioFormat )
{
case CV_8S :
newFormat . subType = MFAudioFormat_PCM ;
newFormat . bit_per_sample = 8 ;
break ;
case CV_16S :
newFormat . subType = MFAudioFormat_PCM ;
newFormat . bit_per_sample = 16 ;
break ;
case CV_32S :
newFormat . subType = MFAudioFormat_PCM ;
newFormat . bit_per_sample = 32 ;
case CV_32F :
newFormat . subType = MFAudioFormat_Float ;
newFormat . bit_per_sample = 32 ;
break ;
default :
break ;
}
return initStream ( dwAudioStreamIndex , newFormat ) ;
}
bool CvCapture_MSMF : : configureVideoOutput ( MediaType newType , cv : : uint32_t outFormat )
2013-04-03 09:01:20 +08:00
{
2020-02-07 20:03:20 +08:00
FormatStorage formats ;
formats . read ( videoFileSource . Get ( ) ) ;
2020-05-27 22:52:17 +08:00
std : : pair < FormatStorage : : MediaID , MediaType > bestMatch = formats . findBestVideoFormat ( newType ) ;
if ( bestMatch . second . isEmpty ( ) )
{
CV_LOG_DEBUG ( NULL , " Can not find video stream with requested parameters " ) ;
return false ;
}
2021-10-20 21:18:24 +08:00
dwVideoStreamIndex = bestMatch . first . stream ;
dwStreamIndices . push_back ( dwVideoStreamIndex ) ;
2020-02-07 20:03:20 +08:00
nativeFormat = bestMatch . second ;
MediaType newFormat = nativeFormat ;
2021-10-20 21:18:24 +08:00
2020-04-01 19:40:11 +08:00
if ( convertFormat )
2018-04-12 20:26:18 +08:00
{
2020-02-07 20:03:20 +08:00
switch ( outFormat )
2013-04-03 09:01:20 +08:00
{
2020-02-07 20:03:20 +08:00
case CV_CAP_MODE_BGR :
case CV_CAP_MODE_RGB :
newFormat . subType = captureMode = = MODE_HW ? MFVideoFormat_RGB32 : MFVideoFormat_RGB24 ;
newFormat . stride = ( captureMode = = MODE_HW ? 4 : 3 ) * newFormat . width ;
newFormat . sampleSize = newFormat . stride * newFormat . height ;
break ;
case CV_CAP_MODE_GRAY :
newFormat . subType = MFVideoFormat_YUY2 ;
newFormat . stride = newFormat . width ;
newFormat . sampleSize = newFormat . stride * newFormat . height * 3 / 2 ;
break ;
case CV_CAP_MODE_YUYV :
newFormat . subType = MFVideoFormat_YUY2 ;
newFormat . stride = 2 * newFormat . width ;
newFormat . sampleSize = newFormat . stride * newFormat . height ;
break ;
default :
return false ;
2018-04-12 20:26:18 +08:00
}
2020-02-07 20:03:20 +08:00
newFormat . interlaceMode = MFVideoInterlace_Progressive ;
newFormat . isFixedSize = true ;
if ( nativeFormat . subType = = MFVideoFormat_MP43 ) //Unable to estimate FPS for MP43
newFormat . frameRateNum = 0 ;
2013-04-03 09:01:20 +08:00
}
2020-02-07 20:03:20 +08:00
// we select native format first and then our requested format (related issue #12822)
if ( ! newType . isEmpty ( ) ) // camera input
2021-10-20 21:18:24 +08:00
{
initStream ( dwVideoStreamIndex , nativeFormat ) ;
}
return initStream ( dwVideoStreamIndex , newFormat ) ;
}
bool CvCapture_MSMF : : configureOutput ( )
{
if ( FAILED ( videoFileSource - > SetStreamSelection ( ( DWORD ) MF_SOURCE_READER_ALL_STREAMS , false ) ) )
{
CV_LOG_WARNING ( NULL , " Failed to reset streams " ) ;
return false ;
}
bool tmp = true ;
if ( videoStream ! = - 1 )
tmp = ( ! device_status ) ? configureVideoOutput ( MediaType ( ) , outputVideoFormat ) : configureVideoOutput ( MediaType : : createDefault_Video ( ) , outputVideoFormat ) ;
if ( audioStream ! = - 1 )
tmp & = ( ! device_status ) ? configureAudioOutput ( MediaType ( ) ) : configureAudioOutput ( MediaType : : createDefault_Audio ( ) ) ;
return tmp ;
2013-04-03 09:01:20 +08:00
}
2013-04-16 21:25:10 +08:00
2021-03-01 23:51:04 +08:00
bool CvCapture_MSMF : : open ( int index , const cv : : VideoCaptureParameters * params )
2013-04-03 09:01:20 +08:00
{
2018-04-12 20:26:18 +08:00
close ( ) ;
2020-02-07 20:03:20 +08:00
if ( index < 0 )
2018-06-26 19:04:02 +08:00
return false ;
2021-03-01 23:51:04 +08:00
if ( params )
{
configureHW ( * params ) ;
2021-12-04 18:37:10 +08:00
if ( ! ( configureStreams ( * params ) & & setAudioProperties ( * params ) ) )
return false ;
2021-10-20 21:18:24 +08:00
}
if ( videoStream ! = - 1 & & audioStream ! = - 1 | | videoStream = = - 1 & & audioStream = = - 1 )
{
CV_LOG_DEBUG ( NULL , " Only one of the properties CAP_PROP_AUDIO_STREAM " < < audioStream < < " and " < < CAP_PROP_VIDEO_STREAM < < " must be different from -1 " ) ;
return false ;
2021-03-01 23:51:04 +08:00
}
2020-02-07 20:03:20 +08:00
DeviceList devices ;
2021-10-20 21:18:24 +08:00
UINT32 count = 0 ;
if ( audioStream ! = - 1 )
count = devices . read ( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID ) ;
if ( videoStream ! = - 1 )
count = devices . read ( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID ) ;
2020-02-07 20:03:20 +08:00
if ( count = = 0 | | static_cast < UINT32 > ( index ) > count )
2013-04-03 09:01:20 +08:00
{
2020-02-07 20:03:20 +08:00
CV_LOG_DEBUG ( NULL , " Device " < < index < < " not found (total " < < count < < " devices) " ) ;
return false ;
}
_ComPtr < IMFAttributes > attr = getDefaultSourceConfig ( ) ;
_ComPtr < IMFSourceReaderCallback > cb = new SourceReaderCB ( ) ;
attr - > SetUnknown ( MF_SOURCE_READER_ASYNC_CALLBACK , cb . Get ( ) ) ;
_ComPtr < IMFMediaSource > src = devices . activateSource ( index ) ;
if ( ! src . Get ( ) | | FAILED ( MFCreateSourceReaderFromMediaSource ( src . Get ( ) , attr . Get ( ) , & videoFileSource ) ) )
{
CV_LOG_DEBUG ( NULL , " Failed to create source reader " ) ;
return false ;
2013-04-03 09:01:20 +08:00
}
2013-04-16 21:25:10 +08:00
2020-02-07 20:03:20 +08:00
isOpen = true ;
2021-10-20 21:18:24 +08:00
device_status = true ;
2020-02-07 20:03:20 +08:00
camid = index ;
readCallback = cb ;
duration = 0 ;
2021-10-20 21:18:24 +08:00
if ( configureOutput ( ) )
2020-02-07 20:03:20 +08:00
{
2021-10-20 21:18:24 +08:00
frameStep = captureVideoFormat . getFrameStep ( ) ;
2020-02-07 20:03:20 +08:00
}
2021-03-01 23:51:04 +08:00
if ( isOpen & & ! openFinalize_ ( params ) )
{
close ( ) ;
return false ;
}
2021-12-04 18:37:10 +08:00
if ( isOpen )
{
if ( audioStream ! = - 1 )
if ( ! checkAudioProperties ( ) )
return false ;
}
2021-03-01 23:51:04 +08:00
2018-04-25 23:19:14 +08:00
return isOpen ;
2013-04-03 09:01:20 +08:00
}
2018-04-19 23:24:02 +08:00
2021-03-01 23:51:04 +08:00
bool CvCapture_MSMF : : open ( const cv : : String & _filename , const cv : : VideoCaptureParameters * params )
2018-04-19 23:24:02 +08:00
{
close ( ) ;
2018-04-25 23:19:14 +08:00
if ( _filename . empty ( ) )
2018-04-19 23:24:02 +08:00
return false ;
2021-03-01 23:51:04 +08:00
if ( params )
{
configureHW ( * params ) ;
2021-12-04 18:37:10 +08:00
if ( ! ( configureStreams ( * params ) & & setAudioProperties ( * params ) ) )
return false ;
2021-03-01 23:51:04 +08:00
}
2018-04-19 23:24:02 +08:00
// Set source reader parameters
2020-02-07 20:03:20 +08:00
_ComPtr < IMFAttributes > attr = getDefaultSourceConfig ( ) ;
cv : : AutoBuffer < wchar_t > unicodeFileName ( _filename . length ( ) + 1 ) ;
MultiByteToWideChar ( CP_ACP , 0 , _filename . c_str ( ) , - 1 , unicodeFileName . data ( ) , ( int ) _filename . length ( ) + 1 ) ;
if ( SUCCEEDED ( MFCreateSourceReaderFromURL ( unicodeFileName . data ( ) , attr . Get ( ) , & videoFileSource ) ) )
2018-04-19 23:24:02 +08:00
{
2020-02-07 20:03:20 +08:00
isOpen = true ;
2021-10-20 21:18:24 +08:00
usedVideoSampleTime = 0 ;
if ( configureOutput ( ) )
2018-04-19 23:24:02 +08:00
{
2020-02-07 20:03:20 +08:00
filename = _filename ;
2021-10-20 21:18:24 +08:00
frameStep = captureVideoFormat . getFrameStep ( ) ;
2020-02-07 20:03:20 +08:00
PROPVARIANT var ;
HRESULT hr ;
if ( SUCCEEDED ( hr = videoFileSource - > GetPresentationAttribute ( ( DWORD ) MF_SOURCE_READER_MEDIASOURCE , MF_PD_DURATION , & var ) ) & &
var . vt = = VT_UI8 )
2018-04-19 23:24:02 +08:00
{
2020-02-07 20:03:20 +08:00
duration = var . uhVal . QuadPart ;
PropVariantClear ( & var ) ;
2018-04-19 23:24:02 +08:00
}
2020-02-07 20:03:20 +08:00
else
duration = 0 ;
2018-04-19 23:24:02 +08:00
}
}
2021-03-01 23:51:04 +08:00
if ( isOpen & & ! openFinalize_ ( params ) )
{
close ( ) ;
return false ;
}
2021-10-20 21:18:24 +08:00
if ( isOpen )
2021-12-04 18:37:10 +08:00
{
if ( audioStream ! = - 1 )
2021-10-20 21:18:24 +08:00
{
2021-12-04 18:37:10 +08:00
if ( ! checkAudioProperties ( ) )
return false ;
if ( videoStream ! = - 1 )
{
isOpen = grabFrame ( ) ;
if ( isOpen )
grabIsDone = true ;
}
2021-10-20 21:18:24 +08:00
}
2021-12-04 18:37:10 +08:00
}
2018-04-25 23:19:14 +08:00
return isOpen ;
2018-04-19 23:24:02 +08:00
}
2021-03-01 23:51:04 +08:00
bool CvCapture_MSMF : : openFinalize_ ( const VideoCaptureParameters * params )
{
if ( params )
{
std : : vector < int > unused_params = params - > getUnused ( ) ;
for ( int key : unused_params )
{
if ( ! setProperty ( key , params - > get < double > ( key ) ) )
{
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: can't set property " < < key ) ;
return false ;
}
}
}
VideoAccelerationType actual_va_type = ( captureMode = = MODE_HW ) ? VIDEO_ACCELERATION_D3D11 : VIDEO_ACCELERATION_NONE ;
if ( va_type ! = VIDEO_ACCELERATION_NONE & & va_type ! = VIDEO_ACCELERATION_ANY )
{
if ( va_type ! = actual_va_type )
{
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: Can't select requested video acceleration through CAP_PROP_HW_ACCELERATION: "
< < va_type < < " (actual is " < < actual_va_type < < " ). Bailout " ) ;
return false ;
}
}
else
{
va_type = actual_va_type ;
}
return true ;
}
2021-10-20 21:18:24 +08:00
bool CvCapture_MSMF : : configureStreams ( const cv : : VideoCaptureParameters & params )
2013-04-03 09:01:20 +08:00
{
2021-10-20 21:18:24 +08:00
if ( params . has ( CAP_PROP_VIDEO_STREAM ) )
2018-06-13 17:47:53 +08:00
{
2021-10-20 21:18:24 +08:00
double value = params . get < double > ( CAP_PROP_VIDEO_STREAM ) ;
if ( value = = - 1 | | value = = 0 )
videoStream = static_cast < int > ( value ) ;
else
2018-06-13 17:47:53 +08:00
{
2021-10-20 21:18:24 +08:00
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: CAP_PROP_VIDEO_STREAM parameter value is invalid/unsupported: " < < value ) ;
return false ;
2018-06-13 17:47:53 +08:00
}
2021-10-20 21:18:24 +08:00
}
if ( params . has ( CAP_PROP_AUDIO_STREAM ) )
{
double value = params . get < double > ( CAP_PROP_AUDIO_STREAM ) ;
if ( value = = - 1 | | value > - 1 )
audioStream = static_cast < int > ( value ) ;
else
2018-06-13 17:47:53 +08:00
{
2021-10-20 21:18:24 +08:00
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: CAP_PROP_AUDIO_STREAM parameter value is invalid/unsupported: " < < value ) ;
2018-06-13 17:47:53 +08:00
return false ;
}
2021-10-20 21:18:24 +08:00
}
return true ;
}
bool CvCapture_MSMF : : setAudioProperties ( const cv : : VideoCaptureParameters & params )
{
if ( params . has ( CAP_PROP_AUDIO_DATA_DEPTH ) )
{
int value = static_cast < int > ( params . get < double > ( CAP_PROP_AUDIO_DATA_DEPTH ) ) ;
if ( value ! = CV_8S & & value ! = CV_16S & & value ! = CV_32S & & value ! = CV_32F )
2018-06-13 17:47:53 +08:00
{
2021-10-20 21:18:24 +08:00
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: CAP_PROP_AUDIO_DATA_DEPTH parameter value is invalid/unsupported: " < < value ) ;
2018-06-13 17:47:53 +08:00
return false ;
}
2021-10-20 21:18:24 +08:00
else
{
outputAudioFormat = value ;
}
2018-06-13 17:47:53 +08:00
}
2021-12-04 18:37:10 +08:00
if ( params . has ( CAP_PROP_AUDIO_SAMPLES_PER_SECOND ) )
{
int value = static_cast < int > ( params . get < double > ( CAP_PROP_AUDIO_SAMPLES_PER_SECOND ) ) ;
if ( value < 0 )
{
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: CAP_PROP_AUDIO_SAMPLES_PER_SECOND parameter can't be negative: " < < value ) ;
return false ;
}
else
{
audioSamplesPerSecond = value ;
}
}
2021-10-20 21:18:24 +08:00
if ( params . has ( CAP_PROP_AUDIO_SYNCHRONIZE ) )
{
2021-12-04 18:37:10 +08:00
int value = static_cast < UINT32 > ( params . get < double > ( CAP_PROP_AUDIO_SYNCHRONIZE ) ) ;
2021-10-20 21:18:24 +08:00
syncLastFrame = ( value ! = 0 ) ? true : false ;
}
return true ;
}
2021-12-04 18:37:10 +08:00
bool CvCapture_MSMF : : checkAudioProperties ( )
{
if ( audioSamplesPerSecond ! = 0 )
{
_ComPtr < IMFMediaType > type ;
UINT32 actualAudioSamplesPerSecond = 0 ;
HRESULT hr = videoFileSource - > GetCurrentMediaType ( dwAudioStreamIndex , & type ) ;
if ( SUCCEEDED ( hr ) )
{
type - > GetUINT32 ( MF_MT_AUDIO_SAMPLES_PER_SECOND , & actualAudioSamplesPerSecond ) ;
if ( actualAudioSamplesPerSecond ! = audioSamplesPerSecond )
{
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: CAP_PROP_AUDIO_SAMPLES_PER_SECOND parameter value is invalid/unsupported: " < < audioSamplesPerSecond
< < " . Current value of CAP_PROP_AUDIO_SAMPLES_PER_SECOND: " < < actualAudioSamplesPerSecond ) ;
close ( ) ;
return false ;
}
return true ;
}
return false ;
}
return true ;
}
2021-10-20 21:18:24 +08:00
bool CvCapture_MSMF : : grabVideoFrame ( )
{
DWORD streamIndex , flags ;
HRESULT hr ;
usedVideoSample . Release ( ) ;
bool returnFlag = false ;
bool stopFlag = false ;
if ( audioStream ! = - 1 )
2013-04-03 09:01:20 +08:00
{
2021-10-20 21:18:24 +08:00
usedVideoSample . swap ( impendingVideoSample ) ;
std : : swap ( usedVideoSampleTime , impendingVideoSampleTime ) ;
}
while ( ! stopFlag )
{
for ( ; ; )
2013-04-03 09:01:20 +08:00
{
2018-06-08 22:06:45 +08:00
CV_TRACE_REGION ( " ReadSample " ) ;
if ( ! SUCCEEDED ( hr = videoFileSource - > ReadSample (
2021-10-20 21:18:24 +08:00
dwVideoStreamIndex , // Stream index.
2018-06-08 22:06:45 +08:00
0 , // Flags.
& streamIndex , // Receives the actual stream index.
& flags , // Receives status flags.
2021-10-20 21:18:24 +08:00
& impendingVideoSampleTime , // Receives the time stamp.
& impendingVideoSample // Receives the sample or NULL.
2018-06-08 22:06:45 +08:00
) ) )
break ;
2021-10-20 21:18:24 +08:00
if ( streamIndex ! = dwVideoStreamIndex )
2018-06-08 22:06:45 +08:00
break ;
if ( flags & ( MF_SOURCE_READERF_ERROR | MF_SOURCE_READERF_ALLEFFECTSREMOVED | MF_SOURCE_READERF_ENDOFSTREAM ) )
break ;
2021-10-20 21:18:24 +08:00
if ( impendingVideoSample )
2018-06-08 22:06:45 +08:00
break ;
2018-04-12 20:26:18 +08:00
if ( flags & MF_SOURCE_READERF_STREAMTICK )
{
2018-06-09 22:38:32 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Stream tick detected. Retrying to grab the frame " ) ;
2018-04-12 20:26:18 +08:00
}
2013-04-03 09:01:20 +08:00
}
2021-10-20 21:18:24 +08:00
if ( SUCCEEDED ( hr ) )
{
if ( streamIndex ! = dwVideoStreamIndex )
{
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Wrong stream read. Abort capturing " ) ;
close ( ) ;
}
else if ( flags & MF_SOURCE_READERF_ERROR )
{
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Stream reading error. Abort capturing " ) ;
close ( ) ;
}
else if ( flags & MF_SOURCE_READERF_ALLEFFECTSREMOVED )
{
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Stream decoding error. Abort capturing " ) ;
close ( ) ;
}
else if ( flags & MF_SOURCE_READERF_ENDOFSTREAM )
{
vEOS = true ;
lastFrame = true ;
stopFlag = true ;
if ( audioStream = = - 1 )
returnFlag = false ;
else if ( usedVideoSample )
returnFlag = true ;
CV_LOG_DEBUG ( NULL , " videoio(MSMF): End of video stream detected " ) ;
}
else
{
CV_LOG_DEBUG ( NULL , " videoio(MSMF): got video frame with timestamp= " < < impendingVideoSampleTime ) ;
if ( audioStream ! = - 1 )
{
if ( ! usedVideoSample )
{
usedVideoSample . swap ( impendingVideoSample ) ;
std : : swap ( usedVideoSampleTime , impendingVideoSampleTime ) ;
videoStartOffset = usedVideoSampleTime ;
}
else
{
stopFlag = true ;
}
if ( impendingVideoSample )
{
nFrame + + ;
videoSampleDuration = impendingVideoSampleTime - usedVideoSampleTime ;
requiredAudioTime = impendingVideoSampleTime - givenAudioTime ;
givenAudioTime + = requiredAudioTime ;
}
}
else
{
usedVideoSample . swap ( impendingVideoSample ) ;
std : : swap ( usedVideoSampleTime , impendingVideoSampleTime ) ;
stopFlag = true ;
nFrame + + ;
}
if ( flags & MF_SOURCE_READERF_NEWSTREAM )
{
CV_LOG_DEBUG ( NULL , " videoio(MSMF): New stream detected " ) ;
}
if ( flags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED )
{
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Stream native media type changed " ) ;
}
if ( flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED )
{
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Stream current media type changed " ) ;
}
returnFlag = true ;
}
}
}
return returnFlag ;
}
2013-04-16 21:25:10 +08:00
2021-10-26 22:33:53 +08:00
bool CvCapture_MSMF : : configureAudioFrame ( )
{
if ( ! audioSamples . empty ( ) | | ! bufferAudioData . empty ( ) & & aEOS )
{
_ComPtr < IMFMediaBuffer > buf = NULL ;
std : : vector < BYTE > audioDataInUse ;
BYTE * ptr = NULL ;
DWORD maxsize = 0 , cursize = 0 ;
CV_TRACE_REGION ( " get_contiguous_buffer " ) ;
for ( auto item : audioSamples )
{
if ( ! SUCCEEDED ( item - > ConvertToContiguousBuffer ( & buf ) ) )
{
CV_TRACE_REGION ( " get_buffer " ) ;
DWORD bcnt = 0 ;
if ( ! SUCCEEDED ( item - > GetBufferCount ( & bcnt ) ) )
break ;
if ( bcnt = = 0 )
break ;
if ( ! SUCCEEDED ( item - > GetBufferByIndex ( 0 , & buf ) ) )
break ;
}
if ( ! SUCCEEDED ( buf - > Lock ( & ptr , & maxsize , & cursize ) ) )
break ;
size_t lastSize = bufferAudioData . size ( ) ;
bufferAudioData . resize ( lastSize + cursize ) ;
for ( unsigned int i = 0 ; i < cursize ; i + + )
{
bufferAudioData [ lastSize + i ] = * ( ptr + i ) ;
}
CV_TRACE_REGION_NEXT ( " unlock " ) ;
buf - > Unlock ( ) ;
buf = NULL ;
}
audioSamples . clear ( ) ;
audioSamplePos + = chunkLengthOfBytes / ( ( captureAudioFormat . bit_per_sample / 8 ) * captureAudioFormat . nChannels ) ;
chunkLengthOfBytes = ( videoStream ! = - 1 ) ? ( LONGLONG ) ( ( requiredAudioTime * captureAudioFormat . nSamplesPerSec * captureAudioFormat . nChannels * ( captureAudioFormat . bit_per_sample ) / 8 ) / 1e7 ) : cursize ;
if ( ( videoStream ! = - 1 ) & & ( chunkLengthOfBytes % ( ( int ) ( captureAudioFormat . bit_per_sample ) / 8 * ( int ) captureAudioFormat . nChannels ) ! = 0 ) )
{
if ( ( double ) audioSamplePos / captureAudioFormat . nSamplesPerSec + audioStartOffset * 1e-7 - usedVideoSampleTime * 1e-7 > = 0 )
chunkLengthOfBytes - = numberOfAdditionalAudioBytes ;
numberOfAdditionalAudioBytes = ( ( int ) ( captureAudioFormat . bit_per_sample ) / 8 * ( int ) captureAudioFormat . nChannels )
- chunkLengthOfBytes % ( ( int ) ( captureAudioFormat . bit_per_sample ) / 8 * ( int ) captureAudioFormat . nChannels ) ;
chunkLengthOfBytes + = numberOfAdditionalAudioBytes ;
}
if ( lastFrame & & ! syncLastFrame | | aEOS & & ! vEOS )
{
chunkLengthOfBytes = bufferAudioData . size ( ) ;
audioSamplePos + = chunkLengthOfBytes / ( ( captureAudioFormat . bit_per_sample / 8 ) * captureAudioFormat . nChannels ) ;
}
CV_Check ( ( double ) chunkLengthOfBytes , chunkLengthOfBytes > = INT_MIN | | chunkLengthOfBytes < = INT_MAX , " MSMF: The chunkLengthOfBytes is out of the allowed range " ) ;
copy ( bufferAudioData . begin ( ) , bufferAudioData . begin ( ) + ( int ) chunkLengthOfBytes , std : : back_inserter ( audioDataInUse ) ) ;
bufferAudioData . erase ( bufferAudioData . begin ( ) , bufferAudioData . begin ( ) + ( int ) chunkLengthOfBytes ) ;
if ( audioFrame . empty ( ) )
{
switch ( outputAudioFormat )
{
case CV_8S :
cv : : Mat ( ( int ) chunkLengthOfBytes / ( captureAudioFormat . nChannels ) , captureAudioFormat . nChannels , CV_8S , audioDataInUse . data ( ) ) . copyTo ( audioFrame ) ;
break ;
case CV_16S :
cv : : Mat ( ( int ) chunkLengthOfBytes / ( 2 * captureAudioFormat . nChannels ) , captureAudioFormat . nChannels , CV_16S , audioDataInUse . data ( ) ) . copyTo ( audioFrame ) ;
break ;
case CV_32S :
cv : : Mat ( ( int ) chunkLengthOfBytes / ( 4 * captureAudioFormat . nChannels ) , captureAudioFormat . nChannels , CV_32S , audioDataInUse . data ( ) ) . copyTo ( audioFrame ) ;
break ;
case CV_32F :
cv : : Mat ( ( int ) chunkLengthOfBytes / ( 4 * captureAudioFormat . nChannels ) , captureAudioFormat . nChannels , CV_32F , audioDataInUse . data ( ) ) . copyTo ( audioFrame ) ;
break ;
default :
break ;
}
}
audioDataInUse . clear ( ) ;
audioDataInUse . shrink_to_fit ( ) ;
return true ;
}
else
{
return false ;
}
}
2021-10-20 21:18:24 +08:00
bool CvCapture_MSMF : : grabAudioFrame ( )
{
DWORD streamIndex , flags ;
HRESULT hr ;
_ComPtr < IMFSample > audioSample = NULL ;
audioSamples . clear ( ) ;
bool returnFlag = false ;
audioTime = 0 ;
int numberOfSamples = - 1 ;
if ( bufferedAudioDuration * 1e7 > requiredAudioTime )
return true ;
while ( ( ! vEOS ) ? audioTime < = requiredAudioTime : ! aEOS )
{
if ( audioStartOffset - usedVideoSampleTime > videoSampleDuration )
return true ;
for ( ; ; )
{
CV_TRACE_REGION ( " ReadSample " ) ;
if ( ! SUCCEEDED ( hr = videoFileSource - > ReadSample (
dwAudioStreamIndex , // Stream index.
0 , // Flags.
& streamIndex , // Receives the actual stream index.
& flags , // Receives status flags.
& audioSampleTime , // Receives the time stamp.
& audioSample // Receives the sample or NULL.
) ) )
break ;
if ( streamIndex ! = dwAudioStreamIndex )
break ;
if ( flags & ( MF_SOURCE_READERF_ERROR | MF_SOURCE_READERF_ALLEFFECTSREMOVED | MF_SOURCE_READERF_ENDOFSTREAM ) )
break ;
if ( audioSample )
break ;
if ( flags & MF_SOURCE_READERF_STREAMTICK )
{
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Stream tick detected. Retrying to grab the frame " ) ;
}
}
2018-04-12 20:26:18 +08:00
if ( SUCCEEDED ( hr ) )
2013-04-03 09:01:20 +08:00
{
2021-10-20 21:18:24 +08:00
if ( streamIndex ! = dwAudioStreamIndex )
2018-04-12 20:26:18 +08:00
{
Fix modules/ typos
Found using `codespell -q 3 -S ./3rdparty -L activ,amin,ang,atleast,childs,dof,endwhile,halfs,hist,iff,nd,od,uint`
2019-08-16 06:02:09 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Wrong stream read. Abort capturing " ) ;
2018-04-12 20:26:18 +08:00
close ( ) ;
}
else if ( flags & MF_SOURCE_READERF_ERROR )
{
2018-06-09 22:38:32 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Stream reading error. Abort capturing " ) ;
2018-04-12 20:26:18 +08:00
close ( ) ;
}
else if ( flags & MF_SOURCE_READERF_ALLEFFECTSREMOVED )
{
2018-06-09 22:38:32 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Stream decoding error. Abort capturing " ) ;
2018-04-12 20:26:18 +08:00
close ( ) ;
}
else if ( flags & MF_SOURCE_READERF_ENDOFSTREAM )
{
2021-10-20 21:18:24 +08:00
aEOS = true ;
if ( videoStream ! = - 1 & & ! vEOS )
returnFlag = true ;
2021-10-26 22:33:53 +08:00
if ( videoStream = = - 1 )
audioSamplePos + = chunkLengthOfBytes / ( ( captureAudioFormat . bit_per_sample / 8 ) * captureAudioFormat . nChannels ) ;
2021-10-20 21:18:24 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): End of audio stream detected " ) ;
break ;
2018-04-12 20:26:18 +08:00
}
else
2013-04-03 09:01:20 +08:00
{
2021-10-20 21:18:24 +08:00
audioSamples . push_back ( audioSample ) ;
audioSample = NULL ;
numberOfSamples + + ;
audioSamples [ numberOfSamples ] - > GetSampleDuration ( & audioSampleDuration ) ;
CV_LOG_DEBUG ( NULL , " videoio(MSMF): got audio frame with timestamp= " < < audioSampleTime < < " duration= " < < audioSampleDuration ) ;
audioTime + = ( LONGLONG ) ( audioSampleDuration + bufferedAudioDuration * 1e7 ) ;
if ( nFrame = = 1 & & audioStartOffset = = - 1 )
{
audioStartOffset = audioSampleTime - audioSampleDuration ;
requiredAudioTime - = audioStartOffset ;
}
2018-04-12 20:26:18 +08:00
if ( flags & MF_SOURCE_READERF_NEWSTREAM )
2013-04-03 18:48:23 +08:00
{
2018-06-09 22:38:32 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): New stream detected " ) ;
2013-04-03 09:01:20 +08:00
}
2018-04-12 20:26:18 +08:00
if ( flags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED )
2013-04-03 09:01:20 +08:00
{
2018-06-09 22:38:32 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Stream native media type changed " ) ;
2013-04-03 09:01:20 +08:00
}
2018-04-12 20:26:18 +08:00
if ( flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED )
{
2018-06-09 22:38:32 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): Stream current media type changed " ) ;
2018-04-12 20:26:18 +08:00
}
2021-10-20 21:18:24 +08:00
returnFlag = true ;
}
}
else
{
CV_LOG_DEBUG ( NULL , " videoio(MSMF): ReadSample() method is not succeeded " ) ;
return false ;
}
}
2021-10-26 22:33:53 +08:00
returnFlag & = configureAudioFrame ( ) ;
2021-10-20 21:18:24 +08:00
return returnFlag ;
}
bool CvCapture_MSMF : : grabFrame ( )
{
CV_TRACE_FUNCTION ( ) ;
if ( grabIsDone )
{
grabIsDone = false ;
2021-12-06 14:54:48 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): return pre-grabbed frame " < < usedVideoSampleTime ) ;
2021-10-20 21:18:24 +08:00
return true ;
}
audioFrame = Mat ( ) ;
if ( readCallback ) // async "live" capture mode
{
audioSamples . push_back ( NULL ) ;
HRESULT hr = 0 ;
SourceReaderCB * reader = ( ( SourceReaderCB * ) readCallback . Get ( ) ) ;
DWORD dwStreamIndex = 0 ;
if ( videoStream ! = - 1 )
dwStreamIndex = dwVideoStreamIndex ;
if ( audioStream ! = - 1 )
dwStreamIndex = dwAudioStreamIndex ;
if ( ! reader - > m_reader )
{
// Initiate capturing with async callback
reader - > m_reader = videoFileSource . Get ( ) ;
reader - > m_dwStreamIndex = dwStreamIndex ;
if ( FAILED ( hr = videoFileSource - > ReadSample ( dwStreamIndex , 0 , NULL , NULL , NULL , NULL ) ) )
{
CV_LOG_ERROR ( NULL , " videoio(MSMF): can't grab frame - initial async ReadSample() call failed: " < < hr ) ;
reader - > m_reader = NULL ;
return false ;
2013-04-03 18:48:23 +08:00
}
2013-04-03 09:01:20 +08:00
}
2021-10-20 21:18:24 +08:00
BOOL bEOS = false ;
2021-12-06 14:54:48 +08:00
LONGLONG timestamp = 0 ;
if ( FAILED ( hr = reader - > Wait ( videoStream = = - 1 ? INFINITE : 10000 , ( videoStream ! = - 1 ) ? usedVideoSample : audioSamples [ 0 ] , timestamp , bEOS ) ) ) // 10 sec
2021-10-20 21:18:24 +08:00
{
CV_LOG_WARNING ( NULL , " videoio(MSMF): can't grab frame. Error: " < < hr ) ;
return false ;
}
if ( bEOS )
{
CV_LOG_WARNING ( NULL , " videoio(MSMF): EOS signal. Capture stream is lost " ) ;
return false ;
}
if ( videoStream ! = - 1 )
2021-12-06 14:54:48 +08:00
usedVideoSampleTime = timestamp ;
2021-10-26 22:33:53 +08:00
if ( audioStream ! = - 1 )
return configureAudioFrame ( ) ;
2021-12-06 14:54:48 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): grabbed frame " < < usedVideoSampleTime ) ;
2021-10-20 21:18:24 +08:00
return true ;
}
else if ( isOpen )
{
if ( vEOS )
return false ;
bool returnFlag = true ;
if ( videoStream ! = - 1 )
{
if ( ! vEOS )
returnFlag & = grabVideoFrame ( ) ;
if ( ! returnFlag )
return false ;
}
if ( audioStream ! = - 1 )
{
bufferedAudioDuration = ( double ) ( bufferAudioData . size ( ) / ( ( captureAudioFormat . bit_per_sample / 8 ) * captureAudioFormat . nChannels ) ) / captureAudioFormat . nSamplesPerSec ;
audioFrame . release ( ) ;
if ( ! aEOS )
returnFlag & = grabAudioFrame ( ) ;
}
return returnFlag ;
2013-04-03 09:01:20 +08:00
}
2018-04-12 20:26:18 +08:00
return false ;
2013-04-03 09:01:20 +08:00
}
2013-04-16 21:25:10 +08:00
2021-10-20 21:18:24 +08:00
bool CvCapture_MSMF : : retrieveVideoFrame ( cv : : OutputArray frame )
2013-04-03 18:48:23 +08:00
{
2018-06-08 22:06:45 +08:00
CV_TRACE_FUNCTION ( ) ;
2021-12-06 14:54:48 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): retrieve video frame start... " ) ;
2018-06-08 22:06:45 +08:00
do
2013-04-03 09:01:20 +08:00
{
2021-10-20 21:18:24 +08:00
if ( ! usedVideoSample )
2018-06-08 22:06:45 +08:00
break ;
2018-04-12 20:26:18 +08:00
_ComPtr < IMFMediaBuffer > buf = NULL ;
2018-06-08 22:06:45 +08:00
CV_TRACE_REGION ( " get_contiguous_buffer " ) ;
2021-10-20 21:18:24 +08:00
if ( ! SUCCEEDED ( usedVideoSample - > ConvertToContiguousBuffer ( & buf ) ) )
2018-06-08 22:06:45 +08:00
{
CV_TRACE_REGION ( " get_buffer " ) ;
DWORD bcnt = 0 ;
2021-10-20 21:18:24 +08:00
if ( ! SUCCEEDED ( usedVideoSample - > GetBufferCount ( & bcnt ) ) )
2018-06-08 22:06:45 +08:00
break ;
if ( bcnt = = 0 )
break ;
2021-10-20 21:18:24 +08:00
if ( ! SUCCEEDED ( usedVideoSample - > GetBufferByIndex ( 0 , & buf ) ) )
2018-06-08 22:06:45 +08:00
break ;
}
bool lock2d = false ;
BYTE * ptr = NULL ;
LONG pitch = 0 ;
DWORD maxsize = 0 , cursize = 0 ;
// "For 2-D buffers, the Lock2D method is more efficient than the Lock method"
// see IMFMediaBuffer::Lock method documentation: https://msdn.microsoft.com/en-us/library/windows/desktop/bb970366(v=vs.85).aspx
_ComPtr < IMF2DBuffer > buffer2d ;
if ( convertFormat )
2013-04-03 09:01:20 +08:00
{
2018-06-10 20:32:09 +08:00
if ( SUCCEEDED ( buf . As < IMF2DBuffer > ( buffer2d ) ) )
2013-04-03 09:01:20 +08:00
{
2018-06-08 22:06:45 +08:00
CV_TRACE_REGION_NEXT ( " lock2d " ) ;
if ( SUCCEEDED ( buffer2d - > Lock2D ( & ptr , & pitch ) ) )
2013-04-03 09:01:20 +08:00
{
2018-06-08 22:06:45 +08:00
lock2d = true ;
2018-04-19 23:24:02 +08:00
}
2018-06-08 22:06:45 +08:00
}
}
if ( ptr = = NULL )
{
CV_Assert ( lock2d = = false ) ;
CV_TRACE_REGION_NEXT ( " lock " ) ;
if ( ! SUCCEEDED ( buf - > Lock ( & ptr , & maxsize , & cursize ) ) )
{
break ;
}
}
if ( ! ptr )
break ;
if ( convertFormat )
{
2021-10-20 21:18:24 +08:00
if ( lock2d | | ( unsigned int ) cursize = = captureVideoFormat . sampleSize )
2018-06-08 22:06:45 +08:00
{
2021-10-20 21:18:24 +08:00
switch ( outputVideoFormat )
2018-04-19 23:24:02 +08:00
{
2018-06-08 22:06:45 +08:00
case CV_CAP_MODE_YUYV :
2021-10-20 21:18:24 +08:00
cv : : Mat ( captureVideoFormat . height , captureVideoFormat . width , CV_8UC2 , ptr , pitch ) . copyTo ( frame ) ;
2018-06-08 22:06:45 +08:00
break ;
case CV_CAP_MODE_BGR :
if ( captureMode = = MODE_HW )
2021-10-20 21:18:24 +08:00
cv : : cvtColor ( cv : : Mat ( captureVideoFormat . height , captureVideoFormat . width , CV_8UC4 , ptr , pitch ) , frame , cv : : COLOR_BGRA2BGR ) ;
2018-06-08 22:06:45 +08:00
else
2021-10-20 21:18:24 +08:00
cv : : Mat ( captureVideoFormat . height , captureVideoFormat . width , CV_8UC3 , ptr , pitch ) . copyTo ( frame ) ;
2018-06-08 22:06:45 +08:00
break ;
case CV_CAP_MODE_RGB :
if ( captureMode = = MODE_HW )
2021-10-20 21:18:24 +08:00
cv : : cvtColor ( cv : : Mat ( captureVideoFormat . height , captureVideoFormat . width , CV_8UC4 , ptr , pitch ) , frame , cv : : COLOR_BGRA2BGR ) ;
2018-06-08 22:06:45 +08:00
else
2021-10-20 21:18:24 +08:00
cv : : cvtColor ( cv : : Mat ( captureVideoFormat . height , captureVideoFormat . width , CV_8UC3 , ptr , pitch ) , frame , cv : : COLOR_BGR2RGB ) ;
2018-06-08 22:06:45 +08:00
break ;
case CV_CAP_MODE_GRAY :
2021-10-20 21:18:24 +08:00
cv : : Mat ( captureVideoFormat . height , captureVideoFormat . width , CV_8UC1 , ptr , pitch ) . copyTo ( frame ) ;
2018-06-08 22:06:45 +08:00
break ;
default :
frame . release ( ) ;
break ;
2013-04-03 09:01:20 +08:00
}
}
2018-06-08 22:06:45 +08:00
else
frame . release ( ) ;
2013-04-03 09:01:20 +08:00
}
2018-06-08 22:06:45 +08:00
else
{
cv : : Mat ( 1 , cursize , CV_8UC1 , ptr , pitch ) . copyTo ( frame ) ;
}
CV_TRACE_REGION_NEXT ( " unlock " ) ;
if ( lock2d )
buffer2d - > Unlock2D ( ) ;
else
buf - > Unlock ( ) ;
2021-12-06 14:54:48 +08:00
CV_LOG_DEBUG ( NULL , " videoio(MSMF): retrieve video frame done! " ) ;
2018-06-08 22:06:45 +08:00
return ! frame . empty ( ) ;
} while ( 0 ) ;
2013-04-16 21:25:10 +08:00
2018-04-25 23:19:14 +08:00
frame . release ( ) ;
return false ;
2013-04-03 09:01:20 +08:00
}
2013-04-16 21:25:10 +08:00
2021-10-20 21:18:24 +08:00
bool CvCapture_MSMF : : retrieveAudioFrame ( int index , cv : : OutputArray frame )
{
CV_TRACE_FUNCTION ( ) ;
if ( audioStartOffset - usedVideoSampleTime > videoSampleDuration )
{
frame . release ( ) ;
return true ;
}
do
{
if ( audioFrame . empty ( ) )
{
frame . release ( ) ;
if ( aEOS )
return true ;
}
cv : : Mat data ;
switch ( outputAudioFormat )
{
case CV_8S :
data = cv : : Mat ( 1 , audioFrame . rows , CV_8S ) ;
for ( int i = 0 ; i < audioFrame . rows ; i + + )
data . at < char > ( 0 , i ) = audioFrame . at < char > ( i , index - audioBaseIndex ) ;
break ;
case CV_16S :
data = cv : : Mat ( 1 , audioFrame . rows , CV_16S ) ;
for ( int i = 0 ; i < audioFrame . rows ; i + + )
data . at < short > ( 0 , i ) = audioFrame . at < short > ( i , index - audioBaseIndex ) ;
break ;
case CV_32S :
data = cv : : Mat ( 1 , audioFrame . rows , CV_32S ) ;
for ( int i = 0 ; i < audioFrame . rows ; i + + )
data . at < int > ( 0 , i ) = audioFrame . at < int > ( i , index - audioBaseIndex ) ;
break ;
case CV_32F :
data = cv : : Mat ( 1 , audioFrame . rows , CV_32F ) ;
for ( int i = 0 ; i < audioFrame . rows ; i + + )
data . at < float > ( 0 , i ) = audioFrame . at < float > ( i , index - audioBaseIndex ) ;
break ;
default :
frame . release ( ) ;
break ;
}
if ( ! data . empty ( ) )
data . copyTo ( frame ) ;
return ! frame . empty ( ) ;
} while ( 0 ) ;
return false ;
}
bool CvCapture_MSMF : : retrieveFrame ( int index , cv : : OutputArray frame )
{
CV_TRACE_FUNCTION ( ) ;
if ( index < 0 )
return false ;
if ( ( unsigned int ) index < audioBaseIndex )
{
if ( videoStream = = - 1 )
{
frame . release ( ) ;
return false ;
}
else
return retrieveVideoFrame ( frame ) ;
}
else
{
if ( audioStream = = - 1 )
{
frame . release ( ) ;
return false ;
}
else
return retrieveAudioFrame ( index , frame ) ;
}
}
2018-04-19 23:24:02 +08:00
bool CvCapture_MSMF : : setTime ( double time , bool rough )
{
2021-10-20 21:18:24 +08:00
if ( videoStream = = - 1 )
return false ;
if ( videoStream ! = - 1 & & audioStream ! = - 1 )
if ( time ! = 0 )
return false ;
2018-04-19 23:24:02 +08:00
PROPVARIANT var ;
if ( SUCCEEDED ( videoFileSource - > GetPresentationAttribute ( ( DWORD ) MF_SOURCE_READER_MEDIASOURCE , MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS , & var ) ) & &
2018-04-24 21:18:39 +08:00
var . vt = = VT_UI4 & & var . ulVal & MFMEDIASOURCE_CAN_SEEK )
2018-04-19 23:24:02 +08:00
{
2021-10-20 21:18:24 +08:00
usedVideoSample . Release ( ) ;
2018-04-24 21:18:39 +08:00
bool useGrabbing = time > 0 & & ! rough & & ! ( var . ulVal & MFMEDIASOURCE_HAS_SLOW_SEEK ) ;
2018-04-19 23:24:02 +08:00
PropVariantClear ( & var ) ;
2021-10-20 21:18:24 +08:00
usedVideoSampleTime = ( useGrabbing ) ? 0 : ( LONGLONG ) floor ( time + 0.5 ) ;
nFrame = ( useGrabbing ) ? 0 : usedVideoSampleTime / frameStep ;
givenAudioTime = ( useGrabbing ) ? 0 : nFrame * frameStep ;
2018-04-19 23:24:02 +08:00
var . vt = VT_I8 ;
2021-10-20 21:18:24 +08:00
var . hVal . QuadPart = usedVideoSampleTime ;
2018-04-24 21:18:39 +08:00
bool resOK = SUCCEEDED ( videoFileSource - > SetCurrentPosition ( GUID_NULL , var ) ) ;
2018-04-19 23:24:02 +08:00
PropVariantClear ( & var ) ;
2018-04-24 21:18:39 +08:00
if ( resOK & & useGrabbing )
{
LONGLONG timeborder = ( LONGLONG ) floor ( time + 0.5 ) - frameStep / 2 ;
2021-10-20 21:18:24 +08:00
do { resOK = grabFrame ( ) ; usedVideoSample . Release ( ) ; } while ( resOK & & usedVideoSampleTime < timeborder ) ;
2018-04-24 21:18:39 +08:00
}
return resOK ;
2018-04-19 23:24:02 +08:00
}
return false ;
}
2021-10-20 21:18:24 +08:00
bool CvCapture_MSMF : : setTime ( int numberFrame )
{
if ( videoStream = = - 1 )
return false ;
if ( videoStream ! = - 1 & & audioStream ! = - 1 )
if ( numberFrame ! = 0 )
return false ;
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 )
{
usedVideoSample . Release ( ) ;
PropVariantClear ( & var ) ;
usedVideoSampleTime = 0 ;
nFrame = 0 ;
givenAudioTime = 0 ;
var . vt = VT_I8 ;
var . hVal . QuadPart = usedVideoSampleTime ;
bool resOK = SUCCEEDED ( videoFileSource - > SetCurrentPosition ( GUID_NULL , var ) ) ;
PropVariantClear ( & var ) ;
while ( resOK & & nFrame < numberFrame ) { resOK = grabFrame ( ) ; usedVideoSample . Release ( ) ; } ;
return resOK ;
}
return false ;
}
2020-02-07 20:03:20 +08:00
template < typename CtrlT >
bool CvCapture_MSMF : : readComplexPropery ( long prop , long & val ) const
{
_ComPtr < CtrlT > ctrl ;
if ( FAILED ( videoFileSource - > GetServiceForStream ( ( DWORD ) MF_SOURCE_READER_MEDIASOURCE , GUID_NULL , IID_PPV_ARGS ( & ctrl ) ) ) )
{
CV_LOG_DEBUG ( NULL , " Failed to get service for stream " ) ;
return false ;
}
long paramVal , paramFlag ;
if ( FAILED ( ctrl - > Get ( prop , & paramVal , & paramFlag ) ) )
{
CV_LOG_DEBUG ( NULL , " Failed to get property " < < prop ) ;
// we continue
}
// fallback - get default value
long minVal , maxVal , stepVal ;
if ( FAILED ( ctrl - > GetRange ( prop , & minVal , & maxVal , & stepVal , & paramVal , & paramFlag ) ) )
{
CV_LOG_DEBUG ( NULL , " Failed to get default value for property " < < prop ) ;
return false ;
}
val = paramVal ;
return true ;
}
2018-04-19 23:24:02 +08:00
double CvCapture_MSMF : : getProperty ( int property_id ) const
2013-04-03 09:01:20 +08:00
{
2020-02-07 20:03:20 +08:00
long cVal = 0 ;
2018-06-06 21:00:55 +08:00
if ( isOpen )
2018-04-12 20:26:18 +08:00
switch ( property_id )
{
2018-06-06 21:00:55 +08:00
case CV_CAP_PROP_MODE :
2021-03-01 23:51:04 +08:00
return captureMode ;
case cv : : CAP_PROP_HW_DEVICE :
return hwDeviceIndex ;
case cv : : CAP_PROP_HW_ACCELERATION :
return static_cast < double > ( va_type ) ;
2018-06-06 21:00:55 +08:00
case CV_CAP_PROP_CONVERT_RGB :
return convertFormat ? 1 : 0 ;
case CV_CAP_PROP_SAR_NUM :
2021-10-20 21:18:24 +08:00
return captureVideoFormat . aspectRatioNum ;
2018-06-06 21:00:55 +08:00
case CV_CAP_PROP_SAR_DEN :
2021-10-20 21:18:24 +08:00
return captureVideoFormat . aspectRatioDenom ;
2018-04-12 20:26:18 +08:00
case CV_CAP_PROP_FRAME_WIDTH :
2021-10-20 21:18:24 +08:00
return captureVideoFormat . width ;
2018-04-12 20:26:18 +08:00
case CV_CAP_PROP_FRAME_HEIGHT :
2021-10-20 21:18:24 +08:00
return captureVideoFormat . height ;
2018-04-12 20:26:18 +08:00
case CV_CAP_PROP_FOURCC :
2021-10-20 21:18:24 +08:00
return captureVideoFormat . subType . Data1 ;
2018-04-12 20:26:18 +08:00
case CV_CAP_PROP_FPS :
2021-10-20 21:18:24 +08:00
return captureVideoFormat . getFramerate ( ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_FRAME_COUNT :
if ( duration ! = 0 )
2021-10-20 21:18:24 +08:00
return floor ( ( ( double ) duration / 1e7 ) * captureVideoFormat . getFramerate ( ) + 0.5 ) ;
2018-04-19 23:24:02 +08:00
else
break ;
case CV_CAP_PROP_POS_FRAMES :
2021-10-20 21:18:24 +08:00
return ( double ) nFrame ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_POS_MSEC :
2021-10-20 21:18:24 +08:00
return ( double ) usedVideoSampleTime / 1e4 ;
case CAP_PROP_AUDIO_POS :
return ( double ) audioSamplePos ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_POS_AVI_RATIO :
if ( duration ! = 0 )
2021-10-20 21:18:24 +08:00
return ( double ) usedVideoSampleTime / duration ;
2018-04-19 23:24:02 +08:00
else
break ;
case CV_CAP_PROP_BRIGHTNESS :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMVideoProcAmp > ( VideoProcAmp_Brightness , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_CONTRAST :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMVideoProcAmp > ( VideoProcAmp_Contrast , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_SATURATION :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMVideoProcAmp > ( VideoProcAmp_Saturation , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_HUE :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMVideoProcAmp > ( VideoProcAmp_Hue , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_GAIN :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMVideoProcAmp > ( VideoProcAmp_Gain , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_SHARPNESS :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMVideoProcAmp > ( VideoProcAmp_Sharpness , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_GAMMA :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMVideoProcAmp > ( VideoProcAmp_Gamma , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_BACKLIGHT :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMVideoProcAmp > ( VideoProcAmp_BacklightCompensation , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_MONOCHROME :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMVideoProcAmp > ( VideoProcAmp_ColorEnable , cVal ) )
return cVal = = 0 ? 1 : 0 ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_TEMPERATURE :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMVideoProcAmp > ( VideoProcAmp_WhiteBalance , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_PAN :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMCameraControl > ( CameraControl_Pan , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_TILT :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMCameraControl > ( CameraControl_Tilt , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_ROLL :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMCameraControl > ( CameraControl_Roll , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_IRIS :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMCameraControl > ( CameraControl_Iris , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_EXPOSURE :
case CV_CAP_PROP_AUTO_EXPOSURE :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMCameraControl > ( CameraControl_Exposure , cVal ) )
2018-04-19 23:24:02 +08:00
{
2020-02-07 20:03:20 +08:00
if ( property_id = = CV_CAP_PROP_EXPOSURE )
return cVal ;
else
return cVal = = VideoProcAmp_Flags_Auto ;
2018-04-19 23:24:02 +08:00
}
break ;
case CV_CAP_PROP_ZOOM :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMCameraControl > ( CameraControl_Zoom , cVal ) )
return cVal ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_FOCUS :
case CV_CAP_PROP_AUTOFOCUS :
2020-02-07 20:03:20 +08:00
if ( readComplexPropery < IAMCameraControl > ( CameraControl_Focus , cVal ) )
2018-04-19 23:24:02 +08:00
{
2020-02-07 20:03:20 +08:00
if ( property_id = = CV_CAP_PROP_FOCUS )
return cVal ;
else
return cVal = = VideoProcAmp_Flags_Auto ;
2018-04-19 23:24:02 +08:00
}
break ;
2020-02-07 20:03:20 +08:00
case CV_CAP_PROP_WHITE_BALANCE_BLUE_U :
case CV_CAP_PROP_WHITE_BALANCE_RED_V :
2018-04-19 23:24:02 +08:00
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 :
2021-10-20 21:18:24 +08:00
case CAP_PROP_AUDIO_BASE_INDEX :
return audioBaseIndex ;
case CAP_PROP_AUDIO_TOTAL_STREAMS :
return numberOfAudioStreams ;
case CAP_PROP_AUDIO_TOTAL_CHANNELS :
return captureAudioFormat . nChannels ;
case CAP_PROP_AUDIO_SAMPLES_PER_SECOND :
return captureAudioFormat . nSamplesPerSec ;
case CAP_PROP_AUDIO_DATA_DEPTH :
return outputAudioFormat ;
case CAP_PROP_AUDIO_SHIFT_NSEC :
return ( double ) ( audioStartOffset - videoStartOffset ) * 1e2 ;
2018-04-19 23:24:02 +08:00
default :
break ;
2018-04-12 20:26:18 +08:00
}
return - 1 ;
2013-04-03 09:01:20 +08:00
}
2018-04-19 23:24:02 +08:00
2020-02-07 20:03:20 +08:00
template < typename CtrlT >
bool CvCapture_MSMF : : writeComplexProperty ( long prop , double val , long flags )
{
_ComPtr < CtrlT > ctrl ;
if ( FAILED ( videoFileSource - > GetServiceForStream ( ( DWORD ) MF_SOURCE_READER_MEDIASOURCE , GUID_NULL , IID_PPV_ARGS ( & ctrl ) ) ) )
{
CV_LOG_DEBUG ( NULL , " Failed get service for stream " ) ;
return false ;
}
if ( FAILED ( ctrl - > Set ( prop , ( long ) val , flags ) ) )
{
CV_LOG_DEBUG ( NULL , " Failed to set property " < < prop ) ;
return false ;
}
return true ;
}
2018-04-19 23:24:02 +08:00
bool CvCapture_MSMF : : setProperty ( int property_id , double value )
2013-04-03 09:01:20 +08:00
{
2021-10-20 21:18:24 +08:00
MediaType newFormat = captureVideoFormat ;
2018-06-06 21:00:55 +08:00
if ( isOpen )
2018-04-12 20:26:18 +08:00
switch ( property_id )
2013-04-03 09:01:20 +08:00
{
2018-06-06 21:00:55 +08:00
case CV_CAP_PROP_MODE :
switch ( ( MSMFCapture_Mode ) ( ( int ) value ) )
{
case MODE_SW :
return configureHW ( false ) ;
case MODE_HW :
return configureHW ( true ) ;
default :
return false ;
}
2018-11-13 22:53:35 +08:00
case CV_CAP_PROP_FOURCC :
2021-10-20 21:18:24 +08:00
return configureVideoOutput ( newFormat , ( int ) cvRound ( value ) ) ;
2018-06-06 21:00:55 +08:00
case CV_CAP_PROP_FORMAT :
2021-10-20 21:18:24 +08:00
return configureVideoOutput ( newFormat , ( int ) cvRound ( value ) ) ;
2018-06-06 21:00:55 +08:00
case CV_CAP_PROP_CONVERT_RGB :
2020-04-01 19:40:11 +08:00
convertFormat = ( value ! = 0 ) ;
2021-10-20 21:18:24 +08:00
return configureVideoOutput ( newFormat , outputVideoFormat ) ;
2018-06-06 21:00:55 +08:00
case CV_CAP_PROP_SAR_NUM :
2018-04-19 23:24:02 +08:00
if ( value > 0 )
2020-02-07 20:03:20 +08:00
{
newFormat . aspectRatioNum = ( UINT32 ) cvRound ( value ) ;
2021-10-20 21:18:24 +08:00
return configureVideoOutput ( newFormat , outputVideoFormat ) ;
2020-02-07 20:03:20 +08:00
}
2018-04-12 20:26:18 +08:00
break ;
2018-06-06 21:00:55 +08:00
case CV_CAP_PROP_SAR_DEN :
2018-04-19 23:24:02 +08:00
if ( value > 0 )
2020-02-07 20:03:20 +08:00
{
newFormat . aspectRatioDenom = ( UINT32 ) cvRound ( value ) ;
2021-10-20 21:18:24 +08:00
return configureVideoOutput ( newFormat , outputVideoFormat ) ;
2020-02-07 20:03:20 +08:00
}
2018-06-06 21:00:55 +08:00
break ;
case CV_CAP_PROP_FRAME_WIDTH :
if ( value > = 0 )
2020-02-07 20:03:20 +08:00
{
newFormat . width = ( UINT32 ) cvRound ( value ) ;
2021-10-20 21:18:24 +08:00
return configureVideoOutput ( newFormat , outputVideoFormat ) ;
2020-02-07 20:03:20 +08:00
}
2018-06-06 21:00:55 +08:00
break ;
case CV_CAP_PROP_FRAME_HEIGHT :
if ( value > = 0 )
2020-02-07 20:03:20 +08:00
{
newFormat . height = ( UINT32 ) cvRound ( value ) ;
2021-10-20 21:18:24 +08:00
return configureVideoOutput ( newFormat , outputVideoFormat ) ;
2020-02-07 20:03:20 +08:00
}
2018-04-12 20:26:18 +08:00
break ;
case CV_CAP_PROP_FPS :
2018-04-19 23:24:02 +08:00
if ( value > = 0 )
2020-02-07 20:03:20 +08:00
{
newFormat . setFramerate ( value ) ;
2021-10-20 21:18:24 +08:00
return configureVideoOutput ( newFormat , outputVideoFormat ) ;
2020-02-07 20:03:20 +08:00
}
2018-04-12 20:26:18 +08:00
break ;
2018-04-19 23:24:02 +08:00
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 :
2021-10-20 21:18:24 +08:00
if ( std : : fabs ( captureVideoFormat . getFramerate ( ) ) > 0 )
return setTime ( ( int ) value ) ;
2018-04-19 23:24:02 +08:00
break ;
case CV_CAP_PROP_POS_MSEC :
2018-04-24 21:18:39 +08:00
return setTime ( value * 1e4 , false ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_BRIGHTNESS :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMVideoProcAmp > ( VideoProcAmp_Brightness , value , VideoProcAmp_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_CONTRAST :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMVideoProcAmp > ( VideoProcAmp_Contrast , value , VideoProcAmp_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_SATURATION :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMVideoProcAmp > ( VideoProcAmp_Saturation , value , VideoProcAmp_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_HUE :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMVideoProcAmp > ( VideoProcAmp_Hue , value , VideoProcAmp_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_GAIN :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMVideoProcAmp > ( VideoProcAmp_Gain , value , VideoProcAmp_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_SHARPNESS :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMVideoProcAmp > ( VideoProcAmp_Sharpness , value , VideoProcAmp_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_GAMMA :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMVideoProcAmp > ( VideoProcAmp_Gamma , value , VideoProcAmp_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_BACKLIGHT :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMVideoProcAmp > ( VideoProcAmp_BacklightCompensation , value , VideoProcAmp_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_MONOCHROME :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMVideoProcAmp > ( VideoProcAmp_ColorEnable , value , VideoProcAmp_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_TEMPERATURE :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMVideoProcAmp > ( VideoProcAmp_WhiteBalance , value , VideoProcAmp_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_PAN :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMCameraControl > ( CameraControl_Pan , value , CameraControl_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_TILT :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMCameraControl > ( CameraControl_Tilt , value , CameraControl_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_ROLL :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMCameraControl > ( CameraControl_Roll , value , CameraControl_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_IRIS :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMCameraControl > ( CameraControl_Iris , value , CameraControl_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_EXPOSURE :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMCameraControl > ( CameraControl_Exposure , value , CameraControl_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_AUTO_EXPOSURE :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMCameraControl > ( CameraControl_Exposure , value , value ! = 0 ? VideoProcAmp_Flags_Auto : VideoProcAmp_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_ZOOM :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMCameraControl > ( CameraControl_Zoom , value , CameraControl_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_FOCUS :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMCameraControl > ( CameraControl_Focus , value , CameraControl_Flags_Manual ) ;
2018-04-19 23:24:02 +08:00
case CV_CAP_PROP_AUTOFOCUS :
2020-02-07 20:03:20 +08:00
return writeComplexProperty < IAMCameraControl > ( CameraControl_Focus , value , value ! = 0 ? CameraControl_Flags_Auto : CameraControl_Flags_Manual ) ;
case CV_CAP_PROP_WHITE_BALANCE_BLUE_U :
case CV_CAP_PROP_WHITE_BALANCE_RED_V :
2018-04-19 23:24:02 +08:00
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 ;
2018-03-28 19:03:22 +08:00
}
2018-04-19 23:24:02 +08:00
return false ;
2013-05-23 00:50:54 +08:00
}
2013-05-14 20:17:34 +08:00
2021-03-01 23:51:04 +08:00
cv : : Ptr < cv : : IVideoCapture > cv : : cvCreateCapture_MSMF ( int index , const cv : : VideoCaptureParameters & params )
2013-04-03 09:01:20 +08:00
{
2018-06-30 04:34:14 +08:00
cv : : Ptr < CvCapture_MSMF > capture = cv : : makePtr < CvCapture_MSMF > ( ) ;
if ( capture )
{
2021-03-01 23:51:04 +08:00
capture - > open ( index , & params ) ;
2018-06-30 04:34:14 +08:00
if ( capture - > isOpened ( ) )
return capture ;
}
2018-04-25 23:19:14 +08:00
return cv : : Ptr < cv : : IVideoCapture > ( ) ;
2013-04-03 09:01:20 +08:00
}
2013-05-06 18:36:51 +08:00
2021-03-01 23:51:04 +08:00
cv : : Ptr < cv : : IVideoCapture > cv : : cvCreateCapture_MSMF ( const cv : : String & filename , const cv : : VideoCaptureParameters & params )
2013-05-14 20:17:34 +08:00
{
2018-06-30 04:34:14 +08:00
cv : : Ptr < CvCapture_MSMF > capture = cv : : makePtr < CvCapture_MSMF > ( ) ;
if ( capture )
{
2021-03-01 23:51:04 +08:00
capture - > open ( filename , & params ) ;
2018-06-30 04:34:14 +08:00
if ( capture - > isOpened ( ) )
return capture ;
}
2018-04-25 23:19:14 +08:00
return cv : : Ptr < cv : : IVideoCapture > ( ) ;
2013-05-14 20:17:34 +08:00
}
2013-05-06 18:36:51 +08:00
//
//
// Media Foundation-based Video Writer
//
//
2018-04-25 23:19:14 +08:00
class CvVideoWriter_MSMF : public cv : : IVideoWriter
2013-05-06 18:36:51 +08:00
{
public :
CvVideoWriter_MSMF ( ) ;
virtual ~ CvVideoWriter_MSMF ( ) ;
2018-04-25 23:19:14 +08:00
virtual bool open ( const cv : : String & filename , int fourcc ,
2021-03-01 23:51:04 +08:00
double fps , cv : : Size frameSize , const cv : : VideoWriterParameters & params ) ;
2013-05-06 18:36:51 +08:00
virtual void close ( ) ;
2018-04-25 23:19:14 +08:00
virtual void write ( cv : : InputArray ) ;
2021-03-01 23:51:04 +08:00
virtual double getProperty ( int ) const override ;
2018-04-25 23:19:14 +08:00
virtual bool setProperty ( int , double ) { return false ; }
virtual bool isOpened ( ) const { return initiated ; }
2013-05-06 18:36:51 +08:00
2018-09-16 04:54:03 +08:00
int getCaptureDomain ( ) const CV_OVERRIDE { return cv : : CAP_MSMF ; }
2013-05-06 18:36:51 +08:00
private :
2018-04-05 18:55:42 +08:00
Media_Foundation & MF ;
2021-03-01 23:51:04 +08:00
VideoAccelerationType va_type ;
int va_device ;
2013-05-06 18:36:51 +08:00
UINT32 videoWidth ;
UINT32 videoHeight ;
double fps ;
UINT32 bitRate ;
UINT32 frameSize ;
GUID encodingFormat ;
GUID inputFormat ;
DWORD streamIndex ;
Add support for WinRT in the MF capture framework by removing the disallowed calls to enumerate devices and create a sample grabber sink and adding framework for the MediaCapture interface and a custom sink which interfaces with the sample grabber callback interface. The change requires discussion for making it completely functional as redundancy is required given that if the source is a video file, the old code pathways must be used. Otherwise all IMFMediaSession, IMFMediaSource, and IMFActivate code must use a MediaCapture code path and all sink code must use the CMediaSink custom sink.
Support for the custom sink is extended to non-WinRT not for compatibility as Windows Vista client is a minimum regardless, but because it offers more flexibility, could be faster and is able to be used as an optionally different code path during sink creation based on a future configuration parameter.
My discussion and proposal to finish this change:
Devices are so easily enumerated through WinRT Windows.Devices namespace that wrapping the calls in a library is quite a chore for little benefit though to get the various modes and formats could still be a worthwhile project. For now conditional compilation to remove videodevices and any offending non-video file related activity in videodevice. In my opinion, this is a different , far less fundamental and important change which can possibly be done as a future project and also much more easily implemented in C++/CX.
ImageGrabber has the IMFSampleGrabberSinkCallback replaced with a base class (SharedSampleGrabber) which also be is base class for ImageGrabberRT. This change is necessary as the custom sink does not require a thread to pump events which is done through MediaCapture already. IMFSampleGrabberSinkCallback is the common element between both models and that piece can be shared. Initializing the new ImageGrabberRT is as simple as passing an already initialized MediaCapture object and any video format/encoding parameters.
The concurrency event is necessary to wait for completion and is the way the underlying, IAsyncAction wrappers in the task library work as well. Native WIN32 event objects would be an option if HAVE_CONCURRENCY is not defined. I could even imagine doing it with sleep/thread yield and InterlockedCompareExchange yet I am not enthusiastic about that approach either. Since there is a specific compiler HAVE_ for concurrency, I do not like pulling it in though I think for WinRT it is safe to say we will always have it available though should probably conditionally compile with the Interlocked option as WIN32 events would require HAVE_WIN32.
It looks like C++/CX cannot be used for the IMediaExtension sink (which should not be a problem) as using COM objects requires WRL and though deriving from IMediaExtension can be done, there is little purpose without COM. Objects from C++/CX can be swapped to interact with objects from native C++ as Inspectable* can reinterpret_cast to the ref object IInspectable^ and vice-versa. A solution to the COM class with C++/CX would be great so we could have dual support. Also without #define for every WRL object in use, the code will get quite muddy given that the */^ would need to be ifdef'd everywhere.
Fixed bugs and completed the change. I believe the new classes need to be moved to a header file as the file has become to large and more classes need to be added for handling all the asynchronous problems (one wrapping IAsyncAction in a task and another for making a task out of IAsyncAction). Unfortunately, blocking on the UI thread is not an option in WinRT so a synchronous architecture is considered "illegal" by Microsoft's standards even if implementable (C++/CX ppltasks library throws errors if you try it). Worse, either by design or a bug in the MF MediaCapture class with Custom Sinks causes a crash if stop/start previewing without reinitializing (spPreferredPreviewMediaType is fatally nulled). After decompiling Windows.Media.dll, I worked around this in my own projects by using an activate-able custom sink ID which strangely assigns 1 to this pointer allowing it to be reinitialized in what can only be described as a hack by Microsoft. This would add additional overhead to the project to implement especially for static libraries as it requires IDL/DLL exporting followed by manifest declaration. Better to document that it is not supported.
Furthermore, an additional class for IMFAttributes should be implemented to make clean architecture for passing around attributes as opposed to directly calling non-COM interface calls on the objects and making use of SetProperties which would also be a set up for an object that uses the RuntimeClass activation ID.
The remaining changes are not difficult and will be complete soon along with debug tracing messages.
Update and rename cap_msmf.h to cap_msmf.hpp
Successful test - samples are grabbed
Library updated and cleaned up with comments, marshaling, exceptions and linker settings
Fixed trailing whitespace
VS 2013 support and cleanup consistency plus C++/CX new object fixed
Conflicts:
modules/highgui/src/cap_msmf.cpp
modules/highgui/src/cap_msmf.hpp
modules/highgui/src/ppltasks_winrt.h
Fix merge conflicts
VS 2013 Update 2 library bug fix integrated
a-wi's changed integrated
2013-12-14 16:53:30 +08:00
_ComPtr < IMFSinkWriter > sinkWriter ;
2013-05-06 18:36:51 +08:00
bool initiated ;
LONGLONG rtStart ;
UINT64 rtDuration ;
2013-05-06 22:17:53 +08:00
static const GUID FourCC2GUID ( int fourcc ) ;
2013-05-06 18:36:51 +08:00
} ;
2013-05-22 19:21:23 +08:00
CvVideoWriter_MSMF : : CvVideoWriter_MSMF ( ) :
2018-04-05 18:55:42 +08:00
MF ( Media_Foundation : : getInstance ( ) ) ,
2021-03-01 23:51:04 +08:00
va_type ( VIDEO_ACCELERATION_NONE ) ,
va_device ( - 1 ) ,
2018-07-27 23:25:55 +08:00
videoWidth ( 0 ) ,
videoHeight ( 0 ) ,
fps ( 0 ) ,
bitRate ( 0 ) ,
frameSize ( 0 ) ,
encodingFormat ( ) ,
inputFormat ( ) ,
streamIndex ( 0 ) ,
initiated ( false ) ,
rtStart ( 0 ) ,
rtDuration ( 0 )
2013-05-06 18:36:51 +08:00
{
}
CvVideoWriter_MSMF : : ~ CvVideoWriter_MSMF ( )
{
close ( ) ;
}
2013-05-06 22:17:53 +08:00
const GUID CvVideoWriter_MSMF : : FourCC2GUID ( int fourcc )
{
switch ( fourcc )
{
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' d ' , ' v ' , ' 2 ' , ' 5 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_DV25 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' d ' , ' v ' , ' 5 ' , ' 0 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_DV50 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' d ' , ' v ' , ' c ' , ' ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_DVC ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' d ' , ' v ' , ' h ' , ' 1 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_DVH1 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' d ' , ' v ' , ' h ' , ' d ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_DVHD ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' d ' , ' v ' , ' s ' , ' d ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_DVSD ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' d ' , ' v ' , ' s ' , ' l ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_DVSL ; break ;
2014-09-25 17:42:07 +08:00
# if (WINVER >= 0x0602)
Add support for WinRT in the MF capture framework by removing the disallowed calls to enumerate devices and create a sample grabber sink and adding framework for the MediaCapture interface and a custom sink which interfaces with the sample grabber callback interface. The change requires discussion for making it completely functional as redundancy is required given that if the source is a video file, the old code pathways must be used. Otherwise all IMFMediaSession, IMFMediaSource, and IMFActivate code must use a MediaCapture code path and all sink code must use the CMediaSink custom sink.
Support for the custom sink is extended to non-WinRT not for compatibility as Windows Vista client is a minimum regardless, but because it offers more flexibility, could be faster and is able to be used as an optionally different code path during sink creation based on a future configuration parameter.
My discussion and proposal to finish this change:
Devices are so easily enumerated through WinRT Windows.Devices namespace that wrapping the calls in a library is quite a chore for little benefit though to get the various modes and formats could still be a worthwhile project. For now conditional compilation to remove videodevices and any offending non-video file related activity in videodevice. In my opinion, this is a different , far less fundamental and important change which can possibly be done as a future project and also much more easily implemented in C++/CX.
ImageGrabber has the IMFSampleGrabberSinkCallback replaced with a base class (SharedSampleGrabber) which also be is base class for ImageGrabberRT. This change is necessary as the custom sink does not require a thread to pump events which is done through MediaCapture already. IMFSampleGrabberSinkCallback is the common element between both models and that piece can be shared. Initializing the new ImageGrabberRT is as simple as passing an already initialized MediaCapture object and any video format/encoding parameters.
The concurrency event is necessary to wait for completion and is the way the underlying, IAsyncAction wrappers in the task library work as well. Native WIN32 event objects would be an option if HAVE_CONCURRENCY is not defined. I could even imagine doing it with sleep/thread yield and InterlockedCompareExchange yet I am not enthusiastic about that approach either. Since there is a specific compiler HAVE_ for concurrency, I do not like pulling it in though I think for WinRT it is safe to say we will always have it available though should probably conditionally compile with the Interlocked option as WIN32 events would require HAVE_WIN32.
It looks like C++/CX cannot be used for the IMediaExtension sink (which should not be a problem) as using COM objects requires WRL and though deriving from IMediaExtension can be done, there is little purpose without COM. Objects from C++/CX can be swapped to interact with objects from native C++ as Inspectable* can reinterpret_cast to the ref object IInspectable^ and vice-versa. A solution to the COM class with C++/CX would be great so we could have dual support. Also without #define for every WRL object in use, the code will get quite muddy given that the */^ would need to be ifdef'd everywhere.
Fixed bugs and completed the change. I believe the new classes need to be moved to a header file as the file has become to large and more classes need to be added for handling all the asynchronous problems (one wrapping IAsyncAction in a task and another for making a task out of IAsyncAction). Unfortunately, blocking on the UI thread is not an option in WinRT so a synchronous architecture is considered "illegal" by Microsoft's standards even if implementable (C++/CX ppltasks library throws errors if you try it). Worse, either by design or a bug in the MF MediaCapture class with Custom Sinks causes a crash if stop/start previewing without reinitializing (spPreferredPreviewMediaType is fatally nulled). After decompiling Windows.Media.dll, I worked around this in my own projects by using an activate-able custom sink ID which strangely assigns 1 to this pointer allowing it to be reinitialized in what can only be described as a hack by Microsoft. This would add additional overhead to the project to implement especially for static libraries as it requires IDL/DLL exporting followed by manifest declaration. Better to document that it is not supported.
Furthermore, an additional class for IMFAttributes should be implemented to make clean architecture for passing around attributes as opposed to directly calling non-COM interface calls on the objects and making use of SetProperties which would also be a set up for an object that uses the RuntimeClass activation ID.
The remaining changes are not difficult and will be complete soon along with debug tracing messages.
Update and rename cap_msmf.h to cap_msmf.hpp
Successful test - samples are grabbed
Library updated and cleaned up with comments, marshaling, exceptions and linker settings
Fixed trailing whitespace
VS 2013 support and cleanup consistency plus C++/CX new object fixed
Conflicts:
modules/highgui/src/cap_msmf.cpp
modules/highgui/src/cap_msmf.hpp
modules/highgui/src/ppltasks_winrt.h
Fix merge conflicts
VS 2013 Update 2 library bug fix integrated
a-wi's changed integrated
2013-12-14 16:53:30 +08:00
case CV_FOURCC_MACRO ( ' H ' , ' 2 ' , ' 6 ' , ' 3 ' ) : // Available only for Win 8 target.
2013-05-06 22:17:53 +08:00
return MFVideoFormat_H263 ; break ;
Add support for WinRT in the MF capture framework by removing the disallowed calls to enumerate devices and create a sample grabber sink and adding framework for the MediaCapture interface and a custom sink which interfaces with the sample grabber callback interface. The change requires discussion for making it completely functional as redundancy is required given that if the source is a video file, the old code pathways must be used. Otherwise all IMFMediaSession, IMFMediaSource, and IMFActivate code must use a MediaCapture code path and all sink code must use the CMediaSink custom sink.
Support for the custom sink is extended to non-WinRT not for compatibility as Windows Vista client is a minimum regardless, but because it offers more flexibility, could be faster and is able to be used as an optionally different code path during sink creation based on a future configuration parameter.
My discussion and proposal to finish this change:
Devices are so easily enumerated through WinRT Windows.Devices namespace that wrapping the calls in a library is quite a chore for little benefit though to get the various modes and formats could still be a worthwhile project. For now conditional compilation to remove videodevices and any offending non-video file related activity in videodevice. In my opinion, this is a different , far less fundamental and important change which can possibly be done as a future project and also much more easily implemented in C++/CX.
ImageGrabber has the IMFSampleGrabberSinkCallback replaced with a base class (SharedSampleGrabber) which also be is base class for ImageGrabberRT. This change is necessary as the custom sink does not require a thread to pump events which is done through MediaCapture already. IMFSampleGrabberSinkCallback is the common element between both models and that piece can be shared. Initializing the new ImageGrabberRT is as simple as passing an already initialized MediaCapture object and any video format/encoding parameters.
The concurrency event is necessary to wait for completion and is the way the underlying, IAsyncAction wrappers in the task library work as well. Native WIN32 event objects would be an option if HAVE_CONCURRENCY is not defined. I could even imagine doing it with sleep/thread yield and InterlockedCompareExchange yet I am not enthusiastic about that approach either. Since there is a specific compiler HAVE_ for concurrency, I do not like pulling it in though I think for WinRT it is safe to say we will always have it available though should probably conditionally compile with the Interlocked option as WIN32 events would require HAVE_WIN32.
It looks like C++/CX cannot be used for the IMediaExtension sink (which should not be a problem) as using COM objects requires WRL and though deriving from IMediaExtension can be done, there is little purpose without COM. Objects from C++/CX can be swapped to interact with objects from native C++ as Inspectable* can reinterpret_cast to the ref object IInspectable^ and vice-versa. A solution to the COM class with C++/CX would be great so we could have dual support. Also without #define for every WRL object in use, the code will get quite muddy given that the */^ would need to be ifdef'd everywhere.
Fixed bugs and completed the change. I believe the new classes need to be moved to a header file as the file has become to large and more classes need to be added for handling all the asynchronous problems (one wrapping IAsyncAction in a task and another for making a task out of IAsyncAction). Unfortunately, blocking on the UI thread is not an option in WinRT so a synchronous architecture is considered "illegal" by Microsoft's standards even if implementable (C++/CX ppltasks library throws errors if you try it). Worse, either by design or a bug in the MF MediaCapture class with Custom Sinks causes a crash if stop/start previewing without reinitializing (spPreferredPreviewMediaType is fatally nulled). After decompiling Windows.Media.dll, I worked around this in my own projects by using an activate-able custom sink ID which strangely assigns 1 to this pointer allowing it to be reinitialized in what can only be described as a hack by Microsoft. This would add additional overhead to the project to implement especially for static libraries as it requires IDL/DLL exporting followed by manifest declaration. Better to document that it is not supported.
Furthermore, an additional class for IMFAttributes should be implemented to make clean architecture for passing around attributes as opposed to directly calling non-COM interface calls on the objects and making use of SetProperties which would also be a set up for an object that uses the RuntimeClass activation ID.
The remaining changes are not difficult and will be complete soon along with debug tracing messages.
Update and rename cap_msmf.h to cap_msmf.hpp
Successful test - samples are grabbed
Library updated and cleaned up with comments, marshaling, exceptions and linker settings
Fixed trailing whitespace
VS 2013 support and cleanup consistency plus C++/CX new object fixed
Conflicts:
modules/highgui/src/cap_msmf.cpp
modules/highgui/src/cap_msmf.hpp
modules/highgui/src/ppltasks_winrt.h
Fix merge conflicts
VS 2013 Update 2 library bug fix integrated
a-wi's changed integrated
2013-12-14 16:53:30 +08:00
# endif
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' H ' , ' 2 ' , ' 6 ' , ' 4 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_H264 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' M ' , ' 4 ' , ' S ' , ' 2 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_M4S2 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' M ' , ' J ' , ' P ' , ' G ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_MJPG ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' M ' , ' P ' , ' 4 ' , ' 3 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_MP43 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' M ' , ' P ' , ' 4 ' , ' S ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_MP4S ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' M ' , ' P ' , ' 4 ' , ' V ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_MP4V ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' M ' , ' P ' , ' G ' , ' 1 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_MPG1 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' M ' , ' S ' , ' S ' , ' 1 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_MSS1 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' M ' , ' S ' , ' S ' , ' 2 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_MSS2 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' W ' , ' M ' , ' V ' , ' 1 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_WMV1 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' W ' , ' M ' , ' V ' , ' 2 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_WMV2 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' W ' , ' M ' , ' V ' , ' 3 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_WMV3 ; break ;
2013-05-22 19:21:23 +08:00
case CV_FOURCC_MACRO ( ' W ' , ' V ' , ' C ' , ' 1 ' ) :
2013-05-06 22:17:53 +08:00
return MFVideoFormat_WVC1 ; break ;
default :
return MFVideoFormat_H264 ;
}
}
2018-04-25 23:19:14 +08:00
bool CvVideoWriter_MSMF : : open ( const cv : : String & filename , int fourcc ,
2021-03-01 23:51:04 +08:00
double _fps , cv : : Size _frameSize , const cv : : VideoWriterParameters & params )
2013-05-06 18:36:51 +08:00
{
2018-04-05 18:55:42 +08:00
if ( initiated )
close ( ) ;
2021-03-01 23:51:04 +08:00
if ( params . has ( VIDEOWRITER_PROP_HW_ACCELERATION ) )
{
va_type = params . get < VideoAccelerationType > ( VIDEOWRITER_PROP_HW_ACCELERATION ) ;
if ( va_type ! = VIDEO_ACCELERATION_NONE & & va_type ! = VIDEO_ACCELERATION_ANY )
{
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: MSMF backend doesn't support writer acceleration support. Can't handle VIDEOWRITER_PROP_HW_ACCELERATION parameter. Bailout " ) ;
return false ;
}
}
if ( params . has ( VIDEOWRITER_PROP_HW_DEVICE ) )
{
va_device = params . get < int > ( VIDEOWRITER_PROP_HW_DEVICE ) ;
if ( va_type = = VIDEO_ACCELERATION_NONE & & va_device ! = - 1 )
{
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: Invalid usage of VIDEOWRITER_PROP_HW_DEVICE without requested H/W acceleration. Bailout " ) ;
return false ;
}
if ( va_type = = VIDEO_ACCELERATION_ANY & & va_device ! = - 1 )
{
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: Invalid usage of VIDEOWRITER_PROP_HW_DEVICE with 'ANY' H/W acceleration. Bailout " ) ;
return false ;
}
if ( va_device ! = - 1 )
{
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: VIDEOWRITER_PROP_HW_DEVICE is not supported. Specify -1 (auto) value. Bailout " ) ;
return false ;
}
}
2018-04-05 18:55:42 +08:00
videoWidth = _frameSize . width ;
videoHeight = _frameSize . height ;
2013-05-06 18:36:51 +08:00
fps = _fps ;
2013-05-23 00:50:54 +08:00
bitRate = ( UINT32 ) fps * videoWidth * videoHeight ; // 1-bit per pixel
2013-05-06 22:17:53 +08:00
encodingFormat = FourCC2GUID ( fourcc ) ;
2013-05-06 18:36:51 +08:00
inputFormat = MFVideoFormat_RGB32 ;
2018-04-05 18:55:42 +08:00
_ComPtr < IMFMediaType > mediaTypeOut ;
_ComPtr < IMFMediaType > mediaTypeIn ;
_ComPtr < IMFAttributes > spAttr ;
if ( // Set the output media type.
SUCCEEDED ( MFCreateMediaType ( & mediaTypeOut ) ) & &
SUCCEEDED ( mediaTypeOut - > SetGUID ( MF_MT_MAJOR_TYPE , MFMediaType_Video ) ) & &
SUCCEEDED ( mediaTypeOut - > SetGUID ( MF_MT_SUBTYPE , encodingFormat ) ) & &
SUCCEEDED ( mediaTypeOut - > SetUINT32 ( MF_MT_AVG_BITRATE , bitRate ) ) & &
SUCCEEDED ( mediaTypeOut - > SetUINT32 ( MF_MT_INTERLACE_MODE , MFVideoInterlace_Progressive ) ) & &
SUCCEEDED ( MFSetAttributeSize ( mediaTypeOut . Get ( ) , MF_MT_FRAME_SIZE , videoWidth , videoHeight ) ) & &
2020-04-02 17:49:46 +08:00
SUCCEEDED ( MFSetAttributeRatio ( mediaTypeOut . Get ( ) , MF_MT_FRAME_RATE , ( UINT32 ) ( fps * 1000 ) , 1000 ) ) & &
2018-04-05 18:55:42 +08:00
SUCCEEDED ( MFSetAttributeRatio ( mediaTypeOut . Get ( ) , MF_MT_PIXEL_ASPECT_RATIO , 1 , 1 ) ) & &
// Set the input media type.
SUCCEEDED ( MFCreateMediaType ( & mediaTypeIn ) ) & &
SUCCEEDED ( mediaTypeIn - > SetGUID ( MF_MT_MAJOR_TYPE , MFMediaType_Video ) ) & &
SUCCEEDED ( mediaTypeIn - > SetGUID ( MF_MT_SUBTYPE , inputFormat ) ) & &
SUCCEEDED ( mediaTypeIn - > SetUINT32 ( MF_MT_INTERLACE_MODE , MFVideoInterlace_Progressive ) ) & &
SUCCEEDED ( mediaTypeIn - > SetUINT32 ( MF_MT_DEFAULT_STRIDE , 4 * videoWidth ) ) & & //Assume BGR32 input
SUCCEEDED ( MFSetAttributeSize ( mediaTypeIn . Get ( ) , MF_MT_FRAME_SIZE , videoWidth , videoHeight ) ) & &
2020-04-02 17:49:46 +08:00
SUCCEEDED ( MFSetAttributeRatio ( mediaTypeIn . Get ( ) , MF_MT_FRAME_RATE , ( UINT32 ) ( fps * 1000 ) , 1000 ) ) & &
2018-04-05 18:55:42 +08:00
SUCCEEDED ( MFSetAttributeRatio ( mediaTypeIn . Get ( ) , MF_MT_PIXEL_ASPECT_RATIO , 1 , 1 ) ) & &
// Set sink writer parameters
SUCCEEDED ( MFCreateAttributes ( & spAttr , 10 ) ) & &
SUCCEEDED ( spAttr - > SetUINT32 ( MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS , true ) ) & &
SUCCEEDED ( spAttr - > SetUINT32 ( MF_SINK_WRITER_DISABLE_THROTTLING , true ) )
)
{
// Create the sink writer
2018-04-25 23:19:14 +08:00
cv : : AutoBuffer < wchar_t > unicodeFileName ( filename . length ( ) + 1 ) ;
2018-06-11 06:42:00 +08:00
MultiByteToWideChar ( CP_ACP , 0 , filename . c_str ( ) , - 1 , unicodeFileName . data ( ) , ( int ) filename . length ( ) + 1 ) ;
HRESULT hr = MFCreateSinkWriterFromURL ( unicodeFileName . data ( ) , NULL , spAttr . Get ( ) , & sinkWriter ) ;
2013-05-06 18:36:51 +08:00
if ( SUCCEEDED ( hr ) )
{
2018-04-05 18:55:42 +08:00
// Configure the sink writer and tell it start to start accepting data
if ( SUCCEEDED ( sinkWriter - > AddStream ( mediaTypeOut . Get ( ) , & streamIndex ) ) & &
SUCCEEDED ( sinkWriter - > SetInputMediaType ( streamIndex , mediaTypeIn . Get ( ) , NULL ) ) & &
SUCCEEDED ( sinkWriter - > BeginWriting ( ) ) )
2013-05-06 18:36:51 +08:00
{
initiated = true ;
rtStart = 0 ;
2020-04-02 17:49:46 +08:00
MFFrameRateToAverageTimePerFrame ( ( UINT32 ) ( fps * 1000 ) , 1000 , & rtDuration ) ;
2021-03-01 23:51:04 +08:00
VideoAccelerationType actual_va_type = VIDEO_ACCELERATION_NONE ;
if ( va_type ! = VIDEO_ACCELERATION_NONE & & va_type ! = VIDEO_ACCELERATION_ANY )
{
if ( va_type ! = actual_va_type )
{
CV_LOG_ERROR ( NULL , " VIDEOIO/MSMF: Can't select requested video acceleration through VIDEOWRITER_PROP_HW_ACCELERATION: "
< < va_type < < " (actual is " < < actual_va_type < < " ). Bailout " ) ;
close ( ) ;
return false ;
}
}
else
{
va_type = actual_va_type ;
}
2018-04-05 18:55:42 +08:00
return true ;
2013-05-06 18:36:51 +08:00
}
}
}
2018-04-05 18:55:42 +08:00
return false ;
2013-05-06 18:36:51 +08:00
}
void CvVideoWriter_MSMF : : close ( )
{
2018-04-05 18:55:42 +08:00
if ( initiated )
2013-05-06 18:36:51 +08:00
{
2018-04-05 18:55:42 +08:00
initiated = false ;
sinkWriter - > Finalize ( ) ;
2018-06-10 20:32:09 +08:00
sinkWriter . Release ( ) ;
2013-05-06 18:36:51 +08:00
}
}
2018-04-25 23:19:14 +08:00
void CvVideoWriter_MSMF : : write ( cv : : InputArray img )
2013-05-06 18:36:51 +08:00
{
2018-04-25 23:19:14 +08:00
if ( img . empty ( ) | |
( img . channels ( ) ! = 1 & & img . channels ( ) ! = 3 & & img . channels ( ) ! = 4 ) | |
( UINT32 ) img . cols ( ) ! = videoWidth | | ( UINT32 ) img . rows ( ) ! = videoHeight )
return ;
2013-05-06 18:36:51 +08:00
const LONG cbWidth = 4 * videoWidth ;
const DWORD cbBuffer = cbWidth * videoHeight ;
2018-04-05 18:55:42 +08:00
_ComPtr < IMFSample > sample ;
_ComPtr < IMFMediaBuffer > buffer ;
2013-05-06 18:36:51 +08:00
BYTE * pData = NULL ;
2018-04-05 18:55:42 +08:00
// Prepare a media sample.
if ( SUCCEEDED ( MFCreateSample ( & sample ) ) & &
// Set sample time stamp and duration.
SUCCEEDED ( sample - > SetSampleTime ( rtStart ) ) & &
SUCCEEDED ( sample - > SetSampleDuration ( rtDuration ) ) & &
// Create a memory buffer.
SUCCEEDED ( MFCreateMemoryBuffer ( cbBuffer , & buffer ) ) & &
// Set the data length of the buffer.
SUCCEEDED ( buffer - > SetCurrentLength ( cbBuffer ) ) & &
// Add the buffer to the sample.
SUCCEEDED ( sample - > AddBuffer ( buffer . Get ( ) ) ) & &
// Lock the buffer.
SUCCEEDED ( buffer - > Lock ( & pData , NULL , NULL ) ) )
{
// Copy the video frame to the buffer.
2018-04-25 23:19:14 +08:00
cv : : cvtColor ( img . getMat ( ) , cv : : Mat ( videoHeight , videoWidth , CV_8UC4 , pData , cbWidth ) , img . channels ( ) > 1 ? cv : : COLOR_BGR2BGRA : cv : : COLOR_GRAY2BGRA ) ;
2013-05-06 18:36:51 +08:00
buffer - > Unlock ( ) ;
2018-04-05 18:55:42 +08:00
// Send media sample to the Sink Writer.
if ( SUCCEEDED ( sinkWriter - > WriteSample ( streamIndex , sample . Get ( ) ) ) )
{
rtStart + = rtDuration ;
}
2013-05-06 18:36:51 +08:00
}
}
2021-03-01 23:51:04 +08:00
double CvVideoWriter_MSMF : : getProperty ( int propId ) const
{
if ( propId = = VIDEOWRITER_PROP_HW_ACCELERATION )
{
return static_cast < double > ( va_type ) ;
}
else if ( propId = = VIDEOWRITER_PROP_HW_DEVICE )
{
return static_cast < double > ( va_device ) ;
}
return 0 ;
}
2019-01-14 18:33:38 +08:00
cv : : Ptr < cv : : IVideoWriter > cv : : cvCreateVideoWriter_MSMF ( const std : : string & filename , int fourcc ,
2020-04-28 16:38:39 +08:00
double fps , const cv : : Size & frameSize ,
const VideoWriterParameters & params )
2013-05-06 18:36:51 +08:00
{
2018-06-30 04:34:14 +08:00
cv : : Ptr < CvVideoWriter_MSMF > writer = cv : : makePtr < CvVideoWriter_MSMF > ( ) ;
if ( writer )
{
2021-03-01 23:51:04 +08:00
writer - > open ( filename , fourcc , fps , frameSize , params ) ;
2018-06-30 04:34:14 +08:00
if ( writer - > isOpened ( ) )
return writer ;
}
2018-04-25 23:19:14 +08:00
return cv : : Ptr < cv : : IVideoWriter > ( ) ;
2013-05-06 18:36:51 +08:00
}
2020-04-08 01:25:10 +08:00
# if defined(BUILD_PLUGIN)
2021-03-01 23:51:04 +08:00
# define NEW_PLUGIN
# ifndef NEW_PLUGIN
2020-12-04 11:18:16 +08:00
# define ABI_VERSION 0
# define API_VERSION 0
2020-04-08 01:25:10 +08:00
# include "plugin_api.hpp"
2021-03-01 23:51:04 +08:00
# else
# define CAPTURE_ABI_VERSION 1
# define CAPTURE_API_VERSION 1
# include "plugin_capture_api.hpp"
# define WRITER_ABI_VERSION 1
# define WRITER_API_VERSION 1
# include "plugin_writer_api.hpp"
# endif
2020-04-08 01:25:10 +08:00
namespace cv {
typedef CvCapture_MSMF CaptureT ;
typedef CvVideoWriter_MSMF WriterT ;
static
2021-03-01 23:51:04 +08:00
CvResult CV_API_CALL cv_capture_open_with_params (
const char * filename , int camera_index ,
int * params , unsigned n_params ,
CV_OUT CvPluginCapture * handle
)
2020-04-08 01:25:10 +08:00
{
if ( ! handle )
return CV_ERROR_FAIL ;
* handle = NULL ;
if ( ! filename )
return CV_ERROR_FAIL ;
CaptureT * cap = 0 ;
try
{
2021-03-01 23:51:04 +08:00
cv : : VideoCaptureParameters parameters ( params , n_params ) ;
2020-04-08 01:25:10 +08:00
cap = new CaptureT ( ) ;
bool res ;
if ( filename )
2021-03-01 23:51:04 +08:00
res = cap - > open ( std : : string ( filename ) , & parameters ) ;
2020-04-08 01:25:10 +08:00
else
2021-03-01 23:51:04 +08:00
res = cap - > open ( camera_index , & parameters ) ;
2020-04-08 01:25:10 +08:00
if ( res )
{
* handle = ( CvPluginCapture ) cap ;
return CV_ERROR_OK ;
}
}
2021-02-25 01:45:19 +08:00
catch ( const std : : exception & e )
{
CV_LOG_WARNING ( NULL , " MSMF: Exception is raised: " < < e . what ( ) ) ;
}
2020-04-08 01:25:10 +08:00
catch ( . . . )
{
2021-02-25 01:45:19 +08:00
CV_LOG_WARNING ( NULL , " MSMF: Unknown C++ exception is raised " ) ;
2020-04-08 01:25:10 +08:00
}
if ( cap )
delete cap ;
return CV_ERROR_FAIL ;
}
2021-03-01 23:51:04 +08:00
static
CvResult CV_API_CALL cv_capture_open ( const char * filename , int camera_index , CV_OUT CvPluginCapture * handle )
{
return cv_capture_open_with_params ( filename , camera_index , NULL , 0 , handle ) ;
}
2020-04-08 01:25:10 +08:00
static
CvResult CV_API_CALL cv_capture_release ( CvPluginCapture handle )
{
if ( ! handle )
return CV_ERROR_FAIL ;
CaptureT * instance = ( CaptureT * ) handle ;
delete instance ;
return CV_ERROR_OK ;
}
static
CvResult CV_API_CALL cv_capture_get_prop ( CvPluginCapture handle , int prop , CV_OUT double * val )
{
if ( ! handle )
return CV_ERROR_FAIL ;
if ( ! val )
return CV_ERROR_FAIL ;
try
{
CaptureT * instance = ( CaptureT * ) handle ;
* val = instance - > getProperty ( prop ) ;
return CV_ERROR_OK ;
}
2021-02-25 01:45:19 +08:00
catch ( const std : : exception & e )
{
CV_LOG_WARNING ( NULL , " MSMF: Exception is raised: " < < e . what ( ) ) ;
return CV_ERROR_FAIL ;
}
2020-04-08 01:25:10 +08:00
catch ( . . . )
{
2021-02-25 01:45:19 +08:00
CV_LOG_WARNING ( NULL , " MSMF: Unknown C++ exception is raised " ) ;
2020-04-08 01:25:10 +08:00
return CV_ERROR_FAIL ;
}
}
static
CvResult CV_API_CALL cv_capture_set_prop ( CvPluginCapture handle , int prop , double val )
{
if ( ! handle )
return CV_ERROR_FAIL ;
try
{
CaptureT * instance = ( CaptureT * ) handle ;
return instance - > setProperty ( prop , val ) ? CV_ERROR_OK : CV_ERROR_FAIL ;
}
2021-02-25 01:45:19 +08:00
catch ( const std : : exception & e )
{
CV_LOG_WARNING ( NULL , " MSMF: Exception is raised: " < < e . what ( ) ) ;
return CV_ERROR_FAIL ;
}
2020-04-08 01:25:10 +08:00
catch ( . . . )
{
2021-02-25 01:45:19 +08:00
CV_LOG_WARNING ( NULL , " MSMF: Unknown C++ exception is raised " ) ;
2020-04-08 01:25:10 +08:00
return CV_ERROR_FAIL ;
}
}
static
CvResult CV_API_CALL cv_capture_grab ( CvPluginCapture handle )
{
if ( ! handle )
return CV_ERROR_FAIL ;
try
{
CaptureT * instance = ( CaptureT * ) handle ;
return instance - > grabFrame ( ) ? CV_ERROR_OK : CV_ERROR_FAIL ;
}
2021-02-25 01:45:19 +08:00
catch ( const std : : exception & e )
{
CV_LOG_WARNING ( NULL , " MSMF: Exception is raised: " < < e . what ( ) ) ;
return CV_ERROR_FAIL ;
}
2020-04-08 01:25:10 +08:00
catch ( . . . )
{
2021-02-25 01:45:19 +08:00
CV_LOG_WARNING ( NULL , " MSMF: Unknown C++ exception is raised " ) ;
2020-04-08 01:25:10 +08:00
return CV_ERROR_FAIL ;
}
}
static
2021-03-01 23:51:04 +08:00
CvResult CV_API_CALL cv_capture_retrieve ( CvPluginCapture handle , int stream_idx , cv_videoio_capture_retrieve_cb_t callback , void * userdata )
2020-04-08 01:25:10 +08:00
{
if ( ! handle )
return CV_ERROR_FAIL ;
try
{
CaptureT * instance = ( CaptureT * ) handle ;
Mat img ;
if ( instance - > retrieveFrame ( stream_idx , img ) )
2021-03-01 23:51:04 +08:00
# ifndef NEW_PLUGIN
2020-04-08 01:25:10 +08:00
return callback ( stream_idx , img . data , ( int ) img . step , img . cols , img . rows , img . channels ( ) , userdata ) ;
2021-03-01 23:51:04 +08:00
# else
return callback ( stream_idx , img . data , ( int ) img . step , img . cols , img . rows , img . type ( ) , userdata ) ;
# endif
2020-04-08 01:25:10 +08:00
return CV_ERROR_FAIL ;
}
2021-02-25 01:45:19 +08:00
catch ( const std : : exception & e )
{
CV_LOG_WARNING ( NULL , " MSMF: Exception is raised: " < < e . what ( ) ) ;
return CV_ERROR_FAIL ;
}
2020-04-08 01:25:10 +08:00
catch ( . . . )
{
2021-02-25 01:45:19 +08:00
CV_LOG_WARNING ( NULL , " MSMF: Unknown C++ exception is raised " ) ;
2020-04-08 01:25:10 +08:00
return CV_ERROR_FAIL ;
}
}
static
2021-03-01 23:51:04 +08:00
CvResult CV_API_CALL cv_writer_open_with_params (
const char * filename , int fourcc , double fps , int width , int height ,
int * params , unsigned n_params ,
CV_OUT CvPluginWriter * handle )
2020-04-08 01:25:10 +08:00
{
WriterT * wrt = 0 ;
try
{
2021-03-01 23:51:04 +08:00
VideoWriterParameters parameters ( params , n_params ) ;
2020-04-08 01:25:10 +08:00
wrt = new WriterT ( ) ;
Size sz ( width , height ) ;
2021-03-01 23:51:04 +08:00
if ( wrt & & wrt - > open ( filename , fourcc , fps , sz , parameters ) )
2020-04-08 01:25:10 +08:00
{
* handle = ( CvPluginWriter ) wrt ;
return CV_ERROR_OK ;
}
}
2021-02-25 01:45:19 +08:00
catch ( const std : : exception & e )
{
CV_LOG_WARNING ( NULL , " MSMF: Exception is raised: " < < e . what ( ) ) ;
}
2020-04-08 01:25:10 +08:00
catch ( . . . )
{
2021-02-25 01:45:19 +08:00
CV_LOG_WARNING ( NULL , " MSMF: Unknown C++ exception is raised " ) ;
2020-04-08 01:25:10 +08:00
}
if ( wrt )
delete wrt ;
return CV_ERROR_FAIL ;
}
2021-03-01 23:51:04 +08:00
static
CvResult CV_API_CALL cv_writer_open ( const char * filename , int fourcc , double fps , int width , int height , int isColor ,
CV_OUT CvPluginWriter * handle )
{
int params [ 2 ] = { VIDEOWRITER_PROP_IS_COLOR , isColor } ;
return cv_writer_open_with_params ( filename , fourcc , fps , width , height , params , 1 , handle ) ;
}
2020-04-08 01:25:10 +08:00
static
CvResult CV_API_CALL cv_writer_release ( CvPluginWriter handle )
{
if ( ! handle )
return CV_ERROR_FAIL ;
WriterT * instance = ( WriterT * ) handle ;
delete instance ;
return CV_ERROR_OK ;
}
static
2021-03-01 23:51:04 +08:00
CvResult CV_API_CALL cv_writer_get_prop ( CvPluginWriter handle , int prop , CV_OUT double * val )
2020-04-08 01:25:10 +08:00
{
2021-03-01 23:51:04 +08:00
if ( ! handle )
return CV_ERROR_FAIL ;
if ( ! val )
return CV_ERROR_FAIL ;
try
{
WriterT * instance = ( WriterT * ) handle ;
* val = instance - > getProperty ( prop ) ;
return CV_ERROR_OK ;
}
catch ( . . . )
{
return CV_ERROR_FAIL ;
}
2020-04-08 01:25:10 +08:00
}
static
CvResult CV_API_CALL cv_writer_set_prop ( CvPluginWriter /*handle*/ , int /*prop*/ , double /*val*/ )
{
return CV_ERROR_FAIL ;
}
static
CvResult CV_API_CALL cv_writer_write ( CvPluginWriter handle , const unsigned char * data , int step , int width , int height , int cn )
{
if ( ! handle )
return CV_ERROR_FAIL ;
try
{
CV_Assert ( step > = 0 ) ;
WriterT * instance = ( WriterT * ) handle ;
Size sz ( width , height ) ;
Mat img ( sz , CV_MAKETYPE ( CV_8U , cn ) , ( void * ) data , ( size_t ) step ) ;
instance - > write ( img ) ;
return CV_ERROR_OK ;
}
2021-02-25 01:45:19 +08:00
catch ( const std : : exception & e )
{
CV_LOG_WARNING ( NULL , " MSMF: Exception is raised: " < < e . what ( ) ) ;
return CV_ERROR_FAIL ;
}
2020-04-08 01:25:10 +08:00
catch ( . . . )
{
2021-02-25 01:45:19 +08:00
CV_LOG_WARNING ( NULL , " MSMF: Unknown C++ exception is raised " ) ;
2020-04-08 01:25:10 +08:00
return CV_ERROR_FAIL ;
}
}
2021-03-01 23:51:04 +08:00
} // namespace
# ifndef NEW_PLUGIN
2020-12-04 11:18:16 +08:00
static const OpenCV_VideoIO_Plugin_API_preview plugin_api =
2020-04-08 01:25:10 +08:00
{
{
2020-12-04 11:18:16 +08:00
sizeof ( OpenCV_VideoIO_Plugin_API_preview ) , ABI_VERSION , API_VERSION ,
2020-04-08 01:25:10 +08:00
CV_VERSION_MAJOR , CV_VERSION_MINOR , CV_VERSION_REVISION , CV_VERSION_STATUS ,
" Microsoft Media Foundation OpenCV Video I/O plugin "
} ,
2020-12-04 11:18:16 +08:00
{
2021-03-01 23:51:04 +08:00
/* 1*/ cv : : CAP_MSMF ,
/* 2*/ cv : : cv_capture_open ,
/* 3*/ cv : : cv_capture_release ,
/* 4*/ cv : : cv_capture_get_prop ,
/* 5*/ cv : : cv_capture_set_prop ,
/* 6*/ cv : : cv_capture_grab ,
/* 7*/ cv : : cv_capture_retrieve ,
/* 8*/ cv : : cv_writer_open ,
/* 9*/ cv : : cv_writer_release ,
/* 10*/ cv : : cv_writer_get_prop ,
/* 11*/ cv : : cv_writer_set_prop ,
/* 12*/ cv : : cv_writer_write
2020-12-04 11:18:16 +08:00
}
2020-04-08 01:25:10 +08:00
} ;
const OpenCV_VideoIO_Plugin_API_preview * opencv_videoio_plugin_init_v0 ( int requested_abi_version , int requested_api_version , void * /*reserved=NULL*/ ) CV_NOEXCEPT
{
2020-12-04 11:18:16 +08:00
if ( requested_abi_version = = ABI_VERSION & & requested_api_version < = API_VERSION )
2021-03-01 23:51:04 +08:00
return & plugin_api ;
return NULL ;
}
# else // NEW_PLUGIN
static const OpenCV_VideoIO_Capture_Plugin_API capture_plugin_api =
{
{
sizeof ( OpenCV_VideoIO_Capture_Plugin_API ) , CAPTURE_ABI_VERSION , CAPTURE_API_VERSION ,
CV_VERSION_MAJOR , CV_VERSION_MINOR , CV_VERSION_REVISION , CV_VERSION_STATUS ,
" Microsoft Media Foundation OpenCV Video I/O plugin "
} ,
{
/* 1*/ cv : : CAP_MSMF ,
/* 2*/ cv : : cv_capture_open ,
/* 3*/ cv : : cv_capture_release ,
/* 4*/ cv : : cv_capture_get_prop ,
/* 5*/ cv : : cv_capture_set_prop ,
/* 6*/ cv : : cv_capture_grab ,
/* 7*/ cv : : cv_capture_retrieve ,
} ,
{
/* 8*/ cv : : cv_capture_open_with_params ,
}
} ;
const OpenCV_VideoIO_Capture_Plugin_API * opencv_videoio_capture_plugin_init_v1 ( int requested_abi_version , int requested_api_version , void * /*reserved=NULL*/ ) CV_NOEXCEPT
{
if ( requested_abi_version = = CAPTURE_ABI_VERSION & & requested_api_version < = CAPTURE_API_VERSION )
return & capture_plugin_api ;
2020-12-04 11:18:16 +08:00
return NULL ;
2020-04-08 01:25:10 +08:00
}
2021-03-01 23:51:04 +08:00
static const OpenCV_VideoIO_Writer_Plugin_API writer_plugin_api =
{
{
sizeof ( OpenCV_VideoIO_Writer_Plugin_API ) , WRITER_ABI_VERSION , WRITER_API_VERSION ,
CV_VERSION_MAJOR , CV_VERSION_MINOR , CV_VERSION_REVISION , CV_VERSION_STATUS ,
" Microsoft Media Foundation OpenCV Video I/O plugin "
} ,
{
/* 1*/ cv : : CAP_MSMF ,
/* 2*/ cv : : cv_writer_open ,
/* 3*/ cv : : cv_writer_release ,
/* 4*/ cv : : cv_writer_get_prop ,
/* 5*/ cv : : cv_writer_set_prop ,
/* 6*/ cv : : cv_writer_write
} ,
{
/* 7*/ cv : : cv_writer_open_with_params
}
} ;
const OpenCV_VideoIO_Writer_Plugin_API * opencv_videoio_writer_plugin_init_v1 ( int requested_abi_version , int requested_api_version , void * /*reserved=NULL*/ ) CV_NOEXCEPT
{
if ( requested_abi_version = = WRITER_ABI_VERSION & & requested_api_version < = WRITER_API_VERSION )
return & writer_plugin_api ;
return NULL ;
}
# endif // NEW_PLUGIN
2020-04-08 01:25:10 +08:00
# endif // BUILD_PLUGIN