I wrote this class to wrap around ffmpeg (follow the "how to record your screen" help in the ffmpeg docs) and make some bits easier:
using System;
using System.Diagnostics;
using System.Drawing;
using System.Text;
namespace CJCam
{
public class FfmpegRecorder : Recorder
{
public string OutputPath { get; set; }
private Process _ffmpeg = null;
private readonly StringBuilder _ffLog = new StringBuilder();
//like STDERR: frame=113987 fps= 10 q=-1.0 Lsize= 204000kB time=03:09:58.50 bitrate= 146.6kbits/s
private string _streamStats = "";
~FfmpegRecorder()
{
Dispose();
}
public override void Dispose()
{
}
public FfmpegRecorder(string outputPath, Rectangle recordingRect)
{
ScreenCaptureRecorderRegistry.SetRecordRegion(recordingRect);
OutputPath = outputPath;
}
public override void StartRecording()
{
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = Properties.Settings.Default.CommandLineFfmpegPath,
Arguments = string.Format(
Properties.Settings.Default.CommandLineFfmpegArgs,
OutputPath
),
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};
_ffmpeg = System.Diagnostics.Process.Start(psi);
_ffmpeg.OutputDataReceived += Ffmpeg_OutputDataReceived;
_ffmpeg.ErrorDataReceived += Ffmpeg_ErrorDataReceived;
_ffmpeg.BeginOutputReadLine();
_ffmpeg.BeginErrorReadLine();
_ffmpeg.PriorityClass = ProcessPriorityClass.High;
}
void Ffmpeg_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null && IsInteresting(e.Data))
{
_ffLog.Append("STDOUT: ").AppendLine(e.Data);
}
}
void Ffmpeg_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null && IsInteresting(e.Data))
{
_ffLog.Append("STDERR: ").AppendLine(e.Data);
}
}
bool IsInteresting(string data)
{
if (data.StartsWith("frame="))
{
_streamStats = data;
return false;
}
return true;
}
public override void PauseRecording()
{
throw new NotImplementedException("Cannot pause FFmpeg at this time");
}
public override void StopRecording()
{
if (_ffmpeg == null)
return;
if (_ffmpeg.HasExited)
return;
_ffmpeg.StandardInput.WriteLine("q");
_ffmpeg.WaitForExit(5000);
}
public override string GetLogFile()
{
return _ffLog.AppendLine().Append("CURRENT FRAME:").AppendLine(_streamStats).ToString();
}
}
}
It gets some help from this class:
class ScreenCaptureRecorderRegistry
{
public static void SetRecordRegion(Rectangle region)
{
RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\screen-capture-recorder");
// If the return value is null, the key doesn't exist
if (key == null)
key = Registry.CurrentUser.CreateSubKey("Software\\screen-capture-recorder");
key = Registry.CurrentUser.OpenSubKey("Software\\screen-capture-recorder", true);
key.SetValue("start_x", region.X, RegistryValueKind.DWord);
key.SetValue("start_y", region.Y, RegistryValueKind.DWord);
key.SetValue("capture_width", region.Width, RegistryValueKind.DWord);
key.SetValue("capture_height", region.Height, RegistryValueKind.DWord);
}
}
Then you just put an ffmpeg binary at some place and put the path in settings (CommandLineFfmpegPath
) and some suitable args (settings name CommandLineFfmpegArgs
) for what you want to record
My args are -rtbufsize 2048M -thread_queue_size 512 -f dshow -i video="screen-capture-recorder" -thread_queue_size 512 -f dshow -i audio="Line 1 (Virtual Audio Cable)" -x264opts keyint=50 -map 0:v -map 1:a -pix_fmt yuv420p -y "{0}"
- you'll only have a virtual audio cable if you install it, but you can get ffmpeg to list the sound devices on your system and put one of those instead, or even omit it if you dont want sound.
Screenshot of settings editor:

Then you make an instance of FfmpegRecorder with a rectangle to record - that would be the coordinates of your picturebox, translated to screen coords (watch out for DPI/you have to adjust your values if your Windows doesn't run at 100% "zoom")
If you want to make your life easier/get to the "one line record" I mentioned, just make sure your picturebox is in the same place all the time (maximize the form), set the reg settings one time using regedit, and fire off a Process.Start
to launch ffmpeg with some args. Most of the other fluff in this answer is because I wanted to capture FF's logs, or interact with it, or adjust the recording region to different places all the time