使用 OpenCvSharp 从网络摄像头录制视频 - 生成的文件播放速度很快
Recording Video from Webcam with OpenCvSharp - Resulting File playback to fast
我正在尝试使用 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);
}
}
我正在尝试使用 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);
}
}