Do you have some library to capture a screen to be a compressed video file or some solution that can do it?
Asked
Active
Viewed 7.7k times
2 Answers
49
This code uses SharpAvi available on NuGet.
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);
}
}
}
}
}
Example Usage
- Create a console application.
- Add Reference to
System.DrawingandSystem.Windows.Forms. (The usage ofSystem.Windows.Formscan be avoided if you modify the code). - Install SharpAvi from NuGet.
Code:
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();
}
}
}
Mathew Sachin
- 1,359
- 1
- 14
- 20
-
1Can you describe a little bit more here? – Enamul Hassan Sep 26 '15 at 13:26
-
The app uses user32.dll and gdi32.dll to capture screenshots and writes them into the AviWriter along with audio captured using WaveIn api – Mathew Sachin Sep 26 '15 at 13:57
-
1Worked for me! Thanks for share it Mathew! – Jordi Espada Jun 20 '16 at 13:33
-
What is FourCC here. – Apr 27 '17 at 19:45
-
FourCC stands for 4 'character code'. It is a type defined in SharpAvi, used to identify an encoder installed in the system. – Mathew Sachin Apr 27 '17 at 21:38
-
SharpAvi contains a class: KnownFourCCs.Codecs which contains FourCCs of codecs like MotionJPEG, Xvid, x264, etc. – Mathew Sachin Apr 27 '17 at 21:40
-
What should I pass as FourCC argument – May 03 '17 at 11:29
-
Try passing `KnownFourCCs.Codecs.MotionJpeg`. – Mathew Sachin May 03 '17 at 15:43
-
It is implemented in SharpAvi and should work even if your system does not have any codecs available. – Mathew Sachin May 03 '17 at 15:43
-
Thankyou Mathew Sachin its recording video but how to save this recording – May 19 '17 at 13:16
-
I added an example usage in the answer. Hope that it will answer your question. – Mathew Sachin May 19 '17 at 17:23
-
Mathew I did not find save output file please tell me how to save output as mp4 or other video format. – TAHA SULTAN TEMURI Jun 22 '17 at 13:26
-
1Why captured video has speed x2 or even x3? – Yoda Apr 05 '19 at 11:06
-
1This SharpAvi is speeding up videos, regardless of how slow I feed him bitmaps, even when I added blocking queue. Don't waist your time on the code above. – Yoda Apr 08 '19 at 16:08
-
Additionaly even Captura standalone app has exactly the same performance issues on Xeon, 32GB Ram, 500GB SSD, Quadro 2000 laptop. – Yoda Apr 09 '19 at 08:44
-
Issue with `RecorderParams` constructor in VB. It seems case insensitive, so when creating a new `Recorder` object with `RecorderParams` threw a null filepath exception. The parameter was setting to itself. Fixed by adding an underscore in the constructor arguments, to `filename`. Other than that, great answer. Couldn't have been any easier. – Tyler Montney Sep 16 '19 at 20:41
-
Amazing staff, what about put the link to github to the end? Since the code in the page is great enough. The git hub project run with errors. – jw_ Feb 19 '20 at 11:49
-
How to capture sound at the same time? – jw_ Feb 20 '20 at 02:08
21
Your best option seems to be Windows Media Encoder.
Here are some links:
http://www.codeproject.com/KB/audio-video/CaptureScreenAsVideo.aspx
http://mycomponent.blogspot.com/2009/04/capture-screen-activitiesvideo-using.html
Andre Luus
- 3,594
- 3
- 31
- 45
-
I looking for DirectshowNet, but I don't know what should I use the input filter for screen capture. – Gramero Nov 09 '10 at 06:12