У меня есть 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 возникает при попытке записи в область, помеченную как блок кода. Словно указатель, который мне передает Skype, указывает на какое-то странное или защищенное место, в которое я не могу написать.
Напомним, что теперь ошибка возникает на 100% каждый раз, когда Skype обращается к моему фильтру DirectShow, когда он вызывает GetStreamCaps (), до того, как мне удается инициировать вызов, или я даже могу получить доступ к экрану выбора устройства Видео. Вот соответствующий фрагмент кода:
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;