Directshow RenderStream “the parameter is incorrect”

我怕爱的太早我们不能终老 提交于 2019-12-12 04:56:41

问题


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

When the below code runs it fails on the first RenderStream call with the error: + errMsg 0x09910DB8 "The parameter is incorrect." wchar_t*

Does anybody have any clue how to figure out which parameter is incorrect?

void AudioVideoBuilder::AVBuilder::MakeVideo()
{
    IGraphBuilder *pGraph = NULL;
    ICaptureGraphBuilder2 *pBuild = NULL;

    // Create the Filter Graph Manager.
    HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
        CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);

    if (SUCCEEDED(hr))
    {
        // Create the Capture Graph Builder.
        hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
            CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,
            (void **)&pBuild);
        if (SUCCEEDED(hr))
        {
            pBuild->SetFiltergraph(pGraph);
        }
    };
    if (SUCCEEDED(hr))
    {
        // Create the Capture Graph Builder.
        hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,
            NULL,
            CLSCTX_INPROC_SERVER,
            IID_ICaptureGraphBuilder2,
            (void**)&pBuild);
        IBaseFilter *pMux;
        if (SUCCEEDED(hr))
        {
            hr = pBuild->SetOutputFileName(
                &MEDIASUBTYPE_Avi,  // Specifies AVI for the target file.
                L"C:\\Temp\\Example.avi", // File name.
                &pMux,              // Receives a pointer to the mux.
                NULL);              // (Optional) Receives a pointer to the file sink.

            if (SUCCEEDED(hr))
            {
                IBaseFilter *audioFilter;
                IBaseFilter *videoFilter;
                //GetAudioAndVideoFilters(audioFilter, videoFilter);

                IEnumMoniker *pEnum;
                CaptureDeviceSelector deviceSelector;
                HRESULT hr = deviceSelector.EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
                if (SUCCEEDED(hr))
                {
                    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 (var == "screen-capture-recorder")
                        hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&videoFilter);
                        if (SUCCEEDED(hr))
                        {
                            break;
                        }
                    }
                    hr = deviceSelector.EnumerateDevices(CLSID_AudioInputDeviceCategory, &pEnum);
                    if (SUCCEEDED(hr))
                    {
                        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);
                            }
                            hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&audioFilter);
                            if (SUCCEEDED(hr))
                            {
                                break;
                            }
                        }
                    }
                }
                            //ADDED BASED ON MARTIN'S SUGGESTED ANSWER
            hr = pGraph->AddFilter(audioFilter, NULL);
            if (FAILED(hr))
            {
                _com_error err(hr);
                LPCTSTR errMsg = err.ErrorMessage();
                return;
            }
            hr = pGraph->AddFilter(videoFilter, NULL);
            if (FAILED(hr))
            {
                _com_error err(hr);
                LPCTSTR errMsg = err.ErrorMessage();
                return;
            }       
                hr = pBuild->RenderStream(
                    &PIN_CATEGORY_CAPTURE, // Pin category.
                    &MEDIATYPE_Audio,      // Media type.
                    audioFilter,                  // Capture filter.
                    NULL,                  // Intermediate filter (optional).
                    pMux);                 // Mux or file sink filter.

                if (SUCCEEDED(hr))
                {
                    hr = pBuild->RenderStream(
                        &PIN_CATEGORY_CAPTURE, // Pin category.
                        &MEDIATYPE_Video,      // Media type.
                        videoFilter,                  // 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();
                    }
                }
                else
                {
                    _com_error err(hr); 
                    LPCTSTR errMsg = err.ErrorMessage();
                }
            }
            else
            {
                DWORD error = HRESULT_CODE(hr);
            }
        }
    }
    else
    {
        DWORD error = HRESULT_CODE(hr);
    }
}

回答1:


Apart from other issues in your code (see comments), the primary problem is copy/paste problem: you create CLSID_CaptureGraphBuilder2 twice.

So you create the object first and associate it with your filter graph, and then you create the other one. You add source filters to the first graph, and you request multiplexer filter chain to be created in the other. Those definitely cannot connect, belong to different graphs and hence the error.

Comment the second section, and you can move on:

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

Since you are going to deal with DirectShow filter graphs for some time, I suggest that you learn how to explore your graphs on runtime using GraphEdit (or, I would rather recommend GraphStudioNext instead).

  • How can I reverse engineer a DirectShow graph?

You can add a MessageBox call at any point in your code and keeping the message window popped up you would look at graphs in your application and see the problem immediately.




回答2:


I am not used to RenderStream as I preferred building the Graph by hand. But for all Render methods you have to add the filter before rendering the graph. I think that includes RenderStream even it is not explicit pointed out in:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd390016(v=vs.85).aspx

Use

 pGraph->AddFilter(audioFilter,NULL);

before RenderStream . Of course do that also for video.

I strongly recommend that you at least change the error checking from

if(SUCCEED(hr))
{
// do stuff
    if(SUCCEED(hr))
    {
    // do stuff
        if(SUCCEED(hr))
        {
        // do stuff

        }
   }
}

to

// do stuff
if(FAILED(hr))
 return;
// do stuff
if(FAILED(hr))
 return;
// do stuff
if(FAILED(hr))
 return;

it is more readable.



来源:https://stackoverflow.com/questions/29670733/directshow-renderstream-the-parameter-is-incorrect

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!