Failed to get IAMStreamConfig interface - c++

I could capture the image from webcam and save it as bitmap by using sampleGrabber. And I know I could use the IAMStreamConfig interface to GetFormat and SetFormat the video resolution. My question is, I using FindInterface() to get IAMStreamConfig* but always failed.Is it because I place it in a wrong place or something else I didn't notice. I placed it before RenderStream. Here are some code below, thanks for your patient and help!
INT USBDeviceApp::GetInterfaces()
{
HRESULT hr;
hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **) &pGraphBuilder);
if (FAILED(hr))
return hr;
hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void **) &pCaptureGraphBuilder2);
if (FAILED(hr))
return hr;
hr = pGraphBuilder->QueryInterface(IID_IMediaControl,(LPVOID *)
&pMediaControl);
if (FAILED(hr))
return hr;
hr = pGraphBuilder->QueryInterface(IID_IVideoWindow, (LPVOID *)
&pVideoWindow);
if(FAILED(hr))
{
return hr;
}
hr = pGraphBuilder->QueryInterface(IID_IMediaEvent,(LPVOID *)
&pMediaEvent);
if(FAILED(hr))
{
return hr;
}
// ------------------------
// Create the Sample Grabber.
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&pGrabberF);
if (FAILED(hr))
{
return hr;
}
hr = pGrabberF->QueryInterface(IID_ISampleGrabber,
(void**)&pSampleGrabber);
if(FAILED(hr))
{
AfxMessageBox(_T("Error SampleGrabber QueryInterface"));
}
return 1;
}
INT USBDeviceApp::InitMonikers()
{
HRESULT hr;
ULONG cFetched;
ICreateDevEnum *pCreateDevEnum;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pCreateDevEnum);
if (FAILED(hr))
{
return hr;
}
IEnumMoniker *pEnumMoniker;
hr = pCreateDevEnum->
CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEnumMoniker, 0);
if (FAILED(hr) || !pEnumMoniker)
{
return -1;
}
hr = pEnumMoniker->Next(1, &pMonikerVideo, &cFetched);
if (S_OK == hr)
{
hr = pMonikerVideo->BindToObject(0,0,IID_IBaseFilter,
(void**)&pVideoCaptureFilter);
if (FAILED(hr))
{
return hr;
}
}
pEnumMoniker->Release();
return 1;
}
INT USBDeviceApp::CaptureVideo()
{
HRESULT hr = CoInitialize(NULL);
hr = GetInterfaces();
if (FAILED(hr))
{
AfxMessageBox(_T("Failed to get video interfaces!"));
return hr;
}
hr = pCaptureGraphBuilder2->SetFiltergraph(pGraphBuilder);
if (FAILED(hr))
{
AfxMessageBox(_T("Failed to attach the filter graph to the capture graph!"));
return hr;
}
//IAMStreamConfig *pConfig
hr = pCaptureGraphBuilder2->FindInterface(&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video,
pVideoCaptureFilter,IID_IAMStreamConfig, (void **)&pConfig);
if (FAILED(hr))
{
AfxMessageBox(_T("Couldn't initialize IAMStreamConfig!"));
}
else
{////
int iCount = 0,iSize = 0;
hr = pConfig->GetNumberOfCapabilities(&iCount,&iSize);
if(iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
{
for(int iFormat = 0;iFormat < iCount;iFormat++)
{
VIDEO_STREAM_CONFIG_CAPS scc;
AM_MEDIA_TYPE *pmtConfig;
hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
if(hr)
{
if((pmtConfig->majortype == MEDIATYPE_Video) &&
(pmtConfig->subtype == MEDIASUBTYPE_RGB24) &&
(pmtConfig->formattype == FORMAT_VideoInfo) &&
(pmtConfig->cbFormat >= sizeof (VIDEOINFOHEADER)) &&
(pmtConfig->pbFormat != NULL))
{
VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
pVih->bmiHeader.biWidth = 1280;
pVih->bmiHeader.biHeight = 720;
pVih->bmiHeader.biSizeImage = DIBSIZE(pVih->bmiHeader);
hr = pConfig->SetFormat(pmtConfi);
}
DeleteMediaType(pmtConfig);
}
}
}
}////
hr = InitMonikers();
if(FAILED(hr))
{
return hr;
}
hr = pGraphBuilder->AddFilter(pVideoCaptureFilter, L"Video Capture");
if (FAILED(hr))
{
pVideoCaptureFilter->Release();
return hr;
}
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
hr = pSampleGrabber->SetMediaType(&mt);
hr = pSampleGrabber->SetOneShot(FALSE);
hr = pSampleGrabber->SetBufferSamples(TRUE);
hr = pGraphBuilder->AddFilter(pGrabberF, L"Sample Grabber");
if (FAILED(hr))
{
return hr;
}
hr = pCaptureGraphBuilder2->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pVideoCaptureFilter, pGrabberF, 0 );
if (FAILED(hr))
{
pVideoCaptureFilter->Release();
return hr;
}
hr = pSampleGrabber->GetConnectedMediaType( &mt );
if(FAILED( hr ))
{
return -1;
}
VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;
pVih = (VIDEOINFOHEADER*) mt.pbFormat;
CSampleGrabberCB *CB = new CSampleGrabberCB() ;
if(!FAILED( hr ))
{
CB->Width = vih->bmiHeader.biWidth;
CB->Height = vih->bmiHeader.biHeight;
FreeMediaType( mt );
}
hr = pSampleGrabber->SetCallback( CB, 1 );
pVideoCaptureFilter->Release();
this->SetUpVideoWindow();
hr = pMediaControl->Run();
if (FAILED(hr))
{
return hr;
}
return hr;
}
hr = pCaptureGraphBuilder2->FindInterface()
always failed to get the IAMStreamConfig interface, I really don't know why. Can someone help me, thanks so much!

