Screen recorder producing huge AVI files
up vote
8
down vote
favorite
I'm currently trying to make a screen recorder in C#, and so far it works but the problem is that something as simple as a 20second video will take about 1GB of space. I have it setup so a timer continuously takes screenshots with this method:
void takeScreenshot()
{
Rectangle bounds = Screen.FromControl(this).Bounds;
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
//Create and save screenshot:
string name = path + "//screenshot-" + fileCount + ".jpeg";
bitmap.Save(name, ImageFormat.Jpeg);
inputImageSequence.Add(name);
fileCount++;
//Dispose of bitmap:
bitmap.Dispose();
}
}
And then it stores those pictures in a temporary folder in the D:// drive, and then when it's done it takes all the pictures and creates an AVI video out of them like this:
//Set bounds of video to screen size:
Rectangle bounds = Screen.FromControl(this).Bounds;
int width = bounds.Width;
int height = bounds.Height;
var framRate = 5;
using (var vFWriter = new VideoFileWriter())
{
//Create new video file:
vFWriter.Open(outputPath+"//video.avi", width, height, framRate, VideoCodec.Raw);
//Make each screenshot into a video frame:
foreach (var imageLocation in inputImageSequence)
{
Bitmap imageFrame = System.Drawing.Image.FromFile(imageLocation) as Bitmap;
vFWriter.WriteVideoFrame(imageFrame);
imageFrame.Dispose();
}
vFWriter.Close();
}
//Delete the screenshots and temporary folder:
DeletePath(path);
Any help on reducing the inefficiency of this is appreciated, I'm fairly new to this kind of programming.
c# compression video
add a comment |
up vote
8
down vote
favorite
I'm currently trying to make a screen recorder in C#, and so far it works but the problem is that something as simple as a 20second video will take about 1GB of space. I have it setup so a timer continuously takes screenshots with this method:
void takeScreenshot()
{
Rectangle bounds = Screen.FromControl(this).Bounds;
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
//Create and save screenshot:
string name = path + "//screenshot-" + fileCount + ".jpeg";
bitmap.Save(name, ImageFormat.Jpeg);
inputImageSequence.Add(name);
fileCount++;
//Dispose of bitmap:
bitmap.Dispose();
}
}
And then it stores those pictures in a temporary folder in the D:// drive, and then when it's done it takes all the pictures and creates an AVI video out of them like this:
//Set bounds of video to screen size:
Rectangle bounds = Screen.FromControl(this).Bounds;
int width = bounds.Width;
int height = bounds.Height;
var framRate = 5;
using (var vFWriter = new VideoFileWriter())
{
//Create new video file:
vFWriter.Open(outputPath+"//video.avi", width, height, framRate, VideoCodec.Raw);
//Make each screenshot into a video frame:
foreach (var imageLocation in inputImageSequence)
{
Bitmap imageFrame = System.Drawing.Image.FromFile(imageLocation) as Bitmap;
vFWriter.WriteVideoFrame(imageFrame);
imageFrame.Dispose();
}
vFWriter.Close();
}
//Delete the screenshots and temporary folder:
DeletePath(path);
Any help on reducing the inefficiency of this is appreciated, I'm fairly new to this kind of programming.
c# compression video
add a comment |
up vote
8
down vote
favorite
up vote
8
down vote
favorite
I'm currently trying to make a screen recorder in C#, and so far it works but the problem is that something as simple as a 20second video will take about 1GB of space. I have it setup so a timer continuously takes screenshots with this method:
void takeScreenshot()
{
Rectangle bounds = Screen.FromControl(this).Bounds;
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
//Create and save screenshot:
string name = path + "//screenshot-" + fileCount + ".jpeg";
bitmap.Save(name, ImageFormat.Jpeg);
inputImageSequence.Add(name);
fileCount++;
//Dispose of bitmap:
bitmap.Dispose();
}
}
And then it stores those pictures in a temporary folder in the D:// drive, and then when it's done it takes all the pictures and creates an AVI video out of them like this:
//Set bounds of video to screen size:
Rectangle bounds = Screen.FromControl(this).Bounds;
int width = bounds.Width;
int height = bounds.Height;
var framRate = 5;
using (var vFWriter = new VideoFileWriter())
{
//Create new video file:
vFWriter.Open(outputPath+"//video.avi", width, height, framRate, VideoCodec.Raw);
//Make each screenshot into a video frame:
foreach (var imageLocation in inputImageSequence)
{
Bitmap imageFrame = System.Drawing.Image.FromFile(imageLocation) as Bitmap;
vFWriter.WriteVideoFrame(imageFrame);
imageFrame.Dispose();
}
vFWriter.Close();
}
//Delete the screenshots and temporary folder:
DeletePath(path);
Any help on reducing the inefficiency of this is appreciated, I'm fairly new to this kind of programming.
c# compression video
I'm currently trying to make a screen recorder in C#, and so far it works but the problem is that something as simple as a 20second video will take about 1GB of space. I have it setup so a timer continuously takes screenshots with this method:
void takeScreenshot()
{
Rectangle bounds = Screen.FromControl(this).Bounds;
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
//Create and save screenshot:
string name = path + "//screenshot-" + fileCount + ".jpeg";
bitmap.Save(name, ImageFormat.Jpeg);
inputImageSequence.Add(name);
fileCount++;
//Dispose of bitmap:
bitmap.Dispose();
}
}
And then it stores those pictures in a temporary folder in the D:// drive, and then when it's done it takes all the pictures and creates an AVI video out of them like this:
//Set bounds of video to screen size:
Rectangle bounds = Screen.FromControl(this).Bounds;
int width = bounds.Width;
int height = bounds.Height;
var framRate = 5;
using (var vFWriter = new VideoFileWriter())
{
//Create new video file:
vFWriter.Open(outputPath+"//video.avi", width, height, framRate, VideoCodec.Raw);
//Make each screenshot into a video frame:
foreach (var imageLocation in inputImageSequence)
{
Bitmap imageFrame = System.Drawing.Image.FromFile(imageLocation) as Bitmap;
vFWriter.WriteVideoFrame(imageFrame);
imageFrame.Dispose();
}
vFWriter.Close();
}
//Delete the screenshots and temporary folder:
DeletePath(path);
Any help on reducing the inefficiency of this is appreciated, I'm fairly new to this kind of programming.
c# compression video
c# compression video
edited Nov 28 at 7:24
t3chb0t
33.8k746111
33.8k746111
asked Nov 28 at 3:26
BenCompSci
585
585
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
up vote
13
down vote
takeScreenshot()
- Based on the .NET Naming Guidelines methods should be named using
PascalCasecasingtakeScreenshot()=>TakeScreenshot() - You are enclosing the usage of the
Bitmapinside ausingstatement which is the way to go but callingDispose()on thatBitmapis superfluous because that is what ausingstatement is doing.
If you have two
usingstatements without any code between you can stack them which saves one level of indentation like so (already removed theDispose())
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
//Create and save screenshot:
string name = path + "//screenshot-" + fileCount + ".jpeg";
bitmap.Save(name, ImageFormat.Jpeg);
inputImageSequence.Add(name);
fileCount++;
}
- Comments should explain why something is done in the way it is done. Let the code itself tell what is done by using meaningful named things. In this way your comments won't lie like e.g
//Create and save screenshot:which isn't what that code does. Saving yes but no creating of a screenshot is taking place.
Creating the video
- Try to be consistent. Here you create a
Bitmapand callDispose()instead of using ausingstatement. In addition, sometime you usevarand sometimes you use the concrete type although the type is seen at first glance. - If you are using the
asoperator you should always add anullcheck for that object because anasoperator won't throw an exception but the resulting object may benullwhich will trigger an exception somewhere else.
Implementing these points will look like this:
Rectangle bounds = Screen.FromControl(this).Bounds;
var width = bounds.Width;
var height = bounds.Height;
var framRate = 5;
using (var vFWriter = new VideoFileWriter())
{
vFWriter.Open(outputPath+"//video.avi", width, height, framRate, VideoCodec.Raw);
foreach (var imageLocation in inputImageSequence)
{
using(var imageFrame = (Bitmap)System.Drawing.Image.FromFile(imageLocation))
{
vFWriter.WriteVideoFrame(imageFrame);
}
}
vFWriter.Close();
}
DeletePath(path);
My guess about the big file size is that you are using the VideoCodec.Raw. Try to change it to some other codec and see if this helps.
@Glorfindel thanks for the edits.
– Heslacher
Nov 28 at 13:03
add a comment |
up vote
8
down vote
You could write the screenshots directly to the video stream. This could save you a lot of disk space depending on your capture time.
To make the video file smaller you need to use a codec that compresses the output like MPEG-4.
Finally you could encapsulate the recording in its own class:
public sealed class ScreenRecorder : IDisposable
{
private readonly VideoFileWriter videoFileWriter = new VideoFileWriter();
private readonly string videoFilePath;
private readonly Rectangle bounds;
public ScreenRecorder(string videoFilePath, Rectangle bounds, int frameRate = 5, VideoCodec videoCodec = VideoCodec.MPEG4)
{
if (string.IsNullOrWhiteSpace(videoFilePath))
{
throw new ArgumentException("Must be a valid filename", nameof(videoFilePath));
}
if(frameRate < 1)
{
throw new ArgumentOutOfRangeException(nameof(frameRate));
}
this.videoFilePath = videoFilePath;
this.bounds = bounds;
videoFileWriter.Open(videoFilePath, bounds.Width, bounds.Height, frameRate, videoCodec);
}
public void TakeScreenshot()
{
if (disposed)
{
throw new ObjectDisposedException(nameof(ScreenRecorder));
}
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
videoFileWriter.WriteVideoFrame(bitmap);
}
}
public void Stop() => Dispose();
#region IDisposable Support
private bool disposed = false; // To detect redundant calls
void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
videoFileWriter.Dispose();
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
add a comment |
up vote
4
down vote
Using string concatenation for creating file paths opens you up to a whole lot of headache. Should you use /, //, or \? The answer depends on the environment you are running in. Luckily, the Path class can do all this logic for us:
Instead of
path + "//screenshot-" + fileCount + ".jpeg";
you could do
Path.Combine(path, $"screenshot-{fileCount}.jpeg");
and instead of
outputPath+"//video.avi"
Path.Combine(outputPath, "video.avi")
This way you don't have to worry about using the right fileseparator.
add a comment |
up vote
0
down vote
Thanks to all your help as well as the help of many others, I have actually fully compelted the screen recorder and have typed up an explanation here if anyone is interested: https://benbcompsci.wordpress.com/2018/12/04/c-screen-recorder/
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208582%2fscreen-recorder-producing-huge-avi-files%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
13
down vote
takeScreenshot()
- Based on the .NET Naming Guidelines methods should be named using
PascalCasecasingtakeScreenshot()=>TakeScreenshot() - You are enclosing the usage of the
Bitmapinside ausingstatement which is the way to go but callingDispose()on thatBitmapis superfluous because that is what ausingstatement is doing.
If you have two
usingstatements without any code between you can stack them which saves one level of indentation like so (already removed theDispose())
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
//Create and save screenshot:
string name = path + "//screenshot-" + fileCount + ".jpeg";
bitmap.Save(name, ImageFormat.Jpeg);
inputImageSequence.Add(name);
fileCount++;
}
- Comments should explain why something is done in the way it is done. Let the code itself tell what is done by using meaningful named things. In this way your comments won't lie like e.g
//Create and save screenshot:which isn't what that code does. Saving yes but no creating of a screenshot is taking place.
Creating the video
- Try to be consistent. Here you create a
Bitmapand callDispose()instead of using ausingstatement. In addition, sometime you usevarand sometimes you use the concrete type although the type is seen at first glance. - If you are using the
asoperator you should always add anullcheck for that object because anasoperator won't throw an exception but the resulting object may benullwhich will trigger an exception somewhere else.
Implementing these points will look like this:
Rectangle bounds = Screen.FromControl(this).Bounds;
var width = bounds.Width;
var height = bounds.Height;
var framRate = 5;
using (var vFWriter = new VideoFileWriter())
{
vFWriter.Open(outputPath+"//video.avi", width, height, framRate, VideoCodec.Raw);
foreach (var imageLocation in inputImageSequence)
{
using(var imageFrame = (Bitmap)System.Drawing.Image.FromFile(imageLocation))
{
vFWriter.WriteVideoFrame(imageFrame);
}
}
vFWriter.Close();
}
DeletePath(path);
My guess about the big file size is that you are using the VideoCodec.Raw. Try to change it to some other codec and see if this helps.
@Glorfindel thanks for the edits.
– Heslacher
Nov 28 at 13:03
add a comment |
up vote
13
down vote
takeScreenshot()
- Based on the .NET Naming Guidelines methods should be named using
PascalCasecasingtakeScreenshot()=>TakeScreenshot() - You are enclosing the usage of the
Bitmapinside ausingstatement which is the way to go but callingDispose()on thatBitmapis superfluous because that is what ausingstatement is doing.
If you have two
usingstatements without any code between you can stack them which saves one level of indentation like so (already removed theDispose())
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
//Create and save screenshot:
string name = path + "//screenshot-" + fileCount + ".jpeg";
bitmap.Save(name, ImageFormat.Jpeg);
inputImageSequence.Add(name);
fileCount++;
}
- Comments should explain why something is done in the way it is done. Let the code itself tell what is done by using meaningful named things. In this way your comments won't lie like e.g
//Create and save screenshot:which isn't what that code does. Saving yes but no creating of a screenshot is taking place.
Creating the video
- Try to be consistent. Here you create a
Bitmapand callDispose()instead of using ausingstatement. In addition, sometime you usevarand sometimes you use the concrete type although the type is seen at first glance. - If you are using the
asoperator you should always add anullcheck for that object because anasoperator won't throw an exception but the resulting object may benullwhich will trigger an exception somewhere else.
Implementing these points will look like this:
Rectangle bounds = Screen.FromControl(this).Bounds;
var width = bounds.Width;
var height = bounds.Height;
var framRate = 5;
using (var vFWriter = new VideoFileWriter())
{
vFWriter.Open(outputPath+"//video.avi", width, height, framRate, VideoCodec.Raw);
foreach (var imageLocation in inputImageSequence)
{
using(var imageFrame = (Bitmap)System.Drawing.Image.FromFile(imageLocation))
{
vFWriter.WriteVideoFrame(imageFrame);
}
}
vFWriter.Close();
}
DeletePath(path);
My guess about the big file size is that you are using the VideoCodec.Raw. Try to change it to some other codec and see if this helps.
@Glorfindel thanks for the edits.
– Heslacher
Nov 28 at 13:03
add a comment |
up vote
13
down vote
up vote
13
down vote
takeScreenshot()
- Based on the .NET Naming Guidelines methods should be named using
PascalCasecasingtakeScreenshot()=>TakeScreenshot() - You are enclosing the usage of the
Bitmapinside ausingstatement which is the way to go but callingDispose()on thatBitmapis superfluous because that is what ausingstatement is doing.
If you have two
usingstatements without any code between you can stack them which saves one level of indentation like so (already removed theDispose())
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
//Create and save screenshot:
string name = path + "//screenshot-" + fileCount + ".jpeg";
bitmap.Save(name, ImageFormat.Jpeg);
inputImageSequence.Add(name);
fileCount++;
}
- Comments should explain why something is done in the way it is done. Let the code itself tell what is done by using meaningful named things. In this way your comments won't lie like e.g
//Create and save screenshot:which isn't what that code does. Saving yes but no creating of a screenshot is taking place.
Creating the video
- Try to be consistent. Here you create a
Bitmapand callDispose()instead of using ausingstatement. In addition, sometime you usevarand sometimes you use the concrete type although the type is seen at first glance. - If you are using the
asoperator you should always add anullcheck for that object because anasoperator won't throw an exception but the resulting object may benullwhich will trigger an exception somewhere else.
Implementing these points will look like this:
Rectangle bounds = Screen.FromControl(this).Bounds;
var width = bounds.Width;
var height = bounds.Height;
var framRate = 5;
using (var vFWriter = new VideoFileWriter())
{
vFWriter.Open(outputPath+"//video.avi", width, height, framRate, VideoCodec.Raw);
foreach (var imageLocation in inputImageSequence)
{
using(var imageFrame = (Bitmap)System.Drawing.Image.FromFile(imageLocation))
{
vFWriter.WriteVideoFrame(imageFrame);
}
}
vFWriter.Close();
}
DeletePath(path);
My guess about the big file size is that you are using the VideoCodec.Raw. Try to change it to some other codec and see if this helps.
takeScreenshot()
- Based on the .NET Naming Guidelines methods should be named using
PascalCasecasingtakeScreenshot()=>TakeScreenshot() - You are enclosing the usage of the
Bitmapinside ausingstatement which is the way to go but callingDispose()on thatBitmapis superfluous because that is what ausingstatement is doing.
If you have two
usingstatements without any code between you can stack them which saves one level of indentation like so (already removed theDispose())
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
//Create and save screenshot:
string name = path + "//screenshot-" + fileCount + ".jpeg";
bitmap.Save(name, ImageFormat.Jpeg);
inputImageSequence.Add(name);
fileCount++;
}
- Comments should explain why something is done in the way it is done. Let the code itself tell what is done by using meaningful named things. In this way your comments won't lie like e.g
//Create and save screenshot:which isn't what that code does. Saving yes but no creating of a screenshot is taking place.
Creating the video
- Try to be consistent. Here you create a
Bitmapand callDispose()instead of using ausingstatement. In addition, sometime you usevarand sometimes you use the concrete type although the type is seen at first glance. - If you are using the
asoperator you should always add anullcheck for that object because anasoperator won't throw an exception but the resulting object may benullwhich will trigger an exception somewhere else.
Implementing these points will look like this:
Rectangle bounds = Screen.FromControl(this).Bounds;
var width = bounds.Width;
var height = bounds.Height;
var framRate = 5;
using (var vFWriter = new VideoFileWriter())
{
vFWriter.Open(outputPath+"//video.avi", width, height, framRate, VideoCodec.Raw);
foreach (var imageLocation in inputImageSequence)
{
using(var imageFrame = (Bitmap)System.Drawing.Image.FromFile(imageLocation))
{
vFWriter.WriteVideoFrame(imageFrame);
}
}
vFWriter.Close();
}
DeletePath(path);
My guess about the big file size is that you are using the VideoCodec.Raw. Try to change it to some other codec and see if this helps.
edited Nov 28 at 13:02
Glorfindel
2541614
2541614
answered Nov 28 at 5:43
Heslacher
44.8k460155
44.8k460155
@Glorfindel thanks for the edits.
– Heslacher
Nov 28 at 13:03
add a comment |
@Glorfindel thanks for the edits.
– Heslacher
Nov 28 at 13:03
@Glorfindel thanks for the edits.
– Heslacher
Nov 28 at 13:03
@Glorfindel thanks for the edits.
– Heslacher
Nov 28 at 13:03
add a comment |
up vote
8
down vote
You could write the screenshots directly to the video stream. This could save you a lot of disk space depending on your capture time.
To make the video file smaller you need to use a codec that compresses the output like MPEG-4.
Finally you could encapsulate the recording in its own class:
public sealed class ScreenRecorder : IDisposable
{
private readonly VideoFileWriter videoFileWriter = new VideoFileWriter();
private readonly string videoFilePath;
private readonly Rectangle bounds;
public ScreenRecorder(string videoFilePath, Rectangle bounds, int frameRate = 5, VideoCodec videoCodec = VideoCodec.MPEG4)
{
if (string.IsNullOrWhiteSpace(videoFilePath))
{
throw new ArgumentException("Must be a valid filename", nameof(videoFilePath));
}
if(frameRate < 1)
{
throw new ArgumentOutOfRangeException(nameof(frameRate));
}
this.videoFilePath = videoFilePath;
this.bounds = bounds;
videoFileWriter.Open(videoFilePath, bounds.Width, bounds.Height, frameRate, videoCodec);
}
public void TakeScreenshot()
{
if (disposed)
{
throw new ObjectDisposedException(nameof(ScreenRecorder));
}
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
videoFileWriter.WriteVideoFrame(bitmap);
}
}
public void Stop() => Dispose();
#region IDisposable Support
private bool disposed = false; // To detect redundant calls
void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
videoFileWriter.Dispose();
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
add a comment |
up vote
8
down vote
You could write the screenshots directly to the video stream. This could save you a lot of disk space depending on your capture time.
To make the video file smaller you need to use a codec that compresses the output like MPEG-4.
Finally you could encapsulate the recording in its own class:
public sealed class ScreenRecorder : IDisposable
{
private readonly VideoFileWriter videoFileWriter = new VideoFileWriter();
private readonly string videoFilePath;
private readonly Rectangle bounds;
public ScreenRecorder(string videoFilePath, Rectangle bounds, int frameRate = 5, VideoCodec videoCodec = VideoCodec.MPEG4)
{
if (string.IsNullOrWhiteSpace(videoFilePath))
{
throw new ArgumentException("Must be a valid filename", nameof(videoFilePath));
}
if(frameRate < 1)
{
throw new ArgumentOutOfRangeException(nameof(frameRate));
}
this.videoFilePath = videoFilePath;
this.bounds = bounds;
videoFileWriter.Open(videoFilePath, bounds.Width, bounds.Height, frameRate, videoCodec);
}
public void TakeScreenshot()
{
if (disposed)
{
throw new ObjectDisposedException(nameof(ScreenRecorder));
}
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
videoFileWriter.WriteVideoFrame(bitmap);
}
}
public void Stop() => Dispose();
#region IDisposable Support
private bool disposed = false; // To detect redundant calls
void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
videoFileWriter.Dispose();
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
add a comment |
up vote
8
down vote
up vote
8
down vote
You could write the screenshots directly to the video stream. This could save you a lot of disk space depending on your capture time.
To make the video file smaller you need to use a codec that compresses the output like MPEG-4.
Finally you could encapsulate the recording in its own class:
public sealed class ScreenRecorder : IDisposable
{
private readonly VideoFileWriter videoFileWriter = new VideoFileWriter();
private readonly string videoFilePath;
private readonly Rectangle bounds;
public ScreenRecorder(string videoFilePath, Rectangle bounds, int frameRate = 5, VideoCodec videoCodec = VideoCodec.MPEG4)
{
if (string.IsNullOrWhiteSpace(videoFilePath))
{
throw new ArgumentException("Must be a valid filename", nameof(videoFilePath));
}
if(frameRate < 1)
{
throw new ArgumentOutOfRangeException(nameof(frameRate));
}
this.videoFilePath = videoFilePath;
this.bounds = bounds;
videoFileWriter.Open(videoFilePath, bounds.Width, bounds.Height, frameRate, videoCodec);
}
public void TakeScreenshot()
{
if (disposed)
{
throw new ObjectDisposedException(nameof(ScreenRecorder));
}
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
videoFileWriter.WriteVideoFrame(bitmap);
}
}
public void Stop() => Dispose();
#region IDisposable Support
private bool disposed = false; // To detect redundant calls
void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
videoFileWriter.Dispose();
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
You could write the screenshots directly to the video stream. This could save you a lot of disk space depending on your capture time.
To make the video file smaller you need to use a codec that compresses the output like MPEG-4.
Finally you could encapsulate the recording in its own class:
public sealed class ScreenRecorder : IDisposable
{
private readonly VideoFileWriter videoFileWriter = new VideoFileWriter();
private readonly string videoFilePath;
private readonly Rectangle bounds;
public ScreenRecorder(string videoFilePath, Rectangle bounds, int frameRate = 5, VideoCodec videoCodec = VideoCodec.MPEG4)
{
if (string.IsNullOrWhiteSpace(videoFilePath))
{
throw new ArgumentException("Must be a valid filename", nameof(videoFilePath));
}
if(frameRate < 1)
{
throw new ArgumentOutOfRangeException(nameof(frameRate));
}
this.videoFilePath = videoFilePath;
this.bounds = bounds;
videoFileWriter.Open(videoFilePath, bounds.Width, bounds.Height, frameRate, videoCodec);
}
public void TakeScreenshot()
{
if (disposed)
{
throw new ObjectDisposedException(nameof(ScreenRecorder));
}
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
//Add screen to bitmap:
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
videoFileWriter.WriteVideoFrame(bitmap);
}
}
public void Stop() => Dispose();
#region IDisposable Support
private bool disposed = false; // To detect redundant calls
void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
videoFileWriter.Dispose();
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
edited Nov 28 at 10:19
answered Nov 28 at 9:33
Johnbot
2,179716
2,179716
add a comment |
add a comment |
up vote
4
down vote
Using string concatenation for creating file paths opens you up to a whole lot of headache. Should you use /, //, or \? The answer depends on the environment you are running in. Luckily, the Path class can do all this logic for us:
Instead of
path + "//screenshot-" + fileCount + ".jpeg";
you could do
Path.Combine(path, $"screenshot-{fileCount}.jpeg");
and instead of
outputPath+"//video.avi"
Path.Combine(outputPath, "video.avi")
This way you don't have to worry about using the right fileseparator.
add a comment |
up vote
4
down vote
Using string concatenation for creating file paths opens you up to a whole lot of headache. Should you use /, //, or \? The answer depends on the environment you are running in. Luckily, the Path class can do all this logic for us:
Instead of
path + "//screenshot-" + fileCount + ".jpeg";
you could do
Path.Combine(path, $"screenshot-{fileCount}.jpeg");
and instead of
outputPath+"//video.avi"
Path.Combine(outputPath, "video.avi")
This way you don't have to worry about using the right fileseparator.
add a comment |
up vote
4
down vote
up vote
4
down vote
Using string concatenation for creating file paths opens you up to a whole lot of headache. Should you use /, //, or \? The answer depends on the environment you are running in. Luckily, the Path class can do all this logic for us:
Instead of
path + "//screenshot-" + fileCount + ".jpeg";
you could do
Path.Combine(path, $"screenshot-{fileCount}.jpeg");
and instead of
outputPath+"//video.avi"
Path.Combine(outputPath, "video.avi")
This way you don't have to worry about using the right fileseparator.
Using string concatenation for creating file paths opens you up to a whole lot of headache. Should you use /, //, or \? The answer depends on the environment you are running in. Luckily, the Path class can do all this logic for us:
Instead of
path + "//screenshot-" + fileCount + ".jpeg";
you could do
Path.Combine(path, $"screenshot-{fileCount}.jpeg");
and instead of
outputPath+"//video.avi"
Path.Combine(outputPath, "video.avi")
This way you don't have to worry about using the right fileseparator.
answered Nov 28 at 14:22
JAD
6591320
6591320
add a comment |
add a comment |
up vote
0
down vote
Thanks to all your help as well as the help of many others, I have actually fully compelted the screen recorder and have typed up an explanation here if anyone is interested: https://benbcompsci.wordpress.com/2018/12/04/c-screen-recorder/
add a comment |
up vote
0
down vote
Thanks to all your help as well as the help of many others, I have actually fully compelted the screen recorder and have typed up an explanation here if anyone is interested: https://benbcompsci.wordpress.com/2018/12/04/c-screen-recorder/
add a comment |
up vote
0
down vote
up vote
0
down vote
Thanks to all your help as well as the help of many others, I have actually fully compelted the screen recorder and have typed up an explanation here if anyone is interested: https://benbcompsci.wordpress.com/2018/12/04/c-screen-recorder/
Thanks to all your help as well as the help of many others, I have actually fully compelted the screen recorder and have typed up an explanation here if anyone is interested: https://benbcompsci.wordpress.com/2018/12/04/c-screen-recorder/
answered Dec 4 at 7:10
BenCompSci
585
585
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208582%2fscreen-recorder-producing-huge-avi-files%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown