zoukankan      html  css  js  c++  java
  • VFW实例程序。简单 “视频捕获”,没有压缩、线程、保存、等更多的功能

     
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;
    
    namespace webcam
    {
        public class showVideo
     {
      // showVideo calls
      [DllImport("avicap32.dll")] 
      public static extern IntPtr capCreateCaptureWindowA(byte[] lpszWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, int nID);
      [DllImport("avicap32.dll")] 
      public static extern bool capGetDriverDescriptionA(short wDriver, byte[] lpszName, int cbName, byte[] lpszVer, int cbVer);
      [DllImport("User32.dll")] 
      public static extern bool SendMessage(IntPtr hWnd, int wMsg, bool wParam, int lParam); 
      [DllImport("User32.dll")] 
      public static extern bool SendMessage(IntPtr hWnd, int wMsg, short wParam, int lParam); 
      [DllImport("User32.dll")] 
      public static extern bool SendMessage(IntPtr hWnd, int wMsg, short wParam, FrameEventHandler lParam); 
      [DllImport("User32.dll")] 
      public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, ref BITMAPINFO lParam);
      [DllImport("User32.dll")] 
      public static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int wFlags);
      [DllImport("avicap32.dll")]
      public static extern int capGetVideoFormat(IntPtr hWnd, IntPtr psVideoFormat, int wSize );
     
    //下面这些都是系统USER32.DLL里面的函数 SendMessage使用的消息的类型。是指定的16进制值。
    //这里的字母的含义是用来让我们明白的。重点在于,其后面的16进制值在系统默认中代表什么含义。要和系统默认表值对应。
    
    
      // Constants
      public const int WM_USER = 0x400;
      public const int WS_CHILD = 0x40000000;
      public const int WS_VISIBLE = 0x10000000;
      public const int SWP_NOMOVE = 0x2;
      public const int SWP_NOZORDER = 0x4;
      public const int WM_CAP_DRIVER_CONNECT = WM_USER + 10;   /// 驱动程序连接
      public const int WM_CAP_DRIVER_DISCONNECT = WM_USER + 11;/// 断开启动程序连接
      public const int WM_CAP_SET_CALLBACK_FRAME = WM_USER + 5;
      public const int WM_CAP_SET_PREVIEW = WM_USER + 50;
      public const int WM_CAP_SET_PREVIEWRATE = WM_USER + 52;
      public const int WM_CAP_SET_VIDEOFORMAT = WM_USER + 45;
    
      //VideoHdr 结构   定义了视频数据块的头信息,在编写回调函数时常用到其数据成员lpData(指向数据缓存的指针)和dwBufferLength(数据缓存的大小)。     
      //视频帧到缓存的捕获则需要应用回调函数和相应的数据块结构 VIDEOHDR 
      [StructLayout(LayoutKind.Sequential)] public struct VIDEOHDR
      {
          [MarshalAs(UnmanagedType.I4)]
          public int lpData;  /* 指向数据缓存的指针 */
    
          [MarshalAs(UnmanagedType.I4)]
          public int dwBufferLength;  /* 数据缓存的大小 */
    
          [MarshalAs(UnmanagedType.I4)]
          public int dwBytesUsed; /* Bytes actually used */
    
          [MarshalAs(UnmanagedType.I4)]
          public int dwTimeCaptured;  /* Milliseconds from start of stream */
    
          [MarshalAs(UnmanagedType.I4)]
          public int dwUser;   /* for client's use */
    
          [MarshalAs(UnmanagedType.I4)]
          public int dwFlags; /* assorted flags (see defines) */
    
          [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
          public int[] dwReserved;   /* reserved for driver */
    
      }
    
      //BitmapInfoHeader定义了位图的头部信息
    
    
      [StructLayout(LayoutKind.Sequential)] public struct BITMAPINFOHEADER  //MS定义的结构类型。
      {
       [MarshalAs(UnmanagedType.I4)] public Int32 biSize ;
       [MarshalAs(UnmanagedType.I4)] public Int32 biWidth ;
       [MarshalAs(UnmanagedType.I4)] public Int32 biHeight ;
       [MarshalAs(UnmanagedType.I2)] public short biPlanes;
       [MarshalAs(UnmanagedType.I2)] public short biBitCount ;
       [MarshalAs(UnmanagedType.I4)] public Int32 biCompression;
       [MarshalAs(UnmanagedType.I4)] public Int32 biSizeImage;
       [MarshalAs(UnmanagedType.I4)] public Int32 biXPelsPerMeter;
       [MarshalAs(UnmanagedType.I4)] public Int32 biYPelsPerMeter;
       [MarshalAs(UnmanagedType.I4)] public Int32 biClrUsed;
       [MarshalAs(UnmanagedType.I4)] public Int32 biClrImportant;
      }
    
      //BitmapInfo   位图信息
    
      [StructLayout(LayoutKind.Sequential)] public struct BITMAPINFO
      {
       [MarshalAs(UnmanagedType.Struct, SizeConst=40)] public BITMAPINFOHEADER bmiHeader;//头部信息结构
       [MarshalAs(UnmanagedType.ByValArray, SizeConst=1024)] public Int32[] bmiColors;//像素值数组
      }
         
      public delegate void FrameEventHandler(IntPtr lwnd, IntPtr lpVHdr);//创建委托
         
      // Public methods
      public static object GetStructure(IntPtr ptr,ValueType structure)//得到结构
      {
       return Marshal.PtrToStructure(ptr,structure.GetType());
      }
      //提供值类型的基类。
     //  ValueType 用更合适的值类型实现重写 Object 中的虚方法。请参见从 ValueType 继承的 Enum。
    //数据类型分隔为值类型和引用类型。值类型要么是堆栈分配的,要么是在结构中以内联方式分配的。
     //引用类型是堆分配的。引用类型和值类型都是从最终的基类 Object 派生出来的。
     //当值类型需要充当对象时,就在堆上分配一个包装(该包装能使值类型看上去像引用对象一样),
    //并且将该值类型的值复制给它。该包装被加上标记,以便系统知道它包含一个值类型。这个进程称为装箱,其反向进程称为取消装箱。//装箱和取消装箱能够使任何类型像对象一样进行处理。
    
    
    
      
      public static object GetStructure(int ptr,ValueType structure)
      {
       return GetStructure(new IntPtr(ptr),structure);
      }
         
      public static void Copy(IntPtr ptr,byte[] data)
      {
       Marshal.Copy(ptr,data,0,data.Length);
      }
         
      public static void Copy(int ptr,byte[] data)
      {
       Copy(new IntPtr(ptr),data);
      }
         
      public static int SizeOf(object structure)
      {
       return Marshal.SizeOf(structure); 
      }
     }
    
      //Web Camera Class
     public class WebCamera
     {
      // Constructur
      public WebCamera(IntPtr handle, int width,int height)
      {
       mControlPtr = handle;
       mWidth = width;
       mHeight = height;
      }
         
      // delegate for frame callback
      public delegate void RecievedFrameEventHandler(byte[] data);
      public event RecievedFrameEventHandler RecievedFrame;
    
      private IntPtr lwndC;    //保存无符号句柄
    
      private IntPtr mControlPtr; //保存管理指示器
    
      private int mWidth;
      private int mHeight;
         
      private showVideo.FrameEventHandler mFrameEventHandler; // Delegate instance for the frame callback - must keep alive! gc should NOT collect it
         
      // Close the web camera
      public void CloseWebcam()
      {
       this.capDriverDisconnect(this.lwndC);
      }
         
      // start the web camera
      public void StartWebCam()
      {
       byte[] lpszName = new byte[100];
       byte[] lpszVer = new byte[100];
    
       showVideo.capGetDriverDescriptionA(0, lpszName, 100, lpszVer, 100);//创建缓冲区//取得视频采集设备描述信息
       //参数:其中,参数0指明设备的索引号,参数lpszName指明设备的名称缓冲区的地址,参数100指明设备的名称缓冲区的大小,//参数lpszVer指明设备的描述缓冲区的地址,参数100指明设备的描述缓冲区的大小。
     this.lwndC = showVideo.capCreateCaptureWindowA(lpszName, showVideo.WS_VISIBLE + showVideo.WS_CHILD, 0, 0, mWidth, mHeight, mControlPtr, 0);
       //,参数lpszWindowName指明窗口的名称,参数dwStyle指明窗口的风格,参数x、y、nWidth和nHeight指明窗口的位置和大小,//参数hwndParent指明父窗口的句柄,参数nID指明窗口标识。 
    
    
       //函数返回值Hwnd类型,即摄像设备的句柄,以后的操作基本上都是针对设备句柄进行的.
    //:= CapCreateCaptureWindow 
    //( PChar(‘KruwoSoft'), //捕获窗口的名字 
    //WS_CHILD or WS_VISIBLE,//窗口样式 
    //0, //X坐标 
    //0, //Y坐标 
    //gCapVideoArea.Width, //窗口宽 
    //gCapVideoArea.Height, //窗口高 
    //gCapVideoArea.Handle, //窗口句柄 
    //0); //一般为0 
    
    
       if (this.capDriverConnect(this.lwndC, 0))
       {
        this.capPreviewRate(this.lwndC, 66);
        this.capPreview(this.lwndC, true);//打开预览
        showVideo.BITMAPINFO bitmapinfo = new showVideo.BITMAPINFO(); //创建结构的对象。
           //这里把值类型转换为 引用类型。
           //装箱与拆箱的区别
           //要把苹果放到水果篮子里,就需要把苹果当成水果装。否则苹果只能放在苹果篮子里。那么反过来拿出来的时候,还要还原为苹果。//装箱拆箱本来是为了方便程序员的,
    
        bitmapinfo.bmiHeader.biSize = showVideo.SizeOf(bitmapinfo.bmiHeader);//帧图片 头部定义
        //帧图片 头部定义
        bitmapinfo.bmiHeader.biWidth = 352;//宽
        bitmapinfo.bmiHeader.biHeight = 288;//高
        bitmapinfo.bmiHeader.biPlanes = 1;//Specifies the number of planes for the target device. This value must be set to 1
                                          //为目标设备指定的平面值,不存在多维度。
        bitmapinfo.bmiHeader.biBitCount = 24;
        //biBitCount成员的结构决定了BITMAPINFOHEADER的比特数定义的最大数量,每一个像素色彩的位图。
    
    
        this.capSetVideoFormat(this.lwndC, ref bitmapinfo, showVideo.SizeOf(bitmapinfo));
    
           //委托和事件的定义。
        this.mFrameEventHandler = new showVideo.FrameEventHandler(FrameCallBack);
    
    
        this.capSetCallbackOnFrame(this.lwndC, this.mFrameEventHandler);//回调函数。
        showVideo.SetWindowPos(this.lwndC, 0, 0, 0, mWidth , mHeight , 6);
       } 
      }
     
      // private functions
      private bool capDriverConnect(IntPtr lwnd, short i)
      {
          return showVideo.SendMessage(lwnd, showVideo.WM_CAP_DRIVER_CONNECT, i, 0);//参数 句柄,1024+100,0,0,
      }
     
         //   hWnd:窗口句柄。 wMsg:将要发送的消息。 wParam、lParam:消息的参数,每个消息都有两个参数,参数设置由发送的消息而定。
         //SendMessage(hHwnd, 0x40a, 0, 0),第一个参数是句柄,第二个参数表示的是一个消息,是哪个消息呢?后两个参数是到底为消息提供什么样的东西呢?
    //回答:0x40a 表示 WM_CAP_DRIVER_CONNECT消息,后面两个参数表示消息附带的两个参数,每个消息都有两个参数的。按照VFW的规定,//第一个参数是捕获设备的索引。这儿是0,表示你的第一个捕获设备。第二参数恒为0。为什么?VFW就是这么规定的。
    //具体参见MSND中Enumerating Installed Capture Drivers相关章节。就OK了。
    
      private bool capDriverDisconnect(IntPtr lwnd)
      {
       return showVideo.SendMessage(lwnd, showVideo.WM_CAP_DRIVER_DISCONNECT, 0, 0);
      }
         
      private bool capPreview(IntPtr lwnd, bool f)
      {
          return showVideo.SendMessage(lwnd, showVideo.WM_CAP_SET_PREVIEW, f, 0);//打开预览
      }
     
      private bool capPreviewRate(IntPtr lwnd, short wMS)
      {
       return showVideo.SendMessage(lwnd, showVideo.WM_CAP_SET_PREVIEWRATE, wMS, 0);
      }
      //设置预览时的帧频率 
      //   hWnd:窗口句柄。 wMsg:将要发送的消息。 帧率86,0
        //设置在PREVIEW模式下设定视频窗口的刷新率 设置每40毫秒显示一帧,即显示帧速为每秒25帧
    
      private bool capSetCallbackOnFrame(IntPtr lwnd, showVideo.FrameEventHandler lpProc)
      {     
       return showVideo.SendMessage(lwnd, showVideo.WM_CAP_SET_CALLBACK_FRAME, 0, lpProc);
      }
    
      //回调函数。当在这个句柄中数据接收到一帧时。WM_CAP_SET_CALLBACK_FRAME时。发消息给当前句柄。调用回调函数。
    
    
    
    
    
    
    
    
    
      //    this.capSetVideoFormat(this.lwndC, ref bitmapinfo, showVideo.SizeOf(bitmapinfo));
      //返回对象的非托管大小(以字节为单位)
    
         //这里使用 REF保证图片改变时全部相关信息对应改变。
      //ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。//若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
      private bool capSetVideoFormat(IntPtr hCapWnd, ref showVideo.BITMAPINFO BmpFormat, int CapFormatSize)
      {
       return showVideo.SendMessage(hCapWnd, showVideo.WM_CAP_SET_VIDEOFORMAT, CapFormatSize, ref BmpFormat);//捕获视频数据。//大小和结构,把消息发送到这个句柄上。
      }
     
    
    
    
    
         //每次回调时进入这里
        
      private void FrameCallBack(IntPtr lwnd, IntPtr lpVHdr)//两个句柄
      {
          showVideo.VIDEOHDR videoHeader = new showVideo.VIDEOHDR();//VideoHdr 结构定义
       byte[] VideoData;
       videoHeader = (showVideo.VIDEOHDR)showVideo.GetStructure(lpVHdr,videoHeader);//得到这样的一个结构 内容   参数:句柄,值类型(结构)
       //调用Marshal.PtrToStructure(ptr,structure.GetType());方法
    
       //将数据从非托管内存块封送到托管对象。
       //指向非托管内存块的指针。lpVHdr
       //将数据复制到其中的对象。这必须是格式化类的实例。videoHeader
    
    
       VideoData = new byte[videoHeader.dwBytesUsed];//实际使用的大小,初始化Byte缓冲大小定义
    
       showVideo.Copy(videoHeader.lpData, VideoData);//从非托管内存指针复制到托管数组。
                      //指向数据缓存的指针
       if (this.RecievedFrame != null)
        this.RecievedFrame (VideoData);
      }
     }
    
    
    
    }
    
  • 相关阅读:
    最清晰易懂的Mysql CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP区别
    yield再理解--绝对够透彻
    解决pyspider框架web预览框过小问题
    python中的可哈希与不可哈希
    python json.dumps 中的ensure_ascii 参数引起的中文编码问题
    LeetCode 297. 二叉树的序列化与反序列化 | Python
    LeetCode 1300. 转变数组后最接近目标值的数组和 | Python
    LeetCode 30. 串联所有单词的子串 | Python
    LeetCode 739. 每日温度 | Python
    LeetCode 128. 最长连续序列 | Python
  • 原文地址:https://www.cnblogs.com/mahaisong/p/2153653.html
Copyright © 2011-2022 走看看