问题描述
我正在使用 C# WinForm 应用程序访问 Microsoft Azure Kinect 深度相机的视频片段并在图片框上显示视频。我现在正在寻找一种录制此视频的方法。有没有办法在应用程序运行时录制在我整个图片框上播放的视频?
我使用的是 .NET 框架 4.7.2
解决方法
我编写了这个类来环绕 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的日志,或者与之交互,或者一直将记录区域调整到不同的地方