Directshow RenderStream & quot; параметр неверный & quot;

Я пытаюсь выполнить примеры DirectShow в центре разработки Windows, чтобы создать собственное приложение, которое может захватывать экран и аудио в видео: Захват видео в файл AVI

При выполнении приведенного ниже кода происходит сбой при первом вызове RenderStream с ошибкой:
+ errMsg 0x09910DB8 «Неверный параметр.» wchar_t *

Кто-нибудь знает, как определить, какой параметр неверен?

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

0

Решение

Помимо других проблем в вашем коде (см. Комментарии), основной проблемой является проблема копирования / вставки: вы создаете CLSID_CaptureGraphBuilder2 дважды.

Таким образом, вы сначала создаете объект и связываете его с графиком фильтра, а затем создаете другой. Вы добавляете исходные фильтры к первому графику и запрашиваете цепочку фильтров мультиплексора для создания другого. Те, кто определенно не может соединиться, принадлежат к различным графам и, следовательно, ошибка.

Прокомментируйте второй раздел, и вы можете двигаться дальше:

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

Поскольку вы собираетесь работать с графиками фильтра DirectShow в течение некоторого времени, я предлагаю вам научиться исследовать ваши графики во время выполнения с помощью GraphEdit (или я бы вместо этого рекомендовал GraphStudioNext).

Вы можете добавить MessageBox Звоните в любую точку своего кода и, удерживая окно сообщения открытым, вы посмотрите на графики в вашем приложении и сразу увидите проблему.

1

Другие решения

Я не привык RenderStream поскольку я предпочел строить График вручную. Но для всех методов рендеринга вы должны добавить фильтр перед рендерингом графика. Я думаю, что включает в себя RenderStream, даже если это явно не указано в:

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

использование

 pGraph->AddFilter(audioFilter,NULL);

до RenderStream. Конечно, сделайте это и для видео.

Я настоятельно рекомендую вам хотя бы изменить проверку ошибок с

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

}
}
}

в

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

это более читабельно.

0