График фильтра DirectShow никогда не завершается на некоторых машинах

Я работаю над графом фильтра 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); кое-где позволили исходным потокам уступить место потокам слияния, и проблема, похоже, решена.


person Cory Charlton    schedule 15.08.2013    source источник
comment
Фрагмент кода вряд ли имеет отношение к проблеме. Прежде всего, вам нужно убедиться, что вы успешно создали граф фильтра. Затем, прежде чем запускать график, вам нужно проверить его эффективную топологию, чтобы увидеть, что внутри. На этом этапе вы, вероятно, увидите различия между своими системами. Тогда вы увидите, что делает потоковую передачу неполной.   -  person Roman R.    schedule 15.08.2013
comment
Если вы видите свой график, значит, шпион работает. Однако инструменты удаленного управления шпионами и графами будут зависать, если вы не перекачиваете оконные сообщения во время потоковой передачи - так что это больше проблема с вашим кодом (не фатально, конечно, но перекачка сообщений в любом случае - хорошая идея).   -  person Roman R.    schedule 16.08.2013


Ответы (2)


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

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

Однако, даже если топологии точно совпадают, некоторые фильтры могут действовать иначе по другим причинам. В частности, наличие вашего собственного настраиваемого фильтра на графике имеет высокие шансы, что он теряет уведомление, и график никогда не завершится. Он перестает обрабатывать данные и просто простаивает оттуда (это еще одна вещь, которую вы хотите проверить - снижается ли потребление ЦП до нуля или какая-то обработка все еще происходит, и в этом случае вы можете переквалифицировать проблему в тупик).

Что-то, что вы могли бы более или менее легко решить с этой проблемой, - это начать отсекать фильтры на графике, чтобы определить, какой именно фильтр вызывает проблему. Попытка этих графиков, возможно, обнаружит нарушителя:

File Source -> MPEG Demux -> MPEG4 Decoder -> Color Space Converter -> Null Render
File Source -> MPEG Demux -> MPEG4 Decoder -> Null Render
File Source -> MPEG Demux -> Null Render
person Roman R.    schedule 16.08.2013
comment
Хорошо, так что это привело меня к чему-то. Я удалил наш CTransInPlaceFilter с графика, и он успешно завершился. Все еще не уверен, почему фильтр работает на одном компьютере, а на другом - нет. Вопрос обновлен с более подробной информацией. - person Cory Charlton; 17.08.2013
comment
Вам нужно проверить вещи вокруг IPin::EndOfStream в этом фильтре. Что-то там не так. - person Roman R.; 17.08.2013
comment
Насколько я могу судить, он не внедрял IPin::EndOfStream где-либо и просто полагался на базу. Однако я думаю, что вы можете догадаться о тупике, поскольку я вижу только метод CTransInPlaceFilter::Transform, вызываемый четыре раза, а затем он просто останавливается. На моей рабочей машине я вижу, что метод вызывается соответствующее количество раз в зависимости от количества кадров. - person Cory Charlton; 17.08.2013

Очень сложно сказать, не глядя в целом. Когда я разрабатывал фильтры DS, я много использовал GraphStudio и FilterGraph Spy.

Распространенной ошибкой является использование «автоматических фильтров», которые могут быть недоступны на целевых машинах. Предположим, что ваше видео имеет формат h264 и вы пытаетесь прочитать из него необработанный RGB, DS автоматически предоставит вам фильтры декодера и преобразования цветового пространства. Многие промежуточные фильтры будут сгенерированы без вашего ведома в коде. Вот почему очень важно выгрузить график в визуальном средстве и проверить, как все подключено.

Я предполагаю, что один или несколько из этих «волшебных фильтров» не существуют на вашем сервере развертывания. Вы можете попробовать использовать GraphStudio непосредственно на сервере и подключать все, как если бы вы делали программно, и посмотреть, как и почему это выходит из строя.

person Eric    schedule 15.08.2013
comment
Спасибо за совет. Я посмотрю на эти инструменты и посмотрю, что смогу найти. - person Cory Charlton; 15.08.2013