C#使用 SharpAVI进行 屏幕录制

再 nuget 中 搜索 shapAvi 并添加引用git

github 地址:https://github.com/baSSiLL/SharpAvigithub

 

using SharpAvi; using SharpAvi.Codecs; using SharpAvi.Output; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace BankAutoTransfer.Common { public class Recorder { private readonly int zoomWidth; private readonly int zoomHeight; private readonly AviWriter writer; private readonly IAviVideoStream videoStream; private readonly Thread screenThread; /// <summary>
        /// 上一次图片 /// </summary>
        Bitmap lastBitmap = new Bitmap(10, 10); bool stop = false; /// <summary>
        /// 缩放 /// </summary>
        float zoom = 1; /// <summary>
        /// 鼠标是否点击 /// </summary>
        bool mouseclick = false; /// <summary>
        /// 钩子句柄 /// </summary>
        int hook = 0; /// <summary>
        /// 录制屏幕 /// </summary>
        /// <param name="fileName">要保存的文件名</param>
        /// <param name="codec">编码</param>
        /// <param name="quality">录制质量</param>
        /// <param name="zoom">缩放</param>
        public Recorder(string fileName, FourCC codec, int quality = 70, float zoom = 1.0F) { //设置缩放 宽高
            zoomHeight = (int)Math.Floor(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height * zoom); zoomWidth = (int)Math.Floor(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width * zoom); this.zoom = zoom; //建立视频
            writer = new AviWriter(fileName) { FramesPerSecond = 10, EmitIndex1 = true, }; //建立视频流
            videoStream = CreateVideoStream(codec, quality); videoStream.Name = "Screencast"; //开启一个线程录制屏幕
            screenThread = new Thread(RecordScreen) { Name = typeof(Recorder).Name + ".RecordScreen", IsBackground = true }; //钩子函数用于监控是否点击了鼠标
            hook = WinHook.SetWindowsHookEx(HookType.WH_MOUSE_LL, WinHook.hookProc += MouseHook, Win32Api.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0); screenThread.Start(); } private IAviVideoStream CreateVideoStream(FourCC codec, int quality) { // Select encoder type based on FOURCC of codec
            if (codec == KnownFourCCs.Codecs.Uncompressed) { return writer.AddUncompressedVideoStream(zoomWidth, zoomHeight); } else if (codec == KnownFourCCs.Codecs.MotionJpeg) { return writer.AddMotionJpegVideoStream(zoomWidth, zoomHeight, quality); } else { return writer.AddMpeg4VideoStream(zoomWidth, zoomHeight, (double)writer.FramesPerSecond, // It seems that all tested MPEG-4 VfW codecs ignore the quality affecting parameters passed through VfW API // They only respect the settings from their own configuration dialogs, and Mpeg4VideoEncoder currently has no support for this
 quality: quality, codec: codec, // Most of VfW codecs expect single-threaded use, so we wrap this encoder to special wrapper // Thus all calls to the encoder (including its instantiation) will be invoked on a single thread although encoding (and writing) is performed asynchronously
                    forceSingleThreadedAccess: true); } } /// <summary>
        /// 中止录制 /// </summary>
        public void Stop() { WinHook.UnhookWindowsHookEx(hook); lastBitmap.Dispose(); stop = true; } private void RecordScreen() { while (!stop) { var buffer = GetScreenshot(); // 把图片写入视频流
                videoStream.WriteFrameAsync(true, buffer, 0, buffer.Length).Wait(); } writer.Close(); } private byte[] GetScreenshot() { using (Bitmap avibitmap = GetScreen()) { Point mouseXY = new Point(); Win32Api.GetCursorPos(ref mouseXY); using (Graphics mouseGraphics = Graphics.FromImage(avibitmap)) { //绘制鼠标位置
                    if (mouseclick) mouseGraphics.DrawEllipse(new Pen(new SolidBrush(Color.Red), 10), new Rectangle(mouseXY.X - 10, mouseXY.Y - 10, 20, 20)); else mouseGraphics.DrawEllipse(new Pen(new SolidBrush(Color.Black), 5), new Rectangle(mouseXY.X - 10, mouseXY.Y - 10, 20, 20)); if (zoom != 1) { //缩放
                        using (var copy = new Bitmap(this.zoomWidth, this.zoomHeight)) { var buffer = new byte[copy.Width * copy.Height * 4]; var gcopy = Graphics.FromImage(copy); gcopy.DrawImage(avibitmap, new Rectangle(new Point(0, 0), copy.Size), 0, 0, avibitmap.Width, avibitmap.Height, GraphicsUnit.Pixel); gcopy.Dispose(); var bits = copy.LockBits(new Rectangle(0, 0, copy.Width, copy.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); Marshal.Copy(bits.Scan0, buffer, 0, buffer.Length); copy.UnlockBits(bits); return buffer; } } else { var buffer = new byte[avibitmap.Width * avibitmap.Height * 4]; var bits = avibitmap.LockBits(new Rectangle(0, 0, avibitmap.Width, avibitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); Marshal.Copy(bits.Scan0, buffer, 0, buffer.Length); avibitmap.UnlockBits(bits); return buffer; } } } } private Bitmap GetScreen() { try { var bitmap = new Bitmap(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height); var graphics = Graphics.FromImage(bitmap); graphics.CopyFromScreen(0, 0, 0, 0, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Size); graphics.Dispose(); lastBitmap.Dispose(); lastBitmap = bitmap; } catch { } return (Bitmap)lastBitmap.Clone(); } private int MouseHook(int nCode, int wParam, IntPtr lParam) { if (wParam == CommonConst.WM_LBUTTONDOWN) mouseclick = true; else if (wParam == CommonConst.WM_LBUTTONUP) mouseclick = false; return WinHook.CallNextHookEx(hook, nCode, wParam, lParam); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace BankAutoTransfer.Common { public class WinHook { [DllImport("user32.dll")] public static extern int SetWindowsHookEx( HookType idHook, HookProc lpfn, IntPtr hInstance, int threadId ); public delegate int HookProc(int nCode, int wParam, IntPtr lParam); public static HookProc hookProc; [DllImport("user32.dll")] public static extern int CallNextHookEx( int hhk,      //handle to current hook 
            int nCode,      //hook code passed to hook procedure 
            int wParam,      //value passed to hook procedure 
            IntPtr lParam       //value passed to hook procedure 
 ); [DllImport("user32.dll")] public static extern bool UnhookWindowsHookEx(int hook); } /// <summary>
    /// 设置的钩子类型 /// </summary>
    public enum HookType : int { /// <summary>
        /// WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使咱们能够监视菜单,滚动 ///条,消息框,对话框消息而且发现用户使用ALT+TAB or ALT+ESC 组合键切换窗口。 ///WH_MSGFILTER Hook只能监视传递到菜单,滚动条,消息框的消息,以及传递到通 ///过安装了Hook子过程的应用程序创建的对话框的消息。WH_SYSMSGFILTER Hook ///监视全部应用程序消息。 /// 
        ///WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使咱们能够在模式循环期间 ///过滤消息,这等价于在主消息循环中过滤消息。 ///    
        ///经过调用CallMsgFilter function能够直接的调用WH_MSGFILTER Hook。经过使用这 ///个函数,应用程序可以在模式循环期间使用相同的代码去过滤消息,如同在主消息循 ///环里同样 /// </summary>
        WH_MSGFILTER = -1, /// <summary>
        /// WH_JOURNALRECORD Hook用来监视和记录输入事件。典型的,可使用这 ///个Hook记录连续的鼠标和键盘事件,而后经过使用WH_JOURNALPLAYBACK Hook ///来回放。WH_JOURNALRECORD Hook是全局Hook,它不能象线程特定Hook同样 ///使用。WH_JOURNALRECORD是system-wide local hooks,它们不会被注射到任何行 ///程地址空间 /// </summary>
        WH_JOURNALRECORD = 0, /// <summary>
        /// WH_JOURNALPLAYBACK Hook使应用程序能够插入消息到系统消息队列。可 ///以使用这个Hook回放经过使用WH_JOURNALRECORD Hook记录下来的连续的鼠 ///标和键盘事件。只要WH_JOURNALPLAYBACK Hook已经安装,正常的鼠标和键盘 ///事件就是无效的。WH_JOURNALPLAYBACK Hook是全局Hook,它不能象线程特定 ///Hook同样使用。WH_JOURNALPLAYBACK Hook返回超时值,这个值告诉系统在处 ///理来自回放Hook当前消息以前须要等待多长时间(毫秒)。这就使Hook能够控制实 ///时事件的回放。WH_JOURNALPLAYBACK是system-wide local hooks,它们不会被 ///注射到任何行程地址空间 /// </summary>
        WH_JOURNALPLAYBACK = 1, /// <summary>
        /// 在应用程序中,WH_KEYBOARD Hook用来监视WM_KEYDOWN and ///WM_KEYUP消息,这些消息经过GetMessage or PeekMessage function返回。可使 ///用这个Hook来监视输入到消息队列中的键盘消息 /// </summary>
        WH_KEYBOARD = 2, /// <summary>
        /// 应用程序使用WH_GETMESSAGE Hook来监视从GetMessage or PeekMessage函 ///数返回的消息。你可使用WH_GETMESSAGE Hook去监视鼠标和键盘输入,以及 ///其它发送到消息队列中的消息 /// </summary>
        WH_GETMESSAGE = 3, /// <summary>
        /// 监视发送到窗口过程的消息,系统在消息发送到接收窗口过程以前调用 /// </summary>
        WH_CALLWNDPROC = 4, /// <summary>
        /// 在如下事件以前,系统都会调用WH_CBT Hook子过程,这些事件包括: ///1. 激活,创建,销毁,最小化,最大化,移动,改变尺寸等窗口事件; ///2. 完成系统指令; ///3. 来自系统消息队列中的移动鼠标,键盘事件; ///4. 设置输入焦点事件; ///5. 同步系统消息队列事件。 ///Hook子过程的返回值肯定系统是否容许或者防止这些操做中的一个 /// </summary>
        WH_CBT = 5, /// <summary>
        /// WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使咱们能够监视菜单,滚动 ///条,消息框,对话框消息而且发现用户使用ALT+TAB or ALT+ESC 组合键切换窗口。 ///WH_MSGFILTER Hook只能监视传递到菜单,滚动条,消息框的消息,以及传递到通 ///过安装了Hook子过程的应用程序创建的对话框的消息。WH_SYSMSGFILTER Hook ///监视全部应用程序消息。 /// 
        ///WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使咱们能够在模式循环期间 ///过滤消息,这等价于在主消息循环中过滤消息。 ///    
        ///经过调用CallMsgFilter function能够直接的调用WH_MSGFILTER Hook。经过使用这 ///个函数,应用程序可以在模式循环期间使用相同的代码去过滤消息,如同在主消息循 ///环里同样 /// </summary>
        WH_SYSMSGFILTER = 6, /// <summary>
        /// WH_MOUSE Hook监视从GetMessage 或者 PeekMessage 函数返回的鼠标消息。 ///使用这个Hook监视输入到消息队列中的鼠标消息 /// </summary>
        WH_MOUSE = 7, /// <summary>
        /// 当调用GetMessage 或 PeekMessage 来从消息队列种查询非鼠标、键盘消息时 /// </summary>
        WH_HARDWARE = 8, /// <summary>
        /// 在系统调用系统中与其它Hook关联的Hook子过程以前,系统会调用 ///WH_DEBUG Hook子过程。你可使用这个Hook来决定是否容许系统调用与其它 ///Hook关联的Hook子过程 /// </summary>
        WH_DEBUG = 9, /// <summary>
        /// 外壳应用程序可使用WH_SHELL Hook去接收重要的通知。当外壳应用程序是 ///激活的而且当顶层窗口创建或者销毁时,系统调用WH_SHELL Hook子过程。 ///WH_SHELL 共有5钟状况: ///1. 只要有个top-level、unowned 窗口被产生、起做用、或是被摧毁; ///2. 当Taskbar须要重画某个按钮; ///3. 当系统须要显示关于Taskbar的一个程序的最小化形式; ///4. 当目前的键盘布局状态改变; ///5. 当使用者按Ctrl+Esc去执行Task Manager(或相同级别的程序)。 ///
        ///按照惯例,外壳应用程序都不接收WH_SHELL消息。因此,在应用程序可以接 ///收WH_SHELL消息以前,应用程序必须调用SystemParametersInfo function注册它自 ////// </summary>
        WH_SHELL = 10, /// <summary>
        /// 当应用程序的前台线程处于空闲状态时,可使用WH_FOREGROUNDIDLE ///Hook执行低优先级的任务。当应用程序的前台线程大概要变成空闲状态时,系统就 ///会调用WH_FOREGROUNDIDLE Hook子过程 /// </summary>
        WH_FOREGROUNDIDLE = 11, /// <summary>
        /// 监视发送到窗口过程的消息,系统在消息发送到接收窗口过程以后调用 /// </summary>
        WH_CALLWNDPROCRET = 12, /// <summary>
        /// 监视输入到线程消息队列中的键盘消息 /// </summary>
        WH_KEYBOARD_LL = 13, /// <summary>
        /// 监视输入到线程消息队列中的鼠标消息 /// </summary>
        WH_MOUSE_LL = 14 } }
相关文章
相关标签/搜索