C#视频开发心得

基本概念

RTSP:Real Time Streaming Protocol,实时流传输协议,注意:它类似与FTP协议里的控制端口21,并不处理视频流,视频流承载在RTP协议里。

RTP:Real Transport Protocol,实时传输协议,负责将编码后的视频流打包成适合网络传输的数据包

H264/H265,MPEG-4最新的视频格式,它是视频的存储格式,不用考虑网络传输,网络传输由RTP负责。

ONVIF 标准协议:它比RTSP功能更全面,能统一发现和管理不同品牌的摄像头,并获取它们的RTSP地址。这相当于在RTSP之上,加了一层更智能的"发现和管理"能力。

主码流:分辨率高、码率大、画质清晰。它的主要任务就是用于本地高清录像和存储,为事后回放提供最清晰的证据。追求画质的存储首选。

子码流:分辨率低、码率小、占用带宽少。它主要用于在手机APP或远程客户端上进行实时预览,确保在网络环境不佳时,画面依然能够保持流畅,不会出现卡顿。它优先保障的是观看的流畅性。

网络摄像机(IPC)

硬盘录像机(NVR)

RTSP地址

rtsp://xx:xx@192.168.1.30:554/Streaming/Channels/102 -vf "vflip"

路径中的 102 通常遵循"通道号 + 码流类型"的编码方式。

  • 第一位(1 :表示通道号。在大多数海康设备中,1 代表主通道(即摄像头本身)。
  • 第二位(0102 :用于指定码流类型。
    • 01 :代表主码流。画质最高,适合本地录像存储。
    • 02 :代表子码流。分辨率较低,适合远程预览以节省带宽。
    • 03 :代表第三码流。某些型号支持,用于额外的多流需求。

因此,102 明确指向了 "第 1 通道的子码流"

-vf "vflip" 是一个视频滤镜参数:

  • -vf :是 -filter:v 的缩写,用于应用视频滤镜。
  • vflip:表示"垂直翻转(Vertical Flip)"。它会将视频画面上下颠倒,通常是因为摄像头是倒置安装的(例如吸顶安装)。

rtsp://xx:xx@192.168.1.168:554/Streaming/Channels/102?transportmode=unicast

transportmode=multicastunicast 是 RTSP 地址中用来指定视频流数据在网络中的传输方式的参数。

简单来说,Unicast(单播)是"点对点"传输 ,服务器为每个客户端单独发送一份数据;Multicast(组播)是"点对多点"传输,服务器只发送一份数据,网络设备(如交换机)负责复制给多个客户端。

补充说明

上述地址是预览流,还有一种/Streaming/tracks的rtsp地址,用于回放流。

工具

python有个rtsp-network-scanner工具,能扫描某个ip的rtsp流清单:

复制代码
rtsp-network-scanner scan 192.168.1.100 -u admin -p xxx

还有一个更有效的方法是,下载VLC播放器,在"打开网络串"里输入rtsp流,如果该流正常,就能播放。VLC还能把rtsp流转成本地mp4。

onvif如何发现设备RTSP地址

要求设备支持onvif协议, 先通过WS-Discovery 网络协议(onvif协议的一部分)发现设备,再向设备询问RTSP地址,设备返回自身的RTSP地址。

onvif还可以通过PTZ(云台控制)来旋转摄像头。

工具

python有onvif-scanner包,pip安装后用下面命令扫描局域网:

复制代码
onvif-scan

HLS协议

HLS 是 HTTP Live Streaming 的缩写。这是一个由苹果公司(Apple)在 2009 年提出的基于 HTTP 的自适应码率流媒体网络传输协议。它通过将整个视频流切割成一系列基于 HTTP 的小文件(通常是 .ts 格式)来传输,并生成一个 .m3u8 播放列表文件供客户端按顺序请求播放。

m3u8是播放列表,ts是真正的视频片段。

访问海康摄像头

预览

我们需要实时预览摄像头,并在web上展示,可用如下方案:

  • RTSP拉子码流(节省带宽),用ffmpeg转成hls存到nginx目录下,前端用hls.js在web上播放。

用C#拼接的处理预览流的ffmpeg命令行如下:

c# 复制代码
private static string BuildFFmpegArgs(string rtspUrl, string segmentPattern, string playlistPath,
        CameraPreviewOptions opts)
{
    // -rtsp_transport tcp: more reliable than UDP over lossy networks
    // -c:v copy: most IP cameras already output H.264, copy to save CPU
    // -c:a aac: re-encode audio to AAC for HLS compatibility
    // -f hls: HLS muxer
    // -hls_time: segment length
    // -hls_list_size: rolling window of segments in playlist
    // -hls_flags delete_segments+omit_endlist: delete old segments, keep live stream
    // -hls_segment_filename: pattern for segment files
    return
        $"-rtsp_transport tcp -i \"{rtspUrl}\" " +
        $"-c:v copy -c:a aac " +
        $"-f hls -hls_time {opts.HlsTimeSeconds} -hls_list_size {opts.HlsListSize} " +
        $"-hls_flags delete_segments+omit_endlist " +
        $"-hls_segment_filename \"{segmentPattern}\" \"{playlistPath}\"";
}

子码流尺寸较小,预览流均匀顺序输出,ffmpeg处理一般很稳定,不易出错。

我们注意到,上述命令中,视频流是直接copy,音频流是编码aac,原因是:绝大多数摄像头的视频编码都是 H.264H.265 。它们是视频领域的通用标准,几乎被所有播放器和视频容器(如 MP4)所支持,因此可以直接复制。摄像头的音频编码可能会使用 G.711 (A-law 或 μ-law)或 G.726 ,这些是专门针对 IP 电话和监控设备设计的低带宽、低延迟编码格式。它们并不被标准 MP4 或 TS 容器视为原生支持的主流音频格式(通常为 AAC 或 MP3)。

回放

海康的回放流要先使用/ISAPI/ContentMgmt/search接口查找,而且默认只支持主码流。/ISAPI/ContentMgmt/search接口接受一个起止时间,返回的是一个或多个符合要求的回放RTSP流(因设备内部是分文件存储不同时段的录像的),这些RTSP流的总时长就是起止时间的总时长。

回放流一般是主码流,尺寸很大(可能是子码流的10倍),用ffmpeg实时处理,很容易mux缓冲溢出,报错:

复制代码
Too many packets buffered for output stream 0:0

建议使用如下ffmpeg选项:

复制代码
ffmpeg -rtsp_transport tcp -stimeout 5000000 -i "rtsp://admin:xxxx@192.168.0.6/Streaming/tracks/101/?starttime=20260812T101129Z&endtime=20260812T101139Z&name=00000000180000000&size=1064467600" -c:v copy -c:a aac -t 10 -max_muxing_queue_size 8192 -y out1.mp4 

其中:

-stimeout 5000000必须要给!因回放流有起止时间,但RTSP源到达结束时间时并不会发送EOF,导致tcp连接被挂住,整个ffmpeg进程也因此被挂住。指定-stimeout ,在5秒没接收到数据时,退出进程,增加健壮性。预览流也建议加上该选项,主要预防网络异常导致的ffmpeg进程挂住。

-max_muxing_queue_size 8192,缓解Too many packets buffered问题。这个值设置过大,在处理长时视频时,会导致内存占用很大(我设置8192,结果占了400M内存,总内存也才2G)

复用队列(Muxing Queue)溢出分析

这个错误的核心是 FFmpeg 的 muxer 在"等对齐"时缓冲区撑爆了

FFmpeg 在把多路流(视频 + 音频)封装进输出容器(如 MP4)时,有一个复用队列(muxing queue)。它的工作逻辑是:

  1. 必须等所有输出流都初始化后,muxer 才能开始写入文件
  2. 在此期间,已经读到的某一路流的 packet 会被缓冲在队列里
  3. 如果另一路流迟迟不来(或来得太慢),队列就会不断增长
  4. 超过默认上限(通常是几百个 packet)后,就会报错退出

海康 RTSP 回放流有以下几个特点,恰好踩中这个坑:

问题 说明
时间戳不连续/跳变 回放流的时间戳可能不是从 0 开始的,或者中间有 gap
音视频不同步 音频 packet 可能延迟到达,视频 packet 先堆积
流交错质量差 设备推送的流本身交错(interleaving)就不均匀
-c copy 时无法修正 如果用 copy 模式,FFmpeg 不能重新生成时间戳,只能原样封装,问题更突出

AI建议,对于回放流视频我们不用-c:v copy而是用:

复制代码
-c:v libx264 -preset fast -crf 24

实际上,重编码依然会出现Too many packets buffered问题 ,且,重编码的代价非常高昂,cpu会超负荷(百分之几百)运转。这对于我的项目来说,是没法接受的。

相关推荐
LccKyI23 分钟前
C#基础编程 面试题汇总(三)
笔记·c#
zhaoshuzhaoshu32 分钟前
声学三板斧概念SNR、THD、FR解析
音视频
淼澄研学44 分钟前
基于Docker与iptables的AI智能体网络隔离实操指南
开发语言·python
莫陌尛.1 小时前
Java核心知识点:直接内存、CPU密集型线程池、并行流对比文档
java·开发语言
西峰u1 小时前
Java多线程初阶完整总结|线程、锁、volatile、等待通知、常见案例
java·开发语言·jvm
sweetone1 小时前
可能这是该低音炮的通病——JAMO尊宝A3SUB.5低音炮破音故障之彻底排除
经验分享·音视频
夜雨声烦丿1 小时前
从需求到页面:日期计算器应用的 ArkTS 原生实现
开发语言·javascript·华为·harmonyos
EasyGBS2 小时前
连锁书店如何用国标GB28181公网平台EasyGBS把“远程巡店”做成日常基本功?
服务器·网络·音视频
程序员雪球2 小时前
本地IDEA打断点debug容器
java·开发语言