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

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を次に示します。Csharpの
PureNETDirectShowフィルター
仮想カメラの実装を次に示し
ます。C#のDirectShow仮想ビデオキャプチャソースフィルター

よろしく、マキシム。

于 2012-08-23T08:47:40.420 に答える
1

System.Drawing.Bitmap は COM 型ではなく .net 型であり、COM にはこれに相当するものがないため、COM インターフェイスのパラメーターとして使用することはできません。

.net MemoryStream が実装していないため C# では使いにくいCOM インターフェイスIStreamを使用するか、COM インターフェイスIPictureを使用するか、単にバイトの配列を使用します。

また、DirectShow フィルターは通常、UI スレッドではないスレッドで呼び出されることに注意してください。そのため、フィルター内に適切なロック メカニズムを配置するように注意する必要があります。

于 2012-08-21T13:34:31.213 に答える