将ID3D11Texture2D从C ++发送到C#UWP MediaPlayer

时间:2017-06-21 15:15:21

标签: c# c++ uwp mpeg-dash direct3d11

我有一个C ++非托管DLL,基本上是一个视频播放引擎。它使用WMF流式传输视频,并使用TransferVideoFrame将帧绘制到ID3D11Texture2D。

这一切都很好。

但是,我的任务是实现MPEG_DASH流切换,因此我创建了一个使用MediaPlayer和AdaptiveStreaming类的C#包装器,以使DASH和HLS流工作。

我想弄清楚的是,如何将来自MediaPlayer的帧像素数据发送到C ++ DLL中以将其绘制到ID3DTexture2D。

在C ++中,我有一个函数返回指向ID3D11Texture2D的指针,

ID3D11Texture2D* VideoPlayer::GetVideoTextureSurface()
{
    if (_ctxt.m_spVideoTexSRV) // ComPtr<ID3D11ShaderResourceView>
    {
        return _ctxt.m_spVideoTex.Get(); // ComPtr<ID3D11Texture2D>
    }
    else return nullptr;
}

我从C#调用并获取为IntPtr。

[DllImport("VideoPlayer")]
private static extern IntPtr GetVideoTextureSurface();

在C#中,MediaPlayer有一个方法:

MediaPlayer.CopyFrameToVideoSurface(IDirect3DSurface destination)

我想用它来使MediaPlayer将其框架绘制到C ++ ID3D11Texture3D中。但我不知道如何将IntPtr传递给它。我试图通过直接绘制纹理来避免多次复制帧缓冲区。

我甚至不确定这是否是最佳方法。我可以直接从C ++使用MediaPlayer,但我甚至不确定如何实例化它。在C#中它只是:

MediaPlayer _mediaPlayer = new MediaPlayer();

但是当我尝试用C ++创建它时,我得到错误,&#34;不允许不完整类型&#34;。任何想法,见解或帮助都表示赞赏。

1 个答案:

答案 0 :(得分:0)

DllImport没有问题。

[DllImport("VideoPlayer")]
private static extern IntPtr GetVideoTextureSurface();

您需要将返回的指针编组为ID3D11Texture2D类型的struct。请查看结构here的布局。当您搜索基础纹理资源类型时,您将结束here。因此它是指向描述2D纹理资源的D3D11_TEXTURE2D_DESC结构的指针。

typedef struct D3D11_TEXTURE2D_DESC {
  UINT             Width;
  UINT             Height;
  UINT             MipLevels;
  UINT             ArraySize;
  DXGI_FORMAT      Format;
  DXGI_SAMPLE_DESC SampleDesc;
  D3D11_USAGE      Usage;
  UINT             BindFlags;
  UINT             CPUAccessFlags;
  UINT             MiscFlags;
} D3D11_TEXTURE2D_DESC;

让我们定义我们自己的托管结构

[StructLayout(LayoutKind.Sequential)]
public struct MyStruct : IDirect3DSurface {
    public int Width { get; set; }
    public int Height { get; set; }
    public int MipLevels { get; set; }
    public uint ArraySize { get; set; }
    public DirectXPixelFormat Format { get; set; }
    public Direct3DMultisampleDescription SampleDesc { get; set; }
    public Direct3DUsage Usage { get; set; }
    public uint BindFlags { get; set; }
    public uint CPUAccessFlags { get; set; }
    public uint MiscFlags { get; set; }

    #region I Do not know about this part
    public Action Disposer { get; set; }
    public void Dispose() {
        Disposer();
    }
    #endregion I Do not know about this part

    public Direct3DSurfaceDescription Description => new Direct3DSurfaceDescription {
        Format = Format,
        Height = Height,
        Width = Width,
        MultisampleDescription = SampleDesc
    };
}

这是一个从native到managed struct的简单包装器:

public static MyStruct TestWrapper() {
        var ptr = GetVideoTextureSurface();
        var myStruct = Marshal.PtrToStructure<MyStruct>(ptr);
        myStruct.Disposer = () => Marshal.FreeHGlobal(ptr);
        return myStruct;
    }

现在你可以使用

MediaPlayer.CopyFrameToVideoSurface(myStruct);

希望这有帮助。