Мой фильтр DirectShow аварийно завершает работу Skype 5.x во время разговора. Отлично работает в 4.x, Graph Edit и других программах - PullRequest
2 голосов
/ 21 января 2012

У меня есть 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;

1 Ответ

1 голос
/ 21 января 2012

Много информации, но я могу понять следующее:

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 там равно нулю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...