Microsoft Media Foundation Webcam Interface - visual-c++

I've been working on a c++ interface to capture images from all types of webcams via the Micrsoft Media Foundation. I've already got a bit of code that can connect with several types of webcams and is able to capture images in different resolutions and formats.
I know that under WinXP it is possible to change different parameters of the webcam (like white balance, exposure time e.g.) by using the Direct Show library. Unfortunately the interface in the Direct Show library that made it possible to easily capture single frames from a webcam is removed from Direct Show under Win7. Does anybody know how I can acces these parameters using Microsoft Media Foundation or any other library that I can combine with the Microsoft Media Foundation?

It is possible to call a DirectShow QueryInterface method from WMF. Example code is given at Windows Media Foundation: Controlling Camera Properties.
This should let you set available camera parameters like focus and white balance etc.
HRESULT CMFVideoCaptureDlg::SetupCamera(IMFMediaSource* pCameraSource) {
CComQIPtr<IAMCameraControl> spCameraControl(pCameraSource);
HRESULT hr = S_OK;
if(spCameraControl) {
long min, max, step, def, control;
hr = spCameraControl->GetRange(CameraControl_Exposure, &min, &max, &step, &def, &control);
if(SUCCEEDED(hr))
hr = spCameraControl->Set(CameraControl_Exposure, 1, CameraControl_Flags_Manual);
}
CComQIPtr<IAMVideoProcAmp> spVideo(pCameraSource);
if(spVideo)
hr = spVideo->Set(VideoProcAmp_WhiteBalance, 0, VideoProcAmp_Flags_Auto);
return hr;
}
It turns out Media Foundation does not define any specific interfaces
for these tasks. Curiously enough, it implements interfaces defined by
its predecessor, DirectShow, on its media source (represented by the
IMFMediaSource interface), when that media source is a video camera

DirectShow is still good in Windows 7 (the easiest to check is using GraphEdit and AMCap from Windows SDK). Media Foundation however lacks essential support in earlier versions of Windows.

This article has the following code and it works like a charm!
HRESULT CMFVideoCaptureDlg::SetupCamera(IMFMediaSource* pCameraSource) {
CComQIPtr spCameraControl(pCameraSource);
HRESULT hr = S_OK;
if(spCameraControl) {
long min, max, step, def, control;
hr = spCameraControl->GetRange(CameraControl_Exposure, &min, &max, &step, &def, &control);
if(SUCCEEDED(hr))
hr = spCameraControl->Set(CameraControl_Exposure, 1, CameraControl_Flags_Manual);
}
CComQIPtr spVideo(pCameraSource);
if(spVideo)
hr = spVideo->Set(VideoProcAmp_WhiteBalance, 0, VideoProcAmp_Flags_Auto);
return hr;
}

IAMCameraControl and IANVideoProcAmp still support White balance,pan,zoom in Windows 8. camera control is so far not part of MFT.We have to use Direct Show to do these things.

Related

Does Windows Media Foundation on UWP have a resampler? If so how do I use it?

Using Win32 I have access to CLSID_CResamplerMediaObject which means I can reduce my channel count from say 6 to 2.
On UWP this is no longer defined and the only reference to a resampler I can find is CLSID_AudioResamplerMediaObject. When I create an instance of this class however, and pass it my MFMediaType_Float or MFMediaType_PCM type, it says that the provided types aren't supported...
ComPtr<IUnknown> pTransformUnknown = nullptr;
DxUtil::ThrowIfFailed(CoCreateInstance(CLSID_AudioResamplerMediaObject, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, &pTransformUnknown));
DxUtil::ThrowIfFailed(pTransformUnknown->QueryInterface(IID_PPV_ARGS(&mResampler)));
IMFMediaType* pInputType = nullptr;
DxUtil::ThrowIfFailed(MFCreateMediaType(&pInputType));
DxUtil::ThrowIfFailed(pInputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio));
DxUtil::ThrowIfFailed(pInputType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM)); // Or MFAudioFormat_Float
DxUtil::ThrowIfFailed(pInputType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16));
DxUtil::ThrowIfFailed(pInputType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, 6));
DxUtil::ThrowIfFailed(pInputType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000));
DxUtil::ThrowIfFailed(mAudioSourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, nullptr, pInputType)); // Fails here!
As usual, Microsoft docs aren't helpful, I would appreciate any help!
Input file is Mp4 with 1 aac stream, 6 channels, 16 bit audio.
CLSID_AudioResamplerMediaObject and CLSID_CResamplerMediaObject are the same thing, same GUID of {f447b69e-1884-4a7e-8055-346f74d6edb3}.
The error you mentioned is not coming from audio resampler, you have it from Source Reader API. The error is presumably correctly reported indicating the situation that for given media source the reader cannot provide a conversion to supplied media type. There can be multiple reasons for this to happen.

