Работя върху филтърна графика на 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
, което ме кара да вярвам, че има един или повече "магически филтри", които се вмъкват в графиката.
Актуализация: Благодарение на Roman R. успях да накарам 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();
Всички те са в състояние "Работи". Така че, ако филтърът е свързан правилно и всички филтри работят, защо графиката никога не завършва на "счупените" машини?
Актуализация: Както беше предложено от Roman R. Премахнах нашия CTransInPlaceFilter
от филтърната графика на повредената машина и графиката завърши успешно. Когато CTransInPlaceFilter
е свързан, използването на процесора пада до нула. Така че сега не съм сигурен защо следният код работи на някои машини, но не и на други. Ще започна да добавям някакво регистриране за отстраняване на грешки към CTransInPlaceFilter
, за да се опитам да разбера какво се случва (или не се случва).
Решение: Както беше предложено от Roman R. (имам чувството, че се повтарям :P), проблемът се оказа задънена улица. Всички счупени машини имаха един процесор/ядро, докато работещите машини имаха множество процесори/ядра. Приложението се състои от нишка за изходно видео, нишка за сливане и нишка на местоназначение.
Изходната нишка(и) изпълнява филтърна графика (предполагам, че филтърната графика също работи в собствената си нишка), за да извлече данните от IMediaSample
и да ги постави в CQueue<BYTE*>
.
Нишката за сливане преминава през източниците, извлича примерните данни от източника CQueue<BYTE*>
, обединява кадрите в едно изображение и ги изпраща към CQueue<BYTE*>
, която консумира целевата нишка.
Целевата нишка изпълнява друга филтърна графика, за да кодира видеото/аудиото.
CQueue<BYTE*>
блокира на Put, докато има свободно място. Обикновено това е добре, защото нишката за сливане премахва елементи. Въпреки това на машините с един процесор/ядро нишката за сливане беше блокирана от нишките източник.
Накратко Sleep(0);
тук и там позволи на изходните нишки да отстъпят на нишките за сливане и проблемът изглежда е разрешен.