У меня есть фильтр исходного источника DirectShow, написанный на Delphi 6 с помощью библиотеки компонентов DSPACK. Фильтр работает нормально во время вызова Skype, если клиент Skype использует фильтр: не 5.x или новее. С 5.x клиент Skype становится очень вялым до тех пор, пока он не зависает, а затем я получаю множество плохих сбоев, включая предупреждения предотвращения выполнения данных и типичное диалоговое окно Microsoft «эта программа разбилась». Иногда он срабатывает немедленно, в других случаях он вылетает примерно через 30 секунд или более.Мой фильтр DirectShow выдает Skype 5.x во время разговора. Работает нормально в 4.x, Редактирование графа и другие программы
можно также запустить видеофильтр без ошибок в следующих контекстах:
- С Skype 5.x в окне предварительного просмотра видео фильтра, который вы видите при выборе видео устройства для использования с Skype (не в вызове, а на странице диалога выбора параметров видео).
- Skype 4.x клиент (отлично работает в режиме разговора и отъезда)
- Graph Edit
- DSPACK TVideoWindow экземпляра
- Другие программы, которые используют веб-камера питается
Я сделал некоторые исследования на сети и нашел довольно много жалоб на Skype 5.x и аварий. Потоки, которые я прочитал, предложили загрузить бета-версию 5.7. Я пробовал это, и это не помогло. Он работает немного лучше, но затем все еще падает.
Как тест на голые кости, я изменил свой метод FillBuffer(), чтобы просто поставить статическую растровую карту, которую загружаю при запуске вместо внешнего видеопотока, который я обычно передаю в Skype. Он все еще падает. Кроме того, я даже попробовал запустить DLL-фильтр с фильтром push-файлов с помощью 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;
UPDATE 2: Существует что-то случилось с моим кодом, но я не знаю, что. Graph Edit не вызывает 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;
Да, это то, что я сказал в конце сообщения. Я пытаюсь понять, почему это происходит сейчас. Есть что-то о времени GetStreampCaps() против GetMediaType() или CheckMediaType(), которое происходит до того, как я или DSPACK инициализируют .pbFormat. Есть ли у вас какие-либо идеи о том, что может быть неправильным, или образец кода, который я мог бы посмотреть, что может помочь? –
Вы создали этот тип носителя. Зачем вам писать в поле «NULL»? Просто выделите его и правильно инициализируйте, создайте там хороший тип носителя. –
«Просто выделите его и правильно инициализируйте ...». Это проблема. Мне нужно знать, как и особенно когда это делать. Я посмотрел на код DSPACK, и вызов SetMediaType() - это единственное место, где установлен Fmt.pbFormat. Это происходит только при попытке подключения к выходу источника во время фазы согласования соединения. Skype вызывает GetMediaType(), а затем GetStreamCaps() до того, как SetMediaType() когда-либо называется. Поэтому Fmt.pbFormat - это NIL в то время. Нужно ли устанавливать Fmt.pbFormat на какое-то произвольное значение, чтобы просто поддерживать Skype? –