问题
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