Capture Video From Separate Thread | C#ByteScout Screen Capturing SDK

Capture Video From Separate Thread | C#

Program.cs:

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

CapturingThread.cs:

C#
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:

C#
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.cs:

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