WPF 通過共享內存播放視頻


      wpf中非繼承FrameworkElement的控件,是無法在wpf的界面上展現的,必須用WindowsFormsHost來嵌套,比如一些第三方的ocx,而這其中我個人經常遇到的最郁悶的事情就是在wpf中播放特殊格式的視頻,本人做視頻監控方面的應用,面對各種亂七八糟的視頻格式,有些必須廠商的庫才能播放,可以想象把這些視頻在wpf上播放多難受,一切因為wpf的控件是無句柄的,而用了WindowsFormsHost,控件又會置頂,視頻菜單和視頻疊加無法實現.

      最近看到一個調用VLC播放器的C#開源代碼,其中有Wpf的控件,看完代碼發現,他實際是把視頻的每一幀讀取出來,然后再建一個共享內存,把視頻數據轉為InteropBitmap,InteropBitmap使開發人員能夠提高在互操作方案中由 WPF 承載的非 WPF UIs 的呈現性能,可以直接賦值給Image.Source,這樣通過Image播放每幀畫面,就讓視頻動起來,當然項目中是借了vlc的解碼功能能,如果我們要解自己的視頻格式,就需要自己來實現解碼轉換為InteropBitmap的構成了,要是夠強可以直接改VLC的解碼器,VLC也是開源的.

  借鑒開源代碼中的思路和方法,打算實現自己的播放器,一般第三方解碼庫會提供:句柄播放視頻,播放控制,截圖等功能,我不打算完全實現一個wpf中的播放器,那樣不實際,因為有太多廠商的接口要處理,只打算把句柄播放視頻這里改成Image來展現,為了實現這個功能,先了解一些必備知識。

      內存映射API

//創建內存映射
[DllImport("kernel32", SetLastError = true)]
public static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpAttributes, PageAccess flProtect, int dwMaximumSizeLow, int dwMaximumSizeHigh, string lpName);

//獲取內存映射地址
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, FileMapAccess dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);

//釋放內存映射
[DllImport("kernel32", SetLastError = true)]
public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);

//釋放句柄
[DllImport("kernel32", SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);

  Imaging如何從非托管內存獲取位圖,使用Imaging.CreateBitmapSourceFromMemorySection方法

        //
        // 摘要:
        //     基於所提供的非托管內存位置,返回托管的 System.Windows.Media.Imaging.BitmapSource。
        //
        // 參數:
        //   section:
        //     內存部分的指針。
        //
        //   pixelWidth:
        //     用於指定位圖寬度(以像素為單位)的整數。
        //
        //   pixelHeight:
        //     用於指定位圖高度(以像素為單位)的整數。
        //
        //   format:
        //     枚舉的一個值。
        //
        //   stride:
        //     位圖的跨距。
        //
        //   offset:
        //     圖像從其開始的內存流字節偏移量。
        //
        // 返回結果:
        //     創建的 System.Windows.Media.Imaging.BitmapSource。
        [SecurityCritical]
        public static BitmapSource CreateBitmapSourceFromMemorySection(IntPtr section, int pixelWidth, int pixelHeight, PixelFormat format, int stride, int offset);
CreateBitmapSourceFromMemorySection出來的類型顯的轉換為InteropBitmap,定義依賴屬性綁定到image控件就可以了;

接下來就是怎么把視頻數據一楨楨從內存中映射出來,這個需要和你的視頻解碼提供商有關系了,他解出來的每幀圖片是什么格式,一般都那幾種PixelFormats.Bgr32、PixelFormats.Pbgra32等,根據格式大小等圖片信息,用CreateBitmapSourceFromMemorySection把它從內存中讀取出來,內存隱射做的就是一幀幀的把內存隱射出來給CreateBitmapSourceFromMemorySection來處理,處理完釋放掉,在繼續下一幀,對方要是提供回調函數最好,沒有回調就要自己去對這個視頻內存做處理,視頻組件都會帶着些接口的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM