通过 NDI 流式传输 Powerpoint

问题描述

我目前尝试创建一个 PowerPoint 插件,在开始幻灯片放映后抓取演示窗口并将其发送到 NDI 目的地。

我取得了一些成功(NDI 显示了一些东西),但图片似乎是...可以说:与来源不同。 我想将它用于我们的“灵曦堂”项目。

非常感谢任何帮助! 这是当前的一段代码...:

using NewTek.NDI;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace test
{
  internal class DxCapturer : IDisposable
  {
    private IntPtr _hWnd;
    private SharpDX.Direct3D11.Device _device;
    private OutputDuplication _duplicatedOutput;
    private bool _disposing;
    private Sender _sender;
    private Thread _captureThread;

    [DllImport("user32.dll",SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetWindowRect(IntPtr hWnd,ref RECT lpRect);
    [StructLayout(LayoutKind.Sequential)]
    private struct RECT
    {
      public int Left;
      public int Top;
      public int Right;
      public int Bottom;
    }

    public DxCapturer(IntPtr hWnd)
    {
      _hWnd = hWnd;
      _sender = new Sender("Powerpoint",true,false,null,"Powerpoint");

      var numAdapter = 0;
      var numOutput = 0;

      var factory = new Factory1();
      var adapter = factory.GetAdapter1(numAdapter);
      _device = new SharpDX.Direct3D11.Device(adapter);
      var output = adapter.GetOutput(numOutput);
      var output1 = output.QueryInterface<Output1>();

      _duplicatedOutput = output1.DuplicateOutput(_device);
      _disposing = false;
      _captureThread = new Thread(Capturer) { IsBackground = true,Priority = ThreadPriority.BelowNormal };
      _captureThread.Start();
    }

    public void Dispose()
    {
      _disposing = true;
      _captureThread.Join();

      _device.Dispose();
      _duplicatedOutput.Dispose();
      _sender.Dispose();
    }

    private void Capturer()
    {
      while(!_disposing)
      {
        try
        {
          SharpDX.DXGI.Resource screenResource;
          OutputDuplicateFrameInformation duplicateFrameInformation;

          // Try to get duplicated frame within given time
          _duplicatedOutput.AcquireNextFrame(10000,out duplicateFrameInformation,out screenResource);

          RECT r = new RECT();
          GetWindowRect(_hWnd,ref r);
          var width = r.Right - r.Left;
          var height = r.Bottom - r.Top;

          if (width == 0 || height == 0)
            continue;

          using (var screenTexture = new Texture2D(_device,new Texture2DDescription
          {
            CpuAccessFlags = CpuAccessFlags.Read,BindFlags = BindFlags.None,Format = Format.B8G8R8A8_UNorm,Width = width,Height = height,OptionFlags = ResourceOptionFlags.None,MipLevels = 1,ArraySize = 1,SampleDescription = { Count = 1,Quality = 0 },Usage = ResourceUsage.Staging
          }))
          {
            // copy resource into memory that can be accessed by the CPU
            using (var screenTexture2D = screenResource.QueryInterface<Texture2D>())
            {
              _device.ImmediateContext.CopySubresourceRegion(screenTexture2D,new ResourceRegion { Top = r.Top,Bottom = r.Bottom,Left = r.Left,Right = r.Right,Back = 1,Front = 0 },screenTexture,0);
            }

            // Get the desktop capture texture
            var mapSource = _device.ImmediateContext.MapSubresource(screenTexture,MapMode.Read,SharpDX.Direct3D11.MapFlags.None);

            using (var vf = new VideoFrame(width,height,width / height,30000,1001))
            {
              var sourcePtr = mapSource.DataPointer;
              var destPtr = vf.BufferPtr;
              Utilities.CopyMemory(destPtr,sourcePtr,width * 4 * height);
              _sender.Send(vf);
            }

            _device.ImmediateContext.UnmapSubresource(screenTexture,0);
          }

          screenResource.Dispose();
          _duplicatedOutput.ReleaseFrame();
        }
        catch { }
      }
    }
  }
}

我使用“普通”GDI 功能完成了这项工作,但在配备至强 E3-1505M v5 的工作站上,这会将 CPU 负载推高至约 25% 的 FHD。

我希望使用 DirectX 时负载会低得多 - 但似乎很难抓取屏幕的一部分,尤其是在连接多个屏幕时...

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)