Previewing Webcam using DirectShow - c++

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.

Related

Failed to get IAMStreamConfig interface

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.

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.

How to write an avi file with DirectShow

I'm trying to write an avi video file based on the streaming of my Decklink SDI card, after looking in the internet and here I wrote this code by my problem is that the program doesn't write the file here 's the code:
#include <Windows.h>
#include <DShow.h>
#include <iostream>
int main(void)
{
IGraphBuilder* pGraph = NULL;
ICaptureGraphBuilder2* pBuild = NULL;
IMediaControl* pControl = NULL;
ICreateDevEnum* pDevEnum = NULL;
IEnumMoniker* pEnum = NULL;
IMoniker *pMoniker = NULL;
IMoniker* goodMoniker = NULL;
IBaseFilter* pCap;
HRESULT hr;
//Initialize pGraph
hr = CoInitialize(NULL);
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **) &pGraph);
if(FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return 1;
}
//Initialize pBuild
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**) &pBuild);
if(FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
return 2;
}
pBuild->SetFiltergraph(pGraph);
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&pDevEnum));
if(SUCCEEDED(hr))
{
hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
}
HWND hList;
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<20;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();
}
}
hr = goodMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)(&pCap));
if(SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pCap, L"Capture Filter");
}
IBaseFilter *pMux = NULL;
// hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCap, NULL, NULL);
hr = pBuild->SetOutputFileName(
&MEDIASUBTYPE_Avi, // Specifies AVI for the target file.
L"C:\\stuff.avi", // File name.
&pCap, // Receives a pointer to the mux.
NULL); // (Optional) Receives a pointer to the file sink.
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.
hr = pCap->QueryInterface(IID_IMediaControl,(void**) pControl);
printf("START ");
hr = pControl->Run();
Sleep(100000);
hr = pControl->Stop();
CoUninitialize();
pGraph->Release();
pBuild->Release();
pCap->Release();
}
here is the error message that I get when I try to debbug it :
Unhandled exception at 0x776015de in STREAMMMMM.exe: 0xC0000005: Access violation reading location 0x00000000.
the program crashes in this line :
r = pCap->QueryInterface(IID_IMediaControl,(void**) pControl);
There are tens, if not hundreds, of examples on how to write into AVI with DirectShow on Internet.
This particular code snippet does not even start writing. It only prepares the pipeline and you are not even doing IMediaControl::Run, what you are supposed to do. Further on, you should wait until you wrote enough, and then stop recording and only then release the interface pointers.
Have a look at this Q: Using a DirectShow filter without registering it, via a private CoCreateInstance on what you are missing to start actual capture and writing (IMediaControl::Run and Sleep in particular).

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.

How to get a list of video capture devices (web cameras) on windows? (C++)

So we have a simple C++ win32 console app. All we want is to print list of web cameras and other video capture devices that are avaliable. We want to use windows apis as much as possible - no external libs - after all - all we want is to print out a a list - not to fly onto the moon!) How to do such thing?
My own reserch:
I found this official msdn sample but I still do not get how to output device list onto screen=( (sorry - I am new to C++)
... some more reserch...
In one of simpliest ms samples on topic found this
HRESULT OnInitDialog(HWND hwnd, ChooseDeviceParam *pParam)
{
HRESULT hr = S_OK;
HWND hList = GetDlgItem(hwnd, IDC_DEVICE_LIST);
// Display a list of the devices.
for (DWORD i = 0; i < pParam->count; i++)
{
WCHAR *szFriendlyName = NULL;
hr = pParam->ppDevices[i]->GetAllocatedString(
MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
&szFriendlyName,
NULL
);
if (FAILED(hr))
{
break;
}
int index = ListBox_AddString(hList, szFriendlyName);
ListBox_SetItemData(hList, index, i);
CoTaskMemFree(szFriendlyName);
}
looks like it should do the job but I do not get how to include this into simple command line app so to output data...
also from this series:
How to get a list of video capture devices on linux? and special details on getting cameras NAMES with correct, tested answers
How to get a list of video capture devices on Mac OS? with correct, not yet tested by my answers
How to get a list of video capture devices on windows? with correct, tested answers
How to get a list video capture devices NAMES using Qt (crossplatform)?
From the examples shown, copy the following code into dev.c. Then open the command line with all the SDK variables set. At the command line link to ole32.lib and oleaut32.lib. It will then show you all the devices.
cl dev.c ole32.lib oleaut32.lib
dev.exe will give out the list on the command line.
#include <windows.h>
#include <dshow.h>
#pragma comment(lib, "strmiids")
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 = NULL;
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);
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("WaveIn ID: %d\n", var.lVal);
VariantClear(&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);
}
pPropBag->Release();
pMoniker->Release();
}
}
void main()
{
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
IEnumMoniker *pEnum;
hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
if (SUCCEEDED(hr))
{
DisplayDeviceInformation(pEnum);
pEnum->Release();
}
hr = EnumerateDevices(CLSID_AudioInputDeviceCategory, &pEnum);
if (SUCCEEDED(hr))
{
DisplayDeviceInformation(pEnum);
pEnum->Release();
}
CoUninitialize();
}
}
How to let user select a video recording device (web-cam) with OpenCV?
the answer isnt opencv specific
Here is C++ code to list connected webcams on a windows machine without any additional libraries
/* List connected webcams on windows machine
Build: g++ cameralist.cpp -lstrmiids -lole32 -loleaut32
microsoft docs https://learn.microsoft.com/en-us/windows/win32/directshow/using-the-system-device-enumerator
*/
#include <windows.h>
#include <dshow.h>
HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
// Create the System Device Enumerator.
HRESULT hr;
ICreateDevEnum *pDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void **)&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 = NULL;
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);
VariantClear(&var);
}
hr = pPropBag->Write(L"FriendlyName", &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);
}
pPropBag->Release();
pMoniker->Release();
}
}
int main()
{
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
IEnumMoniker *pEnum;
hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
if (SUCCEEDED(hr))
{
DisplayDeviceInformation(pEnum);
pEnum->Release();
}
CoUninitialize();
}
return 0;
}