昨夜飘风
昨 夜, 风, 飘 过; 枯 树, 叶, 飞 落。

      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来处理,处理完释放掉,在继续下一帧,对方要是提供回调函数最好,没有回调就要自己去对这个视频内存做处理,视频组件都会带着些接口的。
posted on 2013-05-29 17:36  昨夜飘风  阅读(4641)  评论(6编辑  收藏  举报