2017-05-26 149 views
0

我在微軟官方網站上搜索了關於MMFCreateDXGISurfaceBuffer但它全部用C++編寫。我想在c#中使用MMFCreateDXGISurfaceBuffer,但找不到任何有關如何正確使用該方法的參考。如何在MediaFundation.Net中使用MMFCreateDXGISurfaceBuffer?

在C++下面是代碼。

MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), pAcquiredDesktopImage, 0, FALSE, &pMediaBuffer) 

我想上面的代碼轉換爲C#和下面是我的代碼,但似乎不正確的,因爲我得到E_NOINTERFACE

MFExtern.MFCreateDXGISurfaceBuffer(typeof(SharpDX.Direct3D11.Texture2D).GUID, texture, 0, false, out buffer); 

我使用SharpDX DXGI和MediaFoundation.Net在我的應用程序。我不知道如果

typeof(SharpDX.Direct3D11.Texture2D).GUID 

相當於

__uuidof(ID3D11Texture2D) 

下面是包裝MMFCreateDXGISurfaceBuffer

[DllImport("mfplat.dll", ExactSpelling = true), SuppressUnmanagedCodeSecurity] 
    public static extern HResult MFCreateDXGISurfaceBuffer(
     [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, 
     [MarshalAs(UnmanagedType.Interface)] object punkSurface, 
     int uSubresourceIndex, 
     [MarshalAs(UnmanagedType.Bool)] bool fBottomUpWhenLinear, 
     out IMFMediaBuffer ppBuffer 
    ); 

有人能教我如何在MediaFOundation.Net使用MFCreateDXGISurfaceBuffer 。由於

編輯:我用MFTrace和下面是它失敗的

1716,2494 03:19:20.59013 CMFTransformDetours::SetInputType @02E96B4C Failed MT: MF_MT_FRAME_SIZE=5866925327104 (1366,768);MF_MT_MAJOR_TYPE=MEDIATYPE_Video;MF_MT_FRAME_RATE=257698037761 (60,1);MF_MT_PIXEL_ASPECT_RATIO=4294967297 (1,1);MF_MT_INTERLACE_MODE=2;MF_MT_SUBTYPE=MFVideoFormat_RGB32 

林不知道如果我設置正確,因爲我用料表面的Direct3D水槽輸入類型的日誌。

+0

此線程上的代碼是我想要在C#中轉換。使用SharpDX和MediaFoundation.Net https://stackoverflow.com/questions/34857680/mf-sinkwriter-memory-problems – kripto

回答

1

我認爲這是你的帖子(https://sourceforge.net/p/mfnet/discussion/711229/thread/9814e58b/#c149);我在那邊回答,但在StackOverflow上看到你的問題,並認爲我應該重現我的答案。


MFCreateDXGISurfaceBuffer接受一個IUnknown作爲第二個參數,所以你可以通過它任何看起來像一個COM對象,無論是本地或託管。但是,內部MFCreateDXGISurfaceBuffer實際上是在尋找一個實現接口的對象,這就是爲什麼您必須將該接口的IID作爲第一個參數傳遞的原因。

由於您將SharpDX Texture2D託管對象本身傳遞到MFCreateDXGISurfaceBuffer,您的代碼可能會失敗。你會認爲這會在.NET端(即編譯器或編組錯誤)失敗,但.NET interop編組實際上使得P/Invoke函數調用成爲可能。這是因爲任何.NET類都可以被轉換爲object,並且可以通過CCW(COM可調用包裝器)將所有.NET對象編組爲一個本機對象。

你從MFCreateDXGISurfaceBuffer得到一個E_NOINTERFACE的原因是因爲.NET互操作編組與本機CCW包裹SharpDX Texture2D對象,手中的CCW關閉該功能,然後函數試圖看看對象(它看作是本地的IUnknown)支持ID3D11Texture2D接口。 MFCreateDXGISurfaceBuffer通過使用IUnknown提供的COM QueryInterface函數來完成此操作。但是,SharpDX Texture2D類沒有實現接口ID3D11Texture2D,所以當查詢編組版本Texture2D時查詢失敗,並且QueryInterface將返回E_NOINTERFACE

要解決此問題,您需要獲取本機COM指針,SharpDX Texture2D正在封裝而不是傳入SharpDX對象本身。所有的SharpDX對象都來自基類ComObject類,它提供了一個NativePointer屬性訪問器,它爲您提供了一個IntPtr實際包裝的COM對象。這是您的案例中的實際COM ID3D11Texture2D指針,但現在我們需要從中獲取object而不是IntPtr。這看起來是這樣的:

HResult hr; 
IMFMediaBuffer buffer; 

// "Marshal" is from the System.Runtime.InteropServices namespace 

// This line converts the IntPtr texture.NativePointer in to a .NET RCW 
// (runtime callable wrapper) so that it can be used like a native .NET 
// object. 
object texNativeObject = Marshal.GetObjectForIUnknown(texture.NativePointer); 

// When texNativeObject is passed as an argument to MFCreateDXGISurfaceBuffer, 
// the .NET marshaller will simply unwrap the RCW and provide a native COM 
// pointer to the function. 
hr = MFExtern.MFCreateDXGISurfaceBuffer(
    typeof(SharpDX.Direct3D11.Texture2D).GUID, 
    texNativeObject, 
    0, false, out buffer 
); 

// check "hr" here for success or failure 

// "COMBase" is from the MediaFoundation.Misc namespace 
// If this line causes problems at runtime, just remove it. SafeRelease 
// forces the .NET runtime to release the RCW now, rather than later when 
// a GC happens. It calls Marshal.ReleaseComObject(...) internally. 
COMBase.SafeRelease(texNativeObject); 
texNativeObject = null; 

或者,您可以添加的MFCreateDXGISurfaceBuffer另一種定義,它接受IntPtr作爲第二個參數。您可以將其添加到您自己的代碼中,而不是修改MediaFoundation.NET。

class NativeMethods 
{ 
    // EntryPoint must be provided since we are naming the alternate 
    // version MFCreateDXGISurfaceBuffer2 to separate it from the original 
    [DllImport("mfplat.dll", ExactSpelling = true, EntryPoint = "MFCreateDXGISurfaceBuffer")] 
    public static extern HResult MFCreateDXGISurfaceBuffer2(
     [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, 
     IntPtr punkSurface, 
     int uSubresourceIndex, 
     [MarshalAs(UnmanagedType.Bool)] bool fBottomUpWhenLinear, 
     out IMFMediaBuffer ppBuffer 
    ); 
} 

沒關係使用這樣的複用功能簽名,只是因爲Texture2D.NativePointerIntPtr引用非託管內存。換句話說,你將一個非託管內存地址交給一個非託管函數,這沒關係。

一旦你在你的代碼有替代版本,您可以使用新的MFCreateDXGISurfaceBuffer2功能是這樣的:

HResult hr; 
IMFMediaBuffer buffer; 
hr = NativeMethods.MFCreateDXGISurfaceBuffer2(
    typeof(SharpDX.Direct3D11.Texture2D).GUID, 
    texture.NativePointer, 
    0, false, out buffer 
); 

// check "hr" here 

希望這有助於!

+0

謝謝ozeanix爲此。它現在正在工作。但我遇到了另一個問題,我在這個線程中解釋它。 https://stackoverflow.com/questions/44402898/mf-sinkwriter-write-sample-failed – kripto