Your API call below
pCaptureGraphBuilder2->FindInterface(&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video,
pVideoCaptureFilter,IID_IAMStreamConfig, (void **) &pConfig);
applies several restrictions to the search, including pin category: you are looking for a preview pin. For example, the graph below features three video capture devices and none of them has the dedicated preview pin: preview pin is optional.
You need to take this into account and either relax the search criteria or I would rather suggest that you locate the pin of your interest directly on the capture filter. Then you will set it and and connect it with downstream peer filters. FindInterface is powerful but it also adds chances to get into confusion.

Related

Directshow cant start capture twice

I am trying to follow through the DirectShow examples on the windows dev center to make my own application that can capture screen and audio to video: Capturing Video to an AVI File
The first time capture starts all is ok, but at the second nothing happens, the file with video not appearing. Is it possible that I forgot to uninitialize sometfing?
UPDATE
The problem seems not to be in missing releasing. The second time stream writes the file 1.avi is creating but it empty and when the pMediaControl->Stop(); is done it automatically deletes
UPDATE2
At the second time I found that:
hr = pBuild->RenderStream(
&PIN_CATEGORY_CAPTURE, // Pin category.
&MEDIATYPE_Video, // Media type.
pCap, // Capture filter.
NULL, // Intermediate filter (optional).
pMux); // Mux or file sink filter.
returns E_INVALIDARG. So I added (using this):
if (a == 1) {
CComPtr<IPin> sourcePin;
CComPtr<IPin> dumpPin;
sourcePin = GetPin(pMux, PINDIR_OUTPUT);
dumpPin = GetPin(pCap, PINDIR_INPUT);
hr = ppGraph->Connect(sourcePin, dumpPin);
}
And I found thaht on the second time the dumpPin value is NULL .The hr = ppGraph->AddFilter(pCap, L"Capture Filter"); runs ok. Where can I dig next to find error?
(code is updated)
My code:
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <dshow.h>
#include <atlbase.h>
#include <dshow.h>
#include <vector>
#include <string>
#pragma comment(lib, "strmiids")
IPin *GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir)
{
BOOL bFound = FALSE;
IEnumPins *pEnum;
IPin *pPin;
pFilter->EnumPins(&pEnum);
while (pEnum->Next(1, &pPin, 0) == S_OK)
{
PIN_DIRECTION PinDirThis;
pPin->QueryDirection(&PinDirThis);
if (bFound = (PinDir == PinDirThis))
break;
pPin->Release();
}
pEnum->Release();
return (bFound ? pPin : 0);
}
HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
// Create the System Device Enumerator.
ICreateDevEnum *pDevEnum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
if (SUCCEEDED(hr))
{
// Create an enumerator for the category.
hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
if (hr == S_FALSE)
{
hr = VFW_E_NOT_FOUND; // The category is empty. Treat as an error.
}
pDevEnum->Release();
}
return hr;
}
HRESULT 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
}
struct Capture {
IPropertyBag *pPropBag;
IGraphBuilder *ppGraph;
IBaseFilter *pCap;
ICaptureGraphBuilder2 *pBuild;
};
void DisplayDeviceInformation(IEnumMoniker *pEnum,int a)
{
IMoniker *pMoniker = NULL;
std::vector<Capture> captures;
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);
hr = pPropBag->Read(L"DevicePath", &var, 0);
if (SUCCEEDED(hr))
{
// The device path is not intended for display.
printf("Device path: %S\n", var.bstrVal);
VariantClear(&var);
}
IGraphBuilder *ppGraph;
ICaptureGraphBuilder2 *pBuild; // Capture Graph Builder
hr = InitCaptureGraphBuilder(&ppGraph, &pBuild);
IBaseFilter *pCap; // Video capture filter.
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if (SUCCEEDED(hr))
{
std::wstring name = std::wstring(L"C:\\a\\") + std::to_wstring(a) + std::wstring(L".avi");
const wchar_t *cname = name.c_str();
hr = ppGraph->AddFilter(pCap, L"Capture Filter");
if (SUCCEEDED(hr)) {
IBaseFilter *pMux;
hr = pBuild->SetOutputFileName(
&MEDIASUBTYPE_Avi, // Specifies AVI for the target file.
cname, // File name.
&pMux, // Receives a pointer to the mux.
NULL); // (Optional) Receives a pointer to the file sink.
if (a == 1) {
CComPtr<IPin> sourcePin;
CComPtr<IPin> dumpPin;
sourcePin = GetPin(pMux, PINDIR_OUTPUT);
dumpPin = GetPin(pCap, PINDIR_INPUT);
hr = ppGraph->Connect(sourcePin, dumpPin);
}
hr = pBuild->RenderStream(
&PIN_CATEGORY_CAPTURE, // Pin category.
&MEDIATYPE_Video, // Media type.
pCap, // Capture filter.
NULL, // Intermediate filter (optional).
pMux); // Mux or file sink filter.
// Release the mux filter.
pMux->Release();
IConfigAviMux *pConfigMux = NULL;
hr = pMux->QueryInterface(IID_IConfigAviMux, (void**)&pConfigMux);
if (SUCCEEDED(hr))
{
pConfigMux->SetMasterStream(0);
pConfigMux->Release();
}
IConfigInterleaving *pInterleave = NULL;
hr = pMux->QueryInterface(IID_IConfigInterleaving, (void**)&pInterleave);
if (SUCCEEDED(hr))
{
pInterleave->put_Mode(INTERLEAVE_CAPTURE);
pInterleave->Release();
}
pMux->Release();
}
}
Capture capt;
capt.ppGraph = ppGraph;
capt.pPropBag = pPropBag;
capt.pCap = pCap;
capt.pBuild = pBuild;
captures.push_back(capt);
}
for (auto cap : captures)
{
IMediaControl* pMediaControl;
cap.ppGraph->QueryInterface(&pMediaControl);
pMediaControl->Run();
}
Sleep(5000);
for (auto cap : captures)
{
IMediaControl* pMediaControl;
cap.ppGraph->QueryInterface(&pMediaControl);
pMediaControl->Stop();
pMediaControl->Release();
cap.pCap->Release();
cap.ppGraph->Release();
cap.pBuild->Release();
cap.pPropBag->Release();
}
pMoniker->Release();
}
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
for (int a = 0; a <= 1; a++) {
if (SUCCEEDED(hr))
{
IEnumMoniker *pEnum;
hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
if (SUCCEEDED(hr))
{
DisplayDeviceInformation(pEnum,a);
pEnum->Release();
}
}
}
if (SUCCEEDED(hr))
{
CoUninitialize();
}
int i;
std::cin >> i;
return 0;
}
You might need to Release ppGraph, pBuild, pMediaControl and pCap at the end of DisplayDeviceInformation function and pMux at the end of the cycle. It will be better to use some sort of smart pointers instead.
I didn't figure out how too resolve this, so I just used spawn of external process.

