2

複数のビデオ ストリームを高速フレーム レート (30 fps が必要) で表示する必要がある WPF アプリケーションに取り組んでいます。ビデオ ストリームは 1920x1080 の raw (RGB24) フレームです (System.Drawing.Bitmap に格納されます)。これを達成する方法について誰かアイデアがありますか?

詳細:

  • 以前の試みでは、フレームごとにソースを変更して、標準の WPF イメージ コントロールを使用しました。これは単一のストリームではうまく機能しましたが、複数のストリームをレンダリングする必要があるため、速度が低下しています。
  • また、Image コントロールのソースとして D3D9 共有サーフェスを使用して、Direct2D を使用して描画を処理することも試みました。これは高速でしたが、まだ安定した 30 fps を得ることができません (物事が元に戻るにつれて、24 から 32 fps の間でジャンプします)。
  • ビデオ ストリームはバックグラウンド スレッドで受信され、(ウィンドウの Dispatcher を使用して) 描画用の適切な UI スレッドにマーシャリングされます。その後、すべての描画は UI スレッドで行われます。また、各ウィンドウに独自のスレッドを与えることも試みました。

誰かが見たい場合は、私たちが試したことのコード サンプルを提供できます。

ありがとう!

4

1 に答える 1

5

解決策を探している人は誰でも、DirectX 11 を使用してカスタムの winforms コントロールを作成し、高度に最適化されたコピーをグラフィックス メモリに格納し、そのコントロールを でホストしましたWinformsHost。興味のある人にコードを提供できます。

GPU メモリへの最適化されたコピー

    // Using native memcpy for the fastest possible copy
    [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
    private static extern IntPtr memcpy(IntPtr dest, IntPtr src, UIntPtr count);

    /// <summary>
    /// Copies a bitmap to gpu memory
    /// </summary>
    /// <param name="frame">The image to copy to the gpu</param>
    /// <returns>A texture in gpu memory for the bitmap</returns>
    public Texture2D CopyFrameToGpuMemory(Bitmap frame)
    {
        SampleDescription sampleDesc = new SampleDescription();
        sampleDesc.Count = 1;
        sampleDesc.Quality = 0;

        Texture2DDescription texDesc = new Texture2DDescription()
        {
            ArraySize = 1,
            MipLevels = 1,
            SampleDescription = sampleDesc,
            Format = Format.B8G8R8A8_UNorm,
            CpuAccessFlags = CpuAccessFlags.Write,
            BindFlags = BindFlags.ShaderResource,
            Usage = ResourceUsage.Dynamic,
            Height = frame.Height,
            Width = frame.Width
        };

        Texture2D tex = new Texture2D(Device, texDesc);

        Surface surface = tex.AsSurface();
        DataRectangle mappedRect = surface.Map(SlimDX.DXGI.MapFlags.Write | SlimDX.DXGI.MapFlags.Discard);

        BitmapData pixelData = frame.LockBits(new Rectangle(0, 0, frame.Width, frame.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);

        unsafe //!!!
        {
            byte* pixelDataStart = (byte*)pixelData.Scan0.ToPointer();
            byte* mappedRectDataStart = (byte*)mappedRect.Data.DataPointer.ToPointer();

            for (int y = 0; y < texDesc.Height; y++)
            {
                byte* lineLocationDest = mappedRectDataStart + (y * mappedRect.Pitch);
                byte* lineLocationSrc = pixelDataStart + (y * pixelData.Stride);

                // Copy line by line for best performance
                memcpy((IntPtr)lineLocationDest, (IntPtr)lineLocationSrc, (UIntPtr)(texDesc.Width * 4));
            }
        } //!!!

        frame.UnlockBits(pixelData);

        mappedRect.Data.Dispose();

        surface.Unmap();
        surface.Dispose();

        return tex;
    }
于 2012-09-28T22:21:43.630 に答える