我的DirectShow过滤器在通话过程中崩溃了Skype 5.x.在4.x,Graph Edit和其他程序中运行良好

时间:2012-01-21 01:30:04

标签: delphi video directshow skype dspack

我有一个用Delphi 6编写的带有DSPACK组件库的DirectShow推送源视频过滤器。只要使用过滤器的Skype客户端 5.x或更新版本,过滤器在Skype通话期间运行正常。使用5.x,Skype客户端变得非常迟缓,直到它挂起,然后我收到各种不良崩溃,包括数据执行预防警告和典型的微软“此程序崩溃”对话框。有时它会立即崩溃,有时它会在大约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。当我登录后立即进行DirectShow过滤扫描时,我立即开始从Skype快速失败,并且在我的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;

1 个答案:

答案 0 :(得分: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为零。