cannot readsample from IMFSource in synchronous mode

I am having trouble with a video recording application that I am writing using Microsoft Media Foundation.
Specifically, the read/write function (which I put on a loop that lives on it's own thread) doesn't make it pass the call to ReadSample:
HRESULT WinCapture::rwFunction(void) {
HRESULT hr;
DWORD streamIndex, flags;
LONGLONG llTimeStamp;
IMFSample *pSample = NULL;
EnterCriticalSection(&m_critsec);
// Read another sample.
hr = m_pReader->ReadSample(
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
0,
&streamIndex, // actual
&flags,//NULL, // flags
&llTimeStamp,//NULL, // timestamp
&pSample // sample
);
if (FAILED(hr)) { goto done; }
hr = m_pWriter->WriteSample(0, pSample);
goto done;
done:
return hr;
SafeRelease(&pSample);
LeaveCriticalSection(&m_critsec);
}
The value of hr is an exception code: 0xc00d3704 so the code snippet skips the call to WriteSample.
It is a lot of steps, but I am fairly certain that I am setting up m_pReader (type IMFSource *) correctly.
HRESULT WinCapture::OpenMediaSource(IMFMediaSource *pSource)
{
HRESULT hr = S_OK;
IMFAttributes *pAttributes = NULL;
hr = MFCreateAttributes(&pAttributes, 2);
// use a callback
//if (SUCCEEDED(hr))
//{
// hr = pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this);
//}
// set the desired format type
DWORD dwFormatIndex = (DWORD)formatIdx;
IMFPresentationDescriptor *pPD = NULL;
IMFStreamDescriptor *pSD = NULL;
IMFMediaTypeHandler *pHandler = NULL;
IMFMediaType *pType = NULL;
// create the source reader
if (SUCCEEDED(hr))
{
hr = MFCreateSourceReaderFromMediaSource(
pSource,
pAttributes,
&m_pReader
);
}
// steps to set the selected format type
hr = pSource->CreatePresentationDescriptor(&pPD);
if (FAILED(hr))
{
goto done;
}
BOOL fSelected;
hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD);
if (FAILED(hr))
{
goto done;
}
hr = pSD->GetMediaTypeHandler(&pHandler);
if (FAILED(hr))
{
goto done;
}
hr = pHandler->GetMediaTypeByIndex(dwFormatIndex, &pType);
if (FAILED(hr))
{
goto done;
}
hr = pHandler->SetCurrentMediaType(pType);
{
goto done;
}
hr = m_pReader->SetCurrentMediaType(
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
NULL,
pType
);
// set to maximum framerate?
hr = pHandler->GetCurrentMediaType(&pType);
if (FAILED(hr))
{
goto done;
}
// Get the maximum frame rate for the selected capture format.
// Note: To get the minimum frame rate, use the
// MF_MT_FRAME_RATE_RANGE_MIN attribute instead.
PROPVARIANT var;
if (SUCCEEDED(pType->GetItem(MF_MT_FRAME_RATE_RANGE_MAX, &var)))
{
hr = pType->SetItem(MF_MT_FRAME_RATE, var);
PropVariantClear(&var);
if (FAILED(hr))
{
goto done;
}
hr = pHandler->SetCurrentMediaType(pType);
{
goto done;
}
hr = m_pReader->SetCurrentMediaType(
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
NULL,
pType
);
}
goto done;
done:
SafeRelease(&pPD);
SafeRelease(&pSD);
SafeRelease(&pHandler);
SafeRelease(&pType);
SafeRelease(&pAttributes);
return hr;
}
This code is all copied from Microsoft documentation pages and the SDK sample code. The variable formatIdx is 0, I get it from enumerating the camera formats and choosing the first one.
UPDATE
I have rewritten this program so that it uses callbacks instead of a blocking read/write function and I have exactly the same issue.
Here I get the device and initiate the callback method:
HRESULT WinCapture::initCapture(const WCHAR *pwszFileName, IMFMediaSource *pSource) {
HRESULT hr = S_OK;
EncodingParameters params;
params.subtype = MFVideoFormat_WMV3; // TODO, paramterize this
params.bitrate = TARGET_BIT_RATE;
m_llBaseTime = 0;
IMFMediaType *pType = NULL;
DWORD sink_stream = 0;
EnterCriticalSection(&m_critsec);
hr = m_ppDevices[selectedDevice]->ActivateObject(IID_PPV_ARGS(&pSource));
//m_bIsCapturing = false; // this is set externally here
if (SUCCEEDED(hr))
hr = OpenMediaSource(pSource); // also creates the reader
if (SUCCEEDED(hr))
{
hr = m_pReader->GetCurrentMediaType(
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
&pType
);
}
// Create the sink writer
if (SUCCEEDED(hr))
{
hr = MFCreateSinkWriterFromURL(
pwszFileName,
NULL,
NULL,
&m_pWriter
);
}
if (SUCCEEDED(hr))
hr = ConfigureEncoder(params, pType, m_pWriter, &sink_stream);
// kick off the recording
if (SUCCEEDED(hr))
{
m_llBaseTime = 0;
m_bIsCapturing = TRUE;
hr = m_pReader->ReadSample(
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
0,
NULL,
NULL,
NULL,
NULL
);
}
SafeRelease(&pType);
SafeRelease(&pSource);
pType = NULL;
LeaveCriticalSection(&m_critsec);
return hr;
}
The OpenMediaSource method is here:
HRESULT WinCapture::OpenMediaSource(IMFMediaSource *pSource)
{
HRESULT hr = S_OK;
IMFAttributes *pAttributes = NULL;
hr = MFCreateAttributes(&pAttributes, 2);
// use a callback
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this);
}
// set the desired format type
DWORD dwFormatIndex = (DWORD)formatIdx;
IMFPresentationDescriptor *pPD = NULL;
IMFStreamDescriptor *pSD = NULL;
IMFMediaTypeHandler *pHandler = NULL;
IMFMediaType *pType = NULL;
// create the source reader
if (SUCCEEDED(hr))
{
hr = MFCreateSourceReaderFromMediaSource(
pSource,
pAttributes,
&m_pReader
);
}
// steps to set the selected format type
if (SUCCEEDED(hr)) hr = pSource->CreatePresentationDescriptor(&pPD);
if (FAILED(hr))
{
goto done;
}
BOOL fSelected;
hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD);
if (FAILED(hr))
{
goto done;
}
hr = pSD->GetMediaTypeHandler(&pHandler);
if (FAILED(hr))
{
goto done;
}
hr = pHandler->GetMediaTypeByIndex(dwFormatIndex, &pType);
if (FAILED(hr))
{
goto done;
}
hr = pHandler->SetCurrentMediaType(pType);
if (FAILED(hr))
{
goto done;
}
// get available framerates
hr = MFGetAttributeRatio(pType, MF_MT_FRAME_RATE, &frameRate, &denominator);
std::cout << "frameRate " << frameRate << " denominator " << denominator << std::endl;
hr = m_pReader->SetCurrentMediaType(
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
NULL,
pType
);
// set to maximum framerate?
hr = pHandler->GetCurrentMediaType(&pType);
if (FAILED(hr))
{
goto done;
}
goto done;
done:
SafeRelease(&pPD);
SafeRelease(&pSD);
SafeRelease(&pHandler);
SafeRelease(&pType);
SafeRelease(&pAttributes);
return hr;
}
Here, formatIdx is a field of this class that get sets by the user via the GUI. I leave it 0 in order to test. So, I don't think I am missing any steps to get the camera going, but maybe I am.
When I inspect what applications are using the webcam (using this method) after the call to ActivateObject, I see that my application is using the webcam as expected. But, when I enter the callback routine, I see there are two instances of my application using the webcam. This is the same using a blocking method.
I don't know if that is good or bad, but when I enter my callback method:
HRESULT WinCapture::OnReadSample(
HRESULT hrStatus,
DWORD /*dwStreamIndex*/,
DWORD /*dwStreamFlags*/,
LONGLONG llTimeStamp,
IMFSample *pSample // Can be NULL
)
{
EnterCriticalSection(&m_critsec);
if (!IsCapturing() || m_bIsCapturing == false)
{
LeaveCriticalSection(&m_critsec);
return S_OK;
}
HRESULT hr = S_OK;
if (FAILED(hrStatus))
{
hr = hrStatus;
goto done;
}
if (pSample)
{
if (m_bFirstSample)
{
m_llBaseTime = llTimeStamp;
m_bFirstSample = FALSE;
}
// rebase the time stamp
llTimeStamp -= m_llBaseTime;
hr = pSample->SetSampleTime(llTimeStamp);
if (FAILED(hr)) { goto done; }
hr = m_pWriter->WriteSample(0, pSample);
if (FAILED(hr)) { goto done; }
}
// Read another sample.
hr = m_pReader->ReadSample(
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
0,
NULL, // actual
NULL, // flags
NULL, // timestamp
NULL // sample
);
done:
if (FAILED(hr))
{
//NotifyError(hr);
}
LeaveCriticalSection(&m_critsec);
return hr;
}
hrStatus is the 0x00d3704 error I was getting before, and the callback goes straight to done thus killing the callbacks.
Finally, I should say that I am modeling (read, 'copying') my code from the example MFCaptureToFile in the Windows SDK Samples and that doesn't work either. Although, there I get this weird negative number for the failed HRESULT: -1072875772.
If you have got error [0xC00D3704] - it means that source does not initialized. Such error can be caused by mistake of initialization, busy camera by another application (process) or unsupport of the camera by UVC driver(old cameras support DirectShow driver with partly compatibleness with UVC. It is possible read some general info from old cameras via UVC as friendly name, symbolic link. However, old cameras support DirectShow models - PUSH, while camera pushes bytes into the pipeline, while Media Foundation PULL data - sends special signal and wait data).
For checking your code I would like advise to research articles about capturing video from web cam on site "CodeProject" - search "videoInput" name.

