用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); // 等待线程结束

}

}

}

相关推荐
阿蒙Amon21 分钟前
C#每日面试题-重写和重载的区别
开发语言·c#
阿蒙Amon43 分钟前
C#每日面试题-委托和事件的区别
java·开发语言·c#
bjzhang752 小时前
C#操作SQLite数据库
数据库·sqlite·c#
烛阴3 小时前
C# 正则表达式(3):分组与捕获——从子串提取到命名分组
前端·正则表达式·c#
cver1235 小时前
足球视频检测数据集介绍-160张图片-智能体育转播 运动数据分析 自动化视频剪辑 裁判辅助系统 青训技术分析 虚拟现实体验
数据分析·自动化·音视频
来鸟 鸣间5 小时前
MIPI D-PHY 理解
linux·音视频·sensor·mipi
时光呀时光慢慢走6 小时前
C# WinForms 实战:MQTTS 客户端开发(与 STM32 设备通信)
开发语言·c#
自己的九又四分之三站台7 小时前
OpenCV介绍
人工智能·opencv·计算机视觉
时光呀时光慢慢走7 小时前
MAUI 开发安卓 MQTT 客户端:实现远程控制 (完整源码 + 避坑指南)
android·物联网·mqtt·c#
WebRuntime8 小时前
问世间,exe是何物?直教AI沉默、Web寡言(4)
javascript·c#·.net·web