[转]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控件就可以了;<br><br>接下来就是怎么把视频数据一桢桢从内存中映射出来,这个需要和你的视频解码提供商有关系了,他解出来的每帧图片是什么格式,一般都那几种PixelFormats.Bgr32、PixelFormats.Pbgra32等,根据格式大小等图片信息,用CreateBitmapSourceFromMemorySection把它从内存中读取出来,内存隐射做的就是一帧帧的把内存隐射出来给CreateBitmapSourceFromMemorySection来处理,处理完释放掉,在继续下一帧,对方要是提供回调函数最好,没有回调就要自己去对这个视频内存做处理,视频组件都会带着些接口的。
原文地址:https://www.cnblogs.com/psim/p/3747799.html