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

}

}

}

相关推荐
微帧Visionular9 小时前
AI视频单帧清晰,播放时却闪烁,原因是什么?
人工智能·深度学习·音视频
辰辰观影10 小时前
Windows网盘视频播放器推荐:无广告4K HDR怎么选
音视频
小豆庄12 小时前
视频遮罩追踪退场后ID撞号的排查—多目标场景下的失效
opencv·算法·bug·视频·python3.11
2601_9668274512 小时前
电视端云盘在线播放怎么选?支持4K HDR的应用推荐
音视频
开开心心就好13 小时前
音频降噪剪辑工具,音量裁剪一键处理
运维·服务器·前端·spring·ocr·音视频·1024程序员节
泛凡(Linyongui)14 小时前
基于 CW32L010 的智能厨卫调温旋钮方案--低成本 EC21 编码旋钮全解析
单片机·嵌入式硬件·c#
暴走约伯16 小时前
【VFX工具链源码拆解 02】告别机械劳动(上):一键统改百个子粒子颜色与批量重命名
3d·unity·c#·材质
AI视频工具指南17 小时前
AI视频的声音和画面怎么配合?先分清谁在传递信息
人工智能·aigc·音视频
信息安全失业大专人员17 小时前
每日了解一个智能体-WorkBuddy
开发语言·ai·c#·智能体
呆呆敲代码的小Y18 小时前
【实战精选面试题】C# 面试题详细解答,按难易程度排序
android·java·游戏·c#·游戏开发·unity面试题·c#面试题