How I can show "Local Area Connection" properties dialog

I should show the "Local Area Connection" properties dialog (it is the dialog which has two tabs Networking and Sharing) from my program.
How I can do it?
Now I use this function:
void ShowPropertiesDialog(INetConnection * pConn)
{
HRESULT hr = S_OK;
CLSID clsid;
CComPtr<INetCfg> pNetCfg;
if (SUCCEEDED(pConn->GetUiObjectClassId(&clsid)))
{
CComPtr<IUnknown> pUnk;
if(SUCCEEDED(pUnk.CoCreateInstance(clsid)))
{
CComPtr<INetConnectionPropertyUi> pNetConnectionPropertyUi;
hr = pUnk->QueryInterface(IID_INetConnectionPropertyUi, (void**)&pNetConnectionPropertyUi);
hr = pNetConnectionPropertyUi->SetConnection(pConn);
hr = pNetCfg.CoCreateInstance(CLSID_CNetCfg);
if (SUCCEEDED(hr))
{
CComPtr<INetCfgLock> pNetCfgLock;
hr = pNetCfg->QueryInterface(IID_INetCfgLock, (void**)&pNetCfgLock);
if (SUCCEEDED(hr))
{
hr = pNetCfgLock->AcquireWriteLock(15000, TEXT("MY CLIENT"), NULL);
if (SUCCEEDED(hr))
{
hr = pNetCfg->Initialize(NULL);
if (SUCCEEDED(hr))
{
CComPtr<INetCfgComponent> pTcpIp;
if (SUCCEEDED(pNetCfg->FindComponent(NETCFG_TRANS_CID_MS_TCPIP, &pTcpIp)))
{
hr = pTcpIp->RaisePropertyUi(GetConsoleWindow(), NCRP_SHOW_PROPERTY_UI, pNetConnectionPropertyUi);
}
pNetCfg->Uninitialize();
}
pNetCfgLock->ReleaseWriteLock();
}
}
pNetCfg.Release();
}
}
}
}
use:
hr = pENConnection->Next(1, &pConn, &ulCount);
....
hr = pConn->GetProperties(&pProps);
if (pProps->MediaType == NCM_LAN)
{
ShowPropertiesDialog(pConn);
}
but RaisePropertyUi always returned E_NOINTERFACE :(
Thanks.

DirectShow BindToObject returning invalid handle

EDIT
Just tested playcap.cpp and I'm also getting the same error so I know it's a not a fault with my code.
--
EDIT 2
Edited my code to preserve the goodMoniker pointer. Same error, however.
+if(pMoniker != goodMoniker)
+{
pMoniker->Release();
+}
--
Having a problem with getting my webcam to work with DirectShow. This line:
hr = goodMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)(&pCap));
returns the following error from MSVC++ 2010 EE:
First-chance exception at 0x777ff9d2 in WebcamControlTest.exe: 0xC0000008: An invalid handle was specified.
Full code here (ripped almost completely from MSDN):
#include <DShow.h>
#include <iostream>
int main(void)
{
IGraphBuilder* pGraph = NULL;
ICaptureGraphBuilder2* pBuild = NULL;
HRESULT hr;
//Initialize pGraph
hr = CoInitialize(NULL);
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**) &pBuild);
if(FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return 1;
}
//Initialize pBuild
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 2;
}
pBuild->SetFiltergraph(pGraph);
//Initialize pCap
ICreateDevEnum* pDevEnum = NULL;
IEnumMoniker* pEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&pDevEnum));
if(SUCCEEDED(hr))
{
hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
}
IMoniker* goodMoniker = NULL;
HWND hList;
IMoniker *pMoniker = NULL;
while(pEnum->Next(1, &pMoniker, NULL) == S_OK)
{
IPropertyBag* pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag));
if(FAILED(hr))
{
pMoniker->Release();
continue;
}
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"Description", &varName, 0);
if(FAILED(hr))
{
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
}
if(SUCCEEDED(hr))
{
for(int i=0;i<8;i++)
{
std::cout<<(char)*(varName.bstrVal + i);
}
char yn;
std::cin>>yn;
if(yn=='Y')
{
std::cout<<"SUCCESSFUL"<<std::endl;
goodMoniker = pMoniker;
VariantClear(&varName);
}
}
pPropBag->Release();
if(pMoniker != goodMoniker)
{
pMoniker->Release();
}
}
IBaseFilter* pCap;
hr = goodMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)(&pCap));
if(SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pCap, L"Capture Filter");
}
hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCap, NULL, NULL);
while(SUCCEEDED(hr));
pGraph->Release();
pBuild->Release();
pCap->Release();
}
It might be a driver problem as there is one device that works (a virtual driver for screencapping and not actual webcam input) but I've updated, uninstalled and reinstalled to no luck. Any ideas?
After saving a pointer in goodMoniker you release the object a couple of lines below (pMoniker->Release() ). Now goodMoniker points to a released object. You should have increased its reference count.

