Calling Inherited IUnknown::Release() in a destructor - c++

Why does calling the inherited IUnknown::Release() function on a IWICImagingFactory object in a destructor cause a "CXX0030: Error: expression cannot be evaluated" to be shown each entry in the object's virtual function table (__vfptr)?
This is in reference to an earlier question I posted but I've since realized that the problem only occurs in the destructor. The virtual function table appears valid anywhere else I have checked. However, once in the destructor all entries are shown with the CXX0030 error and attempting to call the inherited IUknown::Release() fails.
Edit: Here is some code to demonstrate:
HRESULT DemoApp::CreateDeviceIndependentResources()
{
HRESULT hr;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &mpDirect2DFactory);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&mpWICFactory)
);
}
//CoCreateInstance returns S_OK.
//Other unrelated code here.
}
HRESULT DemoApp::CreateDeviceResources()
{
HRESULT hr;
//Other unrelated code here for creating device-dependant resources.
//mpBackgroundBitmap is a ID2D1Bitmap*.
if(SUCCEEDED(hr))
{
hr = LoadBitmapFromFile(
mpRenderTarget,
mpWICFactory,
L".\\background.png",
0,
0,
&mpBackgroundBitmap);
}
}
//The below LoadBitmapFromFile() code is taken directly from an MSDN sample.
//I didn't write it.
HRESULT DemoApp::LoadBitmapFromFile(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
PCWSTR uri,
UINT destinationWidth,
UINT destinationHeight,
ID2D1Bitmap **ppBitmap
)
{
IWICBitmapDecoder *pDecoder = NULL;
IWICBitmapFrameDecode *pSource = NULL;
IWICStream *pStream = NULL;
IWICFormatConverter *pConverter = NULL;
IWICBitmapScaler *pScaler = NULL;
HRESULT hr = pIWICFactory->CreateDecoderFromFilename(
uri,
NULL,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (SUCCEEDED(hr))
{
// Create the initial frame.
hr = pDecoder->GetFrame(0, &pSource);
}
if (SUCCEEDED(hr))
{
// Convert the image format to 32bppPBGRA
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
hr = pIWICFactory->CreateFormatConverter(&pConverter);
}
if (SUCCEEDED(hr))
{
// If a new width or height was specified, create an
// IWICBitmapScaler and use it to resize the image.
if (destinationWidth != 0 || destinationHeight != 0)
{
UINT originalWidth, originalHeight;
hr = pSource->GetSize(&originalWidth, &originalHeight);
if (SUCCEEDED(hr))
{
if (destinationWidth == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
}
else if (destinationHeight == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
}
hr = pIWICFactory->CreateBitmapScaler(&pScaler);
if (SUCCEEDED(hr))
{
hr = pScaler->Initialize(
pSource,
destinationWidth,
destinationHeight,
WICBitmapInterpolationModeCubic
);
}
if (SUCCEEDED(hr))
{
hr = pConverter->Initialize(
pScaler,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
}
else // Don't scale the image.
{
hr = pConverter->Initialize(
pSource,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
if (SUCCEEDED(hr))
{
// Create a Direct2D bitmap from the WIC bitmap.
hr = pRenderTarget->CreateBitmapFromWicBitmap(
pConverter,
NULL,
ppBitmap
);
}
SafeRelease(&pDecoder);
SafeRelease(&pSource);
SafeRelease(&pStream);
SafeRelease(&pConverter);
SafeRelease(&pScaler);
return hr;
}
//Now I call SafeRelease() in my destructor and the virtual function table entires are showing the error.
DemoApp::~DemoApp()
{
SafeRelease(&mpDirect2DFactory);
SafeRelease(&mpWICFactory); //here is the problem apparently
SafeRelease(&mpDWriteFactory);
SafeRelease(&mpRenderTarget);
SafeRelease(&mpBackgroundBitmap);
}
//SafeRelease is defined as:
template<class Interface>
inline void SafeRelease(Interface** ppInterfaceToRelease)
{
if(*ppInterfaceToRelease != NULL)
{
(*ppInterfaceToRelease)->Release();
(*ppInterfaceToRelease) = NULL;
}
}
The problem is when I call SafeRelease() on the WICFactory object, I get:
First-chance exception at 0x0024e135 in DemoApp.exe: 0xC0000005: Access violation reading location 0x6d5c28f0.
Unhandled exception at 0x0024e135 in DemoApp.exe: 0xC0000005: Access violation reading location 0x6d5c28f0.

I struggled with this problem lately too. The problem is that the creation and release of IWICImagingFactory depends on CoInitialize/CoUninitialize being called before and after, respectively. In your application it is likely that CoUninitialize() is called before the IWICImagingFactory is released in the destructor, which causes a crash. Note that ID2D1RenderTarget and such do not seem to be affected and can still be released after CoUninitialize() is called.
Remove the call to CoUninitialize() from RunMessageLoop() or wherever it is and put it after the release call in the destructor and the crash should go away.

Calling virtual functions inside the constructor or destructor does not call the function you assume it will call. It always results in call to the functions of that same class.
You can assume virtual dispatch is disabled in constructor and destructors.
An more appropriate way of saying this is:
During the execution of a constructor or destructor, virtual calls on the object for which the constructor or destructor is run behave as if the dynamic type of the object expression used in the call is equal to the class of the constructor or destructor.
Courtesy: A lengthy discussion in C++ Lounge, Where finally, #JohannesSchaublitb came up with this apt definition, which most of us seemed to agree on.

Related

How to initialize IWICBitmapDecoder with Windows Imaging Component API

Actually I belive that this problem is easy to solve. It only needs a minor correction. This is the first time that I use Windows Imaging Component (WIC). I am trying to display a PNG picture in my window using Win32 or the Windows API as Microsoft likes to call it. I have written code to initialize it. It requires many steps. I have included a PNG image in my .exe file. Maybe you can look at my code to see what is missing:
void ShowImage() {
IWICBitmapDecoder** ppIDecoder;
IStream* pIStream;
HRESULT hr;
ID2D1RenderTarget* pRenderTarget;
IWICImagingFactory* pIWICFactory = 0;
PCWSTR resourceName, resourceType;
UINT destinationWidth;
UINT destinationHeight;
ID2D1Bitmap** ppBitmap;
IWICBitmapDecoder* pDecoder = NULL;
IWICBitmapFrameDecode* pSource = NULL;
IWICBitmapSource* pISource;
IWICStream* pStream = NULL;
IWICFormatConverter* pConverter = NULL;
IWICBitmapScaler* pScaler = NULL;
HRSRC imageResHandle = NULL;
HGLOBAL imageResDataHandle = NULL;
void* pImageFile = NULL;
DWORD imageFileSize = 0;
// Locate the resource. Aaahhh I should have called Makeintresource and written "PNG"
imageResHandle = FindResource(hInst, MAKEINTRESOURCE(103), L"PNG");
hr = imageResHandle ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) {
// Load the resource.
imageResDataHandle = LoadResource(hInst, imageResHandle);
hr = imageResDataHandle ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr)) {
// Lock it to get a system memory pointer.
pImageFile = LockResource(imageResDataHandle);
hr = pImageFile ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr)) {
// Calculate the size.
imageFileSize = SizeofResource(hInst, imageResHandle);
hr = imageFileSize ? S_OK : E_FAIL;
}
// call coinitialize IWICImagingFactory
if(SUCCEEDED(hr))
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
// Create WIC factory
if (SUCCEEDED(hr)) {
hr = CoCreateInstance(CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pIWICFactory)
);
}
if (SUCCEEDED(hr)) {
// Create a WIC stream to map onto the memory.
hr = pIWICFactory->CreateStream(&pStream);
}
if (SUCCEEDED(hr)) {
// Initialize the stream with the memory pointer and size.
hr = pStream->InitializeFromMemory(reinterpret_cast <BYTE*>(pImageFile),
imageFileSize);
}
if (SUCCEEDED(hr)) {
// Create a decoder for the stream.
--->hr = pIWICFactory->CreateDecoderFromStream(pStream, 0, WICDecodeMetadataCacheOnLoad, ppIDecoder);
}
}
I tried the above code which compiles without errors. All the function calls succeed except the last one that I marked with --->. Then the debugger shows a runtime exception because "The variable 'ppIDecoder' is being used without being initialized."
How do I initialize ppIDecoder?
As said, this problem should be quick to solve.

How do I implement `BeginRead` in the IMFByteStream interface

I have created ReadByteContainer to store current data and ReadByteAsyncCallback for the callback. Are there alternatives that would work better?
HRESULT MediaByteStream::BeginRead(
BYTE *pb,
ULONG cb,
IMFAsyncCallback *pCallback,
IUnknown *punkState)
{
HRESULT hr = S_OK;
// Create a new read byte container.
ReadByteContainer* readBytes = new ReadByteContainer(pb, cb);
ReadByteAsyncCallback* readCallback = new ReadByteAsyncCallback(this);
// If not created.
if (readBytes == NULL)
{
return E_OUTOFMEMORY;
}
// If not created.
if (readCallback == NULL)
{
return E_OUTOFMEMORY;
}
IMFAsyncResult *pResult = NULL;
readBytes->_readCallback = readCallback;
// Creates an asynchronous result object. Use this function if you are implementing an asynchronous method.
hr = MFCreateAsyncResult(readBytes, pCallback, punkState, &pResult);
if (SUCCEEDED(hr))
{
// Start a new work item thread.
hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, readCallback, pResult);
pResult->Release();
}
// Return the result.
return hr;
}
If pb remains valid until EndRead occurs, you can avoid the copy (new ReadByteContainer), and just keep pb as is.
Normally your MediaByteStream implements IMFAsyncCallback so you should call MFPutWorkItem like this (avoid new ReadByteAsyncCallback) :
hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, this, pResult);
Also, i don't see some lock mechanism inside BeginRead. If you use it in a multithreading environment you should handle this. Close can be call when BeginRead has been called and did not finish, so you will face problems.

How to use property pages on unregistrated filter?

I use filter DS LAME for compressing audio. I loaded it from file "lame.ax" as follows:
// pPath - path to LAME "lame.ax"
HRESULT CMyFilter::CreateObjectFromPath(wchar_t *pPath, REFCLSID clsid, IUnknown **ppUnk)
{
// load the target DLL directly
if (!m_hLibFilter) m_hLibFilter = LoadLibrary(pPath);
if (!m_hLibFilter)
{
return HRESULT_FROM_WIN32(GetLastError());
}
// the entry point is an exported function
FN_DLLGETCLASSOBJECT fn = (FN_DLLGETCLASSOBJECT)GetProcAddress(m_hLibFilter, "DllGetClassObject");
if (fn == NULL)
{
return HRESULT_FROM_WIN32(GetLastError());
}
// create a class factory
IUnknownPtr pUnk;
HRESULT hr = fn(clsid, IID_IUnknown, (void**)(IUnknown**)&pUnk);
if (SUCCEEDED(hr))
{
IClassFactoryPtr pCF = pUnk;
if (pCF == NULL)
{
hr = E_NOINTERFACE;
}
else
{
// ask the class factory to create the object
hr = pCF->CreateInstance(NULL, IID_IUnknown, (void**)ppUnk);
}
}
return hr;
}
further
HRESULT hr = 0;
IUnknown *ppUnk = 0;
ULONG lRef = 0;
hr = CreateObjectFromPath(L"lame.ax", CLSID_LAMEDShowFilter, (IUnknown **)&ppUnk);
hr = ppUnk->QueryInterface(&m_pFilter);
lRef = ppUnk->Release();
It works perfectly. LAME encoding audio.
I want to show the filter settings - property page, but this code failed
bool ShowConfigWindow(HWND hParent)
{
ISpecifyPropertyPages *pProp;
HRESULT hr = m_pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
if (SUCCEEDED(hr))
{
// Get the filter's name and IUnknown pointer.
FILTER_INFO FilterInfo;
hr = m_pFilter->QueryFilterInfo(&FilterInfo);
IUnknown *pFilterUnk;
m_pFilter->QueryInterface(IID_IUnknown, (void **)&pFilterUnk);
// Show the page.
CAUUID caGUID;
pProp->GetPages(&caGUID);
pProp->Release();
HRESULT hr = OleCreatePropertyFrame(
hParent, // Parent window
0, 0, // Reserved
FilterInfo.achName, // Caption for the dialog box
1, // Number of objects (just the filter)
&pFilterUnk, // Array of object pointers.
caGUID.cElems, // Number of property pages
caGUID.pElems, // Array of property page CLSIDs
0, // Locale identifier
0, NULL // Reserved
);
// Clean up.
pFilterUnk->Release();
FilterInfo.pGraph->Release();
CoTaskMemFree(caGUID.pElems);
}
return true;
}
I find https://groups.google.com/forum/#!topic/microsoft.public.win32.programmer.directx.video/jknSbMenWeM
I should call CoRegisterClassObject for each property page, but how to do it?
Or what the right way?
OleCreatePropertyFrame takes property page class identifiers (CLSIDs) so you need to find a way to make them "visible" for the API.
Use of CoRegisterClassObject is one of the ways to achieve the mentioned task (perhaps the easiest, another method would be reg-free COM). You need to retrieve IClassFactory pointers for property page CLSIDs the same way as you do it in the first snippet. Then instead of calling IClassFactory::CreateInstance you use the interface pointers as arguments for CoRegisterClassObject API. Make sure you do it on the same thread as the following OleCreatePropertyFrame call. CoRevokeClassObject will clean things up afterwards.

How to use DirectShow and webcam to preview an image

I'm trying to use C++ and DirectShow to display my webcam... but I'm having some troubles.
The following code gives me a segmentation fault on:
m_pDF->EnumPins(&pinEnum);
my cpp code:
#include <tchar.h>
#include <strsafe.h>
#include <dshow.h>
#include <atlbase.h>
#include <d3d9.h>
#include <vmr9.h>
#pragma comment(lib,"Strmiids.lib")
#define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
// Create the System Device Enumerator.
ICreateDevEnum *pDevEnum; // Video and Audio interface object
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum)); // Creates the system device enumerator
if (SUCCEEDED(hr))
{
// Create an enumerator for the category.
hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0); // Enumeration of 'category' objects
if (hr == S_FALSE)
{
hr = VFW_E_NOT_FOUND; // The category is empty. Treat as an error.
}
pDevEnum->Release(); // Deletes Enumeration object
}
return hr;
}
void main(void)
{
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL; // contains methods for stopping and starting the graph
IMediaEvent *pEvent = NULL; // methods for getting events from the Filter Graph Manager
IPin *m_pCamOutPin;
IBaseFilter *m_pDF=NULL;
IMoniker *pM;
IEnumMoniker *pEnum; // Enumerator object
// Initialize the COM library.
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return;
}
// Create the filter graph manager and query for interfaces.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
return;
}
// Bind
hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
pEnum->Next(1, &pM, NULL);
pM->BindToObject(0, 0, IID_IBaseFilter, (void**)m_pDF);
pM->Release();
hr=pGraph->AddFilter(m_pDF, L"Video Capture");
CComPtr<IEnumPins> pinEnum;
m_pDF->EnumPins(&pinEnum);
hr = pinEnum->Reset();
hr = pinEnum->Next(1, &m_pCamOutPin, NULL);
if (FAILED(hr))
return;
// control
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
// Build the graph. IMPORTANT: Change this string to a file on your system.
hr = pGraph->Render(m_pCamOutPin);
if (SUCCEEDED(hr))
{
// Run the graph.
hr = pControl->Run();
if (SUCCEEDED(hr))
{
// Wait for completion.
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
// Note: Do not use INFINITE in a real application, because it
// can block indefinitely.
}
}
SAFE_RELEASE(pControl);
SAFE_RELEASE(pEvent);
SAFE_RELEASE(pGraph);
CoUninitialize();
}
Any ideas on what am I doing wrong and what do I have to do to get this to work?
m_pDF is a pointer to IBaseFilter:
IBaseFilter *m_pDF=NULL;
BindToObject last parameter is a pointer to a pointer. Which means this functioncall is wrong:
pM->BindToObject(0, 0, IID_IBaseFilter, (void**)m_pDF);
Instead you need to pass the address of m_pDF to get a pointer to a pointer:
pM->BindToObject(0, 0, IID_IBaseFilter, (void**)&m_pDF);
It is not a problem to cast IBaseFilter** to void**, but you can't cast IBaseFilter* to void**.
The crash should be related m_pDF, it not be a valid pointer.
you should add check for pM->BindToObject(0, 0, IID_IBaseFilter, (void**)m_pDF); to know that m_pDF is initialize sucess or not.
and you should also check hr=pGraph->AddFilter(m_pDF, L"Video Capture"); hr is ok or not.
if fail, you can get the error code know the reason.

