【问题标题】:How to capture screen to be video using C# .Net?如何使用 C# .Net 将屏幕捕获为视频?
【发布时间】:2011-05-03 09:01:59
【问题描述】:

您是否有一些库可以将屏幕捕获为压缩视频文件或一些可以做到这一点的解决方案?

【问题讨论】:

    标签: c# .net video video-capture


    【解决方案1】:

    此代码使用 NuGet 上提供的 SharpAvi。

    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Runtime.InteropServices;
    using System.Threading;
    using System.Threading.Tasks;
    using SharpAvi;
    using SharpAvi.Codecs;
    using SharpAvi.Output;
    using System.Windows.Forms;
    
    namespace Captura
    {
        // Used to Configure the Recorder
        public class RecorderParams
        {
            public RecorderParams(string filename, int FrameRate, FourCC Encoder, int Quality)
            {
                FileName = filename;
                FramesPerSecond = FrameRate;
                Codec = Encoder;
                this.Quality = Quality;
    
                Height = Screen.PrimaryScreen.Bounds.Height;
                Width = Screen.PrimaryScreen.Bounds.Width;
            }
    
            string FileName;
            public int FramesPerSecond, Quality;
            FourCC Codec;
    
            public int Height { get; private set; }
            public int Width { get; private set; }
    
            public AviWriter CreateAviWriter()
            {
                return new AviWriter(FileName)
                {
                    FramesPerSecond = FramesPerSecond,
                    EmitIndex1 = true,
                };
            }
    
            public IAviVideoStream CreateVideoStream(AviWriter writer)
            {
                // Select encoder type based on FOURCC of codec
                if (Codec == KnownFourCCs.Codecs.Uncompressed)
                    return writer.AddUncompressedVideoStream(Width, Height);
                else if (Codec == KnownFourCCs.Codecs.MotionJpeg)
                    return writer.AddMotionJpegVideoStream(Width, Height, Quality);
                else
                {
                    return writer.AddMpeg4VideoStream(Width, Height, (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);
                }
            }
        }
    
        public class Recorder : IDisposable
        {
            #region Fields
            AviWriter writer;
            RecorderParams Params;
            IAviVideoStream videoStream;
            Thread screenThread;
            ManualResetEvent stopThread = new ManualResetEvent(false);
            #endregion
    
            public Recorder(RecorderParams Params)
            {
                this.Params = Params;
    
                // Create AVI writer and specify FPS
                writer = Params.CreateAviWriter();
    
                // Create video stream
                videoStream = Params.CreateVideoStream(writer);
                // Set only name. Other properties were when creating stream, 
                // either explicitly by arguments or implicitly by the encoder used
                videoStream.Name = "Captura";
    
                screenThread = new Thread(RecordScreen)
                {
                    Name = typeof(Recorder).Name + ".RecordScreen",
                    IsBackground = true
                };
    
                screenThread.Start();
            }
    
            public void Dispose()
            {
                stopThread.Set();
                screenThread.Join();
    
                // Close writer: the remaining data is written to a file and file is closed
                writer.Close();
    
                stopThread.Dispose();
            }
    
            void RecordScreen()
            {
                var frameInterval = TimeSpan.FromSeconds(1 / (double)writer.FramesPerSecond);
                var buffer = new byte[Params.Width * Params.Height * 4];
                Task videoWriteTask = null;
                var timeTillNextFrame = TimeSpan.Zero;
    
                while (!stopThread.WaitOne(timeTillNextFrame))
                {
                    var timestamp = DateTime.Now;
    
                    Screenshot(buffer);
    
                    // Wait for the previous frame is written
                    videoWriteTask?.Wait();
    
                    // Start asynchronous (encoding and) writing of the new frame
                    videoWriteTask = videoStream.WriteFrameAsync(true, buffer, 0, buffer.Length);
    
                    timeTillNextFrame = timestamp + frameInterval - DateTime.Now;
                    if (timeTillNextFrame < TimeSpan.Zero)
                        timeTillNextFrame = TimeSpan.Zero;
                }
    
                // Wait for the last frame is written
                videoWriteTask?.Wait();
            }
    
            public void Screenshot(byte[] Buffer)
            {
                using (var BMP = new Bitmap(Params.Width, Params.Height))
                {
                    using (var g = Graphics.FromImage(BMP))
                    {
                        g.CopyFromScreen(Point.Empty, Point.Empty, new Size(Params.Width, Params.Height), CopyPixelOperation.SourceCopy);
    
                        g.Flush();
    
                        var bits = BMP.LockBits(new Rectangle(0, 0, Params.Width, Params.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
                        Marshal.Copy(bits.Scan0, Buffer, 0, Buffer.Length);
                        BMP.UnlockBits(bits);
                    }
                }
            }
        }
    }
    

    示例用法

    1. 创建控制台应用程序。
    2. 添加对System.DrawingSystem.Windows.Forms 的引用。 (修改代码可以避免使用System.Windows.Forms)。
    3. 从 NuGet 安装 SharpAvi。

    代码:

    using Captura;
    using System;
    
    namespace ConsoleApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                // Using MotionJpeg as Avi encoder,
                // output to 'out.avi' at 10 Frames per second, 70% quality
                var rec = new Recorder(new RecorderParams("out.avi", 10, SharpAvi.KnownFourCCs.Codecs.MotionJpeg, 70));
    
                Console.WriteLine("Press any key to Stop...");
                Console.ReadKey();
    
                // Finish Writing
                rec.Dispose();
            }
        }
    }
    

    【讨论】:

    • 你能在这里多描述一下吗?
    • 该应用程序使用 user32.dll 和 gdi32.dll 捕获屏幕截图并将它们与使用 WaveIn api 捕获的音频一起写入 AviWriter
    • 为我工作!感谢马修分享!
    • 为什么捕获的视频速度是 x2 甚至 x3?
    • 这个 SharpAvi 正在加速视频,不管我给他的位图有多慢,即使我添加了阻塞队列。不要浪费时间在上面的代码上。
    【解决方案2】:

    【讨论】:

    • 我正在寻找 DirectshowNet,但我不知道应该使用什么输入过滤器进行屏幕捕获。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-14
    相关资源
    最近更新 更多