can't acquire IDXGIDevice or IDXGIDevice1 from ID3D12Device in dx12

I'd like to call IDXGIDevice1::SetMaximumFrameLatency method from my dx12app, for that I need to get a valid IDXGIDevice1 from the current Direct3D 12 device. querying the interface return a E_NOINTERFACE:
IDXGIDevice * pDXGIDevice;
HRESULT hr = myDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&pDXGIDevice);
assert(hr != S_OK); // returns E_NOINTERFACE
IDXGIDevice1 * pDXGIDevice1;
HRESULT hr1 = myDevice->QueryInterface(__uuidof(IDXGIDevice1), (void **)&pDXGIDevice1);
assert(hr != S_OK); // returns E_NOINTERFACE
Not sure if I'm missing something or there is sequence of dxgi logic I need to implement to get a valid IDXGIDevice1 interface.
Would appreciate any hints & thanks in advance!
Klip
For Direct3D 12, this 'legacy pattern' of obtaining the DXGI factory is not supported, so your code above won't work as it's the first step:
ComPtr<IDXGIDevice3> dxgiDevice;
DX::ThrowIfFailed(
m_d3dDevice.As(&dxgiDevice)
);
ComPtr<IDXGIAdapter> dxgiAdapter;
DX::ThrowIfFailed(
dxgiDevice->GetAdapter(&dxgiAdapter)
);
ComPtr<IDXGIFactory4> dxgiFactory;
DX::ThrowIfFailed(
dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory))
);
For Direct3D 12, you should always create the DXGI factory explicitly. See Anatomy of Direct3D 12 Create Device.
In Direct3D 12 swap chains, you explicitly control the backbuffer swapping behavior. Ideally you'd use DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT and then use the waitable object to throttle your rendering speed instead. You can set the latency count via IDXGISwapChain2::SetMaximumFrameLatency which defaults to 3 (MSDN is currently wrong about the defaults).
If you want to support 'higher-than-refresh-rate' updates (such as nVidia G-Sync or AMD FreeSync), then you use the new DXGI_PRESENT_ALLOW_TEARING flag for Present. For details on using this flag, see MSDN or this YouTube video.
See also DirectX 12: Presentation Modes In Windows 10 (YouTube).

How can I read the info of a media file using visual c++?

