1

我正在尝试创建一个源过滤器,该过滤器根据一系列图片制作实时视频流。为此,我创建了一个 IUnknown 接口:

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("F18FC642-5BA2-460D-8D12-23B7ECFA8A3D")]
public interface IVirtualCameraFilter_Crop
{
    void SetCurrentImage(Bitmap img);
    ...
};

在我的程序中,我明白了:

pUnk = Marshal.GetIUnknownForObject(sourceFilter);
Marshal.AddRef(pUnk);
filterInterface = Marshal.GetObjectForIUnknown(pUnk) as IVirtualCameraFilter_Crop;

当我传递简单类型时,一切正常。但是当我尝试传递一个 C# Bitmap 对象时,我得到一个错误unable to cast Com object to <my object type>。或应用程序因错误 APPCRUSH 而关闭。

filterInterface.SetCurrentImage(frame);

我知道这不是正确的方法,但我不知道其他可能的参数传递方式。我试图将 IntPtr 传递给 BitmapData,然后我得到了相同的应用程序迷恋。那么如何将位图传递给 DirectShow 过滤器呢?

结果:完整的代码图片请参考创建界面:

[ComImport, InterfaceType (ComInterfaceType.InterfaceIsIUnknown), Guid ("F18FC642-5BA2-460D-8D12-23B7ECFA8A3D")]
public interface IVirtualCameraFilter_Crop
{
    unsafe void SetPointerToByteArr (byte * array, int length);
};

执行:

unsafe public void SetPointerToByteArr (byte * array, int length)
{
    this.array = new byte [length];
    Marshal.Copy (new IntPtr (array), this.array, 0, length);
}

在应用中:

byte [] text = ... get data;
unsafe
{
    fixed (byte * ptr = & text [0])
     {
          filterInterface.SetPointerToByteArr (ptr, text.Length); 
     }
}
4

2 回答 2

1

System.Drawing.Bitmap 是.net 类型,不是COM 类型,COM 中没有对应的,所以不能作为COM 接口的参数。

要么使用 COM 接口IStream,这在 C# 中不容易使用,因为 .net MemoryStream 没有实现它,或者使用 COM 接口IPicture,或者只是一个字节数组

另请注意,您的 DirectShow 过滤器通常会在不是 UI 线程的线程中调用,因此您应该注意在过滤器中放置适当的锁定机制。

于 2012-08-21T13:34:31.213 回答
1

您不能将 Bitmap 对象直接从 .NET 传递到本机代码。您可以传递 BitmapData IntPtr 但您应该将该数据复制到过滤器 bcs 内的缓冲区中,该指针在您解锁后将无效。传递一个字节数组应该可以正常工作,您可以这样做:

 // interface method declaration
 interface IVirtualCameraFilter_Crop
 {
    [PreserveSig]
    int SetImageData([In,MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] _array,[In] int size);
 }

 // Code implementation
 IVirtualCameraFilter_Crop _filter // your filter interface
 BitmapData _data = // your BitmapLock
 int _size = // your image size while you locking it Width * Height * BPP / 8
 byte[] _array = new byte[_size];
 Marshal.Copy(_data.Scan0,_array,0,_size);
 _filter.SetImageData(_array,_size);
 // Passing IntPtr way will be similar just the changes will be in method declaration in interface 
 [PreserveSig]
 int SetImageData([In] IntPtr _array,[In] int size);
 // This way you can just pass the _data.Scan0 value
 // The C++ interface declaration and handler will be same for both ways

 // C++ interface declaration
 DECLARE_INTERFACE(IVirtualCameraFilter_Crop,IUnknown)
 {
     [PreserveSig]
     STDMETHOD(SetImageData)(LPBYTE _array,long size)PURE;
 }
 //C++ implementation
 STDMETHODIMP CFilter::SetImageData(LPBYTE _array,long size)
 {
    CheckPointer(_array,E_POINTER);
    CopyMemory(_internalArray,_array,size);
    return NOERROR;
 }

过滤器崩溃时的另一件事:
1 - 您没有从给定缓冲区复制数据
2 - 您将数据应用到现有缓冲区而不锁定执行线程
3 - 在 C++ 方法
4 中复制时您没有正确计算数据大小 - 您的结果缓冲区未分配。

实际上我认为你应该尝试在 C# 中完全制作你的过滤器

这是带有示例的 BaseClasses.NET:Pure
NET DirectShow Filters in Csharp
这是虚拟相机实现:
DirectShow Virtual Video Capture Source Filter in C#

问候,马克西姆。

于 2012-08-23T08:47:40.420 回答