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

}

}

}

相关推荐
USB_ABC9 分钟前
视频矩阵核心技术对比:模块化vs固定机箱、硬件帧同步vs软件同步怎么选
矩阵·音视频
Hesionberger33 分钟前
快速求解完全平方数的最少数量
开发语言·数据结构·python·算法·leetcode·c#
逝水无殇13 小时前
C# 运算符重载详解
开发语言·后端·c#
hz5678914 小时前
电子远程评标系统哪家好?安全、合规、易用平台评测指南
安全·云计算·音视频·实时音视频·信息与通信
星空语16 小时前
音频001_Android+Linux车载/手机音频全链路分层架构图
android·linux·音视频
丁小未17 小时前
基于MVVM框架的XUUI HelloWorld 新手教程
unity·性能优化·c#·游戏引擎
ctrl_v助手17 小时前
C#日志工具类log4net的使用
开发语言·c#
Jazz_z17 小时前
通过 Java 实现 Word 转 TXT
java·c#·word
丁小未17 小时前
基于MVVM框架的XUUI MoreComplex案例
unity·c#
hz5678918 小时前
局域网视频会议解决方案,适配政企专网场景
音视频·实时音视频·信息与通信·安全架构