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

}

}

}

相关推荐
热心市民☆5 小时前
C#基础语法
c#
rainmanqqst5 小时前
C#Netcore支持Https
网络协议·http·https·c#
赖small强11 小时前
【音视频开发】Linux UVC (USB Video Class) 驱动框架深度解析
linux·音视频·v4l2·uvc
张人玉11 小时前
Prism 框架笔记及实例
c#·wpf·prism
赖small强11 小时前
【音视频开发】ISP流水线核心模块深度解析
音视频·isp·白平衡·亮度·luminance·gamma 校正·降噪处理
·心猿意码·11 小时前
告别版本地狱:C# 中央包管理
c#
k***459911 小时前
C#数据库操作系列---SqlSugar完结篇
网络·数据库·c#
lzhdim11 小时前
C#开发的应用启动菜单应用(普通版) - 开源研究系列文章 - 个人小作品
开发语言·c#
赖small强12 小时前
【音视频开发】Linux V4L2 (Video for Linux 2) 驱动框架深度解析白皮书
linux·音视频·v4l2·设备节点管理·视频缓冲队列·videobuf2
MM_MS12 小时前
C# 线程与并发编程完全指南:从基础到高级带详细注释版(一篇读懂)
开发语言·机器学习·计算机视觉·c#·简单工厂模式·visual studio