forked from vmille25/CSharp-screen-recorder
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRecorderParams.cs
151 lines (127 loc) · 5.33 KB
/
RecorderParams.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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
{
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);
}
}
}
}
}