I am trying to get an image from the still pin of my camera using directshow (the framework the camera maker has suggested using).
I've been following the DirectShow MS documentation on https://docs.microsoft.com/en-gb/windows/desktop/DirectShow/capturing-an-image-from-a-still-image-pin and although I can find a still pin using the ICaptureGraphBuilder2::FindPin method and have confirmed that the pin exists on the camera using graphedit app, I've hit a brick wall in using the IAMVideoControl::SetMode method to change pin.
The code that I'm using is below:
HRESULT hr = CoInitializeEx(NULL, COINIT::COINIT_MULTITHREADED);
if (FAILED(hr))
Console::WriteLine("Initialise Failed");
else
Console::WriteLine("Initialise Success");
//Initalise graph builder
ICaptureGraphBuilder2 *pBuild;
IGraphBuilder *pGraph;
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&pBuild);
if (FAILED(hr))
Console::WriteLine("Graph builder failed");
else
Console::WriteLine("Graph builder success");
//Create filter graph
hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&pGraph);
if (SUCCEEDED(hr))
{
pBuild->SetFiltergraph(pGraph);
Console::WriteLine("Set filter graph success");
}
else
{
pBuild->Release();
Console::WriteLine("Set filter graph failed");
}
// Create the System Device Enumerator.
ICreateDevEnum *pDevEnum;
IEnumMoniker *pDevicesInfo;
HRESULT hr2 = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
if (SUCCEEDED(hr2))
{
Console::WriteLine("Device enum builder success");
// Create an enumerator for the video category.
hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pDevicesInfo, 0);
if (hr == S_FALSE)
Console::WriteLine("Retrieve video input devices failed");
else
Console::WriteLine("Retrieve video input devices success");
pDevEnum->Release();
}
//loop over video devices and find see3cam_130
IMoniker *pMoniker = NULL;
while (pDevicesInfo->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"FriendlyName", &var, 0);
if (SUCCEEDED(hr))
{
Console::WriteLine("Found video device");
//If correct device, break loop
if (0 == wcscmp(var.bstrVal, L"See3CAM_130"))
{
Console::WriteLine("See3CAM_130");
break;
}
else
{
Console::WriteLine("Comparison failed");
}
printf("%S\n", var.bstrVal);
VariantClear(&var);
}
else
{
Console::WriteLine("Vid Device failed");
}
}
//Create filter for device
IBaseFilter *pCap = NULL;
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if (SUCCEEDED(hr))
{
Console::WriteLine("Filter created");
hr = pGraph->AddFilter(pCap, L"Capture Filter");
if (SUCCEEDED(hr))
{
Console::WriteLine("Capture filter added to filter graph");
}
else
{
Console::WriteLine("Capture filter NOT added to filter graph");
}
}
else
Console::WriteLine("Filter failed");
//Render capture pin first before attempting to set still pin (setting still pin fails with ot without this step)
hr = pBuild->RenderStream(
&PIN_CATEGORY_CAPTURE, // Pin category.
&MEDIATYPE_Video, // Media type.
pCap, // Capture filter.
NULL, // Intermediate filter (optional).
NULL); // Mux or file sink filter.
if (SUCCEEDED(hr))
Console::WriteLine("Stream Render success");
else
Console::WriteLine("Stream Render failed");
//Create a control to run graph
IMediaControl *pControl;
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
if (FAILED(hr))
Console::WriteLine("Graph initalised - Failed");
else
Console::WriteLine("Graph initalised - Success");
// Run the graph.
while (1)
{
hr = pControl->Run();
if (FAILED(hr))
Console::WriteLine("Graph run - Failed");
else
{
Console::WriteLine("Graph run - Success");
break;
}
}
//Find the still pin
IAMVideoControl *pAMVidControl = NULL;
hr = pCap->QueryInterface(IID_IAMVideoControl, (void**)&pAMVidControl);
if (SUCCEEDED(hr))
{
Console::WriteLine("Video Control Initialised - Success");
IPin *pPin = NULL;
hr = pBuild->FindPin(
pCap, // Filter.
PINDIR_OUTPUT, // Look for an output pin.
&PIN_CATEGORY_STILL, // Pin category.
NULL, // Media type (don't care).
FALSE, // Pin must be unconnected.
0, // Get the 0'th pin.
&pPin // Receives a pointer to thepin.
);
if (SUCCEEDED(hr))
{
Console::WriteLine("Find pin - Success");
hr = pAMVidControl->SetMode(pPin, VideoControlFlag_Trigger);
if (FAILED(hr))
Console::WriteLine("Pin Mode Set - Failed");
else
Console::WriteLine("Pin Mode Set - Success");
pPin->Release();
}
else
Console::WriteLine("Find pin - Failed");
}
else
Console::WriteLine("Video Control Initialised - Failed");
Everything succeeds until I try to use the SetMode method and I've no clue as to why...
I'm still a junior developer and quite inexperienced in c++ so I suspect I've missed a step somewhere. I've considered using the directshow.net wrapper but I don't want to waste the time I've spent getting this far.
Any hints on why IAMVideoControl::SetMode method fails in my code?
Note: The HResult error is ERROR_GEN_FAILURE (May be used to indicate that the device has stopped responding (hung) or a general failure has occurred on the device. The device may need to be manually reset.)
CComPtr
, instead of naked pointers, so you wouldn't need to manage reference counting manually. – Algirdas Preidžius