0
votes

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.)

1
1) Defined what you mean "doesn't work". Does it fail? If so, what is the error code? 2) Suggestion: consider using CComPtr, instead of naked pointers, so you wouldn't need to manage reference counting manually.Algirdas Preidžius
1) Edited post to include error message. 2) Good point, I've never used CComPtr but will i future - was using the above code as a scratchpad to try and learn DirectShow.DontBurnTheEwok
Shouldn't SetMode be called before Run? (just guessing)VuVirt
Apparently not - according to the MS Docs anyway. I tried using SetMode before running the graph to see what happened but got the same results - pAMVidControl->SetMode(pPin, VideoControlFlag_Trigger) failed.DontBurnTheEwok

1 Answers

0
votes

i have seen you query and you have to do lot of work to capture still frame.

After you enumerate the still pin, you should connect with sample grabber and null render into camera still pin.

After building and run the graph, you should trigger still mode and the frame will be received in the grabber.

then you can do with the frame whatever you wants.