我编写了这个类来包装 ffmpeg(遵循 ffmpeg 文档中的“how to record your screen”帮助)并简化一些操作:
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();
}
}
}
它从这个类中得到了一些帮助:
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);
}
}
然后你只需在某个地方放置一个 ffmpeg 二进制文件并将路径放入设置 (CommandLineFfmpegPath) 和一些合适的参数 (设置名称 CommandLineFfmpegArgs) 以记录您想要记录的内容
我的参数是-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}" - 如果您安装它,您将只有一条虚拟音频电缆,但您可以让 ffmpeg 列出您系统上的声音设备并放置其中一个,如果您甚至可以省略它不想要声音。
设置编辑器截图:
然后你创建一个带有矩形记录的 FfmpegRecorder 实例 - 这将是你的图片框的坐标,translated to screen coords(注意 DPI/如果你的 Windows 没有以 100% 运行,你必须调整你的值“缩放”)
如果你想让你的生活更轻松/获得我提到的“单行记录”,只要确保你的图片框一直在同一个地方(最大化表格),使用 regedit 设置一次 reg 设置,然后触发Process.Start 以启动带有一些参数的ffmpeg。这个答案中的其他大部分内容是因为我想捕获FF的日志,或者与之交互,或者一直将记录区域调整到不同的地方