Я работаю над графом фильтра DirectShow для извлечения IMediaSample
из видеофайла. Мы получили оригинальную реализацию от разработчика по контракту некоторое время назад, и я бился головой об стену, пытаясь понять, почему этот код работает на моей машине разработки, а не на двух других тестовых серверах, которые у меня есть.
Насколько я могу судить, граф фильтра никогда не завершается на «сломанных» машинах. Я всегда получаю E_ABORT
от IMediaEvent->WaitForCompletion()
звонка. Однако на «рабочей» машине этот вызов обычно возвращает S_OK
примерно после двух циклов.
Обновление: DirectShow Spy, похоже, у меня не работает . Возможно, это потому, что у нас есть незарегистрированный (‹- Как предложенная перекачка сообщений решила эту проблему)CTransInPlaceFilter
обычай собирать IMediaSample
в цепочке? Ошибки нет, но и GraphEdit, и GraphStudio просто зависают при попытке подключиться к удаленному графу.
Используя GraphStudio, я смог получить подтип мультимедиа из декодера MPEG-4 который подключается к нашему CTransInPlaceFilter
. На моей машине это MEDIASUBTYPE_YV12
, но на "сломанной" машине это MEDIASUBTYPE_IYUV
. В методе CheckInputType
нашего CTransInPlaceFilter
мы принимаем только MEDIASUBTYPE_RGB24
, что наводит меня на мысль, что в график вставлен один или несколько «волшебных фильтров».
Обновление: Благодаря Роману Р. мне удалось наладить работу DirectShow Spy. По крайней мере на "битой" машине. На "работающей" машине я получаю нарушение прав доступа, но граф фильтра работает быстро и срывается, так что к нему сложно подключиться.
Я также обнаружил, что у нас есть преобразователь цветового пространства, который может обрабатывать MEDIASUBTYPE_IYUV
на MEDIASUBTYPE_RGB24
выход. Я добавил это на график, и теперь он должен быть правильным.
DirectShow Spy показывает это в виде графика фильтра (мне кажется, он завершен):
File Source -> MPEG Demux -> MPEG4 Decoder -> Color Space Converter -> CTransInPlaceFilter -> Null Render
Однако вызов IMediaEvent->WaitForCompletion()
никогда не возвращает S_OK
, и граф фильтра просто работает вечно. Так что теперь я не понимаю, что происходит. Есть ли что-нибудь еще, что я должен проверить на наличие ошибки или что-то в этом роде?
Обновление: я изменил цикл, чтобы перечислить фильтры на графике и запросить их состояние:
char debugString[512];
int count = 0;
long EvCode;
mediaFilter->SetSyncSource(NULL);
hr = mediaControl->Run();
sprintf(debugString, "mediaControl->Run() %d", hr);
DebugLog(debugString);
while (!m_ThreadKill)
{
hr = mediaEvent->WaitForCompletion(200, &EvCode);
sprintf(debugString, "mediaEvent->WaitForCompletion() %d, %d", hr, count);
DebugLog(debugString);
count++;
IEnumFilters *pEnum = NULL;
IBaseFilter *pFilter;
ULONG cFetched;
graphBuilder->EnumFilters(&pEnum);
while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)
{
FILTER_INFO FilterInfo;
FILTER_STATE FilterState;
char szName[256];
pFilter->GetState(200, &FilterState);
pFilter->QueryFilterInfo(&FilterInfo);
WideCharToMultiByte(CP_ACP, 0, FilterInfo.achName, -1, szName, 256, 0, 0);
sprintf(debugString, "Filter: %s, %d", szName, FilterState);
DebugLog(debugString);
SAFE_RELEASE(FilterInfo.pGraph);
SAFE_RELEASE(pFilter);
}
SAFE_RELEASE(pEnum);
if (hr == S_OK)
{
break;
}
}
sprintf(debugString, "mediaControl->Stop()");
DebugLog(debugString);
mediaControl->Stop();
Все они находятся в состоянии «Работает». Итак, если фильтры подключены правильно и все фильтры работают, почему график никогда не завершается на «сломанных» машинах?
Обновление: По предложению Романа Р. я удалил наш CTransInPlaceFilter
из графа фильтров на сломанной машине, и граф успешно завершился. При подключении CTransInPlaceFilter
загрузка ЦП падает до нуля. Итак, теперь я не уверен, почему следующий код работает на некоторых машинах, но не работает на других. Я начну добавлять журналы отладки в CTransInPlaceFilter
, чтобы попытаться выяснить, что происходит (или не происходит).
Решение. По предложению Романа Р. (я чувствую, что повторяю себя: P) проблема зашла в тупик. Все сломанные машины имели один процессор / ядро, тогда как рабочие машины имели несколько процессоров / ядер. Приложение состоит из потока на исходное видео, потока слияния и потока назначения.
Исходный поток (и) запускает граф фильтра (я предполагаю, что граф фильтра также работает в собственном потоке), чтобы получить данные из IMediaSample
и поместить их в CQueue<BYTE*>
.
Поток слияния проходит по источникам, извлекает образцы данных из источника CQueue<BYTE*>
, объединяет кадры в единое изображение и отправляет их CQueue<BYTE*>
потоку назначения.
Целевой поток запускает другой граф фильтров для кодирования видео / аудио.
CQueue<BYTE*>
блокируется на Put, пока не освободится место. Обычно это нормально, потому что поток слияния удаляет элементы. Однако на машинах с одним процессором / ядром поток слияния блокировался исходными потоками.
Короче говоря, Sleep(0);
кое-где позволили исходным потокам уступить место потокам слияния, и проблема, похоже, решена.