ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenCvSharp实现RTSP拉流MP4分段录制:参数配置与避坑指南

OpenCvSharp实现RTSP拉流MP4分段录制:参数配置与避坑指南 简介面向需要处理RTSP视频流的C#开发者这套基于OpenCvSharp的完整工程方案提供了从实时流读取到分段录制MP4的落地实现。工程基于Visual Studio 2019与.NET Framework 4.7.2构建核心依赖OpenCvSharp 4.8适合需要快速实现视频监控、网络摄像头拉流或长时间录像分段存储的场景。压缩包共198个文件体积约146MB主要包含50个dll运行库、42个xml配置与文档、10个cs核心源码、8个nupkg依赖包以及工程文件、配置文件、示例图片和说明文本等目录结构完整便于直接还原和编译调试。已有942人学习/下载源码更新于20240413可作为实际项目改造的基础。通过阅读源码可理清RTSP拉流参数设置、逐帧编码写MP4、按时间或大小自动切分文件等关键技术点同时配套博客讲解和B站演示视频能有效降低入门门槛。1. 直接用 OpenCvSharp 拉 RTSP 录 MP4 分段为什么第一版总翻车很多第一次做 C# 视频接入的工程师拿到 OpenCvSharp 之后都会觉得「读取 RTSP 流录制 MP4 可分段保存」是个小任务VideoCapture打开地址VideoWriter写出文件再加个定时器切文件三件事而已。实际落地时会发现录出来的文件要么播放器打不开要么只有第一段能放要么分段瞬间丢帧严重的时候进程直接崩溃。问题不出在 OpenCvSharp 本身而是 RTSP 的传输协议协商、MP4 封装对编码格式和关键帧的隐式要求以及分段切换时 VideoWriter 的释放时机这些只要一个参数没对整条链路就不工作。这篇笔记按我实际做过的方案从选型、代码、参数到排错把这条链路完整走一遍新手能照抄老手也能拿去对照自己踩过的坑。2. 先把 RTSP 拉流和 MP4 封装拆明白不然参数全在瞎调2.1 RTSP 不是「一个地址」那么简单传输协议决定拉流成功率RTSP 本身只负责会话控制真正的视频数据跑在 RTP 上而 RTP 既可以走 UDP 也可以走 TCP。摄像头默认通常使用 UDP因为实时性更好、延迟更低。但实际在公网、跨交换机或无线环境下UDP 丢包重传机制很弱经常出现画面花屏、卡顿甚至直接断流。OpenCvSharp 底层走的是 FFmpegFFmpeg 的rtsp_transport参数可以强制客户端使用 TCP让每条 RTP 包都通过 TCP 传输牺牲一点延迟换来稳定性。常见做法是在打开VideoCapture之前设置 OpenCvSharp 暴露的 FFmpeg 选项。这个选项的名字长且容易打错代码里要注意using OpenCvSharp; var capture new VideoCapture(); capture.Set(VideoCaptureProperties.OpenCvFFmpegCaptureOptions, rtsp_transport;tcp); capture.Open(rtspUrl, VideoCaptureAPIs.FFMPEG);这里的OpenCvFFmpegCaptureOptions对应 FFmpeg 的AVOption列表多个参数用分号分隔key 和 value 之间也用分号。这一行没有设置的话等效于让 FFmpeg 自己选传输方式往往就选 UDP。很多人在本地调试能用一部署到现场就黑屏多半是这个选项没写。如果你的项目是在海康、大华摄像头或者 NVR 上采集RTSP 地址里还有一层?查询参数比如是否启用子码流、是否强制主码流。这些参数不会被 OpenCvSharp 自动解析也不会被OpenCvFFmpegCaptureOptions覆盖。常见的做法是把摄像头厂商给定的完整 RTSP URL 原样传入比如海康的标准地址是rtsp://user:passip:554/Streaming/Channels/101这个 URL 本身不包含传输协议设置所以 TCP 设置仍然要靠上面的Set完成。2.2 MP4 容器对编码格式有要求为什么同样能写 AVI 却写不了 MP4OpenCvSharp 的VideoWriter在写文件时是通过 FourCC 编码标识来决定封装格式的。很多人直接把VideoWriter::fourcc(M,P,4,V)当成写 MP4 的标准结果发现文件扩展名是 .mp4但播放器打开后只有声音或直接不能解码这是因为 MP4V即 MPEG-4 Part 2在 FFmpeg 里对应的编码器是mpeg4这种编码虽然兼容性好但画质和压缩率远不如 H.264。而且很多播放器对 MP4 容器里的 MPEG-4 Part 2 视频支持并不好。摄像头 RTSP 流绝大多数输出的是 H.264或者 H.265但 OpenCvSharp 的 VideoWriter 对 H.265 的封装支持较弱所以录 MP4 最好直接用 H.264 编码写入。可惜 OpenCvSharp 自带的 VideoWriter 在老版本 OpenCvSharp 库中不支持 H.264 编码需要依赖 FFmpeg 的 H.264 编码器。解决办法是使用VideoWriter的扩展构造或者明确指定 FFmpeg 的编码器名称。在 OpenCvSharp 4.x 里推荐用下面这种写法using OpenCvSharp; var writer new VideoWriter( segment_001.mp4, VideoWriter.FourCC(H, 2, 6, 4), 25, new Size(1920, 1080));这个四参数的构造函数会尝试用 FFmpeg 定位 H.264 编码器。如果运行环境里 FFmpeg 没有带libx264或者 OpenCvSharp 的 native 库编译时没开启编码器构造会直接抛异常。这时候退而求其次可以用X,V,I,D或M,P,4,V先跑通流程但生产环境我强烈建议确认 H.264 可用。还存在一个更隐蔽的问题MP4 容器对视频流的时间戳、关键帧间隔要求比 AVI 严格得多。普通 AVI 文件就算帧间隔不规律播放器也能通过文件头信息强行渲染MP4 需要每个样本的 duration 和 composition time 对齐到容器的时间尺度否则快速拖动进度条时播放器会工作异常。OpenCvSharp 写 MP4 时时间戳完全取决于你喂给Write的帧和创建 VideoWriter 时设置的 FPS。也就是说如果你实际采集帧率是 20却用 25 创建 writerMP4 里就会产生明显的时间轴错位结果就是录像看起来快进或者卡顿。2.3 分段保存的本质文件切割而不是流切割分段保存这个词容易让人误解为「把一条 RTSP 流切成多段网络流」实际上它指的是「按时长或大小切换本地 MP4 文件」。在 OpenCvSharp 的实现里分段就是这样一个状态机当前文件写到设定时长后停止写入并释放当前VideoWriter再创建下一个文件名的VideoWriter。听起来简单但有几个关键点必须处理好。第一次分段往往发生在文件刚写了几十分钟甚至更短的时候如果当前视频流中正好处于两个关键帧之间那么切出来的前一个文件末尾会缺少完整的关键帧后一个文件开头也会从一个非关键帧开始播放器很可能报错。某些播放器能容忍破损开头但另一些则直接拒绝播放。这就是为什么很多人在「可分段保存」上遇到「只有第一段能打开」的翻车现场第一段是从关键帧开始的后续每段的开头却不是关键帧。解决方案有两个方向一是尽量把分段点对齐到关键帧但这需要读取视频编码层的SEI或者SPS/PPS信息OpenCvSharp 不直接暴露这些二是通过 opencv 的CAP_PROP_FOURCC或 FFmpeg 参数强制关键帧间隔让关键帧按固定周期出现然后在分段时等待下一个关键帧到达再切换。第二种做法在工程上更可控。后面第 4 章会给出具体参数。所以分段功能并不需要复杂的流媒体协议只需要一个定时循环加上一个可变的文件名。接下来给出完整实现。3. 用 C# OpenCvSharp 实现 RTSP 拉流 MP4 分段保存完整代码与参数说明3.1 工程准备NuGet 包和运行环境的三个前置项目建议使用 .NET 6 或更高版本如果是在 WinForm/WPF 里跑目标平台选 x64。需要安装两个 NuGet 包OpenCvSharp4和OpenCvSharp4.runtime.win。前者是库封装后者包含 Windows 上的 native DLL。如果少了第二个包运行时会出现DllNotFoundException或OpenCV native library not found。另外需要确认 FFmpeg 相关 DLL 是否完整。OpenCvSharp4.runtime.win 自带的 native 库里有 opencv_videoio_ffmpeg dll这个 dll 是从 FFmpeg 编译来的负责 RTSP 拉流和 MP4 写入。如果你的运行环境没有安装 VC 运行库或者杀毒软件把 dll 隔离了拉流会静默失败。启动前建议先检查 OpenCvSharp 是否真的能用 FFmpegusing OpenCvSharp; Console.WriteLine(Cv2.GetBuildInformation().Contains(FFMPEG));如果输出True说明 native 库带了 FFmpeg。否则需要换个版本的 runtime 包或者检查系统的 PATH。3.2 拉流、录制、分段切换的核心代码下面这段是我常用的一组实现它完成打开 RTSPTCP、创建 VideoWriter、循环读帧、按指定秒数切换文件、处理断流重连。我把它写成一个可直接改的类关键处都做了注释。using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; using OpenCvSharp; public class RtspSegmentRecorder { private readonly string _rtspUrl; private readonly string _outputDir; private readonly double _fps; private readonly int _segmentSeconds; private readonly Size _frameSize; private readonly ConcurrentQueueMat _frameQueue new(); private readonly CancellationTokenSource _cts new(); private volatile bool _isRunning; public RtspSegmentRecorder(string rtspUrl, string outputDir, double fps, Size frameSize, int segmentSeconds) { _rtspUrl rtspUrl; _outputDir outputDir; _fps fps; _frameSize frameSize; _segmentSeconds segmentSeconds; } public void Start() Task.Run(() CaptureLoop(_cts.Token)); public void Stop() _cts.Cancel(); private void CaptureLoop(CancellationToken token) { using var capture new VideoCapture(); // 强制走 TCP减少 UDP 丢包导致的卡顿 capture.Set(VideoCaptureProperties.OpenCvFFmpegCaptureOptions, rtsp_transport;tcp); if (!capture.Open(_rtspUrl, VideoCaptureAPIs.FFMPEG)) { Console.WriteLine(RTSP 打开失败准备重试); return; } _isRunning true; int segmentIndex 0; DateTime segmentStart DateTime.UtcNow; VideoWriter? writer CreateWriter(segmentIndex); // 注意: 主循环里不要做太耗时的操作写文件放在单独的线程更安全 while (!token.IsCancellationRequested) { using var frame new Mat(); if (!capture.Read(frame) || frame.Empty()) { Console.WriteLine(读取到空帧可能断流); Thread.Sleep(1000); break; // 实际生产环境应在这里触发重连 } // 检查是否需要切段 if ((DateTime.UtcNow - segmentStart).TotalSeconds _segmentSeconds) { writer?.Release(); segmentIndex; writer CreateWriter(segmentIndex); segmentStart DateTime.UtcNow; Console.WriteLine($已切换到第 {segmentIndex} 段); } writer?.Write(frame); } writer?.Release(); _isRunning false; } private VideoWriter? CreateWriter(int index) { string fileName Path.Combine(_outputDir, $segment_{index:D4}.mp4); // FourCC 为 (H,2,6,4) 时需要 FFmpeg 支持 H264 编码 return new VideoWriter(fileName, VideoWriter.FourCC(H, 2, 6, 4), _fps, _frameSize); } }这个实现有几个值得展开说的地方。第一OpenCvFFmpegCaptureOptions的设置必须在Open之前一旦连接建立再 Set 不会生效。第二CaptureLoop中using var frame会在每次循环末尾释放 Mat这里很关键如果释放帧时 writer 还在异步写入就会引发访问非法内存异常。所以下面我还会提供一个写线程方案避免因为frame生命周期和写文件线程之间的交叉而出问题。前面代码里VideoWriter的创建函数没有判断是否构造成功。如果 H.264 编码器不可用new VideoWriter不会立即抛异常而是在Write时返回 false。所以生产环境建议在创建后检查writer.IsOpened()否则后续写帧会静默失败。这也是很多「看起来代码没报错却没有输出任何文件」的原因。3.3 用双线程 帧队列隔离读取和写入单线程循环里capture.Read会阻塞等待下一帧如果网络抖动阻塞时间会很不均匀直接影响writer.Write的节奏。更好的做法是把读取和写入拆成两个线程中间放一个有界队列这样读取线程按照网络节奏拉帧写线程按照固定节拍写文件避免因为单帧慢导致整个循环被拖住。下面给出关键代码private void FrameProducer(CancellationToken token) { using var capture new VideoCapture(); capture.Set(VideoCaptureProperties.OpenCvFFmpegCaptureOptions, rtsp_transport;tcp); if (!capture.Open(_rtspUrl, VideoCaptureAPIs.FFMPEG)) return; while (!token.IsCancellationRequested) { var frame new Mat(); if (!capture.Read(frame) || frame.Empty()) break; frameQueue.Enqueue(frame); Thread.Sleep(1); // 把 CPU 让给写线程 } } private void FrameConsumer(CancellationToken token) { int index 0; DateTime segmentStart DateTime.UtcNow; VideoWriter? writer CreateWriter(index); while (!token.IsCancellationRequested) { if (!frameQueue.TryDequeue(out Mat? frame)) continue; if ((DateTime.UtcNow - segmentStart).TotalSeconds _segmentSeconds) { writer?.Release(); index; writer CreateWriter(index); segmentStart DateTime.UtcNow; } writer.Write(frame); frame.Dispose(); } }这个模型的关键是帧队列要限制大小否则拉流速度大于写盘速度时内存会暴涨。建议使用BlockingCollectionMat并指定容量满了就让采集线程阻塞等待这样自然形成背压。实际项目中我通常把容量设为 100~200 帧写线程大概落后采集线程几百毫秒既能保证连续写入又不会因为堆积太多帧导致延迟被过分拉大。3.4 关键参数帧率、分辨率、编码质量怎么定参数不是越多越好真正影响录制质量的只有下面几个。VideoCapture打开后可以通过Set设置请求分辨率但有些摄像头会强制忽略请求改为输出自己的默认分辨率。这意味着你创建 writer 时用的_frameSize必须和实际读到的帧大小一致否则 writer 会拒绝写入。稳妥做法是先Read第一帧拿它的尺寸去创建 writerusing var firstFrame new Mat(); capture.Read(firstFrame); var actualSize new Size(firstFrame.Width, firstFrame.Height);帧率同样不能想当然。如果摄像头子码流实际只有 15 帧你设成 25 会让 MP4 时间轴加快播放速度不对。建议通过capture.Get(VideoCaptureProperties.Fps)获取实际帧率如果读到 0 或者不可信再硬编码。编码质量上VideoWriter默认质量一般够用但 H.264 的码率控制默认是 CRF 之类的恒定质量模式。想要稳定码率可以继续通过 FFmpeg 选项调整。不过 OpenCvSharp 的 VideoWriter 暴露 FFmpeg 参数的方式比较弱通常我们需要预先设置 FFmpeg 全局选项capture.Set(VideoCaptureProperties.OpenCvFFmpegCaptureOptions, rtsp_transport;tcp|;preset;ultrafast|;crf;23|;gop;50);注意这里管道符分隔的含义OpenCvSharp 允许传入key;value|key;value这样的格式每个|分隔一对 key/value。上面设置了传输协议 TCP、编码预设 ultrafast编码快但文件稍大、CRF 23中等画质、gop关键帧间隔 50 帧25 帧率下每 2 秒一个关键帧。这个gop参数直接关系到分段切换时下一段能否从关键帧开始。如果摄像头是 H.264 编码写入端 FFmpeg 会重新编码强制 GOP 间隔最有效。4. 参数设置与调优让 OpenCvSharp 的写入节奏匹配 RTSP 流4.1 缓冲区大小不是越大越好CAP_PROP_BUFFERSIZE可以设置 FFmpeg 在解码端维护的帧缓冲区大小。默认值是 1意味着Read总是返回最新一帧延迟最低但网络抖动时会一卡一卡。调大到 4~8 可以让解码端缓存更多帧整体更流畅但代价是实时延迟增加大约 1~2 秒。对于录像场景延迟大一点没关系流畅度和稳定性优先对于需要同时预览的场景缓冲区建议保持默认或者只调到 2。实际中很多翻车现场不是卡顿而是缓冲区过大会导致内存持续增长。如果 FPS 是 25缓冲区 5 意味着内存里常驻 5 张 1080p 的 BGR 图每张大约 6MB合计 30MB这个量不大。但如果分辨率是 4K每张 24MB5 张就 120MB并且在录制线程和写线程之间还会有一层帧队列内存翻倍。所以设置完缓冲区后要观察进程内存不要只看画面是不是流畅。4.2 重连策略断开后不能只做一次RTSP 流在长时间运行时几乎必然遇到断流特别是摄像头重启、网络切换、NVR 重启等场景。常规做法是捕获到Read返回 false 后释放 capture然后指数退避重试。具体策略第一次重试等待 1 秒第二次 2 秒最多等待 10 秒重试时先重新初始化VideoCapture不要尝试同一个实例再次Open因为 FFmpeg 内部状态可能已经损坏重连成功之后当前 writer 继续使用但需要注意时间戳跳跃问题。因为断流中间缺了几十秒MP4 文件里当前段的时间轴会出现不连续。建议一旦重连成功就把当前段立即切割新起一段文件这样时间轴混乱的部分只出现在上一段末尾不会污染新段。这段逻辑很容易被忽略很多系统能跑几个小时但 24 小时后人不在现场结果录像在断流点之后全部偏掉排查起来很费劲。4.3 关键帧间隔与分段时间的关系分段保存时最好的做法是分段时间正好是关键帧间隔的整数倍。如果关键帧间隔是 2 秒50 帧分段切在 60 秒结束那么切点正好落在第 30 个关键帧上下一文件从关键帧开始完美。但在 OpenCvSharp 里无法精确控制的是Read出来的帧并不附带 PTS 或关键帧标志。如果你使用gop参数强制了编码关键帧间隔那么可以在分段时额外消耗掉一帧让实际切点略晚于指定秒数等待一个关键帧到达再切换。这个「多录几帧」的代价最小。在我的项目里分段没有采用秒级硬切而是每帧记录帧数当帧数达到segmentFrames且当前帧是关键帧时再切换。判断关键帧的常用手段是通过Mat的字节内容检测但 OpenCvSharp 没有直接 API。另一种简单粗暴方法是用VideoCapture的CAP_PROP_POS_FRAMES无法用于 RTSP所以不靠谱。实际可行的方案是让 FFmpeg 的gop参数把关键帧周期固定然后硬切。如果后续需要精确对齐建议用 FFmpeg 命令行来做二次处理OpenCvSharp 只负责原始分段。5. 分段录制避坑指南5 个血泪经验的复现与解决5.1 现象所有分段只有第一段能播放后续段打不开原因第一段从流开始的关键帧写入后续段开始写入时刚好写入的是采集到的某一个 B 帧或 P 帧MP4 头部记录的编码样本信息不完整播放器无法解码。这在分段时间较短比如 10 秒且摄像头默认关键帧间隔较长比如 4 秒时更容易触发。解决在使用 FFmpeg 编码时设置gop为较小的值比如 25 帧或 50 帧保证关键帧至少每秒一个。同时分段切换时不要立即创建新 writer而是等下一个关键帧到了再切。具体实现上可以在采集循环里检测当前帧相对上一帧是否发生了数据量的突变但误判率高。最可靠做法是接受 FFmpeg 的 GOP 设置切完段后如果新文件第一帧不是关键帧播放器可能仍然能靠后续关键帧恢复播放但为了万无一失我会在分段点把当前 writer 释放然后 Sleep 100ms让采集线程自然抓到下一帧。这个 Sleep 会让丢失一帧但换来了新文件从大概率的关键帧开始。注意不要在 Sleep 期间把 capture 释放否则重连逻辑会被误触发。5.2 现象强行设置CAP_PROP_FPS后录像播放速度异常原因部分摄像头驱动或 FFmpeg 支持通过CAP_PROP_FPS改变读取节奏但 OpenCvSharp 里这个属性往往只是设置读取端的请求不一定生效。如果实际采集到的是 20 帧你按 25 帧创建 writerMP4 的时长会比真实时长短 20%播放器显示的速度变快。解决拉流成功之后先Read几帧统计实际帧率或直接调用capture.Get(VideoCaptureProperties.Fps)取返回值。海康摄像头在子码流上经常返回 12.5 这样的非整数帧率VideoWriter 接受 double 型帧率直接传入即可。不要对帧率做取整操作。5.3 现象摄像头断电重启后程序莫名崩溃而不是正常重连原因VideoCapture.Read返回 false 后底层 FFmpeg 解复用器可能已经处于不稳定状态。此时你如果继续调用Write或者释放捕获对象时同时有另一个帧在正在被写入就会触发 OpenCV 里面的访问冲突异常类似 C# 调用 C 时的AccessViolationException。解决把采集和写入分割到两个线程采集线程只负责Read一旦读到空帧立即把对象标记为断流不再往队列里放帧写入线程在收到断流信号后先释放 writer再等待采集线程重新连接。这样即使底层 FFmpeg 状态崩溃写入线程也不会被拖累。另外要给Read调用加上重试保护如果连续 30 次读取返回 false强制销毁VideoCapture对象再new一个新的。重启进程永远比在一个坏对象上反复重试可靠。5.4 现象分段文件总是比设定时长多几秒且切段那一瞬间画面卡住原因分段逻辑里先writer.Release()再new VideoWriter这个释放过程要写 MP4 的 moov box在机械盘或 SMB 网络盘上可能耗时超过一帧的采集间隔导致采集线程阻塞画面停了一拍。解决不要等写入线程同步释放。使用第三个专门的重置线程做「预创建下一个 writer」在切换时间点前 2 秒就创建好下一个文件的 writer然后锁切换。或者干脆在切换时把writer.Release()放到后台任务但要注意同一个 writer 不能被并发写。我的做法是切段信号发到写线程写线程先结束当前 writer等待 500ms然后创建新 writer。这 500ms 内采集线程不丢弃帧而是积压在队列里这样画面不会卡只是文件时间会稍微延长。积压的帧用后台写线程写完后再开始写新文件这样时间和画面都能保住。5.5 现象录出的 MP4 文件大小正常但无法拖动进度条原因这是 MP4 容器在写入时没有正确合成时间索引导致的。OpenCvSharp 的 VideoWriter 在每次Write一帧时会记录一个时长时长以创建 writer 时的 FPS 为准。如果你传入的 FPS 是 25但实际上帧间隔不均匀网络抖动导致MP4 里各个 sample 的时间戳就错乱了。播放器在加载文件时无法建立正确的索引所以拖动进度条时在整个时间轴上找不到对应的关键帧位置。解决保证 writer 的 FPS 参数更贴近真实采集节奏。如果摄像头输出 25 帧但实际经过 OpenCvSharp 的 Read 会有间歇性丢帧建议在帧计数上统计每秒实际写入帧数再取平均值传给 writer。另外不要使用 MPEG-4 Part 2 编码H.264 的 sample 结构更规范。最后在写完文件后可以用 FFmpeg 的-movflags faststart重新 remux 一次但这个在 OpenCvSharp 内部做不到只能作为后期确认手段。6. 生产环境验证用 ffprobe 检查分段文件以及重连设计每生成一批分段文件绝不能只看文件大小非零就认为成功。我会在录制结束后或批量任务完成后用 FFmpeg 自带的ffprobe逐一检查关键信息。命令很简单ffprobe -v error -select_streams v:0 -show_entries streamcodec_name,width,height,avg_frame_rate -show_entries formatduration -of json segment_0042.mp4这个命令输出视频编码、分辨率、帧率和时长。重点关注两点codec_name是否 h264duration是否接近设定的分段秒数。如果 duration 明显偏短说明时间戳错乱如果 h264 缺失说明 writer 实际用了 fallback 编码。用脚本循环跑整个目录可以快速发现坏文件。对于重连设计我在生产环境里是这样做的每段文件在打开时先写入一个.part临时文件录制结束时重命名为.mp4。如果程序异常崩溃part文件不会被污染下次启动时可以直接扫出残留的part文件并删除。这个习惯帮我杜绝了「录了一个多小时最后发现文件没写完」的惨剧。分段文件名建议带上时间戳而不是纯序号。序号文件在跨天录制时会出现重名覆盖问题。我常用的格式是20240520_143000_001.mp4小时段在文件名里可读性很强排查问题的时候一眼能定位到时刻。最后一个值得养成的习惯录制进程中定期用Process查看自身内存和工作线程数一旦发现OpenCvSharp的对象数量持续增长就说明某个Mat或VideoCapture没有被释放。用using包住Mat让它在每次循环末尾自动 Dispose是避免内存泄漏最省心的方式。做这个功能我自己的经验是OpenCvSharp 不是不能做短视频分段但它适合做「能跑能出文件」的原型真正要稳定 7x24 运行你必须在它上面包一层状态机把断流重连、关键帧对齐、文件完整性检查这些脏活接过来。宁可多写几百行代码把最前面的坑填平也不要留着黑匣子让用户半夜打电话问为什么没录像。希望这些踩坑记录能帮你在走向生产环境时少走几次弯路。本文还有配套的精品资源点击获取
返回列表