2012-08-10 99 views
1

我正在一個WPF應用程序需要以快速幀速率顯示幾個視頻流(我們希望30幀/秒)。視頻流是1920x1080原始(RGB24)幀(它們存儲在System.Drawing.Bitmap中)。有沒有人有任何想法如何實現這一目標?快速視頻顯示WPF

更多細節:

  • 我們以前的嘗試已經使用標準的WPF圖像控制,改變其對每個幀源。這對於單個流很好,但現在我們必須呈現多個流,它正在放緩。
  • 我們也嘗試使用Direct2D來處理繪圖,使用D3D9共享曲面作爲Image控件的源代碼。雖然速度更快,但我們仍然無法獲得30fps的穩定性(在備份時它會在24-32 fps之間跳轉)。
  • 視頻流進來的在後臺線程,然後被編組(使用窗口的分派器),以用於繪圖適當UI線程。所有的繪圖都是在UI線程上完成的。我們也嘗試給每個窗口自己的線程。

我可以提供我們試過的代碼樣本,如果有人想看的話。

謝謝!

回答

4

任何尋找解決方案的人,我們都使用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; 
    } 
+0

你能告訴你更多如何優化複製到顯存? – 2013-01-28 02:17:49

+1

@Thomas我剛剛更新了方法的完整代碼,該方法對您的解決方案感興趣的副本 – 2013-03-06 18:48:18

+0

...可以將它發送給我嗎? linusang {at} yahoo {dot} com – icube 2013-09-05 04:47:48