My DirectShow filter crashes Skype 5.x during a call. Runs fine in 4.x, Graph Edit and other programs

643 views Asked by At

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

There are 1 answers

9
Roman Ryltsov On

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.