2
votes

I'm trying to write a C++ application with directshow that saves video capture to file. The steps in the code are: 1. Create the Capture Graph Builder 2. Create the System Device Enumerator 3. Create the System Device Enumerator - in order to get capture filter 4. Create an enumerator for the video capture category 5. Create query to capture the video

Attaching the code

// gets the device filter
HRESULT getDeviceFilter(REFCLSID clsid, int order, IBaseFilter **pCap)
{

ICreateDevEnum *pDevEnum = NULL;
IEnumMoniker *pEnum = NULL;

// Create the System Device Enumerator.
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
                              CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
                              reinterpret_cast<void**>(&pDevEnum));

if (SUCCEEDED(hr))
{
    // Create an enumerator for the video capture category.
    hr = pDevEnum->CreateClassEnumerator( clsid, &pEnum, 0);
}

IMoniker *pMoniker = NULL;

if (pEnum->Next(1, &pMoniker, NULL) == S_OK)
    hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)pCap);

return hr;
}


int main()
{
IGraphBuilder *pGraph = 0;
ICaptureGraphBuilder2 *pBuild = 0;
IBaseFilter *pCap = 0;
HRESULT hr = CoInitialize(NULL);

// Create the Capture Graph Builder.
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, 
                              NULL, 
                              CLSCTX_INPROC_SERVER, 
                                  IID_ICaptureGraphBuilder2, 
                              (void**)&pBuild );


ICreateDevEnum *pDevEnum = NULL;
IEnumMoniker *pEnum = NULL;

// Create the System Device Enumerator.
hr = CoCreateInstance(CLSID_SystemDeviceEnum, 
                      NULL,
                      CLSCTX_INPROC_SERVER, 
                      IID_ICreateDevEnum,
                      reinterpret_cast<void**>(&pDevEnum));



IBaseFilter *pMux = 0;
hr = pBuild->SetOutputFileName(&MEDIASUBTYPE_Avi,  // Specifies AVI for the target file.
                               L"C:\\Example.avi", // File name.
                               &pMux,              //     Receives a pointer to the mux.
                               NULL);              //     (Optional) Receives a pointer to the file sink.


// gets the first device, VDM tv card
hr = getDeviceFilter(CLSID_VideoInputDeviceCategory, 0, &pCap);


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(1);
    pConfigMux->Release();
}

return 0;
}

However, upon calling RenderStream I get an E_INVALIDARG error

Any suggestions?

Thanks

1
Have you tried the suggestions in my answer?Rudey

1 Answers

1
votes

Take a look at this topic. It seems you have missed some steps.

First of all, you are not using pGraph anywhere. You should create a graph manager, and then initialize the graph builder by providing it with a pointer to the graph manager using SetFilterGraph.

// 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);

    // ...
}

Second, you are using filters that are not managed by a graph manager. Quoting from here:

All of the filters specified by pSource, pIntermediate, and pSink must be added to the graph prior to calling the method.

You will have to add the filters pCap and pMux to the graph manager you created earlier, using AddFilter. You should do this before calling RenderStream. This is so because RenderStream eventually calls connection methods on the manager.


If the above steps do not solve your problem, there are several other things you can try.

Device Filter. You are using the first device of CLSID_VideoInputDeviceCategory, but are you sure this is the correct device? Webcams and such are also included in this category. Make sure that there are no other devices of the same category connected, and try again.

Connection. Every device is different. It could be that your device can't be directly connected to the mux. In this case, we will have to figure out why, and determine whether you need to connect additional filters (like decoders). GraphEdit is a very fast way to find these filters.

Pin Category/Media Type. In my experience, E_INVALIDARG is 90% of the time caused by the first 2 parameters of RenderStream. Try setting the pin category or the media type to NULL.

System Device Enumerator: As you described yourself, you are creating a system device enumerator twice. This seems odd to me, why not use one, for both purposes?


If your code still does not work, you should provide me with more information. Have you achieved your goals when using GraphEdit? How does your VDM TV card filter look like (pins, media types)?