【问题标题】:How to record video playing on a pictureBox?如何录制在pictureBox上播放的视频?
【发布时间】:2021-05-05 00:47:39
【问题描述】:

我正在访问 Microsoft Azure Kinect 深度相机的视频片段,并使用 C# WinForm 应用程序在图片框上显示视频。我正在寻找一种方法来录制这个视频。有没有办法在应用程序运行时录制整个图片框上播放的视频?

我正在使用 .NET 框架 4.7.2

【问题讨论】:

  • 我解决了这个问题,似乎该问题中建议的 AForge 库与不超过 3.5 版的 .NET 框架兼容。我不确定我可以用它来解决这个问题。
  • 为什么需要从图片框中录制而不是直接从源中录制?
  • 在这个问题stackoverflow.com/questions/36744334/… 中是否有支持 .NET v.4.7.2 的 VideoFileWriter
  • 有趣的是,对外部库的一些请求是如何作为离题而关闭的,而其他基本上等同于同一件事的请求却得到了答复

标签: c# winforms video-processing picturebox video-recording


【解决方案1】:

我编写了这个类来包装 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的日志,或者与之交互,或者一直将记录区域调整到不同的地方

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    • 2021-04-06
    • 2014-02-07
    • 2015-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多