Link Search Menu Expand Document

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);
		    }
		}
	}
}

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 
	}
}

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;

	}

}




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();
        }
	}
}

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());
		}
	}
}

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;

            }

        }

    }

}


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;

            }

        }

    }

}


Download Source Code (.zip)

Return to the previous page Explore Screen Capturing SDK