Is there a way to read the info (fps, bitrate, duration, codecs required, etc.) of a media file (avi, mp4, mkv, etc.) on windows using visual studio c++?
I managed to play various files (which I actually don't even want) using directshow (http://msdn.microsoft.com/en-us/library/windows/desktop/dd389098%28v=vs.85%29.aspx) but I don't know how to only get the information from the file.
Edit: I got it working like this...
int height, width, framerate, bitrate;
LARGE_INTEGER duration;
// initialize the COM library
CoInitialize(NULL);
//
IPropertyStore* store = NULL;
SHGetPropertyStoreFromParsingName(L"E:\\test.avi", NULL, GPS_DEFAULT, __uuidof(IPropertyStore), (void**)&store);
PROPVARIANT variant;
store->GetValue(PKEY_Media_Duration, &variant);
duration = variant.hVal;
store->GetValue(PKEY_Video_FrameHeight, &variant);
height = variant.lVal;
store->GetValue(PKEY_Video_FrameWidth, &variant);
width = variant.lVal;
store->GetValue(PKEY_Video_FrameRate, &variant);
framerate = variant.lVal;
store->GetValue(PKEY_Video_TotalBitrate, &variant);
bitrate = variant.lVal;
//
store->Release();
//
CoUninitialize();
You can obtain this information via DirectShow, however if you don't need the playback/streaming pipeline and you are on Windows 7, then you possibly have a better alternate option to get the data from shell properties - those supplying data to display in additional columns of Windows explorer.
SHGetPropertyStoreFromParsingName gets you property store
MSDN entry point for Shell Metadata Providers
Code snippet: How to use the IPropertyStore to obtain Media_Duration?
Have you considered using the MediaInfo SDK? You can get extensive information about all of the audio and video streams available in the container, including codec specifics, as well as everything you were asking about.
Their getting started guide and reference documentation are here:
http://mediaarea.net/en/MediaInfo/Support/SDK/Quick_Start
http://mediaarea.net/en/MediaInfo/Support/SDK/More_Info
Code is available at their SourceForge page here.

How can I select an audio output device in directshow

I was wondering how I can select the output device for audio in directshow. I am able to get available audio output devices in directshow. But how can I make one of these to be audio output device. Its always going for the default audio device. I want to be able to output audio on my choice of device. I have been struggling through google but couldn't find anything useful. All I could get was this link but it doesn't really solve my problem.
Any help will be really helpful for me.
First off, if you're not using DirectShow .NET (DirectShowLib), get that here: It serves as a (very complete) interface between unmanaged DirectShow and C#
What follows is a pretty simple example of how to play an audio file, to the desired audio device
using DirectShowLib;
private IGraphBuilder m_objFilterGraph = null;
private IBasicAudio m_objBasicAudio = null;
private IMediaControl m_objMediaControl = null;
private void playAudioToDevice(string fName, int devIndex)
{
object source = null;
DsDevice[] devices;
devices = DsDevice.GetDevicesOfCat(FilterCategory.AudioRendererCategory);
DsDevice device = (DsDevice)devices[devIndex];
Guid iid = typeof(IBaseFilter).GUID;
device.Mon.BindToObject(null, null, ref iid, out source);
m_objFilterGraph = (IGraphBuilder)new FilterGraph();
m_objFilterGraph.AddFilter((IBaseFilter)source, "Audio Render");
m_objFilterGraph.RenderFile(fName, "");
m_objBasicAudio = m_objFilterGraph as IBasicAudio;
m_objMediaControl = m_objFilterGraph as IMediaControl;
m_objMediaControl.Run();
}
It is up to user to manage audio devices and choose a primary device (such as via Control Panel applet). You can find ways to switch devices programmatically in Windows XP, however in Vista+ it is impossible without interactive user action by design.
See also Larry's answer here: How to change default sound playback device programmatically?
UPDATE: The mentioned above refers to modifying system configuration trying to alter default audio output device. An application is however not limited to default device only. Instead, it can enumerate available devices (see Using the System Device Enumerator + CLSID_AudioRendererCategory) and then create an instance of renderer for specific device with BindToObject call. From there on, it is a regular filter, just bound internally to device of interest.

How to get webcam video stream bytes in c++

I am targeting windows machines. I need to get access to the pointer to the byte array describing the individual streaming frames from an attached usb webcam. I saw the playcap directshow sample from the windows sdk, but I dont see how to get to raw data, frankly, I don't understand how the video actually gets to the window. Since I don't really need anything other than the video capture I would prefer not to use opencv.
Visual Studio 2008 c++
Insert the sample grabber filter. Connect the camera source to the sample grabber and then to the null renderer. The sample grabber is a transform, so you need to feed the output somewhere, but if you don't need to render it, the null renderer is a good choice.
You can configure the sample grabber using ISampleGrabber. You can arrange a callback to your app for each frame, giving you either a pointer to the bits themselves, or a pointer to the IMediaSample object which will also give you the metadata.
You need to implement ISampleGrabberCB on your object, and then you need something like this (pseudo code)
IFilterInfoPtr m_pFilterInfo;
ISampleGrabberPtr m_pGrabber;
m_pGrabber = pFilter;
m_pGrabber->SetBufferSamples(false);
m_pGrabber->SetOneShot(false);
// force to 24-bit mode
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(mt));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
m_pGrabber->SetMediaType(&mt);
m_pGrabber->SetCallback(this, 0);
// SetCallback increments a refcount on ourselves,
// but we own the grabber so this is recursive
/// -- must addref before SetCallback(NULL)
Release();

Resources