c# - 使用 OpenCvSharp 从网络摄像头录制视频 - 使文件播放速度加快
问题描述
我正在尝试使用 OpenCvSharp 从网络摄像头录制视频
我已经可以使用下面的代码录制视频,但是生成的 .mp4 文件播放速度很快(例如,我录制了 5 秒,结果甚至不到一秒)。
我已经玩过延迟AddCameraFrameToRecordingThread
但无济于事
可能是什么问题?或者我可以使用哪些其他库来从网络摄像头录制视频?
namespace BlackBears.Recording
{
using System;
using System.Drawing;
using System.Threading;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Size = OpenCvSharp.Size;
public class Recorder : IDisposable
{
private readonly VideoCaptureAPIs _videoCaptureApi = VideoCaptureAPIs.DSHOW;
private readonly ManualResetEventSlim _writerReset = new(false);
private readonly VideoCapture _videoCapture;
private VideoWriter _videoWriter;
private Thread _writerThread;
private bool IsVideoCaptureValid => _videoCapture is not null && _videoCapture.IsOpened();
public Recorder(int deviceIndex, int frameWidth, int frameHeight, double fps)
{
_videoCapture = VideoCapture.FromCamera(deviceIndex, _videoCaptureApi);
_videoCapture.Open(deviceIndex, _videoCaptureApi);
_videoCapture.FrameWidth = frameWidth;
_videoCapture.FrameHeight = frameHeight;
_videoCapture.Fps = fps;
}
/// <inheritdoc />
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
~Recorder()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
StopRecording();
_videoCapture?.Release();
_videoCapture?.Dispose();
}
}
public void StartRecording(string path)
{
if (_writerThread is not null)
return;
if (!IsVideoCaptureValid)
ThrowHelper.ThrowVideoCaptureNotReadyException();
_videoWriter = new VideoWriter(path, FourCC.XVID, _videoCapture.Fps, new Size(_videoCapture.FrameWidth, _videoCapture.FrameHeight));
_writerReset.Reset();
_writerThread = new Thread(AddCameraFrameToRecordingThread);
_writerThread.Start();
}
public void StopRecording()
{
if (_writerThread is not null)
{
_writerReset.Set();
_writerThread.Join();
_writerThread = null;
_writerReset.Reset();
}
_videoWriter?.Release();
_videoWriter?.Dispose();
_videoWriter = null;
}
private void AddCameraFrameToRecordingThread()
{
var waitTimeBetweenFrames = (int)(1_000 / _videoCapture.Fps);
using var frame = new Mat();
while (!_writerReset.Wait(waitTimeBetweenFrames))
{
if (!_videoCapture.Read(frame))
return;
_videoWriter.Write(frame);
}
}
}
}
解决方案
在玩了很多之后,我自己找到了解决方案。
捕获帧并写入它们的单个线程是不够的。我现在创建了两个线程,一个从相机捕获帧,一个写入它们。为了在生成的文件中获得正确的时序,必须考虑写入创建的延迟。
我最终得到了以下两个在不同线程中运行的函数:
private void CaptureFrameLoop()
{
while (!_threadStopEvent.Wait(0))
{
_videoCapture.Read(_capturedFrame);
}
}
private void AddCameraFrameToRecordingThread()
{
var waitTimeBetweenFrames = 1_000 / _videoCapture.Fps;
var lastWrite = DateTime.Now;
while (!_threadStopEvent.Wait(0))
{
if (DateTime.Now.Subtract(lastWrite).TotalMilliseconds < waitTimeBetweenFrames)
continue;
lastWrite = DateTime.Now;
_videoWriter.Write(_capturedFrame);
}
}
推荐阅读
- java - 如何在不等待线程完成的情况下精确渲染帧
- android - 如何从本地网络中的其他设备向我的移动 http 服务器发送请求?
- php - PHPWord DOMDocument::loadXML():开始和结束标记不匹配:实体中的 br 行 1 和 p,行:1
- javascript - SyntaxError: missing ) 在参数列表 php javascript 之后
- node.js - 使用 OpenID Connect 提供者进行身份验证后如何在客户端上创建会话
- django - Django - 基于类的 TemplateView 的动态模型
- c# - 如何克隆 Visual Studio 项目而无需一次又一次地重写所有代码
- c# - foreach 没有很好地阅读 .descendants 并在 if 之前转到 else 语句
- python - 通过将以前的列与熊猫错误相加来创建新列
- debugging - `kubectl debug` 在 1.20 上挂起,启用了功能门