Capture Video From Separate Thread - C#
Screen Capturing SDK sample in C# demonstrating ‘Capture Video From Separate Thread’
CapturingThread.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Drawing;
using BytescoutScreenCapturingLib;
// NOTE: if you are getting error like "invalid image" related to loading the SDK's dll then
// try to do the following:
// 1) remove the reference to the SDK by View - Solution Explorer
// then click on References, select Bytescout... reference name and right-click it and select Remove
// 2) To re-add click on the menu: Project - Add Reference
// 3) In "Add Reference" dialog switch to "COM" tab and find Bytescout...
// 4) Select it and click "Add"
// 5) Recompile the application
// Note: if you need to run on both x64 and x86 then please make sure you have set "Embed Interop Types" to True for this reference
namespace CaptureFromSeparateThread
{
public class CapturingThread
{
public static void ThreadProc(Object obj)
{
CapturingThreadData data = (CapturingThreadData) obj;
data.Success = true;
// Prepare Capturer:
Capturer capturer = new Capturer(); // create new screen capturer object
capturer.RegistrationName = "demo";
capturer.RegistrationKey = "demo";
capturer.CaptureRectLeft = data.CaptureRectangle.Left;
capturer.CaptureRectTop = data.CaptureRectangle.Top;
capturer.CaptureRectWidth = data.CaptureRectangle.Width;
capturer.CaptureRectHeight = data.CaptureRectangle.Height;
capturer.OutputWidth = 640;
capturer.OutputHeight = 480;
// WMV and WEBM output use WMVVideoBitrate property to control output video bitrate
// so try to increase it by x2 or x3 times if you think the output video are you are getting is laggy
// capturer.WMVVideoBitrate = capturer.WMVVideoBitrate * 2;
capturer.CaptureRectWidth = 320;
capturer.CaptureRectHeight = 240;
data.TempFile = Path.GetTempFileName();
data.TempFile = Path.ChangeExtension(data.TempFile, ".wmv");
capturer.OutputFileName = data.TempFile;
capturer.CapturingType = data.CaptureType;
// set border around captured area if we are not capturing entire screen
if (capturer.CapturingType != CaptureAreaType.catScreen &&
capturer.CapturingType != CaptureAreaType.catWebcamFullScreen)
{
capturer.CaptureAreaBorderType = CaptureAreaBorderType.cabtDashed;
capturer.CaptureAreaBorderColor = (uint) ColorTranslator.ToOle(Color.Red);
}
// Wait for events:
WaitHandle[] events = new WaitHandle[] {data.StartOrResumeEvent, data.PauseEvent, data.StopEvent};
try
{
while (true)
{
int i = WaitHandle.WaitAny(events);
if (events[i] == data.StartOrResumeEvent)
{
if (!capturer.IsRunning)
capturer.Run();
}
else if (events[i] == data.PauseEvent)
{
if (capturer.IsRunning)
capturer.Pause();
}
else if (events[i] == data.StopEvent)
{
capturer.Stop();
break;
}
}
}
catch (Exception ex)
{
data.ErrorText = ex.Message;
data.Success = false;
}
finally
{
// Release resources
Marshal.ReleaseComObject(capturer);
}
}
}
}
+ Show More
Explore SDK documentations here.
CapturingThreadData.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Threading;
using BytescoutScreenCapturingLib;
// NOTE: if you are getting error like "invalid image" related to loading the SDK's dll then
// try to do the following:
// 1) remove the reference to the SDK by View - Solution Explorer
// then click on References, select Bytescout... reference name and right-click it and select Remove
// 2) To re-add click on the menu: Project - Add Reference
// 3) In "Add Reference" dialog switch to "COM" tab and find Bytescout...
// 4) Select it and click "Add"
// 5) Recompile the application
namespace CaptureFromSeparateThread
{
public class CapturingThreadData
{
public CaptureAreaType CaptureType;
public String TempFile;
public Rectangle CaptureRectangle = new Rectangle(0, 0, 320, 240);
public bool Success;
public string ErrorText;
public AutoResetEvent StartOrResumeEvent = new AutoResetEvent(false); // event signalling to start or resume the recodring
public AutoResetEvent PauseEvent = new AutoResetEvent(false); // event signalling to pause the recodring
public AutoResetEvent StopEvent = new AutoResetEvent(false); // event signalling to stop the recording
}
}
+ Show More
Explore SDK documentations here.
Form1.Designer.cs
��namespace CaptureFromSeparateThread
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.cmbCapturingType = new System.Windows.Forms.ComboBox();
this.btnStart = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.btnStop = new System.Windows.Forms.Button();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.btnPauseResume = new System.Windows.Forms.Button();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// cmbCapturingType
//
this.cmbCapturingType.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.cmbCapturingType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbCapturingType.FormattingEnabled = true;
this.cmbCapturingType.Items.AddRange(new object[] {
"Area around the mouse pointer",
"Full screen"});
this.cmbCapturingType.Location = new System.Drawing.Point(97, 12);
this.cmbCapturingType.Name = "cmbCapturingType";
this.cmbCapturingType.Size = new System.Drawing.Size(378, 21);
this.cmbCapturingType.TabIndex = 0;
//
// btnStart
//
this.btnStart.Location = new System.Drawing.Point(3, 3);
this.btnStart.Name = "btnStart";
this.btnStart.Size = new System.Drawing.Size(143, 44);
this.btnStart.TabIndex = 1;
this.btnStart.Text = "Start";
this.btnStart.UseVisualStyleBackColor = true;
this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 15);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(79, 13);
this.label1.TabIndex = 3;
this.label1.Text = "Capturing Type";
//
// btnStop
//
this.btnStop.Enabled = false;
this.btnStop.Location = new System.Drawing.Point(307, 3);
this.btnStop.Name = "btnStop";
this.btnStop.Size = new System.Drawing.Size(143, 44);
this.btnStop.TabIndex = 4;
this.btnStop.Text = "Stop";
this.btnStop.UseVisualStyleBackColor = true;
this.btnStop.Click += new System.EventHandler(this.btnStop_Click);
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 34F));
this.tableLayoutPanel1.Controls.Add(this.btnPauseResume, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.btnStart, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.btnStop, 2, 0);
this.tableLayoutPanel1.Location = new System.Drawing.Point(12, 52);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 1;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(463, 57);
this.tableLayoutPanel1.TabIndex = 5;
//
// btnPauseResume
//
this.btnPauseResume.Enabled = false;
this.btnPauseResume.Location = new System.Drawing.Point(155, 3);
this.btnPauseResume.Name = "btnPauseResume";
this.btnPauseResume.Size = new System.Drawing.Size(143, 44);
this.btnPauseResume.TabIndex = 5;
this.btnPauseResume.Text = "Pause";
this.btnPauseResume.UseVisualStyleBackColor = true;
this.btnPauseResume.Click += new System.EventHandler(this.btnPauseResume_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(487, 121);
this.Controls.Add(this.tableLayoutPanel1);
this.Controls.Add(this.label1);
this.Controls.Add(this.cmbCapturingType);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form1";
this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Capture From Separate Thread";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
this.tableLayoutPanel1.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ComboBox cmbCapturingType;
private System.Windows.Forms.Button btnStart;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button btnStop;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Button btnPauseResume;
}
}
+ Show More
Explore SDK documentations here.
Form1.cs
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using BytescoutScreenCapturingLib;
// NOTE: if you are getting error like "invalid image" related to loading the SDK's dll then
// try to do the following:
// 1) remove the reference to the SDK by View - Solution Explorer
// then click on References, select Bytescout... reference name and right-click it and select Remove
// 2) To re-add click on the menu: Project - Add Reference
// 3) In "Add Reference" dialog switch to "COM" tab and find Bytescout...
// 4) Select it and click "Add"
// 5) Recompile the application
// Note: if you need to run on both x64 and x86 then please make sure you have set "Embed Interop Types" to True for this reference
namespace CaptureFromSeparateThread
{
public partial class Form1 : Form
{
private Thread _capturingThread;
private CapturingThreadData _capturingThreadData; // data to exchange between form and capturing thread
public Form1()
{
InitializeComponent();
_capturingThreadData = new CapturingThreadData();
cmbCapturingType.SelectedIndex = 0;
}
private void btnStart_Click(object sender, EventArgs e)
{
CaptureAreaType captureType = CaptureAreaType.catMouse;
if (cmbCapturingType.SelectedIndex == 1)
captureType = CaptureAreaType.catScreen;
StartRecording(captureType);
}
private void btnPauseResume_Click(object sender, EventArgs e)
{
PauseOrResumeRecording();
}
private void btnStop_Click(object sender, EventArgs e)
{
StopRecording();
}
private void StartRecording(CaptureAreaType captureType)
{
btnStart.Enabled = false;
btnPauseResume.Enabled = true;
btnStop.Enabled = true;
_capturingThreadData.CaptureType = captureType;
// Start thread
_capturingThread = new Thread(CapturingThread.ThreadProc);
_capturingThread.Start(_capturingThreadData);
// Signal to start the recording
_capturingThreadData.StartOrResumeEvent.Set();
}
private void PauseOrResumeRecording()
{
btnStart.Enabled = false;
btnPauseResume.Enabled = true;
btnStop.Enabled = true;
if (btnPauseResume.Text == "Pause")
{
// Signal to pause
_capturingThreadData.PauseEvent.Set();
btnPauseResume.Text = "Resume";
}
else
{
// Signal to resume
_capturingThreadData.StartOrResumeEvent.Set();
btnPauseResume.Text = "Pause";
}
}
private void StopRecording()
{
Cursor = Cursors.WaitCursor;
// Signal to stop
_capturingThreadData.StopEvent.Set();
try
{
_capturingThread.Join();
}
finally
{
Cursor = Cursors.Default;
}
if (!_capturingThreadData.Success)
{
MessageBox.Show("Capturing failed. Error: " + _capturingThreadData.ErrorText);
}
else
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.DefaultExt = "*.wmv";
dlg.Filter = "WMV files (*.wmv)|*.wmv|All files (*.*)|*.*";
dlg.FileName = "Screencast";
dlg.Title = "Save captured video as";
if (dlg.ShowDialog() == DialogResult.OK)
{
File.Copy(_capturingThreadData.TempFile, dlg.FileName, true);
Process.Start(dlg.FileName); // start the video in default associated application
}
File.Delete(_capturingThreadData.TempFile);
}
btnStart.Enabled = true;
btnPauseResume.Enabled = false;
btnStop.Enabled = false;
btnPauseResume.Text = "Pause";
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_capturingThreadData.StopEvent.Set();
}
}
}
+ Show More
Explore SDK documentations here.
Program.cs
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace CaptureFromSeparateThread
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
+ Show More
Explore SDK documentations here.
Resources.Designer.cs
��//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.5448
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CaptureFromSeparateThread.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CaptureFromSeparateThread.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
+ Show More
Explore SDK documentations here.
Settings.Designer.cs
��//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.5448
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CaptureFromSeparateThread.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}
+ Show More
Explore SDK documentations here.