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

发布于 2024-12-28 07:34:25 字数 3920 浏览 2 评论 0原文

我有一个用 Delphi 6 和 DSPACK 组件库编写的 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 的外部视频流。它仍然崩溃。此外,我什至尝试运行推送源过滤器 DLL,并将 FastMM4 设置为对每个 FillBuffer() 调用以及将媒体样本传递到下游引脚的调用进行完整内存扫描。没有任何错误。

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

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

I have a DirectShow push source video filter written in Delphi 6 with the DSPACK component library. The filter runs fine during a Skype call as long as the Skype client utilizing the filter is not 5.x or newer. With 5.x the Skype client gets really sluggish until it hangs and then I get a variety of bad crashes including Data Execution Prevention warnings and the typical Microsoft "this program has crashed" dialog box. Sometimes it crashes immediately, other times it crashes after about 30 seconds or more into a call.

I can also run the video filter without error in the following contexts:

  • With Skype 5.x in the video filter preview window that you see when selecting a video device to use with Skype (not in a call, but at the Video Options selection dialog page).
  • Skype 4.x client (runs perfectly in a call and out)
  • Graph Edit
  • A DSPACK TVideoWindow instance
  • Other programs that utilize webcam feeds

I did some research on the web and did find quite a few complaints about Skype 5.x and crashes. The threads I read suggested downloading the 5.7 beta. I tried that and it did not help. It runs a little better, but then still crashes.

As a bare bones test I changed my FillBuffer() method to just deliver a static bitmap that I load upon start up instead of the external video stream I normally relay to Skype. It Still crashes. Also, I even tried running the push source filter DLL with FastMM4 set to do a full memory scan with every FillBuffer() call and the call that delivers the media sample to the downstream pin. No errors whatsoever.

Since Skype obviously works with other webcam drivers or there would be a huge outcry on the web, what could my filter possibly be doing that it does not like?

UPDATE: Upon further testing I have come across something strange. Originally, the GetMediaType() call in my filter had 4 formats. I knocked that down to 1 format: 24-bit with compression set to BI_RGB since that is what I receive externally and then pass on to Skype. Immediately I started getting a fast failure from Skype when it does it's DirectShow filter scan after logging in, and the failure occurred during my GetStreamCaps() call. Since Skype has anti-debugging code, I painstakingly added trace messages to my GetStreamCaps() call after every line and discovered that it happens during my first attempt to access it's media format variable (see below). It appears that I am having trouble accessing the memory area that Skype passes to my DirectShow filter. Why having only 1 media format to offer versus the previous 4 makes the failures happen faster is an unknown.

This is sheer speculation on my part, but is it possible that some kind of weird memory area access privileges error is occurring between Skype and my filter? The fact that Skype occasionally reported a Data Execution Prevention error before when I get to the point of initiating a call, along with the other general crashes, makes me wonder if something exotic is going on. A DEP error happens when you try to write to an area marked as a code block. It's as if the pointer Skype passes to me is pointing to some strange or protected place that I can't write to.

To recapitulate, now the error happens 100% every time Skype accesses my DirectShow filter when it calls GetStreamCaps(), before I ever get to initiate a call, or I am even able to access the Video device selection screen. Here's the relevant code snippet:

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: There is something wrong with my code but I don't know what. Graph Edit does not call GetStreamCaps() like Skype does. I added some more trace statements and it turns out that in the code above, the media type object returned by the DSPACK CreateMediaType() call has a NIL pbFormat field so that explains the fast failure. If anyone knows what I need to do to get a propertly configured pbFormat field please let me know. Below is the code from DSPACK that does the CreateMediaType() operation:

  // 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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

独夜无伴 2025-01-04 07:34:25

很多信息,但我可以掌握以下内容:

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

A lot of info but I could grasp the following:

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;

The only reason you can hit access violation here is if you are incorrectly initializing .pbFormat. Or, otherwise you correctly initializing it into NULL and then accessing as a real pointer.

Your update 2 tells for NULL version, or .cbFormat is zero there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文