C# 将.NET位图对象传递给COM(DirectShow筛选器)

C# 将.NET位图对象传递给COM(DirectShow筛选器),c#,.net,com,directshow,iunknown,C#,.net,Com,Directshow,Iunknown,我正在尝试创建一个源过滤器,根据一系列图片生成实时视频流。 为此,我制作了一个IUnknown接口: [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("F18FC642-5BA2-460D-8D12-23B7ECFA8A3D")] public interface IVirtualCameraFilter_Crop { void SetCurrentImage(Bitmap img); .

我正在尝试创建一个源过滤器,根据一系列图片生成实时视频流。 为此,我制作了一个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#位图对象时,我得到一个错误
,无法将Com对象转换为
。或应用程序因错误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); 
     }
}

System.Drawing.Bitmap是.net类型,而不是COM类型,并且在COM中没有等效项,因此不能将其用作COM接口的参数

或者使用COM接口,这在C#中不容易使用,因为.net MemoryStream没有实现它,或者使用COM接口,或者


还请注意,DirectShow筛选器通常会在非UI线程的线程中调用,因此您应该注意在筛选器中放置适当的锁定机制。

您不能将位图对象直接从.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及其示例:

以下是虚拟摄像机的实现:

问候,,
格言。

对上一条评论进行评论。在那里尝试示例+尝试并查看高级示例,COM问题和多线程问题在那里得到解决,因此工作正常;而且对于过滤器实现来说非常容易。您在COM和DirectShow方面似乎没有太多经验。因此,将.NET位图作为数组或流传递,并在C#中完整地创建筛选器有什么区别?关于应用程序压缩,如果筛选器未捕获任何例外情况,请建议使用MessageBox
s。“你似乎在COM和DirectShow方面没有太多经验”这是真的。这些评论不适合你,关于经验,因为还有其他人的评论。当然,您应该在过滤器中使用try catch stations。MessageBox不建议使用,您可以将数据输出到调试器中,并使用ASSERT检查条件。