2

我有一个使用 DSPACK 组件库用 Delphi 6 编写的 DirectShow 推送源视频过滤器。只要使用过滤器的 Skype 客户端不是5.x 或更新版本,过滤器就可以在 Skype 通话期间正常运行。在 5.x 中,Skype 客户端变得非常缓慢,直到它挂起,然后我得到了各种严重的崩溃,包括数据执行保护警告和典型的 Microsoft“这个程序已经崩溃”对话框。有时它会立即崩溃,有时它会在通话大约 30 秒或更长时间后崩溃。

我还可以在以下情况下运行视频过滤器而不会出错:

  • 在视频过滤器预览窗口中使用 Skype 5.x,您在选择要与 Skype 一起使用的视频设备时看到该窗口(不是在通话中,而是在视频选项选择对话框页面上)。
  • Skype 4.x 客户端(在通话中完美运行)
  • 图表编辑
  • 一个 DSPACK TVideoWindow 实例
  • 使用网络摄像头源的其他程序

我在网上做了一些研究,确实发现了很多关于 Skype 5.x 和崩溃的投诉。我阅读的主题建议下载 5.7 beta。我试过了,但没有帮助。它运行得更好一些,但仍然崩溃。

作为一个简单的测试,我改变了我的 FillBuffer() 方法,只提供一个我在启动时加载的静态位图,而不是我通常中继到 Skype 的外部视频流。它仍然崩溃。此外,我什至尝试运行设置了 FastMM4 的推送源过滤器 DLL,以对每个 FillBuffer() 调用和将媒体样本传递到下游引脚的调用进行全内存扫描。没有任何错误。

由于 Skype 显然可以与其他网络摄像头驱动程序一起使用,否则会在网络上引起强烈抗议,我的过滤器可能会做什么它不喜欢的事情?

更新:经过进一步测试,我遇到了一些奇怪的事情。最初,我的过滤器中的 GetMediaType() 调用有 4 种格式。我将其降低为 1 种格式:24 位,压缩设置为 BI_RGB,因为这是我从外部接收然后传递给 Skype 的。登录后,我立即开始从 Skype 快速失败,它是 DirectShow 过滤器扫描,并且失败发生在我的 GetStreamCaps() 调用期间。由于 Skype 有反调试代码,我煞费苦心地将跟踪消息添加到每行之后的 GetStreamCaps() 调用中,并发现它发生在我第一次尝试访问它的媒体格式变量时(见下文)。看来我无法访问 Skype 传递给我的 DirectShow 过滤器的内存区域。为什么只提供 1 种媒体格式而不是之前的 4 种格式会使故障发生得更快是未知数。

这纯粹是我的猜测,但是否有可能在 Skype 和我的过滤器之间发生某种奇怪的内存区域访问权限错误?事实上,在我开始通话之前,Skype 偶尔会报告数据执行保护错误,以及其他一般崩溃,这让我想知道是否发生了一些奇怪的事情。当您尝试写入标记为代码块的区域时,会发生 DEP 错误。就好像 Skype 传递给我的指针指向某个我无法写入的陌生或受保护的地方。

概括地说,现在每次 Skype 在调用 GetStreamCaps() 时访问我的 DirectShow 过滤器时,在我开始呼叫之前,或者我什至能够访问视频设备选择屏幕之前,错误都会发生 100%。这是相关的代码片段:

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:我的代码有问题,但我不知道是什么。Graph Edit 不像 Skype 那样调用 GetStreamCaps()。我添加了更多跟踪语句,结果发现在上面的代码中,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;
4

1 回答 1

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那里为零。

于 2012-01-21T08:24:54.247 回答