DirectShow: webcam preview and image capture

After looking at a very similar question and seeing almost identical code, I've decided to ask this question separately. I want to show a video preview of the webcam's video stream to the default window DirectShow uses, and I also want the ability to "take a picture" of the video stream at any given moment.
I started with the DirectShow examples on MSDN, as well as the AMCap sample code, and have something I believe should should the preview part, but does not. I've found no examples of grabbing an image from the video stream except using SampleGrabber, which is deprecated and therefore I am trying not to use it.
Below is my code, line for line. Note that most of the code in EnumerateCameras is commented out. That code would've been for attaching to another window, which I don't want to do. In the MSDN documentation, it explicitly states that the VMR_7 creates its own window to display the video stream. I get no errors in my app, but this window never appears.
My question then is this: What am I doing wrong? Alternatively, if you know of a simple example of what I am trying to do, link me to it. AMCap is not a simple example, for reference.
NOTE: InitalizeVMR is for running in windowless state, which is my ultimate goal (integrating into a DirectX game). For now, however, i just want it to run in the simplest mode possible.
EDIT: The first portion of this question, that is previewing the camera stream, is solved. I am now just looking for an alternative to the deprecated SampleGrabber class so I can snap a photo at any moment and save it to a file.
EDIT: After looking for almost an hour on google, the general concensus seems to be that you HAVE to use ISampleGrabber. Please let me know if you find anything different.
Testing code (main.cpp):
CWebcam* camera = new CWebcam();
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
MessageBox(NULL, L"text", L"caption", NULL);
if (SUCCEEDED(hr))
{
camera->Create();
camera->EnumerateCameras();
camera->StartCamera();
}
int d;
cin >> d;
Webcam.cpp:
#include "Webcam.h"
CWebcam::CWebcam() {
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
//m_pTexInst = nullptr;
//m_pTexRes = nullptr;
}
CWebcam::~CWebcam() {
CoUninitialize();
m_pDeviceMonikers->Release();
m_pMediaController->Release();
}
BOOL CWebcam::Create() {
InitCaptureGraphBuilder(&m_pFilterGraph, &m_pCaptureGraph);
hr = m_pFilterGraph->QueryInterface(IID_IMediaControl, (void **)&m_pMediaController);
return TRUE;
}
void CWebcam::Destroy() {
}
void CWebcam::EnumerateCameras() {
HRESULT hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &m_pDeviceMonikers);
if (SUCCEEDED(hr))
{
//DisplayDeviceInformation(m_pDeviceMonikers);
//m_pDeviceMonikers->Release();
IMoniker *pMoniker = NULL;
if(m_pDeviceMonikers->Next(1, &pMoniker, NULL) == S_OK)
{
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&m_pCameraFilter);
if (SUCCEEDED(hr))
{
hr = m_pFilterGraph->AddFilter(m_pCameraFilter, L"Capture Filter");
}
}
// connect the output pin to the video renderer
if(SUCCEEDED(hr))
{
hr = m_pCaptureGraph->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
m_pCameraFilter, NULL, NULL);
}
//InitializeVMR(hwnd, m_pFilterGraph, &m_pVMRControl, 1, FALSE);
//get the video window that will be displayed from the filter graph
IVideoWindow *pVideoWindow = NULL;
hr = m_pFilterGraph->QueryInterface(IID_IVideoWindow, (void **)&pVideoWindow);
/*if(hr != NOERROR)
{
printf("This graph cannot preview properly");
}
else
{
//get the video stream configurations
hr = m_pCaptureGraph->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, m_pCameraFilter,
IID_IAMStreamConfig, (void **)&m_pVideoStreamConfig);
//Find out if this is a DV stream
AM_MEDIA_TYPE *pMediaTypeDV;
//fake window handle
HWND window = NULL;
if(m_pVideoStreamConfig && SUCCEEDED(m_pVideoStreamConfig->GetFormat(&pMediaTypeDV)))
{
if(pMediaTypeDV->formattype == FORMAT_DvInfo)
{
// in this case we want to set the size of the parent window to that of
// current DV resolution.
// We get that resolution from the IVideoWindow.
IBasicVideo* pBasivVideo;
// If we got here, gcap.pVW is not NULL
//ASSERT(pVideoWindow != NULL);
hr = pVideoWindow->QueryInterface(IID_IBasicVideo, (void**)&pBasivVideo);
/*if(SUCCEEDED(hr))
{
HRESULT hr1, hr2;
long lWidth, lHeight;
hr1 = pBasivVideo->get_VideoHeight(&lHeight);
hr2 = pBasivVideo->get_VideoWidth(&lWidth);
if(SUCCEEDED(hr1) && SUCCEEDED(hr2))
{
ResizeWindow(lWidth, abs(lHeight));
}
}
}
}
RECT rc;
pVideoWindow->put_Owner((OAHWND)window); // We own the window now
pVideoWindow->put_WindowStyle(WS_CHILD); // you are now a child
GetClientRect(window, &rc);
pVideoWindow->SetWindowPosition(0, 0, rc.right, rc.bottom); // be this big
pVideoWindow->put_Visible(OATRUE);
}*/
}
}
BOOL CWebcam::StartCamera() {
if(m_bIsStreaming == FALSE)
{
m_bIsStreaming = TRUE;
hr = m_pMediaController->Run();
if(FAILED(hr))
{
// stop parts that ran
m_pMediaController->Stop();
return FALSE;
}
return TRUE;
}
return FALSE;
}
void CWebcam::EndCamera() {
if(m_bIsStreaming)
{
hr = m_pMediaController->Stop();
m_bIsStreaming = FALSE;
//invalidate client rect as well so that it must redraw
}
}
BOOL CWebcam::CaptureToTexture() {
return TRUE;
}
HRESULT CWebcam::InitCaptureGraphBuilder(
IGraphBuilder **ppGraph, // Receives the pointer.
ICaptureGraphBuilder2 **ppBuild // Receives the pointer.
)
{
if (!ppGraph || !ppBuild)
{
return E_POINTER;
}
IGraphBuilder *pGraph = NULL;
ICaptureGraphBuilder2 *pBuild = NULL;
// Create the Capture Graph Builder.
HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pBuild );
if (SUCCEEDED(hr))
{
// Create the Filter Graph Manager.
hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&pGraph);
if (SUCCEEDED(hr))
{
// Initialize the Capture Graph Builder.
pBuild->SetFiltergraph(pGraph);
// Return both interface pointers to the caller.
*ppBuild = pBuild;
*ppGraph = pGraph; // The caller must release both interfaces.
return S_OK;
}
else
{
pBuild->Release();
}
}
return hr; // Failed
}
HRESULT CWebcam::EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
// Create the System Device Enumerator.
ICreateDevEnum *pSystemDeviceEnumerator;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSystemDeviceEnumerator));
if (SUCCEEDED(hr))
{
// Create an enumerator for the category.
hr = pSystemDeviceEnumerator->CreateClassEnumerator(category, ppEnum, 0);
if (hr == S_FALSE)
{
hr = VFW_E_NOT_FOUND; // The category is empty. Treat as an error.
}
pSystemDeviceEnumerator->Release();
}
return hr;
}
void CWebcam::DisplayDeviceInformation(IEnumMoniker *pEnum)
{
IMoniker *pMoniker = NULL;
int counter = 0;
while (pEnum->Next(1, &pMoniker, NULL) == S_OK)
{
IPropertyBag *pPropBag;
HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
if (FAILED(hr))
{
pMoniker->Release();
continue;
}
VARIANT var;
VariantInit(&var);
// Get description or friendly name.
hr = pPropBag->Read(L"Description", &var, 0);
if (FAILED(hr))
{
hr = pPropBag->Read(L"FriendlyName", &var, 0);
}
if (SUCCEEDED(hr))
{
printf("%d: %S\n", counter, var.bstrVal);
VariantClear(&var);
}
hr = pPropBag->Write(L"FriendlyName", &var);
// WaveInID applies only to audio capture devices.
hr = pPropBag->Read(L"WaveInID", &var, 0);
if (SUCCEEDED(hr))
{
printf("%d: WaveIn ID: %d\n", counter, var.lVal);
VariantClear(&var);
}
hr = pPropBag->Read(L"DevicePath", &var, 0);
if (SUCCEEDED(hr))
{
// The device path is not intended for display.
printf("%d: Device path: %S\n", counter, var.bstrVal);
VariantClear(&var);
}
pPropBag->Release();
pMoniker->Release();
counter++;
}
}
HRESULT CWebcam::InitializeVMR(
HWND hwndApp, // Application window.
IGraphBuilder* pFG, // Pointer to the Filter Graph Manager.
IVMRWindowlessControl** ppWc, // Receives the interface.
DWORD dwNumStreams, // Number of streams to use.
BOOL fBlendAppImage // Are we alpha-blending a bitmap?
)
{
IBaseFilter* pVmr = NULL;
IVMRWindowlessControl* pWc = NULL;
*ppWc = NULL;
// Create the VMR and add it to the filter graph.
HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer, NULL,
CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);
if (FAILED(hr))
{
return hr;
}
hr = pFG->AddFilter(pVmr, L"Video Mixing Renderer");
if (FAILED(hr))
{
pVmr->Release();
return hr;
}
// Set the rendering mode and number of streams.
IVMRFilterConfig* pConfig;
hr = pVmr->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);
if (SUCCEEDED(hr))
{
pConfig->SetRenderingMode(VMRMode_Windowless);
// Set the VMR-7 to mixing mode if you want more than one video
// stream, or you want to mix a static bitmap over the video.
// (The VMR-9 defaults to mixing mode with four inputs.)
if (dwNumStreams > 1 || fBlendAppImage)
{
pConfig->SetNumberOfStreams(dwNumStreams);
}
pConfig->Release();
hr = pVmr->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWc);
if (SUCCEEDED(hr))
{
pWc->SetVideoClippingWindow(hwndApp);
*ppWc = pWc; // The caller must release this interface.
}
}
pVmr->Release();
// Now the VMR can be connected to other filters.
return hr;
}
In windowless mode VMR would not create separate window. Since you started initialization for widnowless mode, you have to follow SetVideoClippingWindow with IVMRWindowlessControl::SetVideoPosition call to provide position within the window, see VMR Windowless Mode on MSDN.
Another sample code snippet for you: http://www.assembla.com/code/roatl-utilities/subversion/nodes/trunk/FullScreenWindowlessVmrSample01/MainDialog.h#ln188