用OpencvSharp编写视频录制工具

代码如下:

using System;

using System.Drawing;

using System.IO;

using System.Threading;

using System.Windows.Forms;

using OpenCvSharp;

using OpenCvSharp.Extensions;

using Size = OpenCvSharp.Size;

namespace CameraRecorder

{

public partial class MainForm : Form

{

// RTSP 配置

//private string _rtspUrl = "rtsp://username:password@ip:port/stream";

private string _rtspUrl = System.Configuration.ConfigurationManager.AppSettings["CameraURL"].Trim();

private const int ReconnectInterval = 5000; // 重连间隔(ms)

// 录制配置

private const string SaveDirectory = @"D:\VideoRecords\";

private const int Fps = 25;

private FourCC VideoCodec = FourCC.X264;

// 状态控制

private volatile bool _isRecording;

private Thread _recordingThread;

private VideoCapture _videoCapture;

private VideoWriter _videoWriter;

private DateTime _currentHour;

private int _fileIndex = 0; // 文件索引,用于同一小时内的分段

public MainForm()

{

InitializeComponent();

CheckDirectory();

}

private void CheckDirectory()

{

if (!Directory.Exists(SaveDirectory))

{

Directory.CreateDirectory(SaveDirectory);

}

}

private void btnStart_Click(object sender, EventArgs e)

{

if (_isRecording) return;

_isRecording = true;

btnStart.Enabled = false;

btnStop.Enabled = true;

_fileIndex = 0; // 重置文件索引

_recordingThread = new Thread(RecordingWorker);

_recordingThread.IsBackground = true;

_recordingThread.Start();

}

private void btnStop_Click(object sender, EventArgs e)

{

StopRecording();

}

private void RecordingWorker()

{

while (_isRecording)

{

try

{

// 创建新的视频捕获对象

_videoCapture = new VideoCapture(_rtspUrl);

// 检查是否成功打开

if (!_videoCapture.IsOpened())

{

Log("无法连接摄像头");

SafeReleaseCapture();

Thread.Sleep(ReconnectInterval);

continue;

}

Log("摄像头连接成功");

var frameSize = new Size(

(int)_videoCapture.Get(VideoCaptureProperties.FrameWidth),

(int)_videoCapture.Get(VideoCaptureProperties.FrameHeight));

// 初始化视频写入器(如果是新小时则重置索引)

if (DateTime.Now.Hour != _currentHour.Hour)

{

_fileIndex = 0;

}

CreateNewVideoWriter(frameSize);

Mat frame = new Mat();

while (_isRecording && _videoCapture.IsOpened())

{

// 检查是否需要创建新文件(每小时或连接中断后)

if (DateTime.Now.Hour != _currentHour.Hour)

{

_fileIndex = 0; // 新小时重置索引

SafeReleaseWriter();

CreateNewVideoWriter(frameSize);

}

// 读取帧

if (_videoCapture.Read(frame) && !frame.Empty())

{

// 写入视频帧

_videoWriter.Write(frame);

// 显示预览

DisplayFrame(frame);

}

else

{

Log("帧读取失败,尝试重连...");

break;

}

// 降低CPU使用率

Thread.Sleep(10);

}

}

catch (Exception ex)

{

Log($"捕获到异常: {ex.Message}");

}

finally

{

// 安全释放资源

SafeReleaseWriter();

SafeReleaseCapture();

}

// 断线重连等待

if (_isRecording)

{

Log($"等待 {ReconnectInterval / 1000}秒后重连...");

Thread.Sleep(ReconnectInterval);

}

}

}

private void CreateNewVideoWriter(Size frameSize)

{

_currentHour = DateTime.Now;

// 生成文件名(带索引)

string fileName;

do

{

fileName = _fileIndex == 0

? $"{_currentHour:yyyyMMdd_HH}.mp4"

: $"{currentHour:yyyyMMdd_HH}{_fileIndex}.mp4";

_fileIndex++;

} while (File.Exists(Path.Combine(SaveDirectory, fileName)));

string filePath = Path.Combine(SaveDirectory, fileName);

// 创建新的视频写入器

_videoWriter = new VideoWriter(filePath, VideoCodec, Fps, frameSize);

Log($"创建视频文件: {fileName}");

}

private void SafeReleaseCapture()

{

try

{

if (_videoCapture != null)

{

_videoCapture.Release();

_videoCapture.Dispose();

_videoCapture = null;

}

}

catch (Exception ex)

{

Log($"释放摄像头资源错误: {ex.Message}");

}

}

private void SafeReleaseWriter()

{

try

{

if (_videoWriter != null)

{

_videoWriter?.Release();

_videoWriter?.Dispose();

_videoWriter = null;

}

}

catch (Exception ex)

{

Log($"释放视频写入器错误: {ex.Message}");

}

}

private void DisplayFrame(Mat frame)

{

if (pictureBoxPreview.InvokeRequired)

{

pictureBoxPreview.Invoke(new Action<Mat>(DisplayFrame), frame);

return;

}

try

{

// 高效更新预览图

using (var tempBitmap = frame.ToBitmap())

{

if (pictureBoxPreview.Image != null)

{

var oldImage = pictureBoxPreview.Image;

pictureBoxPreview.Image = null;

oldImage.Dispose();

}

pictureBoxPreview.Image = (Bitmap)tempBitmap.Clone();

}

}

catch (Exception ex)

{

Log($"预览错误: {ex.Message}");

}

}

private void Log(string message)

{

if (txtLog.InvokeRequired)

{

txtLog.Invoke(new Action<string>(Log), message);

return;

}

txtLog.AppendText($"[{DateTime.Now:HH:mm:ss}] {message}\r\n");

txtLog.ScrollToCaret();

}

private void StopRecording()

{

_isRecording = false;

btnStart.Enabled = true;

btnStop.Enabled = false;

Cv2.WaitKey(500);

// 安全释放资源

SafeReleaseWriter();

SafeReleaseCapture();

}

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)

{

StopRecording();

_recordingThread?.Join(2000); // 等待线程结束

}

}

}

相关推荐
大飞pkz1 小时前
【设计模式】责任链模式
开发语言·设计模式·c#·责任链模式
大飞pkz2 小时前
【设计模式】六大基本原则
开发语言·设计模式·c#·六大原则
椒颜皮皮虾5 小时前
DeploySharp开源发布:让C#部署深度学习模型更加简单
c#·openvino
Rotion_深9 小时前
海康 智能相机二开 绘制底图+测试工具应用框
c#·二次开发·海康·智能相机
蜀中廖化10 小时前
Android Studio 导入 opencv
android·opencv·android studio
王家视频教程图书馆11 小时前
C# asp.net模板代码简单API请求
开发语言·c#·asp.net
SongYuLong的博客12 小时前
ubuntu24.04 实现DLNA音频推送
音视频
浮生如梦_12 小时前
图片转视频
图像处理·人工智能·计算机视觉·音视频
胡耀超12 小时前
音频降噪技术:从原理到工具的完整指南(scipy librosa noisereduce soundfile pedalboard)
音视频·音频·scipy·降噪·soundfile·noisereduce·pedalboard
大飞pkz12 小时前
【设计模式】备忘录模式
开发语言·设计模式·c#·备忘录模式