
代码如下:
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); // 等待线程结束
}
}
}