c++windowsopencvdirectshowvfw

How to show Video capture Filter dialog (camera settings like brightness, exposure)?


I am doing a windows based app where I use a camera. I want to allow the user to change camera settings (VfwCaptureDialog_Source) as it is common in skype or amcap application. For now, I found out that the dialog is from vfw and it can be activated from dshow api. When I do it from AmCap, it is working. Can you help me to get this code working for given webcam (multiple camera support is required)? I use Qt and OpenCV while working with camera. In opencv just camera index is used to select proper camera. The index is from Qt where can I get nice list of camera names. The error I get from this code is 1170 : "The property set specified does not exist on the object"

//libs -lDxva2 -lstrmiids -lvfw32 -lole32 -loleaut32
#include <Windows.h>
#include "strmif.h"
#include "dshow.h"
#include "Vfw.h"

...

HRESULT hr ;
IGraphBuilder*  graph= nullptr;
hr = CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,IID_IGraphBuilder, (void **)&graph );
IMediaControl*  ctrl = nullptr;
hr = graph->QueryInterface( IID_IMediaControl, (void **)&ctrl );
IMediaEventEx*  mediaEvent=nullptr;
hr = graph->QueryInterface(IID_IMediaEvent, (LPVOID *) &mediaEvent);
ICreateDevEnum* devs = nullptr;
hr = CoCreateInstance (CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &devs);
IEnumMoniker*   cams = nullptr;
hr = devs?devs->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &cams, 0):0;
IMoniker*       mon  = nullptr;
hr = cams?cams->Next (1, &mon, nullptr):0;
IBaseFilter*    cam  = nullptr;
hr = mon?mon->BindToObject(nullptr,nullptr,IID_IBaseFilter, (void**)&cam):0;
IEnumPins*      pins = nullptr;
hr = cam?cam->EnumPins(&pins):0;
IPin*           cap  = nullptr;
hr = pins?pins->Next(1,&cap, nullptr):0;

IAMVfwCaptureDialogs *pVfw = nullptr;
hr = cap->QueryInterface(IID_IAMVfwCaptureDialogs, (void**)&pVfw);

if (SUCCEEDED(hr))
{
    // Check if the device supports this dialog box.
    if (S_OK == pVfw->HasDialog(VfwCaptureDialog_Source))
    {
        // Show the dialog box.
        hr = pVfw->ShowDialog(VfwCaptureDialog_Source, HWND(this->winId()));
    }
}
else
{
    error("cap->QueryInterface");
} 

Solution

  • First of all, you skipped a really important part. In your Qt/OpenCV application what is the API used and what exactly you have for given web camera. If it is Video for Windows, then you should look into VFW API on dialog interface. If it is DirectShow then you are basically not interested in VFW dialogs.

    Presumably you interact with cameras via DirectShow (well, it does not make much sense to use VFW, esp. for multiple cameras). Then I doubt that AMCap uses exactly the code path you mentioned in the question. Note AMCap source comment:

    // we use this interface to bring up the 3 dialogs
    // NOTE:  Only the VfW capture filter supports this.  This app only brings
    // up dialogs for legacy VfW capture drivers, since only those have dialogs
    hr = gcap.pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
                                      &MEDIATYPE_Video, gcap.pVCap,
                                      IID_IAMVfwCaptureDialogs, (void **)&gcap.pDlg);
    

    With DirectShow you would typically pop up configuration interface with ISpecifyPropertyPages and OleCreatePropertyFrame. AMCap has relevant code for this as well:

            else if(id - MENU_DIALOG0 == gcap.iVCapDialogPos)
            {
                ISpecifyPropertyPages *pSpec;
                CAUUID cauuid;
    
                hr = gcap.pVCap->QueryInterface(IID_ISpecifyPropertyPages,
                    (void **)&pSpec);
                if(hr == S_OK)
                {
                    hr = pSpec->GetPages(&cauuid);
    
                    hr = OleCreatePropertyFrame(ghwndApp, 30, 30, NULL, 1,
                        (IUnknown **)&gcap.pVCap, cauuid.cElems,
                        (GUID *)cauuid.pElems, 0, 0, NULL);
    
                    CoTaskMemFree(cauuid.pElems);
                    pSpec->Release();
                }
            }
    

    Displaying a Filter's Property Pages on MSDN should be even of more help for you (you already have IBaseFilter interface pointer in your code snippet in the question).