Мой фильтр DirectShow аварийно завершает работу Skype 5.x во время разговора. Отлично работает в 4.x, Graph Edit и других программах
У меня есть push-видео-фильтр DirectShow, написанный на Delphi 6 с библиотекой компонентов DSPACK. Фильтр работает нормально во время вызова Skype, если клиент Skype, использующий фильтр, не является 5.x или новее. С 5.x клиент Skype становится очень вялым, пока он не зависает, а затем я получаю множество серьезных сбоев, включая предупреждения предотвращения выполнения данных и типичное диалоговое окно Microsoft "эта программа потерпела крах". Иногда происходит сбой сразу, иногда происходит сбой примерно через 30 или более секунд при вызове.
Я также могу запустить видеофильтр без ошибок в следующих контекстах:
- С Skype 5.x в окне предварительного просмотра видеофильтра, который вы видите при выборе видеоустройства для использования со Skype (не во время разговора, а на странице диалога выбора параметров видео).
- Skype 4.x клиент (отлично работает в вызове и вне)
- Редактировать график
- Экземпляр DSPACK TVideoWindow
- Другие программы, которые используют веб-каналы
Я провел некоторое исследование в Интернете и нашел довольно много жалоб на Skype 5.x и сбои. Темы, которые я читал, предлагали загрузить бета-версию 5.7. Я попробовал это, и это не помогло. Он работает немного лучше, но потом все равно вылетает.
Как простой тест, я изменил свой метод FillBuffer(), чтобы он просто выдавал статическое растровое изображение, которое я загружаю при запуске, вместо внешнего видеопотока, который я обычно передаю в Skype. Это все еще падает. Кроме того, я даже попытался запустить DLL-фильтр принудительного источника с установленным FastMM4 для полного сканирования памяти при каждом вызове FillBuffer() и вызове, который доставляет образец мультимедиа на выходной контакт. Никаких ошибок вообще.
Поскольку Skype, очевидно, работает с другими драйверами веб-камеры, или в Интернете возникнет огромный протест, что может делать мой фильтр, который ему не нравится?
ОБНОВЛЕНИЕ: После дальнейшего тестирования я столкнулся с чем-то странным. Первоначально вызов GetMediaType() в моем фильтре имел 4 формата. Я выбил этот формат до 1: 24-битный со сжатием, установленным на BI_RGB, поскольку это то, что я получаю извне, а затем передаю в Skype. Сразу же я начал получать быстрый сбой от Skype, когда он выполняет сканирование фильтра DirectShow после входа в систему, и сбой произошел во время моего вызова GetStreamCaps(). Поскольку в Skype есть анти-отладочный код, я тщательно добавлял сообщения трассировки в мой вызов GetStreamCaps() после каждой строки и обнаруживал, что это происходит во время моей первой попытки доступа к его переменной медиа-формата (см. Ниже). Похоже, у меня проблемы с доступом к области памяти, которую Skype передает в мой фильтр DirectShow. Почему наличие только одного формата мультимедиа по сравнению с предыдущими 4 делает сбои быстрее, неизвестно.
Это спекуляция с моей стороны, но возможно ли, что между Skype и моим фильтром возникает какая-то странная ошибка прав доступа к области памяти? Тот факт, что Skype время от времени сообщал об ошибке "Предотвращение выполнения данных", когда я доходил до точки инициирования вызова, наряду с другими общими сбоями, заставляет меня задуматься, происходит ли что-то экзотическое. Ошибка DEP возникает при попытке записи в область, помеченную как блок кода. Словно указатель, который скайп передает мне, указывает на какое-то странное или защищенное место, в которое я не могу написать.
Напомним, что теперь ошибка происходит на 100% каждый раз, когда Skype обращается к моему фильтру DirectShow, когда он вызывает GetStreamCaps(), до того, как мне удается инициировать вызов, или я даже могу получить доступ к экрану выбора устройства Video. Вот соответствующий фрагмент кода:
function TBCPushPinDesktop.GetStreamCaps(iIndex: Integer; out ppmt: PAMMediaType; out pSCC): HResult;
var
pvi:PVIDEOINFOHEADER;
begin
ppmt := CreateMediaType(@Fmt);
pvi:=PVIDEOINFOHEADER(ppmt.pbFormat);
// Error occurs at THIS statement, the first attempt to write to the memory area
// provided by Skype.
pvi.bmiHeader.biCompression := BI_RGB;
.... SNIP ....
end;
ОБНОВЛЕНИЕ 2: Что-то не так с моим кодом, но я не знаю что. Редактирование графика не вызывает GetStreamCaps(), как это делает Skype. Я добавил еще несколько операторов трассировки, и оказалось, что в приведенном выше коде объект типа мультимедиа, возвращаемый вызовом DSPACK CreateMediaType(), имеет поле NIL pbFormat, что объясняет быстрый сбой. Если кто-нибудь знает, что мне нужно сделать, чтобы получить правильно сконфигурированное поле pbFormat, пожалуйста, дайте мне знать. Ниже приведен код из DSPACK, который выполняет операцию CreateMediaType ():
// this also comes in useful when using the IEnumMediaTypes interface so
// that you can copy a media type, you can do nearly the same by creating
// a CMediaType object but as soon as it goes out of scope the destructor
// will delete the memory it allocated (this takes a copy of the memory)
function CreateMediaType(pSrc: PAMMediaType): PAMMediaType;
var pMediaType: PAMMediaType;
begin
ASSERT(pSrc<>nil);
// Allocate a block of memory for the media type
pMediaType := CoTaskMemAlloc(sizeof(TAMMediaType));
if (pMediaType = nil) then
begin
result := nil;
exit;
end;
// Copy the variable length format block
CopyMediaType(pMediaType,pSrc);
result := pMediaType;
end;
//----------------------------------------------------------------------------
// Copies a task-allocated AM_MEDIA_TYPE structure.
//----------------------------------------------------------------------------
procedure CopyMediaType(pmtTarget: PAMMediaType; pmtSource: PAMMediaType);
begin
// We'll leak if we copy onto one that already exists - there's one
// case we can check like that - copying to itself.
ASSERT(pmtSource <> pmtTarget);
//pmtTarget^ := pmtSource^;
move(pmtSource^, pmtTarget^, SizeOf(TAMMediaType));
if (pmtSource.cbFormat <> 0) then
begin
ASSERT(pmtSource.pbFormat <> nil);
pmtTarget.pbFormat := CoTaskMemAlloc(pmtSource.cbFormat);
if (pmtTarget.pbFormat = nil) then
pmtTarget.cbFormat := 0
else
CopyMemory(pmtTarget.pbFormat, pmtSource.pbFormat, pmtTarget.cbFormat);
end;
if (pmtTarget.pUnk <> nil) then pmtTarget.pUnk._AddRef;
end;
1 ответ
Много информации, но я мог понять следующее:
ppmt := CreateMediaType(@Fmt);
pvi:=PVIDEOINFOHEADER(ppmt.pbFormat);
// Error occurs at THIS statement, the first attempt to write to the memory area
// provided by Skype.
pvi.bmiHeader.biCompression := BI_RGB;
Единственная причина, по которой вы можете столкнуться с нарушением доступа, заключается в том, что вы неправильно инициализируете .pbFormat
, Или, иначе, вы правильно инициализируете его в NULL
а затем доступ в качестве реального указателя.
Ваше обновление 2 говорит о NULL
версия или .cbFormat
там ноль.