Previewing Webcam using DirectShow

I keep getting "E_INVALIDARG" when calling RenderStream().
My program output is:
SUCCESS - Initialized COM library.
SUCCESS - Created the Filter Graph Manager.
SUCCESS - Created the Media Control and Media Event Interfaces.
SUCCESS - Enumerated devices.
--------------DEVICE INFORMATION--------------
Integrated Webcam
------------END DEVICE INFORMATION------------
SUCCESS - Bound to moniker.
Here is the code:
#include "stdafx.h"
#include <dshow.h> //direct show
#include <windows.h> //windows
#pragma comment(lib,"Strmiids.lib") //used for direct show
HRESULT 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 EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
// Create the System Device Enumerator.
ICreateDevEnum *pDevEnum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
if (SUCCEEDED(hr))
{
// Create an enumerator for the category.
hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
if (hr == S_FALSE)
{
hr = VFW_E_NOT_FOUND; // The category is empty. Treat as an error.
}
pDevEnum->Release();
}
return hr;
}
void DisplayDeviceInformation(IEnumMoniker *pEnum, IMoniker** pMoniker)
{
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("%S\n", var.bstrVal);
if(0 == wcscmp(var.bstrVal, L"Integrated Webcam"))
{
VariantClear(&var);
pPropBag->Release();
return;
}
VariantClear(&var);
}
hr = pPropBag->Write(L"FriendlyName", &var);
pPropBag->Release();
}
}
void main()
{
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
IGraphBuilder *pGraph = NULL;
ICaptureGraphBuilder2 *pBuild = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library\n");
return;
}
printf("SUCCESS - Initialized COM library.\n");
hr = InitCaptureGraphBuilder(&pGraph, &pBuild);
if (FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.\n");
return;
}
printf("SUCCESS - Created the Filter Graph Manager.\n");
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
if (FAILED(hr))
{
printf("ERROR - Could not create the Media Control or Media Event Interfaces.\n");
return;
}
printf("SUCCESS - Created the Media Control and Media Event Interfaces.\n");
IEnumMoniker *pEnum;
hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
if(FAILED(hr))
{
printf("ERROR - Failed to enumerate devices.\n");
return;
}
printf("SUCCESS - Enumerated devices.\n");
IMoniker* pMoniker = NULL;
printf("--------------DEVICE INFORMATION--------------\n");
DisplayDeviceInformation(pEnum, &pMoniker);
printf("------------END DEVICE INFORMATION------------\n");
IBaseFilter *pCap = NULL;
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if(FAILED(hr))
{
printf("ERROR - Failed to bind to moniker.\n");
return;
}
printf("SUCCESS - Bound to moniker.\n");
hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCap, NULL, NULL);
if(FAILED(hr))
{
printf("ERROR - RenderStream() failed.\n");
return;
}
printf("SUCCESS - RenderStream() succeeded.\n");
hr = pControl->Run();
if(FAILED(hr))
{
printf("ERROR - Run() failed.\n");
return;
}
printf("SUCCESS - Running.\n");
long evCode;
hr = pEvent->WaitForCompletion(INFINITE, &evCode);
if(FAILED(hr))
{
printf("ERROR - WaitForCompletion() failed.\n");
return;
}
hr = pControl->Stop();
if(FAILED(hr))
{
printf("ERROR - Stop() failed.\n");
return;
}
printf("SUCCESS - Stopping.\n");
pControl->Release();
pEvent->Release();
pGraph->Release();
pMoniker->Release();
pEnum->Release();
CoUninitialize();
}
Before using RenderStream you need to IGraphBuilder::AddFilter your camera